-
Notifications
You must be signed in to change notification settings - Fork 38.2k
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
Fix value accumulation for case-sensitive keys in NettyHeadersAdapter #33730
Conversation
addAll has the same issue, and it has also been addressed. |
hey @qnnn thanks for the PR. Can you elaborate on the use case that lead you to come up with this change? I'm guessing this is a matter of enumerating the headers or representing them as a whole? |
@simonbasle I discovered this problem while using the AddRequestHeader GatewayFilter in Spring Cloud Gateway. Through network packet capture, it can be seen that the HTTP requests sent by the Gateway aggregate the values of case-sensitive keys in the HTTP headers. |
Thanks for your feedback. We're exploring what we can do to improve enumeration/iteration of headers through the framework's While all native implementations of http headers enforce case-insensitive access (as mandated by the spec), some still store headers as name-value arrays / lists where each entry's might have differences in casing. This leads to apparent inconsistencies for "whole collection" methods when we try to offer a
Can you confirm whether or not the duplication of values for a given header name happens on the wire however? (eg. using Wireshark) |
@simonbasle Thanks for your patience in explaining this. Yes, I can confirm that the duplication of values for a given header name happens on the wire (confirmed via Wireshark). It seems that some Spring Cloud Gateway's I feel that |
@qnnn Is this use case of headers filtering/reconstruction in |
@sdeleuze Yes, I have verified that there are others as well:
Any implementation that iterates through the
|
Thanks, that helps. We are discussing the best strategy to fix those bugs while keeping a great performance/efficiency. We will get back to you once we have made a decision. |
@sdeleuze It's ok, I understand. Perhaps maintaining a When operating on Map<String, String> map = new LinkedCaseInsensitiveMap<>(8, Locale.ENGLISH);
String headerKey = map.compute("TestHeader", (caseInsensitiveKey, headerKey) -> {
if (!StringUtils.hasText(headerKey)){
return caseInsensitiveKey;
}
return headerKey;
}); |
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.
Correct me if I'm wrong, but the headers case variants are populated by Netty itself, i.e. it comes from the wire. In that case you are addressing the wrong issue.
The change and tests that you proposed impact the intermediate Netty4HeadersAdapter
(adapting Netty DefaultHttpHeaders
to MultiValueMap<String, String>
)... but if you add the test's headers to DefaultHttpHeader
instance itself, then construct a Netty4HeadersAdapter
out of it, tests fail again despite your changes:
@Test
void prepopulatedNativeNetty4() {
DefaultHttpHeaders native = new DefaultHttpHeaders();
native.add("TestHeader", "first");
native.add("TestHEADER", "second");
native.add("SecondHeader", "value");
native.add("TestHeader", "third");
MultiValueMap<String, String> adapter = new Netty4HeadersAdapter(native);
//copying native headers into a new HttpHeaders
HttpHeaders headers = new HttpHeaders();
for (Map.Entry<String, List<String>> entry : adapter.entrySet()) {
headers.addAll(entry.getKey(), entry.getValue());
}
assertThat(headers.get("TestHeader")).as("TestHeader")
.containsExactly("first", "second", "third");
}
@qnnn we continue evaluating the possible fixes and their impact. I will probably close this PR in favor of creating a new issue tracking this, in which case I'll ping you in there. |
@simonbasle Indeed, perhaps this can be reset during the Adapter initialization? In my understanding, Netty itself can function normally. |
Superseded by gh-33823 |
The current
NettyHeaders
supports case-sensitive storage of entry values when using theadd
method. This causes theNettyHeadersAdapter
to accumulate the values for the corresponding key when retrieving headers(see unit test).Add a unit test testHeadersOutput to verify the final output of the headers.