Skip to content

Commit 3e05b9a

Browse files
committed
IPv6 support for http request
Signed-off-by: jansupol <jan.supol@oracle.com>
1 parent bbaa587 commit 3e05b9a

File tree

3 files changed

+54
-5
lines changed

3 files changed

+54
-5
lines changed

core-client/src/main/java/org/glassfish/jersey/client/innate/http/SSLParamConfigurator.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,6 +20,7 @@
2020
import org.glassfish.jersey.client.ClientRequest;
2121
import org.glassfish.jersey.http.HttpHeaders;
2222
import org.glassfish.jersey.internal.PropertiesResolver;
23+
import org.glassfish.jersey.internal.guava.InetAddresses;
2324

2425
import javax.net.ssl.SSLEngine;
2526
import javax.net.ssl.SSLParameters;
@@ -233,7 +234,13 @@ public URI toIPRequestUri() {
233234
String host = uri.getHost();
234235
try {
235236
InetAddress ip = InetAddress.getByName(host);
236-
return UriBuilder.fromUri(uri).host(ip.getHostAddress()).build();
237+
// ipv6 is expected in square brackets in UriBuilder#host() && `#isUriInetAddress()`
238+
if (host.charAt(0) == '[' && host.charAt(host.length() - 1) == ']'
239+
&& InetAddresses.isUriInetAddress('[' + ip.getHostAddress() + ']')) {
240+
return UriBuilder.fromUri(uri).build();
241+
} else {
242+
return UriBuilder.fromUri(uri).host(ip.getHostAddress()).build();
243+
}
237244
} catch (UnknownHostException e) {
238245
return uri;
239246
}

core-client/src/main/java/org/glassfish/jersey/client/innate/http/SniConfigurator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, 2024 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -61,7 +61,7 @@ String getHostName() {
6161
static Optional<SniConfigurator> createWhenHostHeader(URI hostUri, String sniHost, boolean whenDiffer) {
6262
final String trimmedHeader;
6363
if (sniHost != null) {
64-
int index = sniHost.indexOf(':'); // RFC 7230 Host = uri-host [ ":" port ] ;
64+
int index = sniHost.lastIndexOf(':'); // RFC 7230 Host = uri-host [ ":" port ] ;
6565
final String trimmedHeader0 = index != -1 ? sniHost.substring(0, index).trim() : sniHost.trim();
6666
trimmedHeader = trimmedHeader0.isEmpty() ? sniHost : trimmedHeader0;
6767
} else {

core-client/src/test/java/org/glassfish/jersey/client/innate/http/SSLParamConfiguratorTest.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025 Oracle and/or its affiliates. All rights reserved.
33
*
44
* This program and the accompanying materials are made available under the
55
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -27,8 +27,12 @@
2727
import org.hamcrest.Matchers;
2828
import org.junit.jupiter.api.Test;
2929

30+
import javax.ws.rs.ProcessingException;
31+
import javax.ws.rs.client.Client;
3032
import javax.ws.rs.client.ClientBuilder;
3133
import javax.ws.rs.core.MultivaluedHashMap;
34+
import javax.ws.rs.core.Response;
35+
import java.net.ConnectException;
3236
import java.net.URI;
3337
import java.util.Collections;
3438
import java.util.HashMap;
@@ -155,4 +159,42 @@ public void testUriAndHeadersAndConfig() {
155159
MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
156160
MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is("yyy.com"));
157161
}
162+
163+
@Test
164+
public void testIPv6Header() {
165+
final String HOST_HEADER_IPv6 = "[172:30::333b]";
166+
final URI uri = URI.create("http://[172:30::333a]:8080/api/demo/v1");
167+
final JerseyClient client = (JerseyClient) ClientBuilder.newClient();
168+
Map<String, List<Object>> httpHeaders = new MultivaluedHashMap<>();
169+
httpHeaders.put(HttpHeaders.HOST, Collections.singletonList(HOST_HEADER_IPv6 + ":8080"));
170+
SSLParamConfigurator configurator = SSLParamConfigurator.builder()
171+
.uri(uri)
172+
.headers(httpHeaders)
173+
.configuration(client.getConfiguration())
174+
.build();
175+
MatcherAssert.assertThat(configurator.isSNIRequired(), Matchers.is(true));
176+
MatcherAssert.assertThat(configurator.getSNIHostName(), Matchers.is(HOST_HEADER_IPv6));
177+
URI expected = URI.create("http://" + HOST_HEADER_IPv6 + ":8080/api/demo/v1");
178+
MatcherAssert.assertThat(configurator.getSNIUri(), Matchers.is(expected));
179+
MatcherAssert.assertThat(configurator.toIPRequestUri(), Matchers.is(uri));
180+
}
181+
182+
@Test
183+
public void testIpv6Request() {
184+
Client client = ClientBuilder.newClient();
185+
String u = "http://[::1]";
186+
try {
187+
client.target(u)
188+
.request()
189+
.header(HttpHeaders.HOST, "[172:30::333b]:8080")
190+
.header("language-option-two", "true")
191+
.property(ClientProperties.CONNECT_TIMEOUT, 1800 * 1000)
192+
.property(ClientProperties.READ_TIMEOUT, 1800 * 1000)
193+
.get();
194+
} catch (ProcessingException pe) {
195+
if (!ConnectException.class.isInstance(pe.getCause())) {
196+
throw pe;
197+
}
198+
}
199+
}
158200
}

0 commit comments

Comments
 (0)