Skip to content

Commit 2bbb913

Browse files
jansupolsenivam
authored andcommitted
IPv6 support for http request
Signed-off-by: jansupol <[email protected]>
1 parent a1c8068 commit 2bbb913

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

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

Lines changed: 6 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,12 +20,14 @@
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;
2627
import javax.net.ssl.SSLSocket;
2728
import javax.ws.rs.core.Configuration;
2829
import javax.ws.rs.core.UriBuilder;
30+
import java.net.Inet6Address;
2931
import java.net.InetAddress;
3032
import java.net.URI;
3133
import java.net.UnknownHostException;
@@ -233,7 +235,9 @@ public URI toIPRequestUri() {
233235
String host = uri.getHost();
234236
try {
235237
InetAddress ip = InetAddress.getByName(host);
236-
return UriBuilder.fromUri(uri).host(ip.getHostAddress()).build();
238+
// ipv6 is expected in square brackets in UriBuilder#host()
239+
final String hostAddress = ip instanceof Inet6Address ? '[' + ip.getHostAddress() + ']' : ip.getHostAddress();
240+
return UriBuilder.fromUri(uri).host(hostAddress).build();
237241
} catch (UnknownHostException e) {
238242
return uri;
239243
}

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

Lines changed: 5 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,10 @@ 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 ] ;
65+
if (sniHost.indexOf(']', index) != -1) {
66+
index = -1; // beware of ipv6 [:1] without port
67+
}
6568
final String trimmedHeader0 = index != -1 ? sniHost.substring(0, index).trim() : sniHost.trim();
6669
trimmedHeader = trimmedHeader0.isEmpty() ? sniHost : trimmedHeader0;
6770
} else {

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

Lines changed: 57 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,56 @@ 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().toString(),
180+
Matchers.is(uri.toString().replace("::", ":0:0:0:0:0:")));
181+
}
182+
183+
@Test
184+
public void testIpv6Request() {
185+
Client client = ClientBuilder.newClient();
186+
String u = "http://[::1]:8080";
187+
try {
188+
client.target(u)
189+
.request()
190+
.header(HttpHeaders.HOST, "[172:30::333b]:8080")
191+
.get();
192+
} catch (ProcessingException pe) {
193+
if (!ConnectException.class.isInstance(pe.getCause())) {
194+
throw pe;
195+
}
196+
}
197+
}
198+
199+
@Test
200+
public void testIpv6RequestNoPort() {
201+
Client client = ClientBuilder.newClient();
202+
String u = "http://[::1]";
203+
try {
204+
client.target(u)
205+
.request()
206+
.header(HttpHeaders.HOST, "[172:30::333b]")
207+
.get();
208+
} catch (ProcessingException pe) {
209+
if (!ConnectException.class.isInstance(pe.getCause())) {
210+
throw pe;
211+
}
212+
}
213+
}
158214
}

0 commit comments

Comments
 (0)