-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
feat: add Forwarded header parsing and real IP extraction with tests #2744
base: master
Are you sure you want to change the base?
Conversation
cc : @aldas |
@aldas fixed lint error |
cc: @aldas |
1 similar comment
cc: @aldas |
@@ -40,6 +40,8 @@ type Context interface { | |||
// Scheme returns the HTTP protocol scheme, `http` or `https`. | |||
Scheme() string | |||
|
|||
SchemeForwarded() *Forwarded |
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.
Adding new SchemeForwarded
method to Context
interface is a backwards incompatible change. It has to be some utility function or specific IPExtractor
implementation
func (c *context) RealIP() string { | ||
if c.echo != nil && c.echo.IPExtractor != nil { | ||
return c.echo.IPExtractor(c.request) | ||
} | ||
// Check if the "Forwarded" header is present in the request. |
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.
After seeing how complex or how less understood Forwarded
header is - I think it is better not to add it directly to RealIP
method. It is better suited as separate IPExtractor
implementation
func (c *context) SchemeForwarded() *Forwarded { | ||
// Parse and get "Forwarded" header. | ||
// See : https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded | ||
if scheme := c.request.Header.Get(HeaderForwarded); scheme != "" { |
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 only parses single Header. From mozilla article I understand that you can have actually multiple Forwarded
Headers in request.
RFC says https://datatracker.ietf.org/doc/html/rfc7239
A proxy server that wants to add a new "Forwarded" header field value
can either append it to the last existing "Forwarded" header field
after a comma separator or add a new field at the end of the header
block.
Mozilla rephrases this as
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded
If there are multiple proxy servers between the client and server, they may each specify their own forwarding information. This can be done by adding a new Forwarded header to the end of the header block, or by appending the information to the end of the last Forwarded header in a comma-separated list.
There is Nginx issue https://trac.nginx.org/nginx/ticket/1316 that has example for multiple headers in request
|
||
func (c *context) parseForwarded(input string) (Forwarded, error) { | ||
forwarded := Forwarded{} | ||
entries := strings.Split(input, ",") |
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.
To be honest - I do not understand when is semicolon used and when is colon used.
Mozilla documentation says that Directives are key=value pairs, separated by a semicolon.
and This can be done by adding a new Forwarded header to the end of the header block, or by appending the information to the end of the last Forwarded header in a comma-separated list.
Can semicolon and comma be mixed?
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.
Additionally - what about quoted strings that contain comma or semicolon?
RFC says that field value can be value = token / quoted-string
where
These 2 are defined as
token = <Defined in [RFC7230], Section 3.2.6>
quoted-string = <Defined in [RFC7230], Section 3.2.6>
I think rfc7230 section-3.2.6 allows unescaped commas in quoted field value
} | ||
|
||
key := strings.TrimSpace(parts[0]) | ||
value, err := url.QueryUnescape(strings.TrimSpace(parts[1])) |
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 url.QueryUnescape
correct by rfc7230 section-3.2.6?
RFC says that value
is defined as:
forwarded-pair = token "=" value
value = token / quoted-string
token = <Defined in [RFC7230], Section 3.2.6>
quoted-string = <Defined in [RFC7230], Section 3.2.6>
This probably be better off as separate library |
For issue #2694