diff --git a/servicetalk-examples/http/http2/src/main/java/io/servicetalk/examples/http/http2/alpn/HttpUrlClientWithAlpn.java b/servicetalk-examples/http/http2/src/main/java/io/servicetalk/examples/http/http2/alpn/HttpUrlClientWithAlpn.java index 9db9e4d5b8..15f65bc7dd 100644 --- a/servicetalk-examples/http/http2/src/main/java/io/servicetalk/examples/http/http2/alpn/HttpUrlClientWithAlpn.java +++ b/servicetalk-examples/http/http2/src/main/java/io/servicetalk/examples/http/http2/alpn/HttpUrlClientWithAlpn.java @@ -39,7 +39,7 @@ public static void main(String[] args) throws Exception { try (BlockingHttpClient client = HttpClients.forMultiAddressUrl().initializer((scheme, address, builder) -> { // If necessary, users can also take `address` into account for setting distinct protocols or TLS // configurations for various server addresses. - if ("https".equalsIgnoreCase(scheme)) { + if ("https".equals(scheme)) { builder.protocols(h2Default(), h1Default()) // Configure support for HTTP/2 and HTTP/1.1 protocols // Note: DefaultTestCerts contains self-signed certificates that may be used only for local testing. // or demonstration purposes. Never use those for real use-cases. diff --git a/servicetalk-examples/http/mutual-tls/src/main/java/io/servicetalk/examples/http/mutualtls/HttpUrlClientMutualTLS.java b/servicetalk-examples/http/mutual-tls/src/main/java/io/servicetalk/examples/http/mutualtls/HttpUrlClientMutualTLS.java index 60066ddc1e..afdf3fc26f 100644 --- a/servicetalk-examples/http/mutual-tls/src/main/java/io/servicetalk/examples/http/mutualtls/HttpUrlClientMutualTLS.java +++ b/servicetalk-examples/http/mutual-tls/src/main/java/io/servicetalk/examples/http/mutualtls/HttpUrlClientMutualTLS.java @@ -34,7 +34,7 @@ public static void main(String[] args) throws Exception { try (BlockingHttpClient client = HttpClients.forMultiAddressUrl().initializer((scheme, address, builder) -> { // If necessary, users can also take `address` into account for setting distinct TLS configurations for // various server addresses. - if ("https".equalsIgnoreCase(scheme)) { + if ("https".equals(scheme)) { // Note: DefaultTestCerts contains self-signed certificates that may be used only for local testing. // or demonstration purposes. Never use those for real use-cases. builder.sslConfig(new ClientSslConfigBuilder(DefaultTestCerts::loadServerCAPem) diff --git a/servicetalk-examples/http/redirects/src/main/java/io/servicetalk/examples/http/redirects/MultiAddressUrlRedirectClient.java b/servicetalk-examples/http/redirects/src/main/java/io/servicetalk/examples/http/redirects/MultiAddressUrlRedirectClient.java index 9e96b5c987..e079f98dde 100644 --- a/servicetalk-examples/http/redirects/src/main/java/io/servicetalk/examples/http/redirects/MultiAddressUrlRedirectClient.java +++ b/servicetalk-examples/http/redirects/src/main/java/io/servicetalk/examples/http/redirects/MultiAddressUrlRedirectClient.java @@ -77,7 +77,7 @@ public static void main(String... args) throws Exception { // The custom SSL configuration here is necessary only because this example uses self-signed // certificates. For cases when it's enough to use the local trust store, MultiAddressUrl client // already provides default SSL configuration and this step may be skipped. - if ("https".equalsIgnoreCase(scheme)) { + if ("https".equals(scheme)) { builder.sslConfig(new ClientSslConfigBuilder(DefaultTestCerts::loadServerCAPem).build()); } }) diff --git a/servicetalk-http-api/src/main/java/io/servicetalk/http/api/MultiAddressHttpClientBuilder.java b/servicetalk-http-api/src/main/java/io/servicetalk/http/api/MultiAddressHttpClientBuilder.java index 36269b8b9c..e87d7a1c49 100644 --- a/servicetalk-http-api/src/main/java/io/servicetalk/http/api/MultiAddressHttpClientBuilder.java +++ b/servicetalk-http-api/src/main/java/io/servicetalk/http/api/MultiAddressHttpClientBuilder.java @@ -44,7 +44,7 @@ interface SingleAddressInitializer { /** * Configures the passed {@link SingleAddressHttpClientBuilder} for the given {@code scheme} and * {@code address}. - * @param scheme The scheme parsed from the request URI. + * @param scheme The scheme parsed from a {@link HttpRequestMetaData#requestTarget() request URI} in lowercase. * @param address The unresolved address. * @param builder The builder to customize and build a {@link StreamingHttpClient}. */ diff --git a/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/DefaultMultiAddressUrlHttpClientBuilder.java b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/DefaultMultiAddressUrlHttpClientBuilder.java index 4b8d58a35e..cce5fc328b 100644 --- a/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/DefaultMultiAddressUrlHttpClientBuilder.java +++ b/servicetalk-http-netty/src/main/java/io/servicetalk/http/netty/DefaultMultiAddressUrlHttpClientBuilder.java @@ -27,6 +27,7 @@ import io.servicetalk.context.api.ContextMap; import io.servicetalk.http.api.DefaultHttpHeadersFactory; import io.servicetalk.http.api.DefaultStreamingHttpRequestResponseFactory; +import io.servicetalk.http.api.EmptyHttpHeaders; import io.servicetalk.http.api.FilterableReservedStreamingHttpConnection; import io.servicetalk.http.api.FilterableStreamingHttpClient; import io.servicetalk.http.api.HttpContextKeys; @@ -58,6 +59,7 @@ import java.net.InetSocketAddress; import java.net.MalformedURLException; +import java.util.Locale; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; @@ -76,6 +78,8 @@ import static io.servicetalk.http.api.HttpHeaderNames.HOST; import static io.servicetalk.http.api.HttpProtocolVersion.HTTP_1_0; import static io.servicetalk.http.api.HttpProtocolVersion.HTTP_1_1; +import static io.servicetalk.http.api.HttpRequestMetaDataFactory.newRequestMetaData; +import static io.servicetalk.http.api.HttpRequestMethod.GET; import static io.servicetalk.http.netty.DefaultSingleAddressHttpClientBuilder.setExecutionContext; import static java.lang.Math.min; import static java.util.Objects.requireNonNull; @@ -97,7 +101,11 @@ final class DefaultMultiAddressUrlHttpClientBuilder private static final Logger LOGGER = LoggerFactory.getLogger(DefaultMultiAddressUrlHttpClientBuilder.class); - private static final String HTTPS_SCHEME = HTTPS.toString(); + // Use HttpRequestMetaData to access "https" constant used by Uri3986 class to optimize "equals" check to be a + // trivial reference check. + @SuppressWarnings("DataFlowIssue") + private static final String HTTPS_SCHEME = newRequestMetaData(HTTP_1_1, GET, "https://invalid./", + EmptyHttpHeaders.INSTANCE).scheme(); private final Function> builderFactory; private final HttpExecutionContextBuilder executionContextBuilder = new HttpExecutionContextBuilder(); @@ -161,10 +169,11 @@ private static final class CachingKeyFactory implements AsyncCloseable { UrlKey get(final HttpRequestMetaData metaData) throws MalformedURLException { final String requestTarget = metaData.requestTarget(); final String scheme = ensureUrlComponentNonNull(metaData.scheme(), "scheme", requestTarget); + assert scheme.equals(scheme.toLowerCase(Locale.ENGLISH)) : "scheme must be in lowercase"; final String host = ensureUrlComponentNonNull(metaData.host(), "host", requestTarget); final int parsedPort = metaData.port(); final int port = parsedPort >= 0 ? parsedPort : - (HTTPS_SCHEME.equalsIgnoreCase(scheme) ? defaultHttpsPort : defaultHttpPort); + (HTTPS_SCHEME.equals(scheme) ? defaultHttpsPort : defaultHttpPort); setHostHeader(metaData); metaData.requestTarget(absoluteToRelativeFormRequestTarget(requestTarget, scheme, host)); @@ -266,7 +275,7 @@ public StreamingHttpClient apply(final UrlKey urlKey) { requireNonNull(builderFactory.apply(urlKey.hostAndPort)); setExecutionContext(builder, executionContext); - if (HTTPS_SCHEME.equalsIgnoreCase(urlKey.scheme)) { + if (HTTPS_SCHEME.equals(urlKey.scheme)) { builder.sslConfig(DEFAULT_CLIENT_SSL_CONFIG); } @@ -324,7 +333,6 @@ protected Single request( final StreamingHttpRequester delegate, final StreamingHttpRequest request) { return defer(() -> { singleClientStrategyUpdate(request.context(), client.executionContext().executionStrategy()); - return delegate.request(request); }); } diff --git a/servicetalk-http-netty/src/test/java/io/servicetalk/http/netty/SslAndNonSslConnectionsTest.java b/servicetalk-http-netty/src/test/java/io/servicetalk/http/netty/SslAndNonSslConnectionsTest.java index 0ea603401c..ed8365e427 100644 --- a/servicetalk-http-netty/src/test/java/io/servicetalk/http/netty/SslAndNonSslConnectionsTest.java +++ b/servicetalk-http-netty/src/test/java/io/servicetalk/http/netty/SslAndNonSslConnectionsTest.java @@ -236,7 +236,7 @@ void multiAddressClientWithSslToSecureServer() throws Exception { void multiAddressClientToSecureServerThenToNonSecureServer() throws Exception { try (BlockingHttpClient client = HttpClients.forMultiAddressUrl(getClass().getSimpleName()) .initializer((scheme, address, builder) -> { - if ("https".equalsIgnoreCase(scheme)) { + if ("https".equals(scheme)) { builder.sslConfig(new ClientSslConfigBuilder(DefaultTestCerts::loadServerCAPem) .peerHost(serverPemHostname()).build()); } @@ -251,7 +251,7 @@ void multiAddressClientToSecureServerThenToNonSecureServer() throws Exception { void multiAddressClientToNonSecureServerThenToSecureServer() throws Exception { try (BlockingHttpClient client = HttpClients.forMultiAddressUrl(getClass().getSimpleName()) .initializer((scheme, address, builder) -> { - if ("https".equalsIgnoreCase(scheme)) { + if ("https".equals(scheme)) { builder.sslConfig(new ClientSslConfigBuilder(DefaultTestCerts::loadServerCAPem) .peerHost(serverPemHostname()).build()); }