-
Notifications
You must be signed in to change notification settings - Fork 631
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Forwarded / X-Forwarded-* headers #249
Conversation
InetSocketAddress remoteAddress = channel.remoteAddress(); | ||
String scheme = channel.pipeline().get(SslHandler.class) != null ? "https" : "http"; | ||
|
||
String forwarded = request.requestHeaders().get(FORWARDED_HEADER).split(",")[0]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is splitting on the comma ,
character ok? quoted strings in header values are allowed to contain commas BUT in this particular case:
proto=
definition is same as URI scheme (no commas allowed 👍 )for=
definition is that of a Node identifier (no commas allowed 👍 )host=
definition is that of the Host header field / HTTP URI. This one is a bit more complex, but I don't think unencoded commas can appear (🤔)
So this should be ok, but might want to dig into the host
one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See rfc7239 section 5.3 and rfc7230 section 3.2.6.
,
is part of the US-ASCII delimiters, so not allowed there AFAIU.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's for the token
part (here host
), but the value can be a quoted string, which may contain characters in the %x23-5B
range (including the comma %x2C
), in addition to %x21
(!
) but not %x22
(double quotes)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get it - isn't that encoded still at that point?
I just tried sending a Forward: for="exa%x2Cmple.com"
header and serverRequest.remoteAddress().getHostString()
does return "exa%x2Cmple.com"
. Do you have a test case in mind that reproduces the issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nope, just had a gut feeling splitting on ,
might be "too simple". I have thus briefly looked at the RFC, which I have a limited understanding of (since I don't deal with as often as you guys ;) )
from what I understand of the ABNF notation used in the RFC, %x2C
means "a literal comma", not "a comma encoded as %x2C" [1] (so that might be were I'm interpreting things wrong).
rfc7230 section 3.2.6 defines the quoted string qdtext
with such a range: %x23-5B
(which I assume would mean "the literal characters between #
an [
, including A-Z and the comma.
if that's working well enough for SPR, then that's probably good 👍 just challenging the assumptions a bit.
[1] see ABNF rfc section 3.4
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You may be right, actually.
At the same time it seems commas aren't allowed in hostnames (in other RFCs) and it looks like Tomcat is doing the same: https://github.com/apache/tomcat/blob/trunk/java/org/apache/catalina/valves/RemoteIpValve.java#L354
@@ -107,9 +112,13 @@ static HttpServerOperations bindHttp(Channel channel, | |||
this.nettyResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); | |||
this.responseHeaders = nettyResponse.headers(); | |||
this.cookieHolder = Cookies.newServerRequestHolder(requestHeaders()); | |||
if (ch.attr(USE_FORWARDED).get()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check for null
Something like
Attribute<Boolean> useForwarded = ch.attr(USE_FORWARDED);
if (useForwarded != null && useForwarded.get() != null && useForwarded.get()) {
|
||
@Test | ||
public void forwardedForIpV6() { | ||
testClientRequest( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is failing for me
org.junit.ComparisonFailure: expected:<"[OK]"> but was:<"[expected:<"[[2001:db8:cafe::17]]"> but was:<"[2001:db8:cafe:0:0:0:0:17]">]">
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at reactor.ipc.netty.http.server.ConnectionInfoTests.testClientRequest(ConnectionInfoTests.java:206)
at reactor.ipc.netty.http.server.ConnectionInfoTests.forwardedForIpV6(ConnectionInfoTests.java:176)
|
||
@Test | ||
public void forwardedHostIpV6() { | ||
testClientRequest( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is failing for me
org.junit.ComparisonFailure: expected:<"[OK]"> but was:<"[expected:<"[[1abc:2abc:3abc::5ABC:6abc]]"> but was:<"[1abc:2abc:3abc:0:0:0:5abc:6abc]">]">
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at reactor.ipc.netty.http.server.ConnectionInfoTests.testClientRequest(ConnectionInfoTests.java:206)
at reactor.ipc.netty.http.server.ConnectionInfoTests.forwardedHostIpV6(ConnectionInfoTests.java:50)
|
||
@Test | ||
public void xForwardedFor() { | ||
testClientRequest( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is failing for me
org.junit.ComparisonFailure: expected:<"[OK]"> but was:<"[expected:<"[[1abc:2abc:3abc::5ABC:6abc]]"> but was:<"[1abc:2abc:3abc:0:0:0:5abc:6abc]">]">
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at reactor.ipc.netty.http.server.ConnectionInfoTests.testClientRequest(ConnectionInfoTests.java:206)
at reactor.ipc.netty.http.server.ConnectionInfoTests.xForwardedFor(ConnectionInfoTests.java:62)
|
||
@Test | ||
public void xForwardedHost() { | ||
testClientRequest( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is failing for me
org.junit.ComparisonFailure: expected:<"[OK]"> but was:<"[expected:<"[[1abc:2abc:3abc::5ABC:6abc]]"> but was:<"[1abc:2abc:3abc:0:0:0:5abc:6abc]">]">
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at reactor.ipc.netty.http.server.ConnectionInfoTests.testClientRequest(ConnectionInfoTests.java:206)
at reactor.ipc.netty.http.server.ConnectionInfoTests.xForwardedHost(ConnectionInfoTests.java:74)
@@ -0,0 +1,214 @@ | |||
package reactor.ipc.netty.http.server; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add copyright header
@@ -0,0 +1,146 @@ | |||
package reactor.ipc.netty.http.server; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add copyright header
Thanks for the review @violetagg ! |
@violetagg Note that the CI build is still failing because I think that the license automatic check is checking for Happy new year 🎉, I guess! |
yes we need to rebase from master and then it will be ok |
|
This commit adds new information to the `HttpServerRequest`: * the host (server) address * the remote (client) address * the scheme used by the current request This information can be either derived from the current channel, or extracted from the incoming HTTP request headers using "Forwarded" or "X-Forwarded-*". This feature is opt-in, and must be configured during server setup: HttpServer.create().forwarded().port(8080); Closes reactorgh-220
Closed by a8c9b24 |
This is a proposal for gh-220.
This implementation supports both the standard header
"Forward"
, but also non-standard but quite common ones, such as"X-Forwarded-For"
,"X-Forwarded-Host"
,"X-Forwarded-Port"
and"X-Forwarded-Proto"
.I've made available that information directly in the
HttpServerRequest
. Of course this feature is opt-in and disabled by default.Possible improvements:
X-Forwarded-*