Line data Source code
1 : #include "source/extensions/compression/gzip/compressor/zlib_compressor_impl.h" 2 : 3 : #include <memory> 4 : 5 : #include "envoy/common/exception.h" 6 : 7 : #include "source/common/common/assert.h" 8 : 9 : #include "absl/container/fixed_array.h" 10 : 11 : namespace Envoy { 12 : namespace Extensions { 13 : namespace Compression { 14 : namespace Gzip { 15 : namespace Compressor { 16 : 17 758 : ZlibCompressorImpl::ZlibCompressorImpl() : ZlibCompressorImpl(4096) {} 18 : 19 : ZlibCompressorImpl::ZlibCompressorImpl(uint64_t chunk_size) 20 758 : : Common::Base(chunk_size, [](z_stream* z) { 21 758 : deflateEnd(z); 22 758 : delete z; 23 758 : }) { 24 758 : zstream_ptr_->zalloc = Z_NULL; 25 758 : zstream_ptr_->zfree = Z_NULL; 26 758 : zstream_ptr_->opaque = Z_NULL; 27 758 : zstream_ptr_->avail_out = chunk_size_; 28 758 : zstream_ptr_->next_out = chunk_char_ptr_.get(); 29 758 : } 30 : 31 : void ZlibCompressorImpl::init(CompressionLevel comp_level, CompressionStrategy comp_strategy, 32 758 : int64_t window_bits, uint64_t memory_level = 8) { 33 758 : ASSERT(initialized_ == false); 34 758 : const int result = deflateInit2(zstream_ptr_.get(), static_cast<int64_t>(comp_level), Z_DEFLATED, 35 758 : window_bits, memory_level, static_cast<uint64_t>(comp_strategy)); 36 758 : RELEASE_ASSERT(result >= 0, ""); 37 758 : initialized_ = true; 38 758 : } 39 : 40 : void ZlibCompressorImpl::compress(Buffer::Instance& buffer, 41 168248 : Envoy::Compression::Compressor::State state) { 42 168248 : for (const Buffer::RawSlice& input_slice : buffer.getRawSlices()) { 43 167506 : zstream_ptr_->avail_in = input_slice.len_; 44 167506 : zstream_ptr_->next_in = static_cast<Bytef*>(input_slice.mem_); 45 : // Z_NO_FLUSH tells the compressor to take the data in and compresses it as much as possible 46 : // without flushing it out. However, if the data output is greater or equal to the allocated 47 : // chunk size, process() outputs it to the end of the buffer. This is fine, since at the next 48 : // step, the buffer is drained from the beginning of the buffer by the size of input. 49 167506 : process(buffer, Z_NO_FLUSH); 50 167506 : buffer.drain(input_slice.len_); 51 167506 : } 52 : 53 168248 : process(buffer, state == Envoy::Compression::Compressor::State::Finish ? Z_FINISH : Z_SYNC_FLUSH); 54 168248 : } 55 : 56 670018 : bool ZlibCompressorImpl::deflateNext(int64_t flush_state) { 57 670018 : const int result = deflate(zstream_ptr_.get(), flush_state); 58 670018 : switch (flush_state) { 59 757 : case Z_FINISH: 60 757 : if (result != Z_OK && result != Z_BUF_ERROR) { 61 757 : RELEASE_ASSERT(result == Z_STREAM_END, ""); 62 757 : return false; 63 757 : } 64 757 : FALLTHRU; 65 669261 : default: 66 669261 : if (result == Z_BUF_ERROR && zstream_ptr_->avail_in == 0) { 67 334997 : return false; // This means that zlib needs more input, so stop here. 68 334997 : } 69 670018 : RELEASE_ASSERT(result == Z_OK, ""); 70 670018 : } 71 : 72 334264 : return true; 73 670018 : } 74 : 75 335754 : void ZlibCompressorImpl::process(Buffer::Instance& output_buffer, int64_t flush_state) { 76 670018 : while (deflateNext(flush_state)) { 77 334264 : if (zstream_ptr_->avail_out == 0) { 78 8 : updateOutput(output_buffer); 79 8 : } 80 334264 : } 81 : 82 335754 : if (flush_state == Z_SYNC_FLUSH || flush_state == Z_FINISH) { 83 168248 : updateOutput(output_buffer); 84 168248 : } 85 335754 : } 86 : 87 : } // namespace Compressor 88 : } // namespace Gzip 89 : } // namespace Compression 90 : } // namespace Extensions 91 : } // namespace Envoy