-
Notifications
You must be signed in to change notification settings - Fork 325
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 HTTP request builder setHeader case sensitivity #1165
base: master
Are you sure you want to change the base?
Fix HTTP request builder setHeader case sensitivity #1165
Conversation
@@ -232,7 +232,7 @@ public Builder setMethod(String method) | |||
|
|||
public Builder setHeader(String name, String value) | |||
{ | |||
this.headers.removeAll(name); | |||
this.headers.keys().removeIf(key -> key.equalsIgnoreCase(name)); |
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.
good catch!
Does addHeader and addHeaders behave correctly?
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 are supposed to accumulate
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.
Right, it accumulates so not a problem, but there is still a difference and results in names not normalized. But maybe deduplication and normalization is a responsibility of a different class.
So it depends if we want:
ListMultimap<String, String> headers = ArrayListMultimap.create();
headers.put("Key-One", "v1");
headers.put("Key-One", "v1");
headers.put("Key-One", "v2");
headers.put("key-one", "v1");
System.out.println(headers);
To result in:
{Key-One=[v1, v1, v2], key-one=[v1]}
or in:
{key-one=[v1, v1, v1, v2]}
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.
Custom multimap does that:
ListMultimap<String, String> headers = Multimaps.newListMultimap(new TreeMap<>(CASE_INSENSITIVE_ORDER), ArrayList::new);
headers.put("Key-One", "v1");
headers.put("Key-One", "v1");
headers.put("Key-One", "v2");
headers.put("key-one", "v1");
System.out.println(headers);
{Key-One=[v1, v1, v2, v1]}
2cb4603
to
445e70e
Compare
added lowercasing and a test |
|
fce655d
to
f4998a8
Compare
f4998a8
to
d0bfbd7
Compare
replaced lowercasing with case-preserving, per @losipiuk suggestion |
d0bfbd7
to
257a049
Compare
Alternative #1166 |
257a049
to
08e57c4
Compare
08e57c4
to
fe4b7fe
Compare
@@ -43,7 +44,7 @@ public void testBasic() | |||
assertEquals(filtered.getUri(), original.getUri()); | |||
assertEquals(original.getHeaders().size(), 0); | |||
assertEquals(filtered.getHeaders().size(), 1); | |||
assertEquals(filtered.getHeaders().get(TRACETOKEN_HEADER), ImmutableList.of("testBasic")); | |||
assertEquals(filtered.getHeaders().get(TRACETOKEN_HEADER.toLowerCase(ENGLISH)), ImmutableList.of("testBasic")); |
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.
With lowercasing, apps using airlift may need to change too. For example https://github.com/trinodb/trino/blob/a27e5af2d7389a7bc0e906210eafb906f01e4365/core/trino-main/src/test/java/io/trino/operator/MockExchangeRequestProcessor.java#L103
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.
We should probably make Request.getHeaders()
return a case-insensitive map
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.
happy to apply once we know for sure (without "probably"). there was quite a bit back and forth already on this PR. It doesn't cost much because it is small, but it's not cool nonetheless
@electrum @martint can you explicitly decide on the behavior you want to see implemented? happy to apply whatever is needed
added lowercasing again. ptal |
Non preserving hurts my aesthetic soul but I hope I can live with that. |
We shouldn’t lower case header names. What problem are we trying to solve? |
Of course the simplest implementation would be to just change --- http-client/src/main/java/io/airlift/http/client/Request.java
+++ http-client/src/main/java/io/airlift/http/client/Request.java
@@ -232,7 +232,7 @@ public final class Request
public Builder setHeader(String name, String value)
{
- this.headers.removeAll(name);
+ this.headers.keySet().removeIf(key -> key.equalsIgnoreCase(name));
this.headers.put(name, value);
return this;
} in fact this was the first version of this PR. then the PR had case-preserving version (see "before" in this diff https://github.com/airlift/airlift/compare/257a0490937b4f1e23ddbd44e0bf47612c81704a..08e57c46f089d59d97cf29481e2b2d69edcce336) Then @electrum suggested case-preserving isn't worth it. BTW once headers gets thru airlift request builder, their case is later changed in jetty client. It looks like the case normalization in the jetty client happens for all headers registered with
Why? |
Given the HTTP/2 is always lowercase, it's not clear that there is value in preserving header case. This seems like a bad assumption in applications that can appear to work, but will break depending on the protocol version used at runtime. Lowercasing headers makes code simpler and avoids the surprise. |
Hopefully we have agreement that the current behavior of setHeader is wrong. It caused an incident internally at Starburst. @electrum @martint how would you like the code to behave?
|
No description provided.