16 #include "tensorflow_serving/util/net_http/compression/gzip_zlib.h"
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include "absl/strings/str_cat.h"
26 #include "absl/strings/string_view.h"
28 namespace tensorflow {
33 std::random_device rd;
35 typedef std::mt19937_64 RandomEngine;
37 int GetUniformRand(RandomEngine* rng,
int max) {
38 std::uniform_int_distribution<int> uniform(0, max);
44 TEST(GzipHeader, FragmentTest) {
45 RandomEngine rng(rd());
54 {
"\037\213\010\000\216\176\356\075\002\003", 10, 0},
57 {
"\037\213\010\000\216\176\356\075\002\003X", 11, 1},
58 {
"\037\213\010\000\216\176\356\075\002\003XXX", 13, 3},
61 "\037\213\010\010\321\135\265\100\000\003"
66 "\037\213\010\010\321\135\265\100\000\003"
71 "\037\213\010\020\321\135\265\100\000\003"
76 "\037\213\010\020\321\135\265\100\000\003"
81 "\037\213\010\002\321\135\265\100\000\003"
86 "\037\213\010\004\321\135\265\100\000\003"
91 "\037\213\010\004\321\135\265\100\000\003"
96 "\037\213\010\032\321\135\265\100\000\003"
103 "\037\213\010\036\321\135\265\100\000\003"
111 "\037\213\010\036\321\135\265\100\000\003"
122 for (
auto test : tests) {
124 for (
int j = 0; j < 1000; ++j) {
126 const char* p = test.str;
127 int bytes_left = test.len;
131 const int num_fragments = GetUniformRand(&rng, bytes_left);
132 std::vector<int> fragment_starts;
133 for (
int frag_num = 0; frag_num < num_fragments; ++frag_num) {
134 fragment_starts.push_back(GetUniformRand(&rng, bytes_left));
136 sort(fragment_starts.begin(), fragment_starts.end());
138 GZipHeader gzip_headers;
141 while (bytes_left > 0) {
142 const int fragment_len = (frag_num < num_fragments)
143 ? (fragment_starts[frag_num] - bytes_read)
144 : (test.len - bytes_read);
145 EXPECT_GE(fragment_len, 0);
146 const char* header_end =
nullptr;
147 GZipHeader::Status status =
148 gzip_headers.ReadMore(p, fragment_len, &header_end);
149 bytes_read += fragment_len;
150 bytes_left -= fragment_len;
151 EXPECT_GE(bytes_left, 0);
154 if (bytes_left <= test.cruft_len) {
155 EXPECT_EQ(status, GZipHeader::COMPLETE_HEADER);
158 EXPECT_EQ(status, GZipHeader::INCOMPLETE_HEADER);
166 #define MAX_BUF_SIZE 1048500
167 #define MAX_BUF_FLEX 1048576
169 void TestCompression(ZLib* zlib,
const std::string& uncompbuf,
171 uLongf complen = ZLib::MinCompressbufSize(uncompbuf.size());
172 std::string compbuf(complen,
'\0');
173 int err = zlib->Compress((Bytef*)compbuf.data(), &complen,
174 (Bytef*)uncompbuf.data(), uncompbuf.size());
175 EXPECT_EQ(Z_OK, err) <<
" " << uncompbuf.size() <<
" bytes down to "
176 << complen <<
" bytes.";
179 uLongf uncomplen2 = uncompbuf.size();
180 std::string uncompbuf2(uncomplen2,
'\0');
181 err = zlib->Uncompress((Bytef*)&uncompbuf2[0], &uncomplen2,
182 (Bytef*)compbuf.data(), complen);
183 EXPECT_EQ(Z_OK, err);
185 if (msg !=
nullptr) {
186 printf(
"Orig: %7lu Compressed: %7lu %5.3f %s\n", uncomplen2, complen,
187 (
float)complen / uncomplen2, msg);
190 EXPECT_EQ(uncompbuf, absl::string_view(uncompbuf2.data(), uncomplen2))
191 <<
"Uncompression mismatch!";
195 void TestRandomGzipHeaderUncompress(ZLib* zlib) {
196 RandomEngine rng(rd());
205 "\037\213\010\000\216\176\356\075\002\003"
206 "\313\110\315\311\311\327\121\050\317\057\312\111\121\344\002\000"
207 "\300\337\061\266\016\000\000\000",
212 std::string uncompbuf2(MAX_BUF_FLEX,
'\0');
214 for (uint32_t i = 0; i < ABSL_ARRAYSIZE(tests); ++i) {
216 for (
int j = 0; j < 5 * 1000; ++j) {
218 const char* p = tests[i].str;
219 int bytes_left = tests[i].len;
221 int bytes_uncompressed = 0;
225 const int num_fragments = GetUniformRand(&rng, bytes_left);
226 std::vector<int> fragment_starts;
227 for (
int frag_num = 0; frag_num < num_fragments; ++frag_num) {
228 fragment_starts.push_back(GetUniformRand(&rng, bytes_left));
230 sort(fragment_starts.begin(), fragment_starts.end());
234 while (bytes_left > 0) {
235 const int fragment_len = (frag_num < num_fragments)
236 ? (fragment_starts[frag_num] - bytes_read)
237 : (tests[i].len - bytes_read);
238 ASSERT_GE(fragment_len, 0);
239 if (fragment_len != 0) {
240 uLongf uncomplen2 = uncompbuf2.size() - bytes_uncompressed;
241 auto complen_src =
static_cast<uLongf
>(fragment_len);
242 int err = zlib->UncompressAtMost(
243 (Bytef*)&uncompbuf2[0] + bytes_uncompressed, &uncomplen2,
244 (
const Bytef*)p, &complen_src);
245 ASSERT_EQ(err, Z_OK);
246 bytes_uncompressed += uncomplen2;
247 bytes_read += fragment_len;
248 bytes_left -= fragment_len;
249 ASSERT_GE(bytes_left, 0);
255 ASSERT_TRUE(zlib->UncompressChunkDone());
256 EXPECT_EQ(
sizeof(
"hello, world!\n") - 1, bytes_uncompressed);
258 0, strncmp(uncompbuf2.data(),
"hello, world!\n", bytes_uncompressed))
259 <<
"Uncompression mismatch, expected 'hello, world!\\n', "
260 <<
"got '" << absl::string_view(uncompbuf2.data(), bytes_uncompressed)
266 constexpr int32_t kMaxSizeUncompressedData = 10 * 1024 * 1024;
268 void TestErrors(ZLib* zlib,
const std::string& uncompbuf_str) {
269 const char* uncompbuf = uncompbuf_str.data();
270 const uLongf uncomplen = uncompbuf_str.size();
271 std::string compbuf(MAX_BUF_SIZE,
'\0');
272 std::string uncompbuf2(MAX_BUF_FLEX,
'\0');
276 err = zlib->Compress((Bytef*)compbuf.data(), &complen, (Bytef*)uncompbuf,
278 EXPECT_EQ(Z_BUF_ERROR, err);
281 complen = compbuf.size();
282 err = zlib->Compress((Bytef*)compbuf.data(), &complen, (Bytef*)uncompbuf,
284 EXPECT_EQ(Z_OK, err) <<
" " << uncomplen <<
" bytes down to " << complen
287 uLongf uncomplen2 = 10;
288 err = zlib->Uncompress((Bytef*)&uncompbuf2[0], &uncomplen2,
289 (Bytef*)compbuf.data(), complen);
290 EXPECT_EQ(Z_BUF_ERROR, err);
293 uncomplen2 = uncompbuf2.size();
294 err = zlib->Uncompress((Bytef*)&uncompbuf2[0], &uncomplen2,
295 (Bytef*)compbuf.data(), 23);
296 EXPECT_EQ(Z_BUF_ERROR, err);
298 uncomplen2 = uncompbuf2.size();
300 err = zlib->UncompressAtMost((Bytef*)&uncompbuf2[0], &uncomplen2,
301 (Bytef*)compbuf.data(), &comlen2);
302 EXPECT_EQ(Z_OK, err);
304 EXPECT_FALSE(zlib->UncompressChunkDone())
305 <<
"UncompresDone() was happy with its 3 bytes of compressed data";
308 const int changepos = 0;
309 const char oldval = compbuf[changepos];
310 compbuf[changepos]++;
311 uncomplen2 = uncompbuf2.size();
312 err = zlib->Uncompress((Bytef*)&uncompbuf2[0], &uncomplen2,
313 (Bytef*)compbuf.data(), complen);
314 EXPECT_NE(Z_OK, err);
316 compbuf[changepos] = oldval;
320 char tmp_compbuf[10] =
"\255\255\255\255\255\255\255\255\255";
321 uncomplen2 = kMaxSizeUncompressedData;
322 err = zlib->UncompressGzipAndAllocate(
323 (Bytef**)&tmpbuf, &uncomplen2, (Bytef*)tmp_compbuf,
sizeof(tmp_compbuf));
324 EXPECT_NE(Z_OK, err);
325 EXPECT_EQ(
nullptr, tmpbuf);
328 void TestBogusGunzipRequest(ZLib* zlib) {
329 const Bytef compbuf[] =
"This is not compressed";
330 const uLongf complen =
sizeof(compbuf);
332 uLongf uncomplen = 0;
334 zlib->UncompressGzipAndAllocate(&uncompbuf, &uncomplen, compbuf, complen);
335 EXPECT_EQ(Z_DATA_ERROR, err);
338 void TestGzip(ZLib* zlib,
const std::string& uncompbuf_str) {
339 const char* uncompbuf = uncompbuf_str.data();
340 const uLongf uncomplen = uncompbuf_str.size();
341 std::string compbuf(MAX_BUF_SIZE,
'\0');
342 std::string uncompbuf2(MAX_BUF_FLEX,
'\0');
344 uLongf complen = compbuf.size();
345 int err = zlib->Compress((Bytef*)compbuf.data(), &complen, (Bytef*)uncompbuf,
347 EXPECT_EQ(Z_OK, err) <<
" " << uncomplen <<
" bytes down to " << complen
350 uLongf uncomplen2 = uncompbuf2.size();
351 err = zlib->Uncompress((Bytef*)&uncompbuf2[0], &uncomplen2,
352 (Bytef*)compbuf.data(), complen);
353 EXPECT_EQ(Z_OK, err);
354 EXPECT_EQ(uncomplen, uncomplen2) <<
"Uncompression mismatch!";
355 EXPECT_EQ(0, memcmp(uncompbuf, uncompbuf2.data(), uncomplen))
356 <<
"Uncompression mismatch!";
360 err = zlib->UncompressGzipAndAllocate((Bytef**)&tmpbuf, &uncomplen2,
361 (Bytef*)compbuf.data(), complen);
362 EXPECT_EQ(Z_OK, err);
363 EXPECT_EQ(uncomplen, uncomplen2) <<
"Uncompression mismatch!";
364 EXPECT_EQ(0, memcmp(uncompbuf, uncompbuf2.data(), uncomplen))
365 <<
"Uncompression mismatch!";
367 std::allocator<char>().deallocate(tmpbuf, uncomplen2);
371 void TestChunkedGzip(ZLib* zlib,
const std::string& uncompbuf_str,
373 const char* uncompbuf = uncompbuf_str.data();
374 const uLongf uncomplen = uncompbuf_str.size();
375 std::string compbuf(MAX_BUF_SIZE,
'\0');
376 std::string uncompbuf2(MAX_BUF_FLEX,
'\0');
377 EXPECT_GT(num_chunks, 2);
383 const int chunklen = uncomplen / num_chunks;
384 int chunknum, i, err;
387 for (chunknum = 0, i = 0; i < uncomplen; i += chunklen, chunknum++) {
388 uLongf complen = compbuf.size() - cum_len[chunknum];
390 uLongf chunksize = (uncomplen - i) < chunklen ? (uncomplen - i) : chunklen;
391 err = zlib->CompressAtMost((Bytef*)compbuf.data() + cum_len[chunknum],
392 &complen, (Bytef*)uncompbuf + i, &chunksize);
393 ASSERT_EQ(Z_OK, err) <<
" " << uncomplen <<
" bytes down to " << complen
395 cum_len[chunknum + 1] = cum_len[chunknum] + complen;
397 uLongf complen = compbuf.size() - cum_len[chunknum];
398 err = zlib->CompressChunkDone((Bytef*)compbuf.data() + cum_len[chunknum],
400 EXPECT_EQ(Z_OK, err);
401 cum_len[chunknum + 1] = cum_len[chunknum] + complen;
403 for (chunknum = 0, i = 0; i < uncomplen; i += chunklen, chunknum++) {
404 uLongf uncomplen2 = uncomplen - i;
406 int expected = uncomplen2 < chunklen ? uncomplen2 : chunklen;
407 uLongf complen_src = cum_len[chunknum + 1] - cum_len[chunknum];
408 err = zlib->UncompressAtMost((Bytef*)&uncompbuf2[0] + i, &uncomplen2,
409 (Bytef*)compbuf.data() + cum_len[chunknum],
411 EXPECT_EQ(Z_OK, err);
412 EXPECT_EQ(expected, uncomplen2)
413 <<
"Uncompress size is " << uncomplen2 <<
", not " << expected;
416 uLongf uncomplen2 = uncompbuf2.size() - uncomplen;
417 EXPECT_NE(0, uncomplen2);
418 uLongf complen_src = cum_len[chunknum + 1] - cum_len[chunknum];
419 err = zlib->UncompressAtMost((Bytef*)&uncompbuf2[0] + uncomplen, &uncomplen2,
420 (Bytef*)compbuf.data() + cum_len[chunknum],
422 EXPECT_EQ(Z_OK, err);
423 EXPECT_EQ(0, uncomplen2);
424 EXPECT_TRUE(zlib->UncompressChunkDone());
427 EXPECT_EQ(0, memcmp(uncompbuf, uncompbuf2.data(), uncomplen))
428 <<
"Uncompression mismatch!";
432 uncomplen2 = uncompbuf2.size();
433 complen_src = cum_len[1];
434 err = zlib->UncompressAtMost((Bytef*)&uncompbuf2[0], &uncomplen2,
435 (Bytef*)compbuf.data(), &complen_src);
436 EXPECT_EQ(Z_OK, err);
437 EXPECT_EQ(chunklen, uncomplen2) <<
"Uncompression mismatch!";
443 EXPECT_EQ(0, memcmp(uncompbuf, uncompbuf2.data(), uncomplen2))
444 <<
"Uncompression mismatch!";
447 uncomplen2 = uncompbuf2.size();
448 complen_src = cum_len[1];
449 err = zlib->UncompressAtMost((Bytef*)&uncompbuf2[0], &uncomplen2,
450 (Bytef*)compbuf.data(), &complen_src);
451 EXPECT_EQ(Z_DATA_ERROR, err);
455 uncomplen2 = uncompbuf2.size();
456 complen_src = cum_len[1];
457 err = zlib->UncompressAtMost((Bytef*)&uncompbuf2[0], &uncomplen2,
458 (Bytef*)compbuf.data(), &complen_src);
459 EXPECT_EQ(Z_OK, err);
460 EXPECT_EQ(chunklen, uncomplen2) <<
"Uncompression mismatch!";
461 EXPECT_EQ(0, memcmp(uncompbuf, uncompbuf2.data(), uncomplen2))
462 <<
"Uncompression mismatch!";
466 uLong source_len = cum_len[2] - cum_len[1];
467 EXPECT_GT(source_len, 1);
470 err = zlib->UncompressAtMost((Bytef*)&uncompbuf2[0], &uncomplen2,
471 (Bytef*)(compbuf.data() + cum_len[1]),
473 EXPECT_EQ(Z_BUF_ERROR, err);
475 EXPECT_EQ(0, memcmp(uncompbuf + chunklen, uncompbuf2.data(), uncomplen2))
476 <<
"Uncompression mismatch!";
478 const int saveuncomplen2 = uncomplen2;
479 uncomplen2 = uncompbuf2.size() - uncomplen2;
481 err = zlib->UncompressAtMost(
482 (Bytef*)&uncompbuf2[0], &uncomplen2,
483 (Bytef*)(compbuf.data() + cum_len[2] - source_len), &source_len);
485 EXPECT_EQ(Z_OK, err);
487 EXPECT_EQ(0, memcmp(uncompbuf + chunklen + saveuncomplen2, uncompbuf2.data(),
489 <<
"Uncompression mismatch!";
495 void TestFooterBufferTooSmall(ZLib* zlib) {
496 uLongf footer_len = zlib->MinFooterSize() - 1;
497 ASSERT_EQ(9, footer_len);
498 Bytef footer_buffer[9];
499 int err = zlib->CompressChunkDone(footer_buffer, &footer_len);
500 ASSERT_EQ(Z_BUF_ERROR, err);
501 ASSERT_EQ(0, footer_len);
504 TEST(ZLibTest, HugeCompression) {
507 const uLong HUGE_DATA_SIZE = 0x81000000;
510 std::string uncompbuf(HUGE_DATA_SIZE,
'A');
513 zlib.SetCompressionLevel(1);
514 TestCompression(&zlib, uncompbuf,
nullptr);
518 const char kText[] =
"1234567890abcdefghijklmnopqrstuvwxyz";
520 TEST(ZLibTest, Compression) {
521 const std::string uncompbuf = kText;
523 zlib.SetCompressionLevel(6);
525 TestCompression(&zlib, uncompbuf,
"fixed size");
528 TEST(ZLibTest, OtherErrors) {
529 const std::string uncompbuf = kText;
532 TestErrors(&zlib, uncompbuf);
534 TestBogusGunzipRequest(&zlib);
537 TEST(ZLibTest, UncompressChunkedHeaders) {
541 TestRandomGzipHeaderUncompress(&zlib);
544 TEST(ZLibTest, GzipCompression) {
545 const std::string uncompbuf = kText;
548 TestGzip(&zlib, uncompbuf);
551 TestGzip(&zlib, uncompbuf);
554 TEST(ZLibTest, ChunkedCompression) {
555 const std::string uncompbuf = kText;
558 TestChunkedGzip(&zlib, uncompbuf, 5);
561 TestChunkedGzip(&zlib, uncompbuf, 6);
564 TestGzip(&zlib, uncompbuf);
565 TestChunkedGzip(&zlib, uncompbuf, 8);
568 TestFooterBufferTooSmall(&zlib);
570 TestGzip(&zlib, uncompbuf);
573 TEST(ZLibTest, BytewiseRead) {
575 "v nedrah tundry vydra v getrah tyrit v vedrah yadra kedra";
576 size_t text_len = text.size();
577 size_t archive_len = ZLib::MinCompressbufSize(text_len);
578 std::string archive(archive_len,
'\0');
579 size_t decompressed_len = text_len + 1;
580 std::string decompressed(decompressed_len,
'\0');
581 size_t decompressed_offset = 0;
584 int rc = compressor.Compress((Bytef*)archive.data(), &archive_len,
585 (Bytef*)text.data(), text_len);
589 for (
size_t i = 0; i < archive_len; ++i) {
590 size_t source_len = 1;
591 size_t dest_len = decompressed_len - decompressed_offset;
592 rc = zlib.UncompressAtMost(
593 (Bytef*)decompressed.data() + decompressed_offset, &dest_len,
594 (Bytef*)archive.data() + i, &source_len);
596 ASSERT_EQ(source_len, 0);
597 decompressed_offset += dest_len;
600 ASSERT_TRUE(zlib.IsGzipFooterValid());
601 ASSERT_EQ(decompressed_offset, text_len);
603 std::string truncated_output(decompressed.data(), text_len);
604 ASSERT_EQ(truncated_output, text);
607 TEST(ZLibTest, TruncatedData) {
608 const int kBufferLen = 64;
609 std::string uncompressed =
"Hello, World!";
610 std::string compressed(
611 "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xf3\x48\xcd\xc9\xc9"
612 "\xd7\x51\x08\xcf\x2f\xca\x49\x51\x04\x00\xd0\xc3\x4a\xec\x0d"
620 char uncompbuf[kBufferLen];
621 bzero(uncompbuf, kBufferLen);
622 uLongf uncomplen = kBufferLen;
623 int err = zlib.Uncompress(
624 reinterpret_cast<Bytef*
>(uncompbuf), &uncomplen,
625 reinterpret_cast<const Bytef*
>(compressed.c_str()), compressed.size());
626 ASSERT_EQ(err, Z_OK);
627 ASSERT_EQ(uncompressed, absl::string_view(uncompbuf, uncomplen));
631 for (
int len = compressed.size() - 1; len > 0; len--) {
632 SCOPED_TRACE(absl::StrCat(
"Decompressing first ", len,
" out of ",
633 compressed.size(),
" bytes"));
636 char uncompbuf[kBufferLen];
637 bzero(uncompbuf, kBufferLen);
638 uLongf uncomplen = kBufferLen;
639 int err = zlib.Uncompress(
640 reinterpret_cast<Bytef*
>(uncompbuf), &uncomplen,
641 reinterpret_cast<const Bytef*
>(compressed.c_str()), len);
642 ASSERT_NE(err, Z_OK);
647 for (
int len = compressed.size() - 1; len > 0; len--) {
648 SCOPED_TRACE(absl::StrCat(
"Decompressing first ", len,
" out of ",
649 compressed.size(),
" bytes"));
652 char uncompbuf[kBufferLen];
653 bzero(uncompbuf, kBufferLen);
654 uLongf uncomplen = kBufferLen;
655 uLongf complen = len;
656 int err = zlib.UncompressAtMost(
657 reinterpret_cast<Bytef*
>(uncompbuf), &uncomplen,
658 reinterpret_cast<const Bytef*
>(compressed.c_str()), &complen);
659 ASSERT_EQ(err, Z_OK);
660 ASSERT_EQ(complen, 0);
664 testing::StartsWith(std::string(uncompbuf).substr(0, uncomplen)));
666 ASSERT_FALSE(zlib.UncompressChunkDone());
670 TEST(ZLibTest, GzipUncompressedLength) {
674 std::string hello_world(
675 "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xf3\x48\xcd\xc9\xc9"
676 "\xd7\x51\x08\xcf\x2f\xca\x49\x51\x04\x00\xd0\xc3\x4a\xec\x0d"
679 EXPECT_EQ(13, zlib.GzipUncompressedLength(
680 reinterpret_cast<const Bytef*
>(hello_world.c_str()),
681 hello_world.size()));
685 "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x00\x00"
686 "\x00\x00\x00\x00\x00",
689 zlib.GzipUncompressedLength(
690 reinterpret_cast<const Bytef*
>(empty.c_str()), empty.size()));
692 std::string bad_data(
"\x01\x01\x01\x01", 4);
693 for (
int len = 0; len <= bad_data.size(); len++) {
694 EXPECT_EQ(0, zlib.GzipUncompressedLength(
695 reinterpret_cast<const Bytef*
>(bad_data.c_str()), len));