Skip to content
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 BrotliEncoder bug that does not mark ByteBuf it encodes as read #13497

Merged

Conversation

vietj
Copy link
Contributor

@vietj vietj commented Jul 19, 2023

Expected behavior

The BrotliEncoder respects the implicit HttpContentCompressor contract that ByteBuf should be marked as read (readableBytes() == 0).

Actual behavior

The BrotliEncoder does not mark encoded ByteBuf as read, HttpContent encoded by HttpContentCompressor can have their content be sent twice once decoded and once encoded, corrupting the response. This happens because the Brotli4J library uses the ByteBuf NIO buffer and does not read it through the ByteBuf like other compressor usually do.

Steps to reproduce

Sending a chunked HTTP response encoded with the Brotli compressor reproduces it.

Netty version

Any Brotli4j version, but I haven't checked.

The contract between HttpContentCompressor and compression encoders assumes that encoders will mark the encoded ByteBuf as read after they have been encoded, otherwise the HttpContentCompressor will send encoded chunk twice (one time decoded and one time encoded). The BrotliEncoder peeks the ByteBuf nio buffer and pass it to the BrotliChannelEncoder without marking the ByteBuf and does not respect the implicit contract with HttpContentCompressor.

The BrotliEncoder now will set skip bytes of encoded ByteBuf, in addition the test generic AbstractEncoderTest has been modified to ensure that the readable bytes of a ByteBuf is equals to 0 after it has been encoded.

This fixes the bug.
Copy link
Contributor

@franz1981 franz1981 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, good find @vietj !!

@franz1981
Copy link
Contributor

@hyperxpro wanna take a look bud?

Copy link
Contributor

@hyperxpro hyperxpro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix. :)

@hyperxpro
Copy link
Contributor

@hyperxpro wanna take a look bud?

I was under the impression that ByteBuf would get discarded later but seems not. :(

@vietj
Copy link
Contributor Author

vietj commented Jul 19, 2023

@hyperxpro wanna take a look bud?

I was under the impression that ByteBuf would get discarded later but seems not. :(

Actually it can be passed to the HTTP encoder when it is used in a response that has a content.

I think that having the HttpContentCompressor recreate a new response with the new encoded buffer and discard the other one would be much cleaner. Currently it relies on the fact that the HTTP encoder will skip encoding a zero length chunk as side effect.

@hyperxpro
Copy link
Contributor

Error:  testCompressionOfBatchedFlowOfData{ByteBuf}[2]  Time elapsed: 0.062 s  <<< ERROR!
io.netty.handler.codec.EncoderException: java.lang.IllegalArgumentException: minimumReadableBytes : -54 (expected: >= 0)

@normanmaurer
Copy link
Member

@hyperxpro my bad ... fixed

@normanmaurer
Copy link
Member

@hyperxpro wanna take a look bud?

I was under the impression that ByteBuf would get discarded later but seems not. :(

Actually it can be passed to the HTTP encoder when it is used in a response that has a content.

I think that having the HttpContentCompressor recreate a new response with the new encoded buffer and discard the other one would be much cleaner. Currently it relies on the fact that the HTTP encoder will skip encoding a zero length chunk as side effect.

@vietj maybe you want to do another PR as well ?

@vietj
Copy link
Contributor Author

vietj commented Jul 19, 2023

@hyperxpro wanna take a look bud?

I was under the impression that ByteBuf would get discarded later but seems not. :(

Actually it can be passed to the HTTP encoder when it is used in a response that has a content.
I think that having the HttpContentCompressor recreate a new response with the new encoded buffer and discard the other one would be much cleaner. Currently it relies on the fact that the HTTP encoder will skip encoding a zero length chunk as side effect.

@vietj maybe you want to do another PR as well ?

I will give a try @normanmaurer

@normanmaurer normanmaurer merged commit 61d75db into netty:4.1 Jul 19, 2023
12 checks passed
@normanmaurer
Copy link
Member

@vietj thanks a lot!

@normanmaurer normanmaurer added this to the 4.1.95.Final milestone Jul 19, 2023
@vietj vietj deleted the brotli-encoder-should-skip-bytebuf-bytes branch July 19, 2023 15:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants