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 a4a24024a8..8d5b2e9cbf 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 @@ -76,7 +76,6 @@ import static io.servicetalk.http.api.HttpExecutionStrategies.offloadAll; import static io.servicetalk.http.api.HttpExecutionStrategies.offloadNone; 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; @@ -172,7 +171,7 @@ UrlKey get(final HttpRequestMetaData metaData) throws MalformedURLException { final int parsedPort = metaData.port(); final int port = parsedPort >= 0 ? parsedPort : (HTTPS_SCHEME.equals(scheme) ? defaultHttpsPort : defaultHttpPort); - setHostHeader(metaData); + setHostHeader(metaData, host, parsedPort); metaData.requestTarget(absoluteToRelativeFormRequestTarget(metaData.requestTarget(), scheme, host)); final String key = scheme + ':' + host + ':' + port; @@ -190,6 +189,18 @@ private static String ensureUrlComponentNonNull(@Nullable final String value, return value; } + private static void setHostHeader(final HttpRequestMetaData metaData, final String host, final int port) { + if (metaData.version().compareTo(HTTP_1_1) >= 0 && !metaData.headers().contains(HOST)) { + // Host header must be identical to authority component of the target URI, + // as described in https://datatracker.ietf.org/doc/html/rfc7230#section-5.4 + String authority = host; + if (port >= 0) { + authority = authority + ':' + port; + } + metaData.headers().add(HOST, authority); + } + } + // This code is similar to io.servicetalk.http.utils.RedirectSingle#absoluteToRelativeFormRequestTarget // but cannot be shared because we don't have an internal module for http private static String absoluteToRelativeFormRequestTarget(final String requestTarget, @@ -285,7 +296,7 @@ public StreamingHttpClient apply(final UrlKey urlKey) { private static void singleClientStrategyUpdate(ContextMap context, HttpExecutionStrategy singleStrategy) { HttpExecutionStrategy requestStrategy = context.getOrDefault(HTTP_EXECUTION_STRATEGY_KEY, defaultStrategy()); - assert null != requestStrategy : "Request strategy unexpectedly null"; + assert requestStrategy != null : "Request strategy unexpectedly null"; HttpExecutionStrategy useStrategy = defaultStrategy() == requestStrategy ? // For all apis except async streaming default conversion has already been done. // This is the default to required strategy resolution for the async streaming client. @@ -496,14 +507,4 @@ private static int verifyPortRange(final int port) { } return port; } - - private static void setHostHeader(HttpRequestMetaData metaData) { - if (!HTTP_1_0.equals(metaData.version()) && !metaData.headers().contains(HOST)) { - CharSequence authority = metaData.host(); - if (metaData.port() >= 0) { - authority = authority + ":" + metaData.port(); - } - metaData.headers().add(HOST, authority); - } - } }