-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
http: add HTTP/1.1 case preservation #15619
Conversation
1) Add new stateful header formatter extension point 2) Add preserve case formatter extension Fixes #14363 Signed-off-by: Matt Klein <mklein@lyft.com>
@asraa @alyssawilk @jmarantz @snowp PTAL. I'm pretty happy with how this turned out. It's quite clean and the perf overhead when not in use should be negligible. |
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.
Epic! Looks great overall. A few minor comments so far.
source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.cc
Outdated
Show resolved
Hide resolved
source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.cc
Outdated
Show resolved
Hide resolved
Signed-off-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Matt Klein <mklein@lyft.com>
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 looks great, just a couple small comments
source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.cc
Show resolved
Hide resolved
source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.cc
Outdated
Show resolved
Hide resolved
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.
looks great; just a few nits.
.../extensions/http/header_formatters/preserve_case/preserve_case_formatter_integration_test.cc
Show resolved
Hide resolved
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 seems great overall. Couple minor comments.
source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.cc
Show resolved
Hide resolved
.../extensions/http/header_formatters/preserve_case/preserve_case_formatter_integration_test.cc
Outdated
Show resolved
Hide resolved
.../extensions/http/header_formatters/preserve_case/preserve_case_formatter_integration_test.cc
Outdated
Show resolved
Hide resolved
source/extensions/http/header_formatters/preserve_case/preserve_case_formatter.cc
Outdated
Show resolved
Hide resolved
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.
Awesome, I'm sure loads of users are going to love this one.
Two drive by comment from the "what could possibly go wrong" department.
My first thought was "What about T-E header which we add and remove?" Looks like you handle that case, but mind adding it to the integration test?
From a user experience perspective I suspect folks will probably want snow's proper casing along with your preserve casing, so if there's a header addition (say we gunzip and go from content length to transfer encoding) or header creation (send local reply with content length) we "create" the right one. Do we expect them to play well together? If so I'd suggest having the canonical config use both, update docs explaining why users who want preserve probably want create, and integration test the transformation example.
This is interesting. I didn't think about them being stacked like this. This is not how it works today. What does everyone think about this? Right now it's actually possible in the proto to configure this. I can potentially deprecate and make it repeated? That would be a pretty big change and I'm not sure it's worth it? Thoughts? |
We're adding this case preservation system to handle clients/servers who do case sensitive compares. |
OK this should be ready for another pass, thanks. |
@@ -439,11 +440,16 @@ struct Http1Settings { | |||
// Performs proper casing of header keys: the first and all alpha characters following a | |||
// non-alphanumeric character is capitalized. | |||
ProperCase, | |||
// A stateful formatter extension has been configured. | |||
StatefulFormatter, |
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 think given @alyssawilk insight that we might want to generate mixed-case results for synthesized headers while preserving the case of others, maybe we want to avoid checking in the API that has these choices as exclusive?
I think from a data structure perspective we'd need to actually eliminate StatefulFormatter as a choice here and just allow users to configure both the enum and a stateful formatter (or repeated stateful formatters if we think that might be useful in the future). Does it make sense to do that now before the initial checkin?
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'm less concerned about the code and more about the API. My understanding from the thread above is that we decided if we need this in the future we can implement a nested formatter inside the preserve case formatter for unknown headers? Because of that I think we decide we can punt for now until someone asks for it?
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.
Personally, I would think that any other than nested or another extension (one that may not even be in the core repo) would need to handle prioritization. For instance if you defined a stateful (preserve case), and stateless (proper case), in the current form the stateless would just end up proper casing the header keys that the stateful formatter was looking to preserve. Am I missing something @jmarantz, as it stands I'd agree 💯 with @mattklein123.
Signed-off-by: Matt Klein <mklein@lyft.com>
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.
Looks good besides the one comment.
I think we might not be propagating the casing in situation where we copy the downstream headers (e.g. request shadowing), but it might not be worth trying to solve this now.
tools/code_format/check_format.py
Outdated
@@ -65,7 +65,9 @@ | |||
# perform temporary registrations. | |||
REGISTER_FACTORY_TEST_ALLOWLIST = ( | |||
"./test/common/config/registry_test.cc", "./test/integration/clusters/", | |||
"./test/integration/filters/") | |||
"./test/integration/filters/", | |||
"./test/extensions/http/header_formatters/preserve_case/preserve_case_formatter_integration_test.cc" |
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.
The comment above suggests you should be using InjectFactory
instead of of REGISTER_FACTORY, thoughts?
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 isn't possible for integration tests. This is here for the same reason test/integration/filters
is here.
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.
Huh I thought I'd seen InjectFactory used in integration tests, but I could be wrong here
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.
Ah OK it looks like it can. Sure I can fix that.
Yes, it won't work in that case. I think it's not very hard to fix. We could add a clone() method to the formatter, and then clone it during header map copy. I didn't do this because I doubt anyone will notice and I didn't want to use shared_ptr. wdyt? |
I think if it's limited to request shadowing it's probably fine to leave for now, I imagine the main use case will be to format response headers, so the shadowing case is probably not important. I wasn't sure if there were other header copying cases that we needed to cover |
Any copying case can be fixed relatively easily by allowing formatter cloning, but like I said, I would rather wait until someone complains, because I doubt they will. It won't be hard to fix at that point. |
Signed-off-by: Matt Klein <mklein@lyft.com>
@snowp updated per comments |
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.
Thanks!
is this going to be available on the latest release only or is it going to be back-ported to some older releases? |
# HTTP header formatters | ||
# | ||
|
||
"envoy.http.stateful_header_formatters.preserve_case": "//source/extensions/http/header_formatters/preserve_case:preserve_case_formatter" |
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.
missing , at the end of the line.
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.
Will fix this in my current PR
@mattklein123 Is there an optimal option/improvement/suggestion for skipping this for http2 clusters when in case like istio, ingress gateway needs to allow both http1/2 traffic. We ran into istio/istio#36299 when using auto_config for case preserve leveraging envoy to auto detect http1.1/2 depending on upstream config but it didn't pick up as expected. |
This only takes effect for H1. If something else is happening I would open a new issue with repro instructions, etc. |
Thanks @mattklein123 : I have mentioned details of reproducing in istio/istio#36299 as it happens while using auto_config for case preserve in httpprotocol options vs explicit_http_config as mentioned in the doc. I am not sure if I should open a new issue here too or continue on the one on istio side. |
Filed new issue for the same #19149 |
1) Add new stateful header formatter extension point; 2) Add preserve case formatter extension; Fixes envoyproxy#14363 Signed-off-by: jiangshantao <jiangshantao-dbg@qq.com>
* feat: http: add HTTP/1.1 case preservation (envoyproxy#15619) 1) Add new stateful header formatter extension point; 2) Add preserve case formatter extension; Fixes envoyproxy#14363 Signed-off-by: jiangshantao <jiangshantao-dbg@qq.com> * fix: fix Error envoy_cc_library() got unexpected keyword argument: category Signed-off-by: jiangshantao <jiangshantao-dbg@qq.com> * fix: source/common/http/http1/settings.cc:39:39: error: unused parameter 'validate_scheme' Signed-off-by: jiangshantao <jiangshantao-dbg@qq.com> * feat: preserve case with proper case config Signed-off-by: jiangshantao <jiangshantao-dbg@qq.com> Co-authored-by: jiangshantao <jiangshantao-dbg@qq.com>
Fixes #14363
Risk Level: Low
Testing: New integration test
Docs Changes: Added
Release Notes: Added
Platform Specific Features: N/A