diff --git a/plugins/esi/lib/EsiGunzip.cc b/plugins/esi/lib/EsiGunzip.cc index ec1341d8182..19bfc6c2057 100644 --- a/plugins/esi/lib/EsiGunzip.cc +++ b/plugins/esi/lib/EsiGunzip.cc @@ -72,29 +72,32 @@ EsiGunzip::stream_decode(const char *data, int data_len, std::string &udata) int32_t curr_buf_size; do { - _zstrm.next_out = reinterpret_cast(raw_buf); - _zstrm.avail_out = BUF_SIZE; - inflate_result = inflate(&_zstrm, Z_SYNC_FLUSH); - curr_buf_size = -1; - if ((inflate_result == Z_OK) || (inflate_result == Z_BUF_ERROR)) { - curr_buf_size = BUF_SIZE - _zstrm.avail_out; - } else if (inflate_result == Z_STREAM_END) { + _zstrm.next_out = reinterpret_cast(raw_buf); + _zstrm.avail_out = BUF_SIZE; + auto const avail_in_before = _zstrm.avail_in; + inflate_result = inflate(&_zstrm, Z_SYNC_FLUSH); + if ((inflate_result == Z_OK) || (inflate_result == Z_BUF_ERROR) || (inflate_result == Z_STREAM_END)) { curr_buf_size = BUF_SIZE - _zstrm.avail_out; + } else { + TSError("[%s] Failure while inflating; error code %d", __FUNCTION__, inflate_result); + _success = false; + return false; } if (curr_buf_size > BUF_SIZE) { TSError("[%s] buf too large", __FUNCTION__); break; } - if (curr_buf_size < 1) { - TSError("[%s] buf below zero", __FUNCTION__); + if (curr_buf_size < 1 && avail_in_before == _zstrm.avail_in) { break; } // push empty object onto list and add data to in-list object to // avoid data copy for temporary - buf_list.push_back(string()); - string &curr_buf = buf_list.back(); - curr_buf.assign(raw_buf, curr_buf_size); + if (curr_buf_size > 0) { + buf_list.push_back(string()); + string &curr_buf = buf_list.back(); + curr_buf.assign(raw_buf, curr_buf_size); + } if (inflate_result == Z_STREAM_END) { break; diff --git a/plugins/esi/test/gzip_test.cc b/plugins/esi/test/gzip_test.cc index a6bd50fa593..5d19366a7ca 100644 --- a/plugins/esi/test/gzip_test.cc +++ b/plugins/esi/test/gzip_test.cc @@ -26,12 +26,16 @@ #include +#include "EsiGunzip.h" #include "Utils.h" #include "gzip.h" using std::string; using namespace EsiLib; +extern void enableFakeErrorLog(); +extern string gFakeErrorLog; + TEST_CASE("test esi plugin - gzip") { SECTION("===================== Test 1") @@ -102,4 +106,26 @@ TEST_CASE("test esi plugin - gzip") // check output of gunzip CHECK(gunzip(expected_cdata, 32, buf_list) == false); } + + SECTION("streaming gunzip does not log an error for chunks with no output") + { + const char expected_data[] = "Hello World!"; + + string cdata; + REQUIRE(gzip(expected_data, 12, cdata)); + + EsiGunzip gunzip; + string data; + + enableFakeErrorLog(); + REQUIRE(gunzip.stream_decode(cdata.data(), GZIP_HEADER_SIZE, data)); + CHECK(data.empty()); + CHECK(gFakeErrorLog.empty()); + + REQUIRE(gunzip.stream_decode(cdata.data() + GZIP_HEADER_SIZE, cdata.size() - GZIP_HEADER_SIZE, data)); + REQUIRE(gunzip.stream_finish()); + + CHECK(data == expected_data); + CHECK(gFakeErrorLog.empty()); + } } diff --git a/plugins/esi/test/print_funcs.cc b/plugins/esi/test/print_funcs.cc index 2596a462054..d73b973d654 100644 --- a/plugins/esi/test/print_funcs.cc +++ b/plugins/esi/test/print_funcs.cc @@ -34,9 +34,11 @@ static const int LINE_SIZE = 1024 * 1024; namespace { bool fakeDebugLogEnabled; -} +bool fakeErrorLogEnabled; +} // namespace std::string gFakeDebugLog; +std::string gFakeErrorLog; void enableFakeDebugLog() @@ -45,6 +47,13 @@ enableFakeDebugLog() gFakeDebugLog.assign(""); } +void +enableFakeErrorLog() +{ + fakeErrorLogEnabled = true; + gFakeErrorLog.assign(""); +} + void DbgCtl::print(const char *tag, const char * /* file */, const char * /* function */, int /* line */, const char *fmt, ...) { @@ -101,4 +110,7 @@ TSError(const char *fmt, ...) vsnprintf(buf, LINE_SIZE, fmt, ap); printf("Error: %s\n", buf); va_end(ap); + if (fakeErrorLogEnabled) { + gFakeErrorLog.append(buf); + } }