Skip to content

Commit ca50360

Browse files
joerg1985diemol
andauthored
[java] Handle redirects inside the JdkHttpClient (#11816)
Handle redirects inside the JdkHttpClient Co-authored-by: Diego Molina <[email protected]>
1 parent ec3ed70 commit ca50360

2 files changed

Lines changed: 45 additions & 13 deletions

File tree

java/src/org/openqa/selenium/remote/http/jdk/JdkHttpClient.java

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.io.UncheckedIOException;
4040
import java.net.Authenticator;
4141
import java.net.PasswordAuthentication;
42+
import java.net.ProtocolException;
4243
import java.net.Proxy;
4344
import java.net.ProxySelector;
4445
import java.net.SocketAddress;
@@ -62,8 +63,6 @@
6263
import java.util.logging.Level;
6364
import java.util.logging.Logger;
6465

65-
import static java.net.http.HttpClient.Redirect.ALWAYS;
66-
6766
public class JdkHttpClient implements HttpClient {
6867
public static final Logger LOG = Logger.getLogger(JdkHttpClient.class.getName());
6968
private final JdkHttpMessages messages;
@@ -82,7 +81,7 @@ public class JdkHttpClient implements HttpClient {
8281

8382
java.net.http.HttpClient.Builder builder = java.net.http.HttpClient.newBuilder()
8483
.connectTimeout(config.connectionTimeout())
85-
.followRedirects(ALWAYS)
84+
.followRedirects(java.net.http.HttpClient.Redirect.NEVER)
8685
.executor(executorService);
8786

8887
Credentials credentials = config.credentials();
@@ -289,7 +288,42 @@ public HttpResponse execute(HttpRequest req) throws UncheckedIOException {
289288

290289
BodyHandler<byte[]> byteHandler = BodyHandlers.ofByteArray();
291290
try {
292-
return messages.createResponse(client.send(messages.createRequest(req), byteHandler));
291+
URI rawUri = messages.getRawUri(req);
292+
293+
// We need a custom handling of redirects to:
294+
// - increase the maximum number of retries to 100
295+
// - avoid a downgrade of POST requests, see the javadoc of j.n.h.HttpClient.Redirect
296+
// - not run into https://bugs.openjdk.org/browse/JDK-8304701
297+
for (int i = 0; i < 100; i++) {
298+
java.net.http.HttpRequest request = messages.createRequest(req, rawUri);
299+
java.net.http.HttpResponse<byte[]> response = client.send(request, byteHandler);
300+
301+
switch (response.statusCode()) {
302+
case 301:
303+
case 302:
304+
case 303:
305+
case 307:
306+
case 308:
307+
URI location = rawUri.resolve(response.headers()
308+
.firstValue("location")
309+
.orElseThrow(() -> new ProtocolException(
310+
"HTTP " + response.statusCode() + " without 'location' header set"
311+
)));
312+
313+
if ("https".equalsIgnoreCase(rawUri.getScheme()) && !"https".equalsIgnoreCase(location.getScheme()) ) {
314+
throw new SecurityException("Downgrade from secure to insecure connection.");
315+
} else if ("wss".equalsIgnoreCase(rawUri.getScheme()) && !"wss".equalsIgnoreCase(location.getScheme()) ) {
316+
throw new SecurityException("Downgrade from secure to insecure connection.");
317+
}
318+
319+
rawUri = location;
320+
continue;
321+
default:
322+
return messages.createResponse(response);
323+
}
324+
}
325+
326+
throw new ProtocolException("Too many redirects: 101");
293327
} catch (HttpTimeoutException e) {
294328
throw new TimeoutException(e);
295329
} catch (IOException e) {

java/src/org/openqa/selenium/remote/http/jdk/JdkHttpMessages.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public JdkHttpMessages(ClientConfig config) {
4545
this.config = Objects.requireNonNull(config, "Client config");
4646
}
4747

48-
public java.net.http.HttpRequest createRequest(HttpRequest req) {
49-
String rawUrl = getRawUrl(config.baseUri(), req.getUri());
48+
public java.net.http.HttpRequest createRequest(HttpRequest req, URI rawUri) {
49+
String rawUrl = rawUri.toString();
5050

5151
// Add query string if necessary
5252
String queryString = StreamSupport.stream(req.getQueryParameterNames().spliterator(), false)
@@ -129,20 +129,18 @@ private BodyPublisher notChunkingBodyPublisher(HttpRequest req) {
129129
return BodyPublishers.fromPublisher(chunking, Long.parseLong(length));
130130
}
131131

132-
private String getRawUrl(URI baseUrl, String uri) {
132+
public URI getRawUri(HttpRequest req) {
133+
URI baseUrl = config.baseUri();
134+
String uri = req.getUri();
133135
String rawUrl;
136+
134137
if (uri.startsWith("ws://") || uri.startsWith("wss://") ||
135-
uri.startsWith("http://") || uri.startsWith("https://")) {
138+
uri.startsWith("http://") || uri.startsWith("https://")) {
136139
rawUrl = uri;
137140
} else {
138141
rawUrl = baseUrl.toString().replaceAll("/$", "") + uri;
139142
}
140143

141-
return rawUrl;
142-
}
143-
144-
public URI getRawUri(HttpRequest req) {
145-
String rawUrl = getRawUrl(config.baseUri(), req.getUri());
146144
return URI.create(rawUrl);
147145
}
148146

0 commit comments

Comments
 (0)