Skip to content

Commit bfc3beb

Browse files
vieirognu-andrew
authored andcommitted
8232625: HttpClient redirect policy should be more conservative
When enabled, HttpClient redirect is fixed to drop the body when the request method is changed, and to relay any redirection code it does not understand to the caller. Reviewed-by: andrew Backport-of: b347739
1 parent 0df5d27 commit bfc3beb

File tree

5 files changed

+514
-12
lines changed

5 files changed

+514
-12
lines changed

src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.net.http.HttpClient;
4242
import java.net.http.HttpHeaders;
4343
import java.net.http.HttpRequest;
44+
4445
import jdk.internal.net.http.common.HttpHeadersBuilder;
4546
import jdk.internal.net.http.common.Utils;
4647
import jdk.internal.net.http.websocket.OpeningHandshake;
@@ -152,13 +153,14 @@ private static void checkTimeout(Duration duration) {
152153
/** Returns a new instance suitable for redirection. */
153154
public static HttpRequestImpl newInstanceForRedirection(URI uri,
154155
String method,
155-
HttpRequestImpl other) {
156-
return new HttpRequestImpl(uri, method, other);
156+
HttpRequestImpl other,
157+
boolean mayHaveBody) {
158+
return new HttpRequestImpl(uri, method, other, mayHaveBody);
157159
}
158160

159161
/** Returns a new instance suitable for authentication. */
160162
public static HttpRequestImpl newInstanceForAuthentication(HttpRequestImpl other) {
161-
HttpRequestImpl request = new HttpRequestImpl(other.uri(), other.method(), other);
163+
HttpRequestImpl request = new HttpRequestImpl(other.uri(), other.method(), other, true);
162164
if (request.isWebSocket()) {
163165
Utils.setWebSocketUpgradeHeaders(request);
164166
}
@@ -171,7 +173,8 @@ public static HttpRequestImpl newInstanceForAuthentication(HttpRequestImpl other
171173
*/
172174
private HttpRequestImpl(URI uri,
173175
String method,
174-
HttpRequestImpl other) {
176+
HttpRequestImpl other,
177+
boolean mayHaveBody) {
175178
assert method == null || Utils.isValidName(method);
176179
this.method = method == null? "GET" : method;
177180
this.userHeaders = other.userHeaders;
@@ -184,13 +187,21 @@ private HttpRequestImpl(URI uri,
184187
this.proxy = other.proxy;
185188
this.expectContinue = other.expectContinue;
186189
this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
187-
this.requestPublisher = other.requestPublisher; // may be null
190+
this.requestPublisher = mayHaveBody ? publisher(other) : null; // may be null
188191
this.acc = other.acc;
189192
this.timeout = other.timeout;
190193
this.version = other.version();
191194
this.authority = null;
192195
}
193196

197+
private BodyPublisher publisher(HttpRequestImpl other) {
198+
BodyPublisher res = other.requestPublisher;
199+
if (!Objects.equals(method, other.method)) {
200+
res = null;
201+
}
202+
return res;
203+
}
204+
194205
/* used for creating CONNECT requests */
195206
HttpRequestImpl(String method, InetSocketAddress authority, HttpHeaders headers) {
196207
// TODO: isWebSocket flag is not specified, but the assumption is that

src/java.net.http/share/classes/jdk/internal/net/http/RedirectFilter.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -89,6 +89,31 @@ private static String redirectedMethod(int statusCode, String orig) {
8989
}
9090
}
9191

92+
private static boolean isRedirecting(int statusCode) {
93+
// < 300: not a redirect codes
94+
if (statusCode < 300) return false;
95+
// 309-399 Unassigned => don't follow
96+
// > 399: not a redirect code
97+
if (statusCode > 308) return false;
98+
switch (statusCode) {
99+
// 300: MultipleChoice => don't follow
100+
case 300:
101+
return false;
102+
// 304: Not Modified => don't follow
103+
case 304:
104+
return false;
105+
// 305: Proxy Redirect => don't follow.
106+
case 305:
107+
return false;
108+
// 306: Unused => don't follow
109+
case 306:
110+
return false;
111+
// 301, 302, 303, 307, 308: OK to follow.
112+
default:
113+
return true;
114+
}
115+
}
116+
92117
/**
93118
* Checks to see if a new request is needed and returns it.
94119
* Null means response is ok to return to user.
@@ -102,13 +127,13 @@ private HttpRequestImpl handleResponse(Response r) {
102127
if (rcode == HTTP_NOT_MODIFIED)
103128
return null;
104129

105-
if (rcode >= 300 && rcode <= 399) {
130+
if (isRedirecting(rcode)) {
106131
URI redir = getRedirectedURI(r.headers());
107132
String newMethod = redirectedMethod(rcode, method);
108133
Log.logTrace("response code: {0}, redirected URI: {1}", rcode, redir);
109134
if (canRedirect(redir) && ++exchange.numberOfRedirects < max_redirects) {
110135
Log.logTrace("redirect to: {0} with method: {1}", redir, newMethod);
111-
return HttpRequestImpl.newInstanceForRedirection(redir, newMethod, request);
136+
return HttpRequestImpl.newInstanceForRedirection(redir, newMethod, request, rcode != 303);
112137
} else {
113138
Log.logTrace("not redirecting");
114139
return null;

0 commit comments

Comments
 (0)