Skip to content

Commit 9ed51fb

Browse files
arturobernalgok2c
authored andcommitted
HTTPCLIENT-2372 - Normalize HttpHost port comparison to treat implicit default ports as equal (#643)
1 parent e2e07eb commit 9ed51fb

5 files changed

Lines changed: 77 additions & 4 deletions

File tree

httpclient5/src/main/java/org/apache/hc/client5/http/impl/DefaultRedirectStrategy.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@
3232
import java.util.Iterator;
3333
import java.util.Locale;
3434

35+
import org.apache.hc.client5.http.SchemePortResolver;
3536
import org.apache.hc.client5.http.protocol.RedirectStrategy;
3637
import org.apache.hc.client5.http.utils.URIUtils;
3738
import org.apache.hc.core5.annotation.Contract;
39+
import org.apache.hc.core5.annotation.Internal;
3840
import org.apache.hc.core5.annotation.ThreadingBehavior;
3941
import org.apache.hc.core5.http.Header;
4042
import org.apache.hc.core5.http.HttpException;
@@ -56,18 +58,31 @@
5658
@Contract(threading = ThreadingBehavior.STATELESS)
5759
public class DefaultRedirectStrategy implements RedirectStrategy {
5860

61+
private final SchemePortResolver schemePortResolver;
62+
5963
/**
6064
* Default instance of {@link DefaultRedirectStrategy}.
6165
*/
6266
public static final DefaultRedirectStrategy INSTANCE = new DefaultRedirectStrategy();
6367

68+
@Internal
69+
public DefaultRedirectStrategy(final SchemePortResolver schemePortResolver) {
70+
this.schemePortResolver = schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE;
71+
}
72+
73+
public DefaultRedirectStrategy() {
74+
this(null);
75+
}
76+
6477
@Override
6578
public boolean isRedirectAllowed(
6679
final HttpHost currentTarget,
6780
final HttpHost newTarget,
6881
final HttpRequest redirect,
6982
final HttpContext context) {
70-
if (!currentTarget.equals(newTarget)) {
83+
84+
// If authority (host + effective port) differs, strip sensitive headers
85+
if (!isSameAuthority(currentTarget, newTarget)) {
7186
for (final Iterator<Header> it = redirect.headerIterator(); it.hasNext(); ) {
7287
final Header header = it.next();
7388
if (header.isSensitive()
@@ -80,6 +95,20 @@ public boolean isRedirectAllowed(
8095
return true;
8196
}
8297

98+
private boolean isSameAuthority(final HttpHost h1, final HttpHost h2) {
99+
if (h1 == null || h2 == null) {
100+
return false;
101+
}
102+
final String host1 = h1.getHostName();
103+
final String host2 = h2.getHostName();
104+
if (!host1.equalsIgnoreCase(host2)) {
105+
return false;
106+
}
107+
final int port1 = schemePortResolver.resolve(h1);
108+
final int port2 = schemePortResolver.resolve(h2);
109+
return port1 == port2;
110+
}
111+
83112
@Override
84113
public boolean isRedirected(
85114
final HttpRequest request,

httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,7 @@ public CloseableHttpAsyncClient build() {
836836
if (!redirectHandlingDisabled) {
837837
RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
838838
if (redirectStrategyCopy == null) {
839-
redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
839+
redirectStrategyCopy = schemePortResolver != null ? new DefaultRedirectStrategy(schemePortResolver) : DefaultRedirectStrategy.INSTANCE;
840840
}
841841
execChainDefinition.addFirst(
842842
new AsyncRedirectExec(routePlannerCopy, redirectStrategyCopy),

httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ public CloseableHttpAsyncClient build() {
10231023
if (!redirectHandlingDisabled) {
10241024
RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
10251025
if (redirectStrategyCopy == null) {
1026-
redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
1026+
redirectStrategyCopy = schemePortResolver != null ? new DefaultRedirectStrategy(schemePortResolver) : DefaultRedirectStrategy.INSTANCE;
10271027
}
10281028
execChainDefinition.addFirst(
10291029
new AsyncRedirectExec(routePlannerCopy, redirectStrategyCopy),

httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,7 @@ public CloseableHttpClient build() {
10111011
if (!redirectHandlingDisabled) {
10121012
RedirectStrategy redirectStrategyCopy = this.redirectStrategy;
10131013
if (redirectStrategyCopy == null) {
1014-
redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;
1014+
redirectStrategyCopy = schemePortResolver != null ? new DefaultRedirectStrategy(schemePortResolver) : DefaultRedirectStrategy.INSTANCE;
10151015
}
10161016
execChainDefinition.addFirst(
10171017
new RedirectExec(routePlannerCopy, redirectStrategyCopy),

httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestDefaultRedirectStrategy.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,4 +324,48 @@ void testRedirectAllowed() throws Exception {
324324
null));
325325
}
326326

327+
328+
329+
330+
@Test
331+
void testRedirectAllowedDefaultPortNormalization() {
332+
final DefaultRedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
333+
334+
// HTTPS with explicit 443 vs HTTPS with no port (defaults to 443)
335+
final HttpHost explicitHttps = new HttpHost("https", "example.com", 443);
336+
final HttpHost implicitHttps = new HttpHost("https", "example.com", -1);
337+
Assertions.assertTrue(redirectStrategy.isRedirectAllowed(
338+
explicitHttps,
339+
implicitHttps,
340+
BasicRequestBuilder.get("/")
341+
.addHeader(HttpHeaders.AUTHORIZATION, "token")
342+
.build(),
343+
null));
344+
Assertions.assertTrue(redirectStrategy.isRedirectAllowed(
345+
implicitHttps,
346+
explicitHttps,
347+
BasicRequestBuilder.get("/")
348+
.addHeader(HttpHeaders.COOKIE, "cookie=123")
349+
.build(),
350+
null));
351+
352+
final HttpHost explicitHttp = new HttpHost("http", "example.org", 80);
353+
final HttpHost implicitHttp = new HttpHost("http", "example.org", -1);
354+
Assertions.assertTrue(redirectStrategy.isRedirectAllowed(
355+
explicitHttp,
356+
implicitHttp,
357+
BasicRequestBuilder.get("/")
358+
.addHeader(HttpHeaders.AUTHORIZATION, "token123")
359+
.build(),
360+
null));
361+
Assertions.assertTrue(redirectStrategy.isRedirectAllowed(
362+
implicitHttp,
363+
explicitHttp,
364+
BasicRequestBuilder.get("/")
365+
.addHeader(HttpHeaders.COOKIE, "cookie=abc")
366+
.build(),
367+
null));
368+
}
369+
370+
327371
}

0 commit comments

Comments
 (0)