Skip to content

Commit 77621ce

Browse files
authored
Parse X-Forwarded-Port header even if X-Forwarded-Host is not present (#2761)
Always takes into account any available X-Forwarded-Port header even if the X-Forwarded-Host header is missing. Fixes #2751
1 parent fcfa6a4 commit 77621ce

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

reactor-netty-http/src/main/java/reactor/netty/http/server/DefaultHttpForwardedHeaderHandler.java

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -98,25 +98,31 @@ private ConnectionInfo parseXForwardedInfo(ConnectionInfo connectionInfo, HttpRe
9898
}
9999
String hostHeader = request.headers().get(X_FORWARDED_HOST_HEADER);
100100
if (hostHeader != null) {
101-
String scheme = connectionInfo.getScheme();
102-
int port = scheme.equalsIgnoreCase("https") || scheme.equalsIgnoreCase("wss") ?
103-
DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT;
104101
connectionInfo = connectionInfo.withHostAddress(
105-
AddressUtils.parseAddress(hostHeader.split(",", 2)[0].trim(), port, DEFAULT_FORWARDED_HEADER_VALIDATION));
106-
String portHeader = request.headers().get(X_FORWARDED_PORT_HEADER);
107-
if (portHeader != null && !portHeader.isEmpty()) {
108-
String portStr = portHeader.split(",", 2)[0].trim();
109-
if (portStr.chars().allMatch(Character::isDigit)) {
110-
port = Integer.parseInt(portStr);
111-
}
112-
else if (DEFAULT_FORWARDED_HEADER_VALIDATION) {
113-
throw new IllegalArgumentException("Failed to parse a port from " + portHeader);
114-
}
115-
connectionInfo = connectionInfo.withHostAddress(
116-
AddressUtils.createUnresolved(connectionInfo.getHostAddress().getHostString(), port));
102+
AddressUtils.parseAddress(hostHeader.split(",", 2)[0].trim(),
103+
getDefaultHostPort(connectionInfo), DEFAULT_FORWARDED_HEADER_VALIDATION));
104+
}
105+
106+
String portHeader = request.headers().get(X_FORWARDED_PORT_HEADER);
107+
if (portHeader != null && !portHeader.isEmpty()) {
108+
String portStr = portHeader.split(",", 2)[0].trim();
109+
if (portStr.chars().allMatch(Character::isDigit)) {
110+
int port = Integer.parseInt(portStr);
111+
connectionInfo = new ConnectionInfo(
112+
AddressUtils.createUnresolved(connectionInfo.getHostAddress().getHostString(), port),
113+
connectionInfo.getHostName(), port, connectionInfo.getRemoteAddress(), connectionInfo.getScheme());
114+
}
115+
else if (DEFAULT_FORWARDED_HEADER_VALIDATION) {
116+
throw new IllegalArgumentException("Failed to parse a port from " + portHeader);
117117
}
118118
}
119119
return connectionInfo;
120120
}
121121

122+
private int getDefaultHostPort(ConnectionInfo connectionInfo) {
123+
String scheme = connectionInfo.getScheme();
124+
return scheme.equalsIgnoreCase("https") || scheme.equalsIgnoreCase("wss") ?
125+
DEFAULT_HTTPS_PORT : DEFAULT_HTTP_PORT;
126+
}
127+
122128
}

reactor-netty-http/src/test/java/reactor/netty/http/server/ConnectionInfoTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,32 @@ void xForwardedForMultipleHostAndPortAndProto() {
367367
});
368368
}
369369

370+
@Test
371+
void xForwardedForAndHostOnly() throws SSLException {
372+
SslContext clientSslContext = SslContextBuilder.forClient()
373+
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
374+
SslContext serverSslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
375+
376+
testClientRequest(
377+
clientRequestHeaders -> {
378+
clientRequestHeaders.add("Host", "a.example.com");
379+
clientRequestHeaders.add("X-Forwarded-For", "192.168.0.1");
380+
clientRequestHeaders.add("X-Forwarded-Port", "8443");
381+
clientRequestHeaders.add("X-Forwarded-Proto", "https");
382+
},
383+
serverRequest -> {
384+
Assertions.assertThat(serverRequest.remoteAddress().getHostString()).isEqualTo("192.168.0.1");
385+
Assertions.assertThat(serverRequest.hostAddress().getHostString())
386+
.containsPattern("^0:0:0:0:0:0:0:1(%\\w*)?|127.0.0.1$");
387+
Assertions.assertThat(serverRequest.hostPort()).isEqualTo(8443);
388+
Assertions.assertThat(serverRequest.hostName()).isEqualTo("a.example.com");
389+
Assertions.assertThat(serverRequest.scheme()).isEqualTo("https");
390+
},
391+
httpClient -> httpClient.secure(ssl -> ssl.sslContext(clientSslContext)),
392+
httpServer -> httpServer.secure(ssl -> ssl.sslContext(serverSslContext)),
393+
true);
394+
}
395+
370396
@Test
371397
void customForwardedHandlerForMultipleHost() {
372398
testClientRequest(

0 commit comments

Comments
 (0)