http conn man: add an option to strip trailing host dot.#15568
http conn man: add an option to strip trailing host dot.#15568snowp merged 23 commits intoenvoyproxy:mainfrom
Conversation
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
|
Hi @maheshkurund, welcome and thank you for your contribution. We will try to review your Pull Request as quickly as possible. In the meantime, please take a look at the contribution guidelines if you have not done so already. |
|
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
| filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose); | ||
| } | ||
|
|
||
| // Filters observe host header w/o trailing dot in host when trailing dot removal is configured |
There was a problem hiding this comment.
Do you think dot stripping could be tested more directly? Instantiate ConnectionManagerImpl, create a RequestDecoder by invoking ConnectionManagerImpl::newStream(), then invoke RequestDecoder::decodeHeaders() and verify the contents of the "host" header. WDYT?
There was a problem hiding this comment.
yes, added test for this, please check and let me know. Thank you.
There was a problem hiding this comment.
Ultimately, I'm not sure why three tests that very closely resemble each other are needed (they all verify that a) header map is updated, and b) that filters in the filter chain see that change. Perhaps just RemoveTrailingHostDot or FilterShouldUseHostWithoutTrailingDot is sufficient?
There was a problem hiding this comment.
Agree, will remove RemoveTrailingHostDot test and add check to verify host header after RequestDecoder::decodeHeaders() in FilterShouldUseHostWithoutTrailingDot and RouteShouldUseHostWithoutTrailingDot.
…ders(). Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
| // This affects the upstream host header. | ||
| // Without setting this option, incoming requests with host `example.com.` will not match against | ||
| // route with :ref:`domains<envoy_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`. | ||
| bool strip_trailing_host_dot = 44; |
There was a problem hiding this comment.
Drive by question for mdroth, do we think it's worth moving this and strip_matching_host_port together in a host mutation proto or just and wait and see if we get more?
There was a problem hiding this comment.
At this point, there are a whole bunch of options here related to URI normalization, not just the host ones but also the path ones. I'd be open to moving all of those options to a separate UriNormalizationOptions message, but I'd also be okay with keeping them here, since they're unlikely to ever be used anywhere else.
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
|
/retest |
|
Retrying Azure Pipelines: |
| EXPECT_CALL(*filter, setDecoderFilterCallbacks(_)); | ||
|
|
||
| EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status { | ||
| decoder_ = &conn_manager_->newStream(response_encoder_); |
There was a problem hiding this comment.
Couldn't you reduce the test to setup and lines 854-857? Then verify the contents of authority in headers...
There was a problem hiding this comment.
Is it ok to verify host header after RequestDecoder::decodeHeaders() in existing tests? Or should I keep only single test which just verifies host header after RequestDecoder::decodeHeaders() as you mentioned above?
…t_dot Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
|
/retest |
|
Retrying Azure Pipelines: |
| return Http::okStatus(); | ||
| })); | ||
| Buffer::OwnedImpl fake_input("1234"); | ||
| conn_manager_->onData(fake_input, false); |
There was a problem hiding this comment.
I don't think you need to call onData callback (and set the expectation above), instead you should be able to do
conn_manager_->createCodec(fake_input);
There was a problem hiding this comment.
thank you. Updated the code with suggestion.
|
The tests look good, with one minor suggestion for a change. Also, please merge in the latest changes from main. |
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
|
/retest |
|
Retrying Azure Pipelines: |
|
/retest |
|
Retrying Azure Pipelines: |
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
|
/retest |
|
Retrying Azure Pipelines: |
snowp
left a comment
There was a problem hiding this comment.
Thanks for working on this!
source/common/http/header_utility.cc
Outdated
|
|
||
| void HeaderUtility::stripTrailingHostDot(RequestHeaderMap& headers) { | ||
| auto host = headers.getHostValue(); | ||
| // Find last dot and return if not found or take off end if last |
There was a problem hiding this comment.
Maybe just // If the host ends in a period, remove it.
There was a problem hiding this comment.
Yes fits well here, will update.
source/common/http/header_utility.cc
Outdated
| // Check if the dot is just before a colon, which means it must be the port | ||
| // because although the host may contain a colon via an IPv6 bracketed | ||
| // address, and although that IPv6 address may also contain dots when | ||
| // embedding an address per RFC 4291 2.2.3, the dot will never directly | ||
| // precede the colon like it would in foo.com.:123 |
There was a problem hiding this comment.
Maybe split this sentence up? It's very long
There was a problem hiding this comment.
yah, will fix it.
source/common/http/header_utility.cc
Outdated
| headers.setHost(host); | ||
| return; | ||
| } | ||
| // Check if the dot is just before a colon, which means it must be the port |
There was a problem hiding this comment.
If the dot is just before a colon, it must be preceding the port number.
| // Determines if trailing dot of the host should be removed from host/authority header before any | ||
| // processing of request by HTTP filters or routing. | ||
| // This affects the upstream host header. | ||
| // Without setting this option, incoming requests with host `example.com.` will not match against | ||
| // route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`. |
There was a problem hiding this comment.
This should probably include something about how this handles the host:port case
There was a problem hiding this comment.
Will following comment helps here in case of host:port?
In case host/authority header value has port part with host, on setting this option it removes trailing dot from host keeping port value as is i.e host
example.com.:443will becomeexample.com:443.
source/common/http/header_utility.cc
Outdated
| // precede the colon like it would in foo.com.:123 | ||
| if (host[dot_index + 1] == ':') { | ||
| // Does a memcpy internally, but since we only have access to a string_view | ||
| // anyways, this is acceptable compared to a string::erase of a copy |
There was a problem hiding this comment.
nit: end comments with period
source/common/http/header_utility.cc
Outdated
| // embedding an address per RFC 4291 2.2.3, the dot will never directly | ||
| // precede the colon like it would in foo.com.:123 | ||
| if (host[dot_index + 1] == ':') { | ||
| // Does a memcpy internally, but since we only have access to a string_view |
There was a problem hiding this comment.
What does a memcpy? If you're talking about it copying data to a new string we do that on L238 as well, so this call out seems to be a bit unnecessary
There was a problem hiding this comment.
Will remove it.
| filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose); | ||
| } | ||
|
|
||
| // Observe host header w/o trailing dot in host when trailing dot removal is configured |
There was a problem hiding this comment.
nit: here and below, end comments with period as comments should use proper grammar (even if other tests don't do this, no reason to not do it for new code :) )
There was a problem hiding this comment.
agree, will fix this.
| {"abc.com.", "abc.com"}, // dns w/ dot | ||
| {"abc.com:443", "abc.com:443"}, // dns port w/o dot | ||
| {"abc.com.:443", "abc.com:443"}, // dns port w/ dot | ||
| {"[fc00::1].:443", "[fc00::1]:443"}, // ipv6 w/ dot |
There was a problem hiding this comment.
qq is this a valid input? Not sure when we'd get a . after an IP?
There was a problem hiding this comment.
Yah, its not valid input, its added by mistake and will remove it.
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
|
/retest |
|
Retrying Azure Pipelines: |
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
snowp
left a comment
There was a problem hiding this comment.
Sorry for the delay here, got some for comments for you. Thanks for iterating on this!
| // This affects the upstream host header. | ||
| // Without setting this option, incoming requests with host `example.com.` will not match against | ||
| // route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`. | ||
| // When incoming requests with host/authority header has port part with host, on setting this option it removes trailing dot from host keeping port |
There was a problem hiding this comment.
Maybe When the incoming request contains a host/authority header includes a port number, setting this option will strip trailing dots from the host section, leaving the port as is (e.g. ...?
There was a problem hiding this comment.
thanks, will update.
|
|
||
| New Features | ||
| ------------ | ||
|
|
source/common/http/header_utility.cc
Outdated
| // Because although the host may contain a colon via an IPv6 bracketed | ||
| // address, and although that IPv6 address may also contain dots when | ||
| // embedding an address per RFC 4291 2.2.3. In this case the dot will never |
There was a problem hiding this comment.
This is a bit tricky to read, maybe something like IPv6 addresses may contain colons or dots, but the dot will never directly precede the colon, so this check should be sufficient to detect a trailing port number.?
There was a problem hiding this comment.
sure, will update it.
| filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose); | ||
| } | ||
|
|
||
| // Observe host header w/o trailing dot in host when trailing dot removal is configured. |
There was a problem hiding this comment.
This makes it sound like the input doesn't have a trailing dot, maybe Observe tat we strip the trailing dot ...?
There was a problem hiding this comment.
thanks, will change.
| } | ||
|
|
||
| // Observe host header w/o trailing dot in host when trailing dot removal is configured. | ||
| TEST_F(HttpConnectionManagerImplTest, StripTrailingHostDot) { |
There was a problem hiding this comment.
Mind adding a test where we set this config option but pass through a header without a trailing dot?
There was a problem hiding this comment.
Sure. will add.
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
snowp
left a comment
There was a problem hiding this comment.
Some more nits, thanks for iterating!
| // route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`. | ||
| // When incoming requests with host/authority header has port part with host, on setting this option it removes trailing dot from host keeping port | ||
| // value as is (e.g. host value `example.com.:443` will be updated to `example.com:443`). | ||
| // When the incoming request contains a host/authority header includes a port number, setting this option will strip trailing dots |
There was a problem hiding this comment.
thanks, addressed.
| // route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`. | ||
| // When incoming requests with host/authority header has port part with host, on setting this option it removes trailing dot from host keeping port | ||
| // value as is (e.g. host value `example.com.:443` will be updated to `example.com:443`). | ||
| // When the incoming request contains a host/authority header includes a port number, setting this option will strip trailing dots |
There was a problem hiding this comment.
a trailing dot, if present, from the host section
otherwise this sounds like we strip multiple dots? I think we only do one right?
There was a problem hiding this comment.
Yes, we do remove only one dot, updated in latest commit.
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
|
/retest |
|
Retrying Azure Pipelines: |
snowp
left a comment
There was a problem hiding this comment.
LGTM, thanks!
@markdroth mind giving the API a look? Thanks
|
/lgtm api |
|
Thanks @dmitri-d @snowp @markdroth for reviewing this change. |
howardjohn
left a comment
There was a problem hiding this comment.
This is a bit late but it would be great if this, and the other strip_ options supported stripping only internally and preserving the original when forwarding upstream. Otherwise its not super usable for a transparent proxy
…15568) Add an option in connection manager which allow to strip trailing host dot from Host/authority header (e.g transforms "example.com." to "example.com"). Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund mahesh.kurund@oneconvergence.com
Commit Message:
Add an option in connection manager which allow to strip trailing host dot from Host/authority header. (e.g transforms "example.com." to "example.com").
Additional Description:
This change would eliminate the need of specifying domain entry with dot (e.g example.com.) while matching it with domain's inside the virtual host. For example, if the request has a host header "example.com." and strip_trailing_host_dot flag is set then it transforms into "example.com" by stripping the trailing dot and matches "domains" configured in VirtualHost.
Fixes #14748
Risk Level: Low
Testing: Unit, integration and manual.
Docs Changes: Inline in proto file.
Release Notes:
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Deprecated:]
[Optional API Considerations:]