-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
gzip filter: make sure the stream ends properly #3025
Changes from 1 commit
d3c3ded
86e4b86
9a0d529
d0c4239
74063b9
d8239b3
56b5e88
6552468
767fb60
2b568b9
dff37df
9b010f0
d44d929
2d85fe8
5400b19
5a486f2
8a9ccce
059441e
2fd4876
3713794
467df23
467af66
d8f923e
ebd3e6d
a291b5c
4a1dd67
3f3a175
9ef74ad
0523291
e10d6aa
b36f2fc
ac6ec76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,5 +82,28 @@ void ZlibCompressorImpl::updateOutput(Buffer::Instance& output_buffer) { | |
zstream_ptr_->next_out = chunk_char_ptr_.get(); | ||
} | ||
|
||
void ZlibCompressorImpl::reset() { | ||
const bool result = deflateReset(zstream_ptr_.get()); | ||
RELEASE_ASSERT(result == Z_OK); | ||
} | ||
|
||
void ZlibCompressorImpl::finish(Buffer::Instance& output_buffer) { | ||
// Once the Z_FINISH parameter is provided, deflate() will begin to complete the compressed output | ||
// stream. However depending on how much output space is provided, deflate() may have to be called | ||
// several times until it has provided the complete compressed stream, even after it has consumed | ||
// all of the input. The flush parameter must continue to be Z_FINISH for those subsequent calls. | ||
// Ref: https://zlib.net/zlib_how.html. | ||
const int result = deflate(zstream_ptr_.get(), Z_FINISH); | ||
updateOutput(output_buffer); | ||
if (result == Z_OK || result == Z_BUF_ERROR) { | ||
finish(output_buffer); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: prefer to do this in a loop vs recursively (even though I know the recursion depth will be small). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could do something similar to
... and then handle the logic inside deflateNext(..):
Just a suggestion, but it is up to you :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks. This is nicer. 👍 |
||
} else { | ||
// While Z_OK, Z_BUF_ERROR (covered in above case) and Z_STREAM_END are the acceptable values, | ||
// the Z_STREAM_ERROR is only possible if the stream is not initialized properly. Ref: | ||
// https://zlib.net/zlib_how.html. | ||
RELEASE_ASSERT(result == Z_STREAM_END); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's important to have testing coverage here too. |
||
} | ||
} | ||
|
||
} // namespace Compressor | ||
} // namespace Envoy |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,6 +81,18 @@ class ZlibCompressorImpl : public Compressor { | |
*/ | ||
uint64_t checksum(); | ||
|
||
/** | ||
* This is required to re-init the stream after calling finish(_). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it. |
||
*/ | ||
void reset(); | ||
|
||
/** | ||
* Completes the compressed output stream. To indicate that the currently pointed data is the last | ||
* chunk of input data to compress. | ||
* @param output_buffer supplies the buffer to output compressed data. | ||
*/ | ||
void finish(Buffer::Instance& output_buffer); | ||
|
||
// Compressor | ||
void compress(const Buffer::Instance& input_buffer, Buffer::Instance& output_buffer) override; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -139,11 +139,15 @@ FilterDataStatus GzipFilter::encodeData(Buffer::Instance& data, bool end_stream) | |
|
||
if (end_stream) { | ||
compressor_.flush(compressed_data_); | ||
compressor_.finish(compressed_data_); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I haven't look at this code much at all, but it seems like flush/finish finish can be logically combined? Shouldn't finish implicitly flush before finishing? |
||
} | ||
|
||
if (compressed_data_.length()) { | ||
data.drain(n_data); | ||
data.move(compressed_data_); | ||
|
||
// Reset is required to re-init the compressor's z_stream. | ||
compressor_.reset(); | ||
return Http::FilterDataStatus::Continue; | ||
} | ||
|
||
|
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 think we need some death tests to exercise this logic.
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. Will try to have it.