Support SNI for JNH connector
Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpClientProperties.java b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpClientProperties.java
index 3a48d2c..a964200 100644
--- a/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpClientProperties.java
+++ b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpClientProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -57,25 +57,34 @@
public static final String SSL_PARAMETERS = "jersey.config.jnh.client.sslParameters";
/**
- * An instance of the {@link java.net.Authenticator} class that should be used to retrieve
- * credentials from a user.
- *
+ * <p>
+ * An instance of the {@link java.net.Authenticator} class that should be used to retrieve
+ * credentials from a user.
+ * </p>
+ * <p>
+ * The name of the configuration property is <tt>{@value}</tt>.
+ * </p>
*/
public static final String PREEMPTIVE_BASIC_AUTHENTICATION =
"jersey.config.jnh.client.preemptiveBasicAuthentication";
/**
- * A value of {@code false} indicates the client should handle cookies
- * automatically using HttpClient's default cookie policy. A value
- * of {@code false} will cause the client to ignore all cookies.
- * <p/>
- * The value MUST be an instance of {@link java.lang.Boolean}.
- * If the property is absent the default value is {@code false}
+ * <p>
+ * A value of {@code false} indicates the client should handle cookies
+ * automatically using HttpClient's default cookie policy. A value
+ * of {@code false} will cause the client to ignore all cookies.
+ * </p>
+ * <p>
+ * The value MUST be an instance of {@link java.lang.Boolean}.
+ * If the property is absent the default value is {@code false}
+ * </p>
+ * <p>
+ * The name of the configuration property is <tt>{@value}</tt>.
+ * </p>
*/
public static final String DISABLE_COOKIES =
"jersey.config.jnh.client.disableCookies";
-
/**
* Prevent this class from instantiation.
*/
diff --git a/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnector.java b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnector.java
index 7530c4e..975f5d8 100644
--- a/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnector.java
+++ b/connectors/jnh-connector/src/main/java/org/glassfish/jersey/jnh/connector/JavaNetHttpConnector.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -25,6 +25,7 @@
import org.glassfish.jersey.client.ClientResponse;
import org.glassfish.jersey.client.innate.ClientProxy;
import org.glassfish.jersey.client.innate.Expect100ContinueUsage;
+import org.glassfish.jersey.client.innate.http.SSLParamConfigurator;
import org.glassfish.jersey.client.spi.AsyncConnectorCallback;
import org.glassfish.jersey.client.spi.Connector;
import org.glassfish.jersey.internal.Version;
@@ -49,14 +50,12 @@
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
-import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import java.util.logging.Logger;
-import java.util.zip.GZIPOutputStream;
/**
* Provides a Jersey client {@link Connector}, which internally uses Java's {@link HttpClient}.
@@ -104,11 +103,14 @@
} else {
httpClientBuilder.followRedirects(HttpClient.Redirect.NORMAL);
}
+
SSLParameters sslParameters =
getPropertyOrNull(configuration, JavaNetHttpClientProperties.SSL_PARAMETERS, SSLParameters.class);
+ sslParameters = new SniSslParameters(sslParameters).getSslParameters(client);
if (sslParameters != null) {
httpClientBuilder.sslParameters(sslParameters);
}
+
final Authenticator preemptiveAuthenticator =
getPropertyOrNull(configuration,
JavaNetHttpClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION, Authenticator.class);
@@ -170,12 +172,18 @@
* @return the {@link HttpRequest} instance for the {@link HttpClient} request
*/
private HttpRequest getHttpRequest(ClientRequest request) {
+ final SSLParamConfigurator sniConfig = SSLParamConfigurator.builder()
+ .uri(request.getUri())
+ .configuration(request.getConfiguration())
+ .build();
+
+ final URI sniUri = sniConfig.isSNIRequired() ? sniConfig.toIPRequestUri() : request.getUri();
+
HttpRequest.Builder builder = HttpRequest.newBuilder();
- builder.uri(request.getUri());
+ builder.uri(sniUri);
HttpRequest.BodyPublisher bodyPublisher = HttpRequest.BodyPublishers.noBody();
if (request.hasEntity()) {
try {
- request.enableBuffering();
ByteArrayOutputStreamProvider byteBufferStreamProvider = new ByteArrayOutputStreamProvider();
request.setStreamProvider(byteBufferStreamProvider);
request.writeEntity();
@@ -296,4 +304,29 @@
}
return null;
}
+
+ private static class SniSslParameters {
+ private final SSLParameters sslParameters;
+
+ private SniSslParameters(SSLParameters sslParameters) {
+ this.sslParameters = sslParameters;
+ }
+
+ private SSLParameters getSslParameters(Client client) {
+ SSLParamConfigurator sniConfig = SSLParamConfigurator.builder()
+ .configuration(client.getConfiguration())
+ .build();
+
+ if (sniConfig.isSNIRequired()) {
+ SSLParameters sslParameters = this.sslParameters;
+ if (sslParameters == null) {
+ sslParameters = new SSLParameters();
+ }
+ sniConfig.setSNIServerName(sslParameters);
+ return sslParameters;
+ } else {
+ return sslParameters;
+ }
+ }
+ }
}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
index 909af8d..556148d 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/ClientProperties.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -463,6 +463,24 @@
*/
public static final String QUERY_PARAM_STYLE = "jersey.config.client.uri.query.param.style";
+ /**
+ * <p>
+ * Most connectors support HOST header value to be used as an SNIHostName. However, the HOST header is restricted in JDK.
+ * {@code HttpUrlConnector} and {@code JavaNetHttpConnector} need
+ * to have an extra System Property set to allow HOST header.
+ * As an option to HOST header, this property allows the HOST name to be pre-set on a Client and does not need to
+ * be set on each request.
+ * </p>
+ * <p>
+ * The value MUST be an instance of {@link java.lang.String}.
+ * </p>
+ * <p>
+ * The name of the configuration property is <tt>{@value}</tt>.
+ * </p>
+ * @since 3.1.2
+ */
+ public static final String SNI_HOST_NAME = "jersey.config.client.sniHostName";
+
private ClientProperties() {
// prevents instantiation
}
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
index 33ef0b6..cb32a5c 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java
@@ -16,18 +16,25 @@
package org.glassfish.jersey.client.innate.http;
+import jakarta.ws.rs.core.Configuration;
+import jakarta.ws.rs.core.HttpHeaders;
+import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.ClientRequest;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import jakarta.ws.rs.core.UriBuilder;
+import org.glassfish.jersey.internal.PropertiesResolver;
+import org.glassfish.jersey.internal.util.PropertiesHelper;
+
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.Properties;
/**
* A unified routines to configure {@link SSLParameters}.
@@ -35,27 +42,36 @@
*/
public final class SSLParamConfigurator {
private final URI uri;
- private final Map<String, List<Object>> httpHeaders;
private final Optional<SniConfigurator> sniConfigurator;
/**
* Builder of the {@link SSLParamConfigurator} instance.
*/
public static final class Builder {
- private ClientRequest clientRequest;
- private URI uri;
- private Map<String, List<Object>> httpHeaders;
+ private URI uri = null;
+ private String sniHostNameHeader = null;
+ private String sniHostNameProperty = null;
private boolean setAlways = false;
/**
- * Sets the {@link ClientRequest} instance.
+ * Sets the SNIHostName and {@link URI} from the {@link ClientRequest} instance.
* @param clientRequest the {@link ClientRequest}
* @return the builder instance
*/
public Builder request(ClientRequest clientRequest) {
- this.clientRequest = clientRequest;
- this.httpHeaders = null;
- this.uri = null;
+ this.sniHostNameHeader = getSniHostNameHeader(clientRequest.getHeaders());
+ this.sniHostNameProperty = clientRequest.resolveProperty(ClientProperties.SNI_HOST_NAME, String.class);
+ this.uri = clientRequest.getUri();
+ return this;
+ }
+
+ /**
+ * Sets the SNIHostName from the {@link Configuration} instance.
+ * @param configuration the {@link Configuration}
+ * @return the builder instance
+ */
+ public Builder configuration(Configuration configuration) {
+ this.sniHostNameProperty = (String) configuration.getProperty(ClientProperties.SNI_HOST_NAME);
return this;
}
@@ -65,7 +81,6 @@
* @return the builder instance
*/
public Builder uri(URI uri) {
- this.clientRequest = null;
this.uri = uri;
return this;
}
@@ -76,8 +91,7 @@
* @return the builder instance
*/
public Builder headers(Map<String, List<Object>> httpHeaders) {
- this.clientRequest = null;
- this.httpHeaders = httpHeaders;
+ this.sniHostNameHeader = getSniHostNameHeader(httpHeaders);
return this;
}
@@ -99,12 +113,31 @@
public SSLParamConfigurator build() {
return new SSLParamConfigurator(this);
}
+
+ private static String getSniHostNameHeader(Map<String, List<Object>> httpHeaders) {
+ List<Object> hostHeaders = httpHeaders.get(HttpHeaders.HOST);
+ if (hostHeaders == null || hostHeaders.get(0) == null) {
+ return null;
+ }
+
+ final String hostHeader = hostHeaders.get(0).toString();
+ final String trimmedHeader;
+ if (hostHeader != null) {
+ int index = hostHeader.indexOf(':'); // RFC 7230 Host = uri-host [ ":" port ] ;
+ final String trimmedHeader0 = index != -1 ? hostHeader.substring(0, index).trim() : hostHeader.trim();
+ trimmedHeader = trimmedHeader0.isEmpty() ? hostHeader : trimmedHeader0;
+ } else {
+ trimmedHeader = null;
+ }
+
+ return trimmedHeader;
+ }
}
private SSLParamConfigurator(SSLParamConfigurator.Builder builder) {
- this.uri = builder.clientRequest != null ? builder.clientRequest.getUri() : builder.uri;
- this.httpHeaders = builder.clientRequest != null ? builder.clientRequest.getHeaders() : builder.httpHeaders;
- sniConfigurator = SniConfigurator.createWhenHostHeader(uri, httpHeaders, builder.setAlways);
+ String sniHostName = builder.sniHostNameHeader == null ? builder.sniHostNameProperty : builder.sniHostNameHeader;
+ uri = builder.uri;
+ sniConfigurator = SniConfigurator.createWhenHostHeader(uri, sniHostName, builder.setAlways);
}
/**
@@ -178,6 +211,15 @@
}
/**
+ * Set {@link javax.net.ssl.SNIServerName} for the {@link SSLParameters} when SNI should be used
+ * (i.e. {@link jakarta.ws.rs.core.HttpHeaders#HOST} differs from HTTP request host name)
+ * @param parameters the {@link SSLParameters} to be set
+ */
+ public void setSNIServerName(SSLParameters parameters) {
+ sniConfigurator.ifPresent(sni -> sni.updateSSLParameters(parameters));
+ }
+
+ /**
* Set setEndpointIdentificationAlgorithm to HTTPS. This is to prevent man-in-the-middle attacks.
* @param sslEngine the {@link SSLEngine} the algorithm is set for.
* @see SSLParameters#setEndpointIdentificationAlgorithm(String)
diff --git a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
index 39a339d..47a0777 100644
--- a/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
+++ b/core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java
@@ -25,7 +25,6 @@
import java.net.URI;
import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
import java.util.Optional;
/**
@@ -49,32 +48,24 @@
/**
* Create ClientSNI when {@link HttpHeaders#HOST} is set different from the request URI host (or {@code whenDiffer}.is false).
* @param hostUri the Uri of the HTTP request
- * @param headers the HttpHeaders
+ * @param sniHostName the SniHostName either from HttpHeaders or the
+ * {@link org.glassfish.jersey.client.ClientProperties#SNI_HOST_NAME} property from Configuration object.
* @param whenDiffer create {@SniConfigurator only when different from the request URI host}
* @return ClientSNI or empty when {@link HttpHeaders#HOST}
*/
- static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, Map<String, List<Object>> headers, boolean whenDiffer) {
- List<Object> hostHeaders = headers.get(HttpHeaders.HOST);
- if (hostHeaders == null || hostHeaders.get(0) == null) {
+ static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, String sniHostName, boolean whenDiffer) {
+ if (sniHostName == null) {
return Optional.empty();
}
- final String hostHeader = hostHeaders.get(0).toString();
- final String trimmedHeader;
- if (hostHeader != null) {
- int index = hostHeader.indexOf(':'); // RFC 7230 Host = uri-host [ ":" port ] ;
- final String trimmedHeader0 = index != -1 ? hostHeader.substring(0, index).trim() : hostHeader.trim();
- trimmedHeader = trimmedHeader0.isEmpty() ? hostHeader : trimmedHeader0;
- } else {
- return Optional.empty();
+ if (hostUri != null) {
+ final String hostUriString = hostUri.getHost();
+ if (!whenDiffer && hostUriString.equals(sniHostName)) {
+ return Optional.empty();
+ }
}
- final String hostUriString = hostUri.getHost();
- if (!whenDiffer && hostUriString.equals(trimmedHeader)) {
- return Optional.empty();
- }
-
- return Optional.of(new SniConfigurator(trimmedHeader));
+ return Optional.of(new SniConfigurator(sniHostName));
}
/**
@@ -97,7 +88,7 @@
sslSocket.setSSLParameters(sslParameters);
}
- private SSLParameters updateSSLParameters(SSLParameters sslParameters) {
+ SSLParameters updateSSLParameters(SSLParameters sslParameters) {
SNIHostName serverName = new SNIHostName(hostName);
List<SNIServerName> serverNames = new LinkedList<>();
serverNames.add(serverName);
diff --git a/docs/src/main/docbook/appendix-properties.xml b/docs/src/main/docbook/appendix-properties.xml
index c979b32..381d1b9 100644
--- a/docs/src/main/docbook/appendix-properties.xml
+++ b/docs/src/main/docbook/appendix-properties.xml
@@ -1,7 +1,7 @@
<?xml version="1.0"?>
<!--
- Copyright (c) 2013, 2022 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2013, 2023 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -1153,13 +1153,30 @@
<para>
Property for threshold size for content length after which Expect:100-Continue header would be applied
before the main request.
- Default threshold size (64kb) after which which Expect:100-Continue header would be applied before
+ Default threshold size (64kb) after which Expect:100-Continue header would be applied before
the main request.
<literal>Since 2.32</literal>
</para>
</entry>
</row>
<row>
+ <entry>&jersey.client.ClientProperties.SNI_HOST_NAME;</entry>
+ <entry><literal>jersey.config.client.sniHostName</literal></entry>
+ <entry>
+ <para>
+ Most connectors support HOST header value to be used as an SNIHostName. However, the HOST header is restricted in JDK.
+ <literal>HttpUrlConnector</literal> and <literal>JavaNetHttpConnector</literal> need
+ an extra System Property set to allow HOST header.
+ As an option to HOST header, this property allows the HOST name to be pre-set on a Client and does not need to
+ be set on each request.
+ <literal>Since 3.1.2</literal>
+ </para>
+ <para>
+ The value MUST be an instance of &lit.jdk6.String;
+ </para>
+ </entry>
+ </row>
+ <row>
<entry>&jersey.logging.LoggingFeature.LOGGING_FEATURE_LOGGER_NAME_CLIENT;
</entry>
<entry>
diff --git a/docs/src/main/docbook/jersey.ent b/docs/src/main/docbook/jersey.ent
index 702c511..2cc0800 100644
--- a/docs/src/main/docbook/jersey.ent
+++ b/docs/src/main/docbook/jersey.ent
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="iso-8859-1" ?>
<!--
- Copyright (c) 2010, 2022 Oracle and/or its affiliates. All rights reserved.
+ Copyright (c) 2010, 2023 Oracle and/or its affiliates. All rights reserved.
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
@@ -360,6 +360,7 @@
<!ENTITY jersey.client.ClientProperties.DIGESTAUTH_URI_CACHE_SIZELIMIT "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#DIGESTAUTH_URI_CACHE_SIZELIMIT'>ClientProperties.DIGESTAUTH_URI_CACHE_SIZELIMIT</link>" >
<!ENTITY jersey.client.ClientProperties.EXPECT_100_CONTINUE "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#EXPECT_100_CONTINUE'>ClientProperties.EXPECT_100_CONTINUE</link>" >
<!ENTITY jersey.client.ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#EXPECT_100_CONTINUE_THRESHOLD_SIZE'>ClientProperties.EXPECT_100_CONTINUE_THRESHOLD_SIZE</link>" >
+<!ENTITY jersey.client.ClientProperties.SNI_HOST_NAME "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientProperties.html#SNI_HOST_NAME'>ClientProperties.SNI_HOST_NAME</link>" >
<!ENTITY jersey.client.ClientLifecycleListener "<link xlink:href='&jersey.javadoc.uri.prefix;/client/ClientLifecycleListener.html'>ClientLifecycleListener</link>">
<!ENTITY jersey.client.Connector "<link xlink:href='&jersey.javadoc.uri.prefix;/client/spi/Connector.html'>Connector</link>">
<!ENTITY jersey.client.ConnectorProvider "<link xlink:href='&jersey.javadoc.uri.prefix;/client/spi/ConnectorProvider.html'>ConnectorProvider</link>">
diff --git a/tests/e2e-tls/pom.xml b/tests/e2e-tls/pom.xml
index 5c6b7fd..eaa7198 100644
--- a/tests/e2e-tls/pom.xml
+++ b/tests/e2e-tls/pom.xml
@@ -44,6 +44,7 @@
<skipTests>${skip.e2e}</skipTests>
<systemPropertyVariables>
<sun.net.http.allowRestrictedHeaders>true</sun.net.http.allowRestrictedHeaders>
+ <jdk.httpclient.allowRestrictedHeaders>Host</jdk.httpclient.allowRestrictedHeaders>
<property>
<name>ssl.debug</name>
<value>true</value>
@@ -110,6 +111,11 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.glassfish.jersey.connectors</groupId>
+ <artifactId>jersey-jnh-connector</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>org.glassfish.jersey.security</groupId>
<artifactId>oauth1-signature</artifactId>
<version>${project.version}</version>
diff --git a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
index 1e8d893..3964fce 100644
--- a/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
+++ b/tests/e2e-tls/src/test/java/org/glassfish/jersey/tests/e2e/tls/SniTest.java
@@ -16,6 +16,7 @@
package org.glassfish.jersey.tests.e2e.tls;
+import jakarta.ws.rs.client.Invocation;
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
@@ -23,9 +24,9 @@
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.spi.ConnectorProvider;
import org.glassfish.jersey.jdk.connector.JdkConnectorProvider;
+import org.glassfish.jersey.jnh.connector.JavaNetHttpConnectorProvider;
import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
import org.glassfish.jersey.tests.e2e.tls.explorer.SSLCapabilities;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@@ -39,21 +40,19 @@
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
-import java.net.URI;
import java.net.UnknownHostException;
-import java.nio.charset.StandardCharsets;
import java.util.LinkedList;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class SniTest {
private static final int PORT = 8443;
private static final String LOCALHOST = "127.0.0.1";
-
static {
+// Debug
+// System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
+// System.setProperty("jdk.httpclient.allowRestrictedHeaders", "Host");
// JDK specific settings
System.setProperty("jdk.net.hosts.file", SniTest.class.getResource("/hosts").getPath());
}
@@ -64,7 +63,8 @@
new ApacheConnectorProvider(),
new Apache5ConnectorProvider(),
new JdkConnectorProvider(),
- new HttpUrlConnectorProvider()
+ new HttpUrlConnectorProvider(),
+ new JavaNetHttpConnectorProvider()
};
}
@@ -73,10 +73,11 @@
public void server1Test(ConnectorProvider provider) {
ClientConfig clientConfig = new ClientConfig();
clientConfig.connectorProvider(provider);
- serverTest(clientConfig, "www.host1.com");
+ clientConfig.property(ClientProperties.SNI_HOST_NAME, "www.host1.com");
+ serverTest(clientConfig, provider, "www.host1.com");
}
- public void serverTest(ClientConfig clientConfig, String hostName) {
+ public void serverTest(ClientConfig clientConfig, ConnectorProvider provider, String hostName) {
String newHostName = replaceWhenHostNotKnown(hostName);
final List<SNIServerName> serverNames = new LinkedList<>();
final String[] requestHostName = new String[1];
@@ -91,7 +92,7 @@
clientConfig.property(ClientProperties.READ_TIMEOUT, 2000);
clientConfig.property(ClientProperties.CONNECT_TIMEOUT, 2000);
- try (Response r = ClientBuilder.newClient(clientConfig)
+ Invocation.Builder builder = ClientBuilder.newClient(clientConfig)
.register(new ClientRequestFilter() {
@Override
public void filter(ClientRequestContext requestContext) throws IOException {
@@ -100,9 +101,11 @@
})
.target("https://" + (newHostName.equals(LOCALHOST) ? LOCALHOST : "www.host0.com") + ":" + PORT)
.path("host")
- .request()
- .header(HttpHeaders.HOST, hostName + ":8080")
- .get()) {
+ .request();
+ if (!JavaNetHttpConnectorProvider.class.isInstance(provider)) {
+ builder = builder.header(HttpHeaders.HOST, hostName + ":8080");
+ }
+ try (Response r = builder.get()) {
// empty
} catch (Exception e) {
Throwable cause = e;
@@ -111,7 +114,7 @@
&& TimeoutException.class.isInstance(cause)) {
cause = cause.getCause();
}
- if (cause == null && /*IOE*/ !e.getMessage().contains("Stream closed")) {
+ if ((!e.getMessage().contains("Stream closed")) && !e.getMessage().contains("timed out")) {
throw e;
}
}