diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index 52ec53437..03ca0906b 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -24,4 +24,4 @@ jobs: java-version: 21 settings-path: ${{ github.workspace }} - name: Build Project - run: ./mvnw -B --no-transfer-progress package -Dlicense.skip=true + run: ./mvnw -B --no-transfer-progress install -Prelease -Dlicense.skip=true diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties index eacdc9ed1..346d645fd 100644 --- a/.mvn/wrapper/maven-wrapper.properties +++ b/.mvn/wrapper/maven-wrapper.properties @@ -14,5 +14,5 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar diff --git a/components/api/pom.xml b/components/api/pom.xml index d0f28a393..34220fd72 100644 --- a/components/api/pom.xml +++ b/components/api/pom.xml @@ -24,7 +24,6 @@ com.squareup.okhttp3 okhttp - 4.9.3 @@ -58,11 +57,6 @@ guava - - com.google.code.findbugs - annotations - - com.fasterxml.uuid java-uuid-generator diff --git a/components/client/pom.xml b/components/client/pom.xml index 33fa8f660..52e91a0f9 100644 --- a/components/client/pom.xml +++ b/components/client/pom.xml @@ -37,11 +37,6 @@ styx-api - - com.google.code.findbugs - annotations - - io.dropwizard.metrics metrics-json diff --git a/components/client/src/main/java/com/hotels/styx/client/HttpClient.java b/components/client/src/main/java/com/hotels/styx/client/HttpClient.java index 020158c0d..2374a5087 100644 --- a/components/client/src/main/java/com/hotels/styx/client/HttpClient.java +++ b/components/client/src/main/java/com/hotels/styx/client/HttpClient.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ /** * A Styx HTTP client interface. - * + *

* This interface offers a fluent interface to build and configure HTTP * request transactions from a client instance. The requests can be consumed * either aggregated {@link HttpResponse} or streaming {@link LiveHttpRequest} @@ -33,20 +33,7 @@ public interface HttpClient { /** - * Sends a HTTP request message using this client. - * - * @deprecated use {@link #send} instead. - * - * @param request a full HTTP request object - * @return a future of full HTTP request object - */ - @Deprecated - default CompletableFuture sendRequest(HttpRequest request) { - return send(request); - } - - /** - * Sends a HTTP request message using this client. + * Sends an HTTP request message using this client. * * @param request a full HTTP request object * @return a future of full HTTP request object @@ -54,8 +41,8 @@ default CompletableFuture sendRequest(HttpRequest request) { CompletableFuture send(HttpRequest request); /** - * A HTTP request transaction. - * + * An HTTP request transaction. + *

* This interface allows client attributes and context to be customised * for each request without having to rely on configured default values * in the client. @@ -80,7 +67,7 @@ interface Transaction { /** * Converts the transaction object to streaming transaction. - * + *

* A call to {@code streaming()} converts this {@link Transaction} object to * a {@link StreamingTransaction}. This allows responses to be consumed * in streaming responses. @@ -90,7 +77,7 @@ interface Transaction { StreamingTransaction streaming(); /** - * Sends a HTTP request message using this client. + * Sends an HTTP request message using this client. * * @param request a full HTTP request object * @return a future of full HTTP request object @@ -100,7 +87,7 @@ interface Transaction { /** * A streaming HTTP request transaction. - * + *

* This interface allows the response object to be consumed in a streaming * fashion instead of being aggregated into a HttpResponse. */ diff --git a/components/client/src/test/integration/scala/com/hotels/styx/client/OriginSupport.scala b/components/client/src/test/integration/scala/com/hotels/styx/client/OriginSupport.scala index b9a3f8870..a79e56620 100644 --- a/components/client/src/test/integration/scala/com/hotels/styx/client/OriginSupport.scala +++ b/components/client/src/test/integration/scala/com/hotels/styx/client/OriginSupport.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2022 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java b/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java index 7ec1577a9..b87344154 100644 --- a/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java +++ b/components/client/src/test/unit/java/com/hotels/styx/client/netty/connectionpool/NettyConnectionFactoryTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import com.hotels.styx.client.Connection; import com.hotels.styx.client.ConnectionSettings; import com.hotels.styx.support.server.FakeHttpServer; +import com.hotels.styx.support.server.UrlMatchingStrategies; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; diff --git a/components/proxy/pom.xml b/components/proxy/pom.xml index 748cabf1e..c0d9462f8 100644 --- a/components/proxy/pom.xml +++ b/components/proxy/pom.xml @@ -62,11 +62,6 @@ guava - - com.google.code.findbugs - annotations - - org.codehaus.janino diff --git a/components/proxy/src/test/java/com/hotels/styx/admin/handlers/ServiceProviderHandlerTest.java b/components/proxy/src/test/java/com/hotels/styx/admin/handlers/ServiceProviderHandlerTest.java index 2b6fb3634..4f1f34bf5 100644 --- a/components/proxy/src/test/java/com/hotels/styx/admin/handlers/ServiceProviderHandlerTest.java +++ b/components/proxy/src/test/java/com/hotels/styx/admin/handlers/ServiceProviderHandlerTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,13 +17,13 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.hotels.styx.StyxObjectRecord; import com.hotels.styx.api.HttpRequest; import com.hotels.styx.api.HttpResponse; import com.hotels.styx.api.extension.service.spi.StyxService; import com.hotels.styx.routing.config.StyxObjectDefinition; import com.hotels.styx.routing.db.StyxObjectStore; -import com.hotels.styx.StyxObjectRecord; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; import reactor.core.publisher.Mono; @@ -35,10 +35,10 @@ import java.util.Optional; import java.util.stream.Collectors; -import static com.hotels.styx.support.Support.requestContext; import static com.hotels.styx.api.HttpResponseStatus.NOT_FOUND; import static com.hotels.styx.api.HttpResponseStatus.NO_CONTENT; import static com.hotels.styx.api.HttpResponseStatus.OK; +import static com.hotels.styx.support.Support.requestContext; import static java.nio.charset.StandardCharsets.UTF_8; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; diff --git a/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java b/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java index 8279a99a0..0c72db26c 100644 --- a/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java +++ b/components/proxy/src/test/java/com/hotels/styx/proxy/StyxProxyTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -139,6 +139,6 @@ private HttpResponse get(String uri) { } private HttpResponse execute(HttpRequest request) { - return await(client.sendRequest(request)); + return await(client.send(request)); } } diff --git a/components/server/src/main/kotlin/com/hotels/styx/server/netty/SslContexts.kt b/components/server/src/main/kotlin/com/hotels/styx/server/netty/SslContexts.kt index 0796fe6b7..71e5107c8 100644 --- a/components/server/src/main/kotlin/com/hotels/styx/server/netty/SslContexts.kt +++ b/components/server/src/main/kotlin/com/hotels/styx/server/netty/SslContexts.kt @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,12 +17,15 @@ package com.hotels.styx.server.netty import com.hotels.styx.metrics.CentralisedMetrics import com.hotels.styx.server.HttpsConnectorConfig -import io.netty.handler.ssl.* +import io.netty.handler.ssl.OpenSslSessionContext +import io.netty.handler.ssl.OpenSslSessionStats +import io.netty.handler.ssl.SslContext +import io.netty.handler.ssl.SslContextBuilder +import io.netty.handler.ssl.SslProvider import io.netty.handler.ssl.util.SelfSignedCertificate import java.io.File import java.util.concurrent.TimeUnit.MILLISECONDS - /** * Produce an SslContext based on the provided configuration. * @@ -42,12 +45,17 @@ fun HttpsConnectorConfig.newSSLContext(): SslContext = * @param metrics metrics * @return SslContext */ -fun newSSLContext(httpsConnectorConfig: HttpsConnectorConfig, metrics: CentralisedMetrics) = - httpsConnectorConfig.newSSLContext().apply { - registerOpenSslStats(this, metrics) - } +fun newSSLContext( + httpsConnectorConfig: HttpsConnectorConfig, + metrics: CentralisedMetrics, +) = httpsConnectorConfig.newSSLContext().apply { + registerOpenSslStats(this, metrics) +} -private fun registerOpenSslStats(sslContext: SslContext, metrics: CentralisedMetrics) { +private fun registerOpenSslStats( + sslContext: SslContext, + metrics: CentralisedMetrics, +) { sslContext.sessionContext().ifInstanceOf { it.stats().let { stats -> metrics.proxy.server.openssl.run { diff --git a/components/server/src/main/kotlin/com/hotels/styx/server/netty/codec/UrlDecoder.kt b/components/server/src/main/kotlin/com/hotels/styx/server/netty/codec/UrlDecoder.kt index e172f9d44..6248e9c9a 100644 --- a/components/server/src/main/kotlin/com/hotels/styx/server/netty/codec/UrlDecoder.kt +++ b/components/server/src/main/kotlin/com/hotels/styx/server/netty/codec/UrlDecoder.kt @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2023 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -24,16 +24,20 @@ import java.net.URI object UrlDecoder { @JvmStatic - fun decodeUrl(unwiseCharEncoder: UnwiseCharsEncoder, request: HttpRequest): Url { + fun decodeUrl( + unwiseCharEncoder: UnwiseCharsEncoder, + request: HttpRequest, + ): Url { val host = request.headers()[HOST] return if (request.uri().startsWith("/") && host != null) { val encodedUrl = "http://$host${unwiseCharEncoder.encode(request.uri())}" - val uri = try { - URI.create(encodedUrl) - } catch (e: IllegalArgumentException) { - encodedUrl.toHttpUrlOrNull()!!.toUri() - } + val uri = + try { + URI.create(encodedUrl) + } catch (e: IllegalArgumentException) { + encodedUrl.toHttpUrlOrNull()!!.toUri() + } Url.Builder() .path(uri.rawPath) .rawQuery(uri.rawQuery) @@ -44,4 +48,3 @@ object UrlDecoder { } } } - diff --git a/components/test-api/pom.xml b/components/test-api/pom.xml index efd51d0d4..32fd825a5 100644 --- a/components/test-api/pom.xml +++ b/components/test-api/pom.xml @@ -63,7 +63,7 @@ - com.github.tomakehurst + org.wiremock wiremock compile diff --git a/components/test-api/src/test/java/com/hotels/styx/testapi/StyxServerTest.java b/components/test-api/src/test/java/com/hotels/styx/testapi/StyxServerTest.java index dd3685ad8..06aa4f85a 100644 --- a/components/test-api/src/test/java/com/hotels/styx/testapi/StyxServerTest.java +++ b/components/test-api/src/test/java/com/hotels/styx/testapi/StyxServerTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -34,6 +34,7 @@ import java.util.Optional; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.anyUrl; import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; @@ -83,18 +84,18 @@ public void startOrigins() { secureOriginServer.start(); configureFor(originServer1.port()); - stubFor(WireMock.get(urlPathEqualTo("/")).willReturn(aResponse() + stubFor(WireMock.get(anyUrl()).willReturn(aResponse() .withHeader("origin", "first") .withStatus(OK.code()))); configureFor(originServer2.port()); - stubFor(WireMock.get(urlPathEqualTo("/")).willReturn(aResponse() + stubFor(WireMock.get(anyUrl()).willReturn(aResponse() .withHeader("origin", "second") .withStatus(OK.code()))); // HTTP port is still used to identify the WireMockServer, even when we are using it for HTTPS configureFor(secureOriginServer.port()); - stubFor(WireMock.get(urlPathEqualTo("/")).willReturn(aResponse() + stubFor(WireMock.get(anyUrl()).willReturn(aResponse() .withHeader("origin", "secure") .withStatus(OK.code()))); } @@ -119,7 +120,7 @@ public void proxiesToOrigin() { .addRoute("/", originServer1.port()) .start(); - HttpResponse response = await(client.sendRequest(get(format("https://localhost:%d/", styxServer.proxyHttpPort())).build())); + HttpResponse response = await(client.send(get(format("https://localhost:%d/", styxServer.proxyHttpPort())).build())); assertThat(response.status(), is(OK)); configureFor(originServer1.port()); @@ -133,7 +134,7 @@ public void startsProxyOnSpecifiedHttpPort() { .addRoute("/", originServer1.port()) .start(); - HttpResponse response = await(client.sendRequest(get(format("https://localhost:%d/", styxServer.proxyHttpPort())).build())); + HttpResponse response = await(client.send(get(format("https://localhost:%d/", styxServer.proxyHttpPort())).build())); assertThat(response.status(), is(OK)); } @@ -145,7 +146,7 @@ public void startsAdminOnSpecifiedHttpPort() { .addRoute("/", originServer1.port()) .start(); - HttpResponse response = await(client.sendRequest(get(format("https://localhost:%d/admin", styxServer.adminPort())).build())); + HttpResponse response = await(client.send(get(format("https://localhost:%d/admin", styxServer.adminPort())).build())); assertThat(response.status(), is(OK)); } @@ -161,7 +162,7 @@ public void startsProxyOnSpecifiedHttpsPort() { .tlsSettings(new TlsSettings.Builder().build()) .build(); - HttpResponse response = await(tlsClient.sendRequest(get(format("https://localhost:%d/", styxServer.proxyHttpsPort())).build())); + HttpResponse response = await(tlsClient.send(get(format("https://localhost:%d/", styxServer.proxyHttpsPort())).build())); assertThat(response.status(), is(OK)); } @@ -195,7 +196,7 @@ public void proxiesToOriginViaHttps() { .tlsSettings(new TlsSettings.Builder().build()) .build(); - HttpResponse response = await(tlsClient.sendRequest(get(format("https://localhost:%d/", styxServer.proxyHttpsPort())).build())); + HttpResponse response = await(tlsClient.send(get(format("https://localhost:%d/", styxServer.proxyHttpsPort())).build())); assertThat(response.status(), is(OK)); configureFor(secureOriginServer.port()); @@ -212,7 +213,7 @@ public void proxiesToOriginViaHttpsWithRequestOriginallyHttp() { .addRoute("/", backendService) .start(); - HttpResponse response = await(client.sendRequest(get(format("http://localhost:%d/", styxServer.proxyHttpPort())).build())); + HttpResponse response = await(client.send(get(format("http://localhost:%d/", styxServer.proxyHttpPort())).build())); assertThat(response.status(), is(OK)); configureFor(secureOriginServer.port()); @@ -226,12 +227,12 @@ public void routesCorrectly() { .addRoute("/o2/", originServer2.port()) .start(); - HttpResponse response1 = await(client.sendRequest(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); + HttpResponse response1 = await(client.send(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); assertThat(response1.status(), is(OK)); assertThat(response1.header("origin"), isValue("first")); - HttpResponse response2 = await(client.sendRequest(get(format("http://localhost:%d/o2/foo", styxServer.proxyHttpPort())).build())); + HttpResponse response2 = await(client.send(get(format("http://localhost:%d/o2/foo", styxServer.proxyHttpPort())).build())); assertThat(response2.status(), is(OK)); assertThat(response2.header("origin"), isValue("second")); @@ -255,7 +256,7 @@ public void executesPluginsWhenProxying() { .addPluginFactory("response-decorator", pluginFactory, null) .start(); - HttpResponse response = await(client.sendRequest(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); + HttpResponse response = await(client.send(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); assertThat(response.status(), is(OK)); assertThat(response.header("origin"), isValue("first")); assertThat(response.header("plugin-executed"), isValue("yes")); @@ -344,7 +345,7 @@ private Plugin mockPlugin(Map adminInterfaceHandlers) { private HttpResponse doAdminRequest(String path) { String url = format("%s://localhost:%s%s", "http", styxServer.adminPort(), startWithSlash(path)); - return await(client.sendRequest(get(url).build())); + return await(client.send(get(url).build())); } @Test @@ -368,11 +369,11 @@ public void canConfigureWithStyxOrigins() { .addRoute("/o2/", origin(originServer2.port())) .start(); - HttpResponse response1 = await(client.sendRequest(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); + HttpResponse response1 = await(client.send(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); assertThat(response1.status(), is(OK)); assertThat(response1.header("origin"), isValue("first")); - HttpResponse response2 = await(client.sendRequest(get(format("http://localhost:%d/o2/foo", styxServer.proxyHttpPort())).build())); + HttpResponse response2 = await(client.send(get(format("http://localhost:%d/o2/foo", styxServer.proxyHttpPort())).build())); assertThat(response2.status(), is(OK)); assertThat(response2.header("origin"), isValue("second")); @@ -389,11 +390,11 @@ public void canConfigureWithBackendService() { .addRoute("/o2/", new BackendService().addOrigin(originServer2.port())) .start(); - HttpResponse response1 = await(client.sendRequest(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); + HttpResponse response1 = await(client.send(get(format("http://localhost:%d/foo", styxServer.proxyHttpPort())).build())); assertThat(response1.status(), is(OK)); assertThat(response1.header("origin"), isValue("first")); - HttpResponse response2 = await(client.sendRequest(get(format("http://localhost:%d/o2/foo", styxServer.proxyHttpPort())).build())); + HttpResponse response2 = await(client.send(get(format("http://localhost:%d/o2/foo", styxServer.proxyHttpPort())).build())); assertThat(response2.status(), is(OK)); assertThat(response2.header("origin"), isValue("second")); diff --git a/demo/pom.xml b/demo/pom.xml index ab6225fc6..978d7e991 100644 --- a/demo/pom.xml +++ b/demo/pom.xml @@ -25,7 +25,7 @@ kotlin-stdlib - com.github.tomakehurst + org.wiremock wiremock diff --git a/demo/src/test/kotlin/com/hotels/styx/demo/DemoOrigin.kt b/demo/src/test/kotlin/com/hotels/styx/demo/DemoOrigin.kt index 28a166ef8..c45f439df 100644 --- a/demo/src/test/kotlin/com/hotels/styx/demo/DemoOrigin.kt +++ b/demo/src/test/kotlin/com/hotels/styx/demo/DemoOrigin.kt @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,16 +18,14 @@ package com.hotels.styx.demo import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.MappingBuilder import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder -import com.github.tomakehurst.wiremock.client.UrlMatchingStrategy -import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock.aResponse -import com.github.tomakehurst.wiremock.common.FileSource +import com.github.tomakehurst.wiremock.client.WireMock.get +import com.github.tomakehurst.wiremock.client.WireMock.urlMatching import com.github.tomakehurst.wiremock.core.WireMockConfiguration -import com.github.tomakehurst.wiremock.extension.ResponseTransformer -import com.github.tomakehurst.wiremock.http.QueryParameter -import com.github.tomakehurst.wiremock.http.Request -import com.github.tomakehurst.wiremock.http.ResponseDefinition -import com.hotels.styx.api.HttpResponseStatus +import com.github.tomakehurst.wiremock.extension.ResponseTransformerV2 +import com.github.tomakehurst.wiremock.http.Response +import com.github.tomakehurst.wiremock.stubbing.ServeEvent +import com.hotels.styx.api.HttpResponseStatus.statusWithCode /** * This can be executed to launch a fake backend on localhost:9090. @@ -49,10 +47,14 @@ fun main() { println("Demo origin started on port $port") } -fun launchDemoOrigin(port: Int = 9090, path: String = "/"): WireMockServer { - val config = WireMockConfiguration() - .port(port) - .extensions(DemoTransformer()) +fun launchDemoOrigin( + port: Int = 9090, + path: String = "/", +): WireMockServer { + val config = + WireMockConfiguration() + .port(port) + .extensions(DemoTransformer()) return WireMockServer(config).apply { stub(path) { @@ -65,32 +67,36 @@ fun launchDemoOrigin(port: Int = 9090, path: String = "/"): WireMockServer { } } -private class DemoTransformer : ResponseTransformer() { - override fun name(): String = "demo" - - override fun transform(request: Request, responseDefinition: ResponseDefinition, files: FileSource) = - responseDefinition.apply { - status = request.queryParam("status")?.toInt() ?: 200 - - body = request.queryParam("body") - ?: "Demo origin response. Status = ${HttpResponseStatus.statusWithCode(status)}" +private class DemoTransformer : ResponseTransformerV2 { + override fun getName(): String = "demo" + + override fun transform( + response: Response, + serveEvent: ServeEvent, + ): Response = + serveEvent.request.let { req -> + val status = req.queryParameter("status")?.takeIf { it.isPresent }?.firstValue()?.toInt() ?: 200 + Response.Builder.like(response) + .status(status) + .body( + req.queryParameter("body")?.takeIf { it.isPresent }?.firstValue() + ?: "Demo origin response. Status = ${statusWithCode(status)}", + ) + .build() } override fun applyGlobally() = false } -private fun Request.queryParam(name: String): String? = queryParameter(name).value1() -private fun QueryParameter.value1(): String? = if (isPresent) firstValue() else null - -private inline fun WireMockServer.stub(startsWith: String, block: ResponseDefinitionBuilder.() -> Unit) = apply { +private inline fun WireMockServer.stub( + startsWith: String, + block: ResponseDefinitionBuilder.() -> Unit, +) = apply { stubFor( urlMatchingPattern("$startsWith.*").willReturn( - aResponse().apply(block) - ) + aResponse().apply(block), + ), ) } -private fun urlMatchingPattern(pattern: String): MappingBuilder = - WireMock.get(UrlMatchingStrategy().apply { - setUrlPattern(pattern) - }) +private fun urlMatchingPattern(pattern: String): MappingBuilder = get(urlMatching(pattern)) diff --git a/demo/src/test/kotlin/com/hotels/styx/demo/DemoOriginTest.kt b/demo/src/test/kotlin/com/hotels/styx/demo/DemoOriginTest.kt index 811815577..2da96d0b5 100644 --- a/demo/src/test/kotlin/com/hotels/styx/demo/DemoOriginTest.kt +++ b/demo/src/test/kotlin/com/hotels/styx/demo/DemoOriginTest.kt @@ -15,15 +15,16 @@ */ package com.hotels.styx.demo -import io.kotest.matchers.shouldBe import io.kotest.core.spec.style.FeatureSpec +import io.kotest.matchers.shouldBe import java.net.HttpURLConnection import java.net.URL class DemoOriginTest : FeatureSpec({ feature("Normal response") { - val port = launchDemoOrigin(0).port() + val server = launchDemoOrigin(0) + val port = server.port() val (status, body) = call(port, "/") @@ -59,14 +60,20 @@ class DemoOriginTest : FeatureSpec({ } }) -private fun call(port: Int, path: String = "/"): Pair { +private fun call( + port: Int, + path: String = "/", +): Pair { val path0 = if (path.startsWith("/")) path else "/$path" val url = URL("http://localhost:$port$path0") val connection = url.openConnection().apply { connect() } as HttpURLConnection - return Pair(connection.responseCode, connection.inputStream.use { - it.bufferedReader().readText() - }) + return Pair( + connection.responseCode, + connection.inputStream.use { + it.bufferedReader().readText() + }, + ) } diff --git a/docs/developer-guide.md b/docs/developer-guide.md index 3c92eb8ad..51fe02520 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -10,7 +10,7 @@ In this guide we will walk through how to build applications on top of Styx. Building Styx requires Java 21. -The build system requires Apache Maven. The Styx team uses Maven version 3.2.1 +The build system requires Apache Maven. The Styx team uses Maven version 3 for automated continuous integration builds. On Mac OSX, a version installed by HomeBrew is satisfactory. diff --git a/docs/user-guide/basic-usage.md b/docs/user-guide/basic-usage.md index ebb808959..7796cab1f 100644 --- a/docs/user-guide/basic-usage.md +++ b/docs/user-guide/basic-usage.md @@ -12,7 +12,7 @@ Alternatively, you can build styx from source code. ## Building Styx from source code In order to build styx from source code, Java 21 is required. - The build system requires Apache Maven. The Styx CI pipeline uses Maven version 3.2.1 + The build system requires Apache Maven. The Styx CI pipeline uses Maven version 3 for the automated continuous integration builds. On Mac OSX, a version installed by HomeBrew is satisfactory. diff --git a/pom.xml b/pom.xml index 15d42297f..0bb6e35ec 100644 --- a/pom.xml +++ b/pom.xml @@ -100,67 +100,72 @@ 21 + 4.13.1 1.77 - 33.0.0-jre - 2.15.3 + 1.14.12 4.2.25 - 1.10.13 - 4.5.3 - 4.1.106.Final - - 1.0.4 - 2023.0.2 + 33.0.0-jre + 2.1.12 + 2.15.4 + 3.1.12 + 1.12.3 + 4.1.107.Final + 4.12.0 3.0.5 - 1.14.11 + 1.0.4 + 2023.0.3 1.9.22 5.8.0 true - 0.11.0 + 0.11.0 - 4.3.0 + 5.0.0 - 1.4.14 - 2.0.11 + 1.5.1 + 2.0.12 2.12 2.12.18 + 2.8.5 2.2 + 5.10.2 5.10.0 - 1.13.9 - 5.10.1 + 1.13.10 3.0.9 1.17.0 1.0.2 + 3.4.2 3.1.0 3.6.0 - 3.3.0 - 3.11.0 - 3.6.0 + 3.3.1 + 3.12.1 + 3.6.1 3.1.1 3.4.1 - 3.1.2 + 3.2.5 3.1.1 3.3.0 - 3.21.0 - 3.6.0 - 3.4.5 + 3.21.2 + 3.6.3 + 3.5.0 3.0.1 3.3.1 3.12.1 3.3.0 - 3.1.2 + 3.2.5 - 3.4.0 + 3.5.0 0.8.11 - 1.6.8 + 1.6.13 + 4.8.1 jacoco @@ -292,6 +297,12 @@ ${bytebuddy.version} + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + io.micrometer @@ -356,7 +367,7 @@ org.hdrhistogram HdrHistogram - 2.1.12 + ${hdrhistogram.version} @@ -413,7 +424,7 @@ org.codehaus.janino janino - 3.1.11 + ${janino.version} @@ -429,22 +440,6 @@ ${bcpkix-jdk18on.version} - - - com.google.code.findbugs - jsr305 - 3.0.2 - provided - true - - - - com.google.code.findbugs - annotations - 3.0.1 - provided - - com.hotels.styx styx-testsupport @@ -504,21 +499,21 @@ com.typesafe.akka akka-actor_${scala.version} - 2.5.32 + ${akka.version} test com.typesafe.akka akka-testkit_${scala.version} - 2.5.32 + ${akka.version} test - com.github.tomakehurst + org.wiremock wiremock - 1.54 + ${wiremock.version} test @@ -531,7 +526,7 @@ org.jetbrains.kotlinx kotlinx-html-jvm - ${kotlinx.html.version} + ${kotlinx-html.version} @@ -621,7 +616,7 @@ net.alchim31.maven scala-maven-plugin - 4.8.0 + ${scala-maven-plugin.version} scala-test-compile @@ -690,7 +685,7 @@ org.apache.ant ant-launcher - 1.10.7 + 1.10.14 @@ -877,7 +872,7 @@ true - [3.2.1,) + [3.9.6,) [21,) diff --git a/support/api-testsupport/pom.xml b/support/api-testsupport/pom.xml index 49da811df..b40cc7284 100755 --- a/support/api-testsupport/pom.xml +++ b/support/api-testsupport/pom.xml @@ -53,7 +53,7 @@ - com.github.tomakehurst + org.wiremock wiremock compile diff --git a/support/api-testsupport/src/main/java/com/hotels/styx/support/api/FakeHttpServer.java b/support/api-testsupport/src/main/java/com/hotels/styx/support/api/FakeHttpServer.java index f121e574b..ce47ce054 100644 --- a/support/api-testsupport/src/main/java/com/hotels/styx/support/api/FakeHttpServer.java +++ b/support/api-testsupport/src/main/java/com/hotels/styx/support/api/FakeHttpServer.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.MappingBuilder; -import com.github.tomakehurst.wiremock.client.RequestPatternBuilder; import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.UrlMatchingStrategy; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.common.HttpsSettings; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; +import com.github.tomakehurst.wiremock.matching.UrlPattern; import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; @@ -89,9 +89,9 @@ public FakeHttpServer start() { return this; } - public FakeHttpServer stub(UrlMatchingStrategy urlMatchingStrategy, ResponseDefinitionBuilder response) { + public FakeHttpServer stub(UrlPattern urlPattern, ResponseDefinitionBuilder response) { configureFor("localhost", adminPort()); - stubFor(WireMock.get(urlMatchingStrategy).willReturn(response)); + stubFor(WireMock.get(urlPattern).willReturn(response)); return this; } diff --git a/support/testsupport/pom.xml b/support/testsupport/pom.xml index 09860c1a6..b6140431d 100755 --- a/support/testsupport/pom.xml +++ b/support/testsupport/pom.xml @@ -51,7 +51,7 @@ - com.github.tomakehurst + org.wiremock wiremock compile diff --git a/support/testsupport/src/main/java/com/hotels/styx/support/server/FakeHttpServer.java b/support/testsupport/src/main/java/com/hotels/styx/support/server/FakeHttpServer.java index 260e18548..e3fd4fd4d 100644 --- a/support/testsupport/src/main/java/com/hotels/styx/support/server/FakeHttpServer.java +++ b/support/testsupport/src/main/java/com/hotels/styx/support/server/FakeHttpServer.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.MappingBuilder; -import com.github.tomakehurst.wiremock.client.RequestPatternBuilder; import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.UrlMatchingStrategy; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.common.HttpsSettings; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; +import com.github.tomakehurst.wiremock.matching.UrlPattern; import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; @@ -89,9 +89,9 @@ public FakeHttpServer start() { return this; } - public FakeHttpServer stub(UrlMatchingStrategy urlMatchingStrategy, ResponseDefinitionBuilder response) { + public FakeHttpServer stub(UrlPattern urlPattern, ResponseDefinitionBuilder response) { configureFor("localhost", adminPort()); - stubFor(WireMock.get(urlMatchingStrategy).willReturn(response)); + stubFor(WireMock.get(urlPattern).willReturn(response)); return this; } diff --git a/support/testsupport/src/main/java/com/hotels/styx/support/server/UrlMatchingStrategies.java b/support/testsupport/src/main/java/com/hotels/styx/support/server/UrlMatchingStrategies.java index c9bf711c0..3859114bc 100644 --- a/support/testsupport/src/main/java/com/hotels/styx/support/server/UrlMatchingStrategies.java +++ b/support/testsupport/src/main/java/com/hotels/styx/support/server/UrlMatchingStrategies.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,21 +15,19 @@ */ package com.hotels.styx.support.server; -import com.github.tomakehurst.wiremock.client.UrlMatchingStrategy; +import com.github.tomakehurst.wiremock.matching.UrlPattern; + +import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; public final class UrlMatchingStrategies { private UrlMatchingStrategies() { } - public static UrlMatchingStrategy urlStartingWith(String url) { - UrlMatchingStrategy urlStrategy = new UrlMatchingStrategy(); - urlStrategy.setUrlPattern(url + ".*"); - return urlStrategy; + public static UrlPattern urlStartingWith(String url) { + return urlMatching(url + ".*"); } - public static UrlMatchingStrategy urlEndingWith(String url) { - UrlMatchingStrategy urlStrategy = new UrlMatchingStrategy(); - urlStrategy.setUrlPattern(".*" + url); - return urlStrategy; + public static UrlPattern urlEndingWith(String url) { + return urlMatching(".*" + url); } } diff --git a/system-tests/e2e-suite/pom.xml b/system-tests/e2e-suite/pom.xml index b1297d655..d8440da98 100644 --- a/system-tests/e2e-suite/pom.xml +++ b/system-tests/e2e-suite/pom.xml @@ -50,11 +50,6 @@ runtime - - com.google.code.findbugs - jsr305 - - org.scalacheck scalacheck_${scala.version} @@ -100,7 +95,7 @@ - com.github.tomakehurst + org.wiremock wiremock diff --git a/system-tests/e2e-suite/src/test/java/com/hotels/styx/http/StaticFileOnRealServerIT.java b/system-tests/e2e-suite/src/test/java/com/hotels/styx/http/StaticFileOnRealServerIT.java index 467f9f1c6..de91c52c0 100644 --- a/system-tests/e2e-suite/src/test/java/com/hotels/styx/http/StaticFileOnRealServerIT.java +++ b/system-tests/e2e-suite/src/test/java/com/hotels/styx/http/StaticFileOnRealServerIT.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -81,7 +81,7 @@ public void shouldWorkInRealServer() throws Exception { .header("Host", serverEndpoint) .build(); - HttpResponse response = await(client.sendRequest(request)); + HttpResponse response = await(client.send(request)); assertThat(response.bodyAs(UTF_8), is("Hello World")); } diff --git a/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/ProtocolMetricsTest.java b/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/ProtocolMetricsTest.java index ce1ce80cd..498814939 100644 --- a/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/ProtocolMetricsTest.java +++ b/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/ProtocolMetricsTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -118,7 +118,7 @@ private static HttpResponse doRequest(HttpClient client, String protocol, int po .body("foobarbaz", UTF_8) .build(); - return await(client.sendRequest(request)); + return await(client.send(request)); } private static String startWithSlash(String path) { diff --git a/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/StyxMetrics.java b/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/StyxMetrics.java index c8af2f178..feb22b9e8 100644 --- a/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/StyxMetrics.java +++ b/system-tests/e2e-suite/src/test/java/com/hotels/styx/metrics/StyxMetrics.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -159,7 +159,7 @@ private static Object toGauge(Map map) { private static String downloadJsonString(String host, int port) { StyxHttpClient client = new StyxHttpClient.Builder().build(); - HttpResponse response = await(client.sendRequest(get(format("http://%s:%d/admin/metrics", host, port)).build())); + HttpResponse response = await(client.send(get(format("http://%s:%d/admin/metrics", host, port)).build())); return response.bodyAs(UTF_8); } diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/CipherSuitesSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/CipherSuitesSpec.scala index 4d3396b95..2fc39a350 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/CipherSuitesSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/CipherSuitesSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,10 +15,8 @@ */ package com.hotels.styx.client -import java.nio.charset.StandardCharsets.UTF_8 - +import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock._ -import com.github.tomakehurst.wiremock.client.{ValueMatchingStrategy, WireMock} import com.hotels.styx.api.HttpRequest.get import com.hotels.styx.api.HttpResponseStatus.OK import com.hotels.styx.support.ResourcePaths.fixturesHome @@ -28,6 +26,8 @@ import com.hotels.styx.utils.StubOriginHeader.STUB_ORIGIN_INFO import com.hotels.styx.{StyxClientSupplier, StyxProxySpec} import org.scalatest.{FunSpec, SequentialNestedSuiteExecution} +import java.nio.charset.StandardCharsets.UTF_8 + class CipherSuitesSpec extends FunSpec with StyxProxySpec @@ -108,7 +108,7 @@ class CipherSuitesSpec extends FunSpec originA.verify( getRequestedFor( urlEqualTo("/compatible/a")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))) + .withHeader("X-Forwarded-Proto", matching("http"))) } it("Fails to handshake with an origin with incompatible cipher suite.") { @@ -122,12 +122,6 @@ class CipherSuitesSpec extends FunSpec def httpRequest(path: String) = get(styxServer.routerURL(path)).build() - def valueMatchingStrategy(matches: String) = { - val matchingStrategy = new ValueMatchingStrategy() - matchingStrategy.setMatches(matches) - matchingStrategy - } - def originResponse(appId: String) = aResponse .withStatus(200) .withHeader(STUB_ORIGIN_INFO.toString, appId) diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/HealthCheckSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/HealthCheckSpec.scala index 4a4bbd06d..d34a573da 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/HealthCheckSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/HealthCheckSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2023 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,14 +15,12 @@ */ package com.hotels.styx.client -import java.nio.charset.StandardCharsets.UTF_8 - import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.fasterxml.jackson.module.scala.experimental.ScalaObjectMapper +import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock._ -import com.github.tomakehurst.wiremock.client.{ValueMatchingStrategy, WireMock} import com.hotels.styx.api.HttpHeaderNames.HOST import com.hotels.styx.api.HttpRequest import com.hotels.styx.api.HttpResponseStatus._ @@ -32,6 +30,7 @@ import com.hotels.styx.utils.StubOriginHeader.STUB_ORIGIN_INFO import com.hotels.styx.{StyxClientSupplier, StyxProxySpec} import org.scalatest.{FunSpec, SequentialNestedSuiteExecution} +import java.nio.charset.StandardCharsets.UTF_8 import scala.concurrent.duration._ class HealthCheckSpec extends FunSpec diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/TlsVersionSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/TlsVersionSpec.scala index 9896465c2..307d7b7b7 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/TlsVersionSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/client/TlsVersionSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2023 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ */ package com.hotels.styx.client +import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock._ -import com.github.tomakehurst.wiremock.client.{ValueMatchingStrategy, WireMock} import com.hotels.styx.api.HttpRequest.get import com.hotels.styx.api.HttpResponseStatus._ import com.hotels.styx.support.ResourcePaths.fixturesHome @@ -25,6 +25,7 @@ import com.hotels.styx.support.configuration._ import com.hotels.styx.utils.StubOriginHeader.STUB_ORIGIN_INFO import com.hotels.styx.{StyxClientSupplier, StyxProxySpec} import org.scalatest.{FunSpec, SequentialNestedSuiteExecution} + import java.nio.charset.StandardCharsets.UTF_8 class TlsVersionSpec extends FunSpec @@ -115,12 +116,6 @@ class TlsVersionSpec extends FunSpec def httpRequest(path: String) = get(styxServer.routerURL(path)).build() - def valueMatchingStrategy(matches: String) = { - val matchingStrategy = new ValueMatchingStrategy() - matchingStrategy.setMatches(matches) - matchingStrategy - } - describe("Backend Service TLS Protocol Setting") { it("Proxies to TLSv1.3 origin when TLSv1.3 support enabled.") { @@ -131,7 +126,7 @@ class TlsVersionSpec extends FunSpec appOriginTlsv13.verify( getRequestedFor( urlEqualTo("/tls13/a")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))) + .withHeader("X-Forwarded-Proto", matching("http"))) val response2 = decodedRequest(httpRequest("/tlsDefault/a2")) assert(response2.status() == OK) @@ -140,7 +135,7 @@ class TlsVersionSpec extends FunSpec appOriginTlsDefault.verify( getRequestedFor( urlEqualTo("/tlsDefault/a2")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))) + .withHeader("X-Forwarded-Proto", matching("http"))) } it("Proxies to TLSv1.2 origin when TLSv1.2 support is enabled.") { @@ -150,7 +145,7 @@ class TlsVersionSpec extends FunSpec appOriginTlsDefault.verify( getRequestedFor(urlEqualTo("/tlsDefault/b1")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))) + .withHeader("X-Forwarded-Proto", matching("http"))) val response2 = decodedRequest(httpRequest("/tls12/b2")) assert(response2.status() == OK) @@ -158,7 +153,7 @@ class TlsVersionSpec extends FunSpec appOriginTlsv12.verify( getRequestedFor(urlEqualTo("/tls12/b2")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))) + .withHeader("X-Forwarded-Proto", matching("http"))) } it("Refuses to connect to TLSv1.3 origin when TLSv1.3 is disabled") { diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/plugins/AsyncRequestSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/plugins/AsyncRequestSpec.scala index 32ccfcd15..5e8ffcd0b 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/plugins/AsyncRequestSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/plugins/AsyncRequestSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -64,7 +64,7 @@ class AsyncRequestSpec extends FunSpec .addHeader("Content-Length", "0") .build() - val response = Await.result(client.sendRequest(request).toScala, 5.seconds) + val response = Await.result(client.send(request).toScala, 5.seconds) mockServer.verify(1, getRequestedFor(urlStartingWith("/foobar"))) response.bodyAs(UTF_8) should be("I should be here!") diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ChunkedRequestSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ChunkedRequestSpec.scala index 68c419982..5a120092c 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ChunkedRequestSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ChunkedRequestSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,8 +15,9 @@ */ package com.hotels.styx.proxy -import com.github.tomakehurst.wiremock.client.{RequestPatternBuilder, UrlMatchingStrategy, ValueMatchingStrategy} +import com.github.tomakehurst.wiremock.client.WireMock.{matching, urlMatching} import com.github.tomakehurst.wiremock.http.RequestMethod +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder import com.hotels.styx.api.{HttpResponse, HttpResponseStatus, LiveHttpResponse} import com.hotels.styx.javaconvenience.UtilKt import com.hotels.styx.support.TestClientSupport @@ -64,26 +65,14 @@ class ChunkedRequestSpec extends FunSpec UtilKt.copy(new ByteArrayInputStream(chunks), connection.getOutputStream) readResponse(connection) - normalBackend.verify(new RequestPatternBuilder(RequestMethod.POST, urlMatchingStrategy("/chunked/1")) - .withRequestBody(valueMatchingStrategy("abc")) + normalBackend.verify(new RequestPatternBuilder(RequestMethod.POST, urlMatching("/chunked/1")) + .withRequestBody(matching("abc")) ) connection.disconnect() } } - def urlMatchingStrategy(path: String) = { - val pathMatch = new UrlMatchingStrategy() - pathMatch.setUrlPath("/chunked/1") - pathMatch - } - - def valueMatchingStrategy(matches: String) = { - val matchingStrategy = new ValueMatchingStrategy() - matchingStrategy.setMatches("abc") - matchingStrategy - } - @throws(classOf[IOException]) def readResponse(connection: HttpURLConnection): LiveHttpResponse = { val status: Int = connection.getResponseCode diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HeadersSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HeadersSpec.scala index 1ddbc0f41..82a4f3128 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HeadersSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HeadersSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2023 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -315,19 +315,18 @@ class HeadersSpec extends FunSpec describe("bad headers content") { it("should return HTTP BAD_GATEWAY Bad Gateway if origin returns multiple differing content-length headers.") { - recordingBackend.stub(urlPathEqualTo("/headers"), aResponse.withStatus(200) - .withHeader(CONTENT_LENGTH, "50") - .withHeader(CONTENT_LENGTH, "60") - ) + originRespondingWith( + responseWithHeaders( + HttpHeader(CONTENT_LENGTH, "50"), + HttpHeader(CONTENT_LENGTH, "60") + )) - val req = get("/headers") + val req = get("/badheaders") .addHeader(HOST, styxServer.proxyHost) .build() val resp = decodedRequest(req) - recordingBackend.verify(getRequestedFor(urlPathEqualTo("/headers"))) - assert(resp.status() == BAD_GATEWAY) } diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HttpOutboundMessageLoggingSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HttpOutboundMessageLoggingSpec.scala index 3d85c5714..0b3249273 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HttpOutboundMessageLoggingSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/HttpOutboundMessageLoggingSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -115,7 +115,7 @@ class HttpOutboundMessageLoggingSpec extends FunSpec "requestId=[-a-z0-9]+, origin=appOne:generic-app-01:localhost:[0-9]+, request=\\{version=HTTP/1.1, method=GET, uri=http://localhost:[0-9]+/foobar, headers=\\[.*\\], id=[-a-z0-9]+\\}"))) assertThat(logger.log(), hasItem(loggingEvent(INFO, - "requestId=[-a-z0-9]+, response=\\{version=HTTP/1.1, status=200 OK, headers=\\[Transfer-Encoding=chunked, Server=Jetty\\(6.1.26\\)\\]\\}"))) + "requestId=[-a-z0-9]+, response=\\{version=HTTP/1.1, status=200 OK, headers=\\[.*Transfer-Encoding=chunked.*\\]\\}"))) } } } diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ProxySpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ProxySpec.scala index d8722788b..43cda9a1b 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ProxySpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/ProxySpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,11 +15,9 @@ */ package com.hotels.styx.proxy -import java.nio.charset.StandardCharsets.UTF_8 -import java.util.Optional - +import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock._ -import com.github.tomakehurst.wiremock.client.{RequestPatternBuilder, WireMock} +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder import com.hotels.styx.MockServer.responseSupplier import com.hotels.styx.api.HttpHeaderNames._ import com.hotels.styx.api.HttpMethod.CONNECT @@ -41,6 +39,8 @@ import org.hamcrest.MatcherAssert.assertThat import org.scalatest.{BeforeAndAfter, FunSpec} import org.slf4j.LoggerFactory +import java.nio.charset.StandardCharsets.UTF_8 +import java.util.Optional import scala.compat.java8.FutureConverters.CompletionStageOps import scala.concurrent.Await import scala.concurrent.duration._ @@ -135,7 +135,7 @@ class ProxySpec extends FunSpec .addHeader(HOST, styxServer.proxyHost) .build() - val resp = Await.result(client.sendRequest(req).toScala, 5.seconds) + val resp = Await.result(client.send(req).toScala, 5.seconds) recordingBackend.verify(headRequestedFor(urlPathEqualTo("/bodiless"))) diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/UnwiseCharactersSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/UnwiseCharactersSpec.scala index fd8cab34e..0a3980278 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/UnwiseCharactersSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/UnwiseCharactersSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ package com.hotels.styx.proxy import ch.qos.logback.classic.Level._ -import com.github.tomakehurst.wiremock.client.RequestPatternBuilder import com.github.tomakehurst.wiremock.client.WireMock._ +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder import com.hotels.styx._ -import com.hotels.styx.api.HttpRequest.get import com.hotels.styx.api.HttpHeaderNames.HOST +import com.hotels.styx.api.HttpRequest.get import com.hotels.styx.proxy.encoders.ConfigurableUnwiseCharsEncoder import com.hotels.styx.support.backends.FakeHttpServer import com.hotels.styx.support.configuration.{HttpBackend, Origins, StyxConfig} @@ -31,6 +31,7 @@ import org.hamcrest.MatcherAssert._ import org.hamcrest.Matchers.hasItem import org.scalatest._ import org.scalatest.concurrent.Eventually + import scala.concurrent.duration._ class UnwiseCharactersSpec extends FunSpec with StyxProxySpec with Eventually { diff --git a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/https/ProtocolsSpec.scala b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/https/ProtocolsSpec.scala index 1cd3cf3e6..d5047ffcd 100644 --- a/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/https/ProtocolsSpec.scala +++ b/system-tests/e2e-suite/src/test/scala/com/hotels/styx/proxy/https/ProtocolsSpec.scala @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,10 +15,8 @@ */ package com.hotels.styx.proxy.https -import java.nio.charset.StandardCharsets.UTF_8 - +import com.github.tomakehurst.wiremock.client.WireMock import com.github.tomakehurst.wiremock.client.WireMock._ -import com.github.tomakehurst.wiremock.client.{ValueMatchingStrategy, WireMock} import com.hotels.styx.api.HttpHeaderNames.X_FORWARDED_PROTO import com.hotels.styx.api.HttpRequest.get import com.hotels.styx.api.HttpResponseStatus._ @@ -31,6 +29,7 @@ import io.netty.buffer.{ByteBuf, Unpooled} import org.scalatest.{FunSpec, SequentialNestedSuiteExecution} import org.slf4j.LoggerFactory +import java.nio.charset.StandardCharsets.UTF_8 import scala.concurrent.duration._ class ProtocolsSpec extends FunSpec @@ -130,12 +129,6 @@ class ProtocolsSpec extends FunSpec def httpsRequest(path: String) = get(styxServer.secureRouterURL(path)).build() - def valueMatchingStrategy(matches: String) = { - val matchingStrategy = new ValueMatchingStrategy() - matchingStrategy.setMatches(matches) - matchingStrategy - } - describe("Styx routing of HTTP requests") { it("Proxies HTTP protocol to HTTP origins") { val response = decodedRequest(httpRequest("/http/app.x.1")) @@ -145,7 +138,7 @@ class ProtocolsSpec extends FunSpec httpServer.verify( getRequestedFor(urlEqualTo("/http/app.x.1")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))) + .withHeader("X-Forwarded-Proto", matching("http"))) } it("Proxies HTTP protocol to HTTPS origins") { @@ -156,7 +149,7 @@ class ProtocolsSpec extends FunSpec httpsOriginWithoutCert.verify( getRequestedFor(urlEqualTo("/https/trustAllCerts/foo.2")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))) + .withHeader("X-Forwarded-Proto", matching("http"))) } it("Retains existing X-Forwarded-Proto header unmodified") { @@ -171,7 +164,7 @@ class ProtocolsSpec extends FunSpec httpServer.verify( getRequestedFor(urlEqualTo("/http/app.x.3")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("https"))) + .withHeader("X-Forwarded-Proto", matching("https"))) } } @@ -184,7 +177,7 @@ class ProtocolsSpec extends FunSpec assert(response.bodyAs(UTF_8) == "Hello, World!") httpServer.verify( getRequestedFor(urlEqualTo("/http/app.x.4")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("https")) + .withHeader("X-Forwarded-Proto", matching("https")) ) } @@ -195,7 +188,7 @@ class ProtocolsSpec extends FunSpec assert(response.bodyAs(UTF_8) == "Hello, World!") httpsOriginWithoutCert.verify( getRequestedFor(urlEqualTo("/https/trustAllCerts/foo.5")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("https")) + .withHeader("X-Forwarded-Proto", matching("https")) ) } @@ -211,7 +204,7 @@ class ProtocolsSpec extends FunSpec assert(response.bodyAs(UTF_8) == "Hello, World!") httpsOriginWithoutCert.verify( getRequestedFor(urlEqualTo("/https/trustAllCerts/foo.6")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http")) + .withHeader("X-Forwarded-Proto", matching("http")) ) } } diff --git a/system-tests/e2e-testsupport/pom.xml b/system-tests/e2e-testsupport/pom.xml index 862516e1c..c63bead29 100644 --- a/system-tests/e2e-testsupport/pom.xml +++ b/system-tests/e2e-testsupport/pom.xml @@ -35,11 +35,6 @@ styx-proxy - - com.google.code.findbugs - jsr305 - - org.junit.jupiter junit-jupiter @@ -58,7 +53,7 @@ - com.github.tomakehurst + org.wiremock wiremock compile diff --git a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/MockOriginServer.java b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/MockOriginServer.java index cb44306fd..c8f83bd60 100644 --- a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/MockOriginServer.java +++ b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/MockOriginServer.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,20 +16,13 @@ package com.hotels.styx.servers; import com.github.tomakehurst.wiremock.client.MappingBuilder; -import com.github.tomakehurst.wiremock.client.RequestPatternBuilder; import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder; -import com.github.tomakehurst.wiremock.client.UrlMatchingStrategy; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.core.WireMockApp; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.global.NotImplementedRequestDelayControl; -import com.github.tomakehurst.wiremock.http.AdminRequestHandler; -import com.github.tomakehurst.wiremock.http.BasicResponseRenderer; -import com.github.tomakehurst.wiremock.http.ProxyResponseRenderer; import com.github.tomakehurst.wiremock.http.Request; import com.github.tomakehurst.wiremock.http.RequestHandler; -import com.github.tomakehurst.wiremock.http.StubRequestHandler; -import com.github.tomakehurst.wiremock.http.StubResponseRenderer; +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; +import com.github.tomakehurst.wiremock.matching.UrlPattern; import com.google.common.util.concurrent.ServiceManager; import com.hotels.styx.InetServer; import com.hotels.styx.StyxServers; @@ -43,15 +36,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.InetSocketAddress; import java.util.List; -import static com.github.tomakehurst.wiremock.WireMockServer.FILES_ROOT; import static com.github.tomakehurst.wiremock.client.WireMock.configureFor; import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; -import static com.google.common.base.Optional.absent; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static com.hotels.styx.servers.WiremockResponseConverter.toStyxResponse; import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.Collections.emptyMap; +import static java.util.Optional.ofNullable; public final class MockOriginServer { private static final Logger LOGGER = LoggerFactory.getLogger(MockOriginServer.class); @@ -60,10 +53,10 @@ public final class MockOriginServer { private final String appId; private final String originId; private final int adminPort; - - private int serverPort; + private final int serverPort; private final InetServer adminServer; private final InetServer mockServer; + private static WireMockApp wireMockApp; static { System.setProperty("org.mortbay.log.class", "com.github.tomakehurst.wiremock.jetty.LoggerAdapter"); @@ -81,57 +74,47 @@ private MockOriginServer(String appId, String originId, int adminPort, int serve } public static MockOriginServer create(String appId, String originId, int adminPort, HttpConnectorConfig httpConfig) { - WireMockApp wireMockApp = wireMockApp(); + wireMockApp = wireMockApp(); InetServer adminServer = createAdminServer(originId, adminPort, wireMockApp); InetServer mockServer = HttpServers.createHttpServer( - "mock-stub-" + originId, - httpConfig, - mockHandler(originId, wireMockApp, new WireMockConfiguration())); + "mock-stub-" + originId, + httpConfig, + mockHandler(originId, wireMockApp) + ); int serverPort = httpConfig.port(); return new MockOriginServer(appId, originId, adminPort, serverPort, adminServer, mockServer); } public static MockOriginServer create(String appId, String originId, int adminPort, HttpsConnectorConfig httpsConfig) { - WireMockApp wireMockApp = wireMockApp(); + wireMockApp = wireMockApp(); InetServer adminServer = createAdminServer(originId, adminPort, wireMockApp); InetServer mockServer = HttpServers.createHttpsServer( - "mock-stub-" + originId, - httpsConfig, - mockHandler(originId, wireMockApp, new WireMockConfiguration())); + "mock-stub-" + originId, + httpsConfig, + mockHandler(originId, wireMockApp)); int serverPort = httpsConfig.port(); return new MockOriginServer(appId, originId, adminPort, serverPort, adminServer, mockServer); } - private static HttpHandler mockHandler(String originId, WireMockApp wireMockApp, WireMockConfiguration defaultConfig) { - return newHandler(originId, new StubRequestHandler( - wireMockApp, - new StubResponseRenderer( - defaultConfig.filesRoot().child(FILES_ROOT), - wireMockApp.getGlobalSettingsHolder(), - new ProxyResponseRenderer( - defaultConfig.proxyVia(), - defaultConfig.httpsSettings().trustStore(), - defaultConfig.shouldPreserveHostHeader(), - defaultConfig.proxyHostHeader() - ) - ) - )); + private static HttpHandler mockHandler(String originId, WireMockApp wireMockApp) { + return newHandler(originId, wireMockApp.buildStubRequestHandler()); } - private static HttpHandler newHandler(String originId, RequestHandler wireMockHandler) { + private static HttpHandler newHandler(String originId, RequestHandler requestHandler) { return (httpRequest, ctx) -> httpRequest.aggregate(MAX_CONTENT_LENGTH) .map(fullRequest -> { - LOGGER.info("{} received: {}\n{}", new Object[]{originId, fullRequest.url(), fullRequest.body()}); + LOGGER.info("{} received: {}\n{}", originId, fullRequest.url(), fullRequest.body()); return fullRequest; }) .flatMap(fullRequest -> { Request wmRequest = new WiremockStyxRequestAdapter(fullRequest); - com.github.tomakehurst.wiremock.http.Response wmResponse = wireMockHandler.handle(wmRequest); - return Eventual.of(toStyxResponse(wmResponse).stream()); + WiremockHttpResponder responder = new WiremockHttpResponder(); + requestHandler.handle(wmRequest, responder, null); + return Eventual.of(toStyxResponse(responder.getResponse()).stream()); }); } @@ -150,9 +133,9 @@ public MockOriginServer stop() { return this; } - public MockOriginServer stub(UrlMatchingStrategy urlMatchingStrategy, ResponseDefinitionBuilder response) { - WireMock wm = new WireMock("localhost", adminPort()); - wm.register(WireMock.get(urlMatchingStrategy).willReturn(response)); + public MockOriginServer stub(UrlPattern urlPattern, ResponseDefinitionBuilder response) { + configureFor("localhost", adminPort()); + stubFor(WireMock.get(urlPattern).willReturn(response)); return this; } @@ -163,18 +146,18 @@ public MockOriginServer stub(MappingBuilder mappingBuilder, ResponseDefinitionBu } public void verify(int count, RequestPatternBuilder builder) { - WireMock wm = new WireMock("localhost", adminPort()); - wm.verifyThat(count, builder); + configureFor("localhost", adminPort()); + WireMock.verify(count, builder); } public void verify(RequestPatternBuilder builder) { - WireMock wm = new WireMock("localhost", adminPort()); - wm.verifyThat(builder); + configureFor("localhost", adminPort()); + WireMock.verify(builder); } public MockOriginServer reset() { - WireMock wm = new WireMock("localhost", adminPort()); - wm.resetMappings(); + configureFor("localhost", adminPort()); + WireMock.reset(); return this; } @@ -187,11 +170,11 @@ public String originId() { } public int port() { - return mockServer.inetAddress().getPort(); + return serverPort == 0 ? ofNullable(mockServer.inetAddress()).map(InetSocketAddress::getPort).orElse(-1) : serverPort; } public int adminPort() { - return adminServer.inetAddress().getPort(); + return adminPort == 0 ? ofNullable(adminServer.inetAddress()).map(InetSocketAddress::getPort).orElse(-1) : adminPort; } public boolean isRunning() { @@ -199,21 +182,7 @@ public boolean isRunning() { } private static WireMockApp wireMockApp() { - return new WireMockApp( - new NotImplementedRequestDelayControl(), - false, - stubMappings -> { - - }, - mappings -> { - - }, - false, - absent(), - emptyMap(), - null, - null - ); + return new WireMockApp(wireMockConfig(), null); } private static InetServer createAdminServer(String originId, int adminPort, WireMockApp wireMockApp) { @@ -224,20 +193,21 @@ private static InetServer createAdminServer(String originId, int adminPort, Wire } private static HttpHandler adminHandler(WireMockApp wireMockApp) { - return newHandler(new AdminRequestHandler(wireMockApp, new BasicResponseRenderer())); + return newHandler(wireMockApp.buildAdminRequestHandler()); } - private static HttpHandler newHandler(RequestHandler wireMockHandler) { + private static HttpHandler newHandler(RequestHandler requestHandler) { return (httpRequest, ctx) -> httpRequest.aggregate(MAX_CONTENT_LENGTH) .map(fullRequest -> { - LOGGER.info("Received: {}\n{}", new Object[]{fullRequest.url(), fullRequest.body()}); + LOGGER.info("Received: {}\n{}", fullRequest.url(), fullRequest.body()); return fullRequest; }) .flatMap(fullRequest -> { Request wmRequest = new WiremockStyxRequestAdapter(fullRequest); - com.github.tomakehurst.wiremock.http.Response wmResponse = wireMockHandler.handle(wmRequest); - return Eventual.of(toStyxResponse(wmResponse).stream()); + WiremockHttpResponder responder = new WiremockHttpResponder(); + requestHandler.handle(wmRequest, responder, null); + return Eventual.of(toStyxResponse(responder.getResponse()).stream()); }); } } diff --git a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockHttpResponder.java b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockHttpResponder.java new file mode 100644 index 000000000..8b172e100 --- /dev/null +++ b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockHttpResponder.java @@ -0,0 +1,50 @@ +/* + Copyright (C) 2013-2024 Expedia Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +package com.hotels.styx.servers; + +import com.github.tomakehurst.wiremock.http.HttpResponder; +import com.github.tomakehurst.wiremock.http.Request; +import com.github.tomakehurst.wiremock.http.Response; + +import java.util.Map; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +public class WiremockHttpResponder implements HttpResponder { + private Response response; + + @Override + public void respond(Request request, Response response, Map map) { + if (Thread.currentThread().isInterrupted()) { + return; + } + + delayIfRequired(response.getInitialDelay()); + this.response = response; + } + + public Response getResponse() { + return response; + } + + private void delayIfRequired(long delayMillis) { + try { + MILLISECONDS.sleep(delayMillis); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } +} diff --git a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockResponseConverter.java b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockResponseConverter.java index d0401aa93..1da9204c8 100644 --- a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockResponseConverter.java +++ b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockResponseConverter.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockStyxRequestAdapter.java b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockStyxRequestAdapter.java index ba89ca397..502664fb6 100644 --- a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockStyxRequestAdapter.java +++ b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/servers/WiremockStyxRequestAdapter.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,22 +16,31 @@ package com.hotels.styx.servers; import com.github.tomakehurst.wiremock.http.ContentTypeHeader; +import com.github.tomakehurst.wiremock.http.Cookie; +import com.github.tomakehurst.wiremock.http.FormParameter; import com.github.tomakehurst.wiremock.http.HttpHeader; import com.github.tomakehurst.wiremock.http.HttpHeaders; import com.github.tomakehurst.wiremock.http.QueryParameter; import com.github.tomakehurst.wiremock.http.Request; import com.github.tomakehurst.wiremock.http.RequestMethod; import com.hotels.styx.api.HttpRequest; +import com.hotels.styx.api.RequestCookie; +import java.net.URI; +import java.util.Collection; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static com.github.tomakehurst.wiremock.http.HttpHeader.httpHeader; import static io.netty.handler.codec.http.HttpHeaderNames.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpHeaderNames.HOST; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Objects.requireNonNull; +import static java.util.Optional.ofNullable; import static java.util.stream.Collectors.toList; import static java.util.stream.StreamSupport.stream; @@ -49,10 +58,11 @@ public String getUrl() { @Override public String getAbsoluteUrl() { - String host = styxRequest.header(HOST).orElse(""); + URI uri = styxRequest.url().toURI(); + String host = ofNullable(uri.getHost()).isEmpty() ? styxRequest.header(HOST).orElse("") : ""; String protocol = "http"; - return protocol + "://" + host + styxRequest.url().toURI().toString(); + return protocol + "://" + host + uri; } @Override @@ -109,13 +119,91 @@ public byte[] getBody() { return styxRequest.body(); } + @Override + public boolean isBrowserProxyRequest() { + return false; + } + @Override public String getBodyAsString() { return styxRequest.bodyAs(UTF_8); } @Override - public boolean isBrowserProxyRequest() { + public boolean isMultipart() { return false; } + + @Override + public String getScheme() { + // no-op + return styxRequest.url().scheme(); + } + + @Override + public String getHost() { + return styxRequest.url().host().orElse(""); + } + + @Override + public int getPort() { + return styxRequest.url().toURI().getPort(); + } + + @Override + public String getClientIp() { + // no-op + return null; + } + + @Override + public FormParameter formParameter(String s) { + // no-op + return null; + } + + @Override + public Map formParameters() { + // no-op + return null; + } + + @Override + public Map getCookies() { + return styxRequest.cookies() + .stream() + .collect(Collectors.toMap( + RequestCookie::name, + cookie -> new Cookie(cookie.name(), cookie.value()) + )); + } + + @Override + public String getBodyAsBase64() { + // no-op + return null; + } + + @Override + public Collection getParts() { + // no-op + return null; + } + + @Override + public Part getPart(String s) { + // no-op + return null; + } + + @Override + public Optional getOriginalRequest() { + // no-op + return Optional.empty(); + } + + @Override + public String getProtocol() { + return styxRequest.version().toString(); + } } diff --git a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/utils/MetricsSnapshot.java b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/utils/MetricsSnapshot.java index 239325539..181d15ffd 100644 --- a/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/utils/MetricsSnapshot.java +++ b/system-tests/e2e-testsupport/src/main/java/com/hotels/styx/utils/MetricsSnapshot.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2022 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -48,7 +48,7 @@ private MetricsSnapshot(Map tree) { public static MetricsSnapshot downloadFrom(String host, int port) throws IOException { HttpClient client = new StyxHttpClient.Builder().build(); - HttpResponse response = await(client.sendRequest(get(format("http://%s:%d/admin/metrics", host, port)).build())); + HttpResponse response = await(client.send(get(format("http://%s:%d/admin/metrics", host, port)).build())); return new MetricsSnapshot(decodeToMap(response.bodyAs(UTF_8))); } diff --git a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java index e1e698600..82414db80 100644 --- a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java +++ b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/MockOriginServerTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package com.hotels.styx.servers; -import com.github.tomakehurst.wiremock.client.ValueMatchingStrategy; import com.github.tomakehurst.wiremock.client.WireMock; import com.hotels.styx.api.HttpResponse; import com.hotels.styx.api.extension.service.TlsSettings; @@ -32,6 +31,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.matching; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static com.hotels.styx.api.HttpRequest.get; @@ -66,14 +66,14 @@ public void tearDown() { @Test public void configuresEndpoints() { - server = MockOriginServer.create("", "", 0, new HttpConnectorConfig(0)) + server = MockOriginServer.create("TEST_APP", "TEST_ORIGIN", 0, new HttpConnectorConfig(0)) .start() .stub(WireMock.get(urlMatching("/.*")), aResponse() .withStatus(200) .withHeader("a", "b") .withBody("Hello, World!")); - HttpResponse response = await(client.sendRequest( + HttpResponse response = await(client.send( get(format("http://localhost:%d/mock", server.port())) .header("X-Forwarded-Proto", "http") .build())); @@ -83,12 +83,12 @@ public void configuresEndpoints() { assertThat(response.bodyAs(UTF_8), is("Hello, World!")); server.verify(getRequestedFor(urlEqualTo("/mock")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))); + .withHeader("X-Forwarded-Proto", matching("http"))); } @Test - public void configuresTlsEndpoints() throws Exception { - server = MockOriginServer.create("", "", 0, + public void configuresTlsEndpoints() { + server = MockOriginServer.create("TEST_APP", "TEST_ORIGIN", 0, new HttpsConnectorConfig.Builder() .port(0) .build()) @@ -99,7 +99,7 @@ public void configuresTlsEndpoints() throws Exception { .withBody("Hello, World!")); HttpResponse response = await( - tlsClient.sendRequest( + tlsClient.send( get(format("https://localhost:%d/mock", server.port())) .header("X-Forwarded-Proto", "http") .build())); @@ -108,13 +108,7 @@ public void configuresTlsEndpoints() throws Exception { assertThat(response.header("a"), is(Optional.of("b"))); server.verify(getRequestedFor(urlEqualTo("/mock")) - .withHeader("X-Forwarded-Proto", valueMatchingStrategy("http"))); - } - - private ValueMatchingStrategy valueMatchingStrategy(String matches) { - ValueMatchingStrategy strategy = new ValueMatchingStrategy(); - strategy.setMatches(matches); - return strategy; + .withHeader("X-Forwarded-Proto", matching("http"))); } private HostnameVerifier disableHostNameVerification() { diff --git a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockResponseConverterTest.java b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockResponseConverterTest.java index b7cf664dc..2de634504 100644 --- a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockResponseConverterTest.java +++ b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockResponseConverterTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2021 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -15,10 +15,8 @@ */ package com.hotels.styx.servers; -import com.github.tomakehurst.wiremock.http.BasicResponseRenderer; import com.github.tomakehurst.wiremock.http.HttpHeaders; import com.github.tomakehurst.wiremock.http.Response; -import com.github.tomakehurst.wiremock.http.ResponseDefinition; import com.hotels.styx.api.HttpHeader; import com.hotels.styx.api.HttpResponse; import org.junit.jupiter.api.Test; @@ -42,10 +40,9 @@ public class WiremockResponseConverterTest { @Test public void convertsCreatedResponse() { - ResponseDefinition created = ResponseDefinition.created(); - Response render = new BasicResponseRenderer().render(created); + Response response = Response.response().status(CREATED.code()).build(); - HttpResponse styxResponse = toStyxResponse(render); + HttpResponse styxResponse = toStyxResponse(response); assertThat(styxResponse.status(), is(CREATED)); assertThat(styxResponse.bodyAs(UTF_8), is("")); @@ -54,12 +51,17 @@ public void convertsCreatedResponse() { @Test public void convertsResponseWithBody() { - ResponseDefinition response = new ResponseDefinition(HTTP_OK, "{ \"count\" : 0, \"requestJournalDisabled\" : false}"); - response.setHeaders(new HttpHeaders( - httpHeader("Transfer-Encoding", "chunked"), - httpHeader("Content-Type", "application/json"))); - - HttpResponse styxResponse = toStyxResponse(new BasicResponseRenderer().render(response)); + Response response = Response.response() + .headers( + new HttpHeaders( + httpHeader("Transfer-Encoding", "chunked"), + httpHeader("Content-Type", "application/json")) + ) + .status(HTTP_OK) + .body("{ \"count\" : 0, \"requestJournalDisabled\" : false}") + .build(); + + HttpResponse styxResponse = toStyxResponse(response); assertThat(styxResponse.status(), is(OK)); Map actual = headersAsMap(styxResponse); diff --git a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockStyxRequestAdapterTest.java b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockStyxRequestAdapterTest.java index 11ae6e351..9e98c2106 100644 --- a/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockStyxRequestAdapterTest.java +++ b/system-tests/e2e-testsupport/src/test/java/com/hotels/styx/servers/WiremockStyxRequestAdapterTest.java @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2022 Expedia Inc. + Copyright (C) 2013-2024 Expedia Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ import com.github.tomakehurst.wiremock.http.ContentTypeHeader; import com.github.tomakehurst.wiremock.http.QueryParameter; -import com.google.common.base.Optional; import com.hotels.styx.api.HttpRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -142,7 +141,7 @@ public void adaptsGetBodyAsStringWhenPresent() { public void adaptsContentTypeHeaderWhenPresent() { ContentTypeHeader contentType = adapter.contentTypeHeader(); - assertThat(contentType.encodingPart(), is(Optional.of("UTF-8"))); + assertThat(contentType.encodingPart().orElse(null), is("UTF-8")); assertThat(contentType.mimeTypePart(), is("application/json")); }