netty: FullHttpRequest doesn't return proper content anymore
It is server code. Server receives HTTP POST request, which contains body content. Server converts the request to FullHttpRequestand gets its content as a buffer. For some unknown reason buffer became not readable in versions 4.1.64.Final and 4.1.65.Final, but up to version 4.1.63.Final everything worked just fine. Pipeline contains just HttpServerCodec and HttpObjectAggregator.
Expected behavior
FullHttpRequest of Multipart POST request returns proper content of the body.
Actual behavior
FullHttpRequest of Multipart POST request doesn’t return proper content of the body.
Steps to reproduce
Try to read content of FullHttpRequest and get it as a String.
Minimal yet complete reproducer code (or URL to code)
if (req instanceof FullHttpRequest) {
final FullHttpRequest fhr = (FullHttpRequest) req;
// Actually contains data, but is not ready for reading anymore
final ByteBuf bb = fhr.content();
// String is empty now, but was ok in versions <= 4.1.63.Final
final String s = bb.toString(StandardCharsets.UTF_8);
}
Netty version
Works ok up to 4.1.63.Final, but doesn’t work anymore in 4.1.64.Final and 4.1.65.Final
JVM version (e.g. java -version)
openjdk version “16” 2021-03-16 OpenJDK Runtime Environment (build 16+36-2231) OpenJDK 64-Bit Server VM (build 16+36-2231, mixed mode, sharing)
OS version (e.g. uname -a)
Linux x86_64 x86_64 x86_64 GNU/Linux and Windows 10
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 23 (11 by maintainers)
@fredericBregier Thanks for the detailed answer! 👍🏻
I want to use
HttpObjectAgregatorandFullHttpRequestto keep the code simple, even though it may not be the most efficient. Sometimes I think that Netty is too low level for my needs. 😄 But since everything works just fine, I have no reason to rewrite code to some other high level framework. 🤷♂️I want to extract all the possible representations of the POST data. If it is a form, then I want to have
key -> valuepairs. If it is just a simple plain content, I want to have it as aString.So I just changed the order. First I get the content from
FullHttpRequestand then I useHttpPostRequestDecoder, and now I don’t care if it modifies the request or not. 😄@bxqgit OK, I understand.
So you are indeed using a Multipart decoding. I have found several issues in the way you using it:
In general, it is not recommended to use the
HttpObjectAgregatorin your pipeline when facing Multipart. The reason is that it will fully load everything in memory. But as you’re using a Multipart, it might be “too much” for the JVM. So you might change this as follow:First, remove the
HttpObjectAgregatorfrom your pipelineThen adapt your code as follow (inspired from https://github.com/netty/netty/blob/4.1/example/src/main/java/io/netty/example/http/upload/HttpUploadServerHandler.java )
Now to your issue:
FullHttpRequestor using multipleHttpContent(when chunked, the first item is aHttpRequestwithout any content, followed by multipleHttpContent, ending with a lastLastHttpContentthat closes the chunk reception)FullHttpRequestif not chunkedByteBufhas itsreaderIndexsets towriterInder.readerIndexto 0 as you did).HttpRequestis not immutable regarding its content.So it is not an issue but a normal way. You’re not using a decoder correctly.
I don’t know why you want to get the “full” content of a Multipart request into a String, but if so, you can build it through the
HttpDataretrieves from the decoder, as follow:Hoping this is clear enough to help you.
@bxqgit Hi, could you elaborate a bit ? If I understand, your code is doing something like:
HttpServerCodecandHttpObjectAgregatorHttpObjectAgregatoraFullHttpRequest: does it done manually?readerIndexto 0 gives back access to the data)If this is this first scenario, where comes the Multipart things?
Maybe you’re using Multpart things, so it might be point 3 as: 3. Uses
HttpPostMultipartRequestDecoderas:HttpDataFactory factory = new DefaultHttpDataFactory(true or false or limit size);HttpPostMultipartRequestDecoder decoder = new HttpPostMultipartRequestDecoder(factory, request);decoder.offer(content)HttpData(s), and creates a new HttpRequest from theHttpData(s)?decoderandfactoryfactory.cleanAllHttpData();anddecoder.destroy();If this is the second case, why are you using
HttpObjectAgregator? There is no need for that, and of no use withHttpPostMultipartRequestDecoder.Maybe you’re using Multpart things, but as encoder, so it might be point 3 as: 3. Uses
HttpPostRequestEncoderas:HttpPostRequestEncoder encoder = new HttpPostRequestEncoder(true);encoder.addBodyAttribute(...);encoder.addBodyFileUpload(...);HttpRequest newRequest = encoder.finalizeRequest();factory.cleanAllHttpData();anddecoder.destroy();Then, here the
HttpObjectAgregatorusage is probably correct. It is only encoder part that is concerned. As there are Junit tests doing like this, if you could gives more information, that could be helpful.Which scenario is it?