From 3b5bab33089521309b56da9c7f8a5ee0fea8fcb1 Mon Sep 17 00:00:00 2001 From: Ivan Fefer Date: Thu, 3 Sep 2020 19:20:02 +0300 Subject: [PATCH] Fix gzip_decompressor in case of one chunk being exactly equal to buffer size (#636) * add larget chunks test * revert test * Fix gzip decoder in case of chunk being equal to buffer size * add test --- httplib.h | 4 ++-- test/test.cc | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/httplib.h b/httplib.h index 1f44090..b78a650 100644 --- a/httplib.h +++ b/httplib.h @@ -2267,7 +2267,7 @@ public: strm_.next_in = const_cast(reinterpret_cast(data)); std::array buff{}; - do { + while (strm_.avail_in > 0) { strm_.avail_out = buff.size(); strm_.next_out = reinterpret_cast(buff.data()); @@ -2282,7 +2282,7 @@ public: if (!callback(buff.data(), buff.size() - strm_.avail_out)) { return false; } - } while (strm_.avail_out == 0); + } return ret == Z_OK || ret == Z_STREAM_END; } diff --git a/test/test.cc b/test/test.cc index 29f60ca..76678da 100644 --- a/test/test.cc +++ b/test/test.cc @@ -2175,6 +2175,49 @@ TEST_F(ServerTest, GetStreamedChunkedWithGzip2) { EXPECT_EQ(200, res->status); EXPECT_EQ(std::string("123456789"), res->body); } + + +TEST(GzipDecompressor, ChunkedDecompression) { + std::string data; + for (size_t i = 0; i < 32 * 1024; ++i) { + data.push_back(static_cast('a' + i % 26)); + } + + std::string compressed_data; + { + httplib::detail::gzip_compressor compressor; + bool result = compressor.compress( + data.data(), + data.size(), + /*last=*/true, + [&] (const char* data, size_t size) { + compressed_data.insert(compressed_data.size(), data, size); + return true; + }); + ASSERT_TRUE(result); + } + + std::string decompressed_data; + { + httplib::detail::gzip_decompressor decompressor; + + // Chunk size is chosen specificaly to have a decompressed chunk size equal to 16384 bytes + // 16384 bytes is the size of decompressor output buffer + size_t chunk_size = 130; + for (size_t chunk_begin = 0; chunk_begin < compressed_data.size(); chunk_begin += chunk_size) { + size_t current_chunk_size = std::min(compressed_data.size() - chunk_begin, chunk_size); + bool result = decompressor.decompress( + compressed_data.data() + chunk_begin, + current_chunk_size, + [&] (const char* data, size_t size) { + decompressed_data.insert(decompressed_data.size(), data, size); + return true; + }); + ASSERT_TRUE(result); + } + } + ASSERT_EQ(data, decompressed_data); +} #endif #ifdef CPPHTTPLIB_BROTLI_SUPPORT