Expected Behavior
It is expected that reactor-netty always honors the provided X-Forwarded-Port when calling HttpServerRequest#hostPort.
Actual Behavior
The problem is that reactor-netty does not honor the X-Forwarded-Port header if X-Forwarded-Host isn’t set, and thus it can report the port of a proxied connection rather than the actual (forwarded) host port.
As a result, reactor-netty incorrectly reports port 80, while the scheme is https and X-Forwarded-Port is set. This becomes a problem in our setup which is as follows:
We have AWS Application Load Balancers (ALBs) which perform TLS termination and proxy requests to pods running within our Kubernetes clusters. ALBs only add the following headers to a proxied request, as per the documentation:
X-Forwarded-For
X-Forwarded-Proto
X-Forwarded-Port
In addition, the Host header is set by the original request. However, when we call HttpServerRequest#hostPort for a request that requests a URL of the format https://some-host.domain, we would expect hostPort to return 443. Instead, it returns 80.
The following issue may be related: #2714.
This became a problem in combination with the following commit from Spring framework: spring-projects/spring-framework@a2b7a90, where they (correctly) prefer the host address rather than parsing the Host header themselves.
Steps to Reproduce
@Test
void xForwardedForAndHost() {
testClientRequest(
clientRequestHeaders -> {
clientRequestHeaders.add("Host", "a.example.com");
clientRequestHeaders.add("X-Forwarded-For", "192.168.0.1");
clientRequestHeaders.add("X-Forwarded-Port", "443");
clientRequestHeaders.add("X-Forwarded-Proto", "https");
},
serverRequest -> {
Assertions.assertThat(serverRequest.hostPort()).isEqualTo(443);
Assertions.assertThat(serverRequest.hostName()).isEqualTo("a.example.com");
Assertions.assertThat(serverRequest.scheme()).isEqualTo("https");
});
}
This test fails as the port returned is 80 instead of 443.
Possible Solution
Adding the following line results in the expected result:
clientRequestHeaders.add("X-Forwarded-Host", "a.example.com");
Your Environment
- Reactor version(s) used: 2020.0.30, we use the
reactor-bom.
- Other relevant libraries versions (eg.
netty, ...): Netty 1.0.30.
- JVM version (
java -version):
$ java -version
openjdk version "17.0.3" 2022-04-19 LTS
OpenJDK Runtime Environment Zulu17.34+19-CA (build 17.0.3+7-LTS)
OpenJDK 64-Bit Server VM Zulu17.34+19-CA (build 17.0.3+7-LTS, mixed mode, sharing)
- OS and version (eg.
uname -a):
$ uname -a
Linux rick-ommitted 5.15.0-67-generic #74~20.04.1-Ubuntu SMP Wed Feb 22 14:52:34 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
Expected Behavior
It is expected that
reactor-nettyalways honors the providedX-Forwarded-Portwhen callingHttpServerRequest#hostPort.Actual Behavior
The problem is that
reactor-nettydoes not honor theX-Forwarded-Portheader ifX-Forwarded-Hostisn’t set, and thus it can report the port of a proxied connection rather than the actual (forwarded) host port.As a result,
reactor-nettyincorrectly reports port 80, while the scheme ishttpsandX-Forwarded-Portis set. This becomes a problem in our setup which is as follows:We have AWS Application Load Balancers (ALBs) which perform TLS termination and proxy requests to pods running within our Kubernetes clusters. ALBs only add the following headers to a proxied request, as per the documentation:
X-Forwarded-ForX-Forwarded-ProtoX-Forwarded-PortIn addition, the
Hostheader is set by the original request. However, when we callHttpServerRequest#hostPortfor a request that requests a URL of the formathttps://some-host.domain, we would expecthostPortto return443. Instead, it returns80.The following issue may be related: #2714.
This became a problem in combination with the following commit from Spring framework: spring-projects/spring-framework@a2b7a90, where they (correctly) prefer the host address rather than parsing the
Hostheader themselves.Steps to Reproduce
This test fails as the port returned is
80instead of443.Possible Solution
Adding the following line results in the expected result:
Your Environment
reactor-bom.netty, ...): Netty 1.0.30.java -version):uname -a):