-
-
Notifications
You must be signed in to change notification settings - Fork 16.3k
HttpPostMultipartRequestDecoder should decode header field parameters #7265
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
Conversation
5153a3e to
e4a9853
Compare
|
First commit on PR is the actual patch. Second commit was required to please netkins. I was already 5 indents in. |
69f1809 to
78977d5
Compare
| if (!shouldDecode) { | ||
| value = value.substring(1, value.length() - 1); | ||
| } else { | ||
| String[] split = value.split("''", 2); |
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.
Consider replacing String#split with use precompiled Pattern constant or a value.indexOf("''").
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.
Thank you. I don't have much experience in performant Java string work, so I was following the lead of existing code a few lines up where you have value.split("=", 2). Does the compiler/runtime optimize this case because it's a unit-length string and therefore effectively a char?
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.
Yep. For one-char string a String.split in OpenJDK doesn't use Pattern. But the string "''" has two chars.
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 okay thanks. I opted for the precompiled pattern because it seemed simpler.
| } | ||
|
|
||
| private Attribute getContentDispositionAttribute(String... values) { | ||
| Attribute attribute; |
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.
Why is it necessary to declare the attribute 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.
That is how it was before my patch on 4.1. For the actual test/patch, please see my first commit (e4a9853). My second commit, which this comes from, was done because Netkins complained I had gone above 5 indents and should refactor. So I extracted that whole block as its own private function. I would rather not include this second commit in this PR because it obfuscates the patch. But I wanted the green check mark in the list of PRs.
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.
Ok. But now there is no need for this. Just use fast return without variable:
return factory.createAttribute(request, name, value);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.
Yes of course. Fixed this.
| // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html | ||
| if (HttpHeaderValues.FILENAME.contentEquals(name)) { | ||
| // filename value is quoted string so strip them | ||
| if (!shouldDecode) { |
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.
IIUC the RFC 5987 prescribe decoding not only filename header value? Otherwise we should not cut * from name for other headers..
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 thought about that too. But I'm not sure that's the case (what other headers are there? they aren't being tested for flow control in this code). I decided to just cover this case and establish how it might be done if someone encountered this problem with other headers.
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 mean, if we want apply new RFC only for filename header, we should not change the name attribute for other headers. But now you are doing this: name = name.substring(0, last);
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 yes that makes sense. I think I avoid this now. Could add a test 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.
final
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.
Would be better to reduce the possible allocations using filename* constant. Something like this:
private static final String FILENAME_ENCODED = HttpHeaderValues.FILENAME.toString() + '*';
private Attribute getContentDispositionAttribute(String... values) {
String name = cleanString(values[0]);
String value = values[1];
// See http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html
if (HttpHeaderValues.FILENAME.contentEquals(name)) {
// filename value is quoted string so strip them
value = value.substring(1, value.length() - 1);
} else if (FILENAME_ENCODED.equals(name)) {
// filename value is encoded. See https://tools.ietf.org/html/rfc5987
name = name.substring(0, name.length() - 1);
String[] split = doubleSingleQuote.split(value, 2);
value = QueryStringDecoder.decodeComponent(split[1], Charset.forName(split[0]));
} else {
// otherwise we need to clean the value
value = cleanString(value);
}
return factory.createAttribute(request, name, value);
}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. Pushed this version.
|
@dminkovsky RFC says that
Maybe it makes sense to support for this too? At least, take this into account when parsing the value. |
|
Yes, I thought about that, but what would we do with it? Add a |
382ca6c to
c24a4d4
Compare
Ignoring? Just split value through single quote String[] split = value.split("'", 3);
value = QueryStringDecoder.decodeComponent(split[2], Charset.forName(split[0])) |
|
I’m sorry that’s not what I meant. I meant: if we got the language code
value—like you said by splitting a different way—then what would we do with
that value?
пн, 2 окт. 2017 г. в 1:12, Nikolay Fedorovskikh <notifications@github.com>:
… Yes, I thought about that, but what would we do with it?
Ignoring? Just split value through single quote "'".
String[] split = value.split("'", 3);
value = QueryStringDecoder.decodeComponent(split[2], Charset.forName(split[0]))
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#7265 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AANWZe8g7ShFao2EoClhhRKBF-EGuxlNks5soHCvgaJpZM4PpUdL>
.
|
|
I suggest not doing anything with the language field. Just skip this. |
c24a4d4 to
6555dd7
Compare
normanmaurer
left a comment
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.
LGTM
| // See http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html | ||
| if (HttpHeaderValues.FILENAME.contentEquals(name)) { | ||
| // filename value is quoted string so strip them | ||
| value = value.substring(1, value.length() - 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.
consider checking that the first and last chars are actually quotes.
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 was here before this PR. should i modify this behavior in this PR?
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 this check too.
| // filename value is encoded. See https://tools.ietf.org/html/rfc5987 | ||
| name = name.substring(0, name.length() - 1); | ||
| String[] split = DOUBLE_SINGLE_QUOTE.split(value, 2); | ||
| value = QueryStringDecoder.decodeComponent(split[1], Charset.forName(split[0])); |
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.
Here too, you might consider check that the array size is 2 so that you don't throw an NPE.
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.
Considered this, but if not an NPE, then what? There are other spots in the code around this PR that split and don't check.
|
|
||
| // https://github.com/netty/netty/pull/7265 | ||
| @Test | ||
| public void testDecodeContentDispositionFieldParameters() throws Exception { |
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 a negative case? perhaps a malformed header?
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.
Yes, makes sense. Will do.
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.
Added a few tests.
6555dd7 to
7742cbc
Compare
|
@fenik17 just looked again at your previous comment and yes, of course, it's much better this way. thank you for your reviews! |
5bf0c4c to
5de5c86
Compare
1354351 to
2b5dd05
Compare
carl-mastrangelo
left a comment
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.
One comment but otherwise LGTM
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.
@normanmaurer do your tests require you to deref all buffers?
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.
yep I think we should call req.release()
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.
@dminkovsky please address this
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.
@normanmaurer done. Please have a look. Thank you.
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.
if (last > 0 && ...
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.
2b5dd05 to
06dbf04
Compare
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 can avoid an extra allocation:
name = HttpHeaderValues.FILENAME.toString();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.
Yes, makes sense. Fixed. Thanks.
|
By the way, could this make 4.1.17? I see only a 4.0 tag. I am wondering because I am on 4.1 |
|
Everything that is merged into 4.0 will also be merged Into 4.1 |
06dbf04 to
9f4b58a
Compare
|
Good to hear. Thank you. |
9f4b58a to
c485b39
Compare
|
Cherry-picked into 4.1 (8aeba78) and 4.0 (82b7103). @dminkovsky thanks! |
|
@normanmaurer this is not pushed into 4.0? |
Motivation:
I am receiving a
mutlipart/form_dataupload from a Mailgun webhook. This webhook used to send parts like this:but now it posts parts like this:
This new format uses field parameter encoding described in RFC 5987. More about this encoding can be found here.
Netty does not parse this format. The result is the filename is not decoded and the part is not parsed into a
FileUpload.Modification:
HttpPostRequestDecoderTest.javaand updatedHttpPostMultipartRequestDecoder.javaResult:
Fixes #7265 (this):
HttpPostMultipartRequestDecoderidentifies the RFC 5987 format and parses it.