gzip_source_stream_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. // Copyright 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <string>
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/callback.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "net/base/io_buffer.h"
  10. #include "net/base/test_completion_callback.h"
  11. #include "net/filter/filter_source_stream_test_util.h"
  12. #include "net/filter/gzip_source_stream.h"
  13. #include "net/filter/mock_source_stream.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #include "third_party/zlib/zlib.h"
  16. namespace net {
  17. namespace {
  18. const int kBigBufferSize = 4096;
  19. const int kSmallBufferSize = 1;
  20. enum class ReadResultType {
  21. // Each call to AddReadResult is a separate read from the lower layer
  22. // SourceStream.
  23. EVERYTHING_AT_ONCE,
  24. // Whenever AddReadResult is called, each byte is actually a separate read
  25. // result.
  26. ONE_BYTE_AT_A_TIME,
  27. };
  28. // How many bytes to leave unused at the end of |source_data_|. This margin is
  29. // present so that tests that need to append data after the zlib EOF do not run
  30. // out of room in the output buffer.
  31. const size_t kEOFMargin = 64;
  32. struct GzipTestParam {
  33. GzipTestParam(int buf_size,
  34. MockSourceStream::Mode read_mode,
  35. ReadResultType read_result_type)
  36. : buffer_size(buf_size),
  37. mode(read_mode),
  38. read_result_type(read_result_type) {}
  39. const int buffer_size;
  40. const MockSourceStream::Mode mode;
  41. const ReadResultType read_result_type;
  42. };
  43. } // namespace
  44. class GzipSourceStreamTest : public ::testing::TestWithParam<GzipTestParam> {
  45. protected:
  46. GzipSourceStreamTest() : output_buffer_size_(GetParam().buffer_size) {}
  47. // Helpful function to initialize the test fixture.|type| specifies which type
  48. // of GzipSourceStream to create. It must be one of TYPE_GZIP and
  49. // TYPE_DEFLATE.
  50. void Init(SourceStream::SourceType type) {
  51. EXPECT_TRUE(SourceStream::TYPE_GZIP == type ||
  52. SourceStream::TYPE_DEFLATE == type);
  53. source_data_len_ = kBigBufferSize - kEOFMargin;
  54. for (size_t i = 0; i < source_data_len_; i++)
  55. source_data_[i] = i % 256;
  56. encoded_data_len_ = kBigBufferSize;
  57. CompressGzip(source_data_, source_data_len_, encoded_data_,
  58. &encoded_data_len_, type != SourceStream::TYPE_DEFLATE);
  59. output_buffer_ = base::MakeRefCounted<IOBuffer>(output_buffer_size_);
  60. auto source = std::make_unique<MockSourceStream>();
  61. if (GetParam().read_result_type == ReadResultType::ONE_BYTE_AT_A_TIME)
  62. source->set_read_one_byte_at_a_time(true);
  63. source_ = source.get();
  64. stream_ = GzipSourceStream::Create(std::move(source), type);
  65. }
  66. // If MockSourceStream::Mode is ASYNC, completes reads from |mock_stream|
  67. // until there's no pending read, and then returns |callback|'s result, once
  68. // it's invoked. If Mode is not ASYNC, does nothing and returns
  69. // |previous_result|.
  70. int CompleteReadsIfAsync(int previous_result,
  71. TestCompletionCallback* callback,
  72. MockSourceStream* mock_stream) {
  73. if (GetParam().mode == MockSourceStream::ASYNC) {
  74. EXPECT_EQ(ERR_IO_PENDING, previous_result);
  75. while (mock_stream->awaiting_completion())
  76. mock_stream->CompleteNextRead();
  77. return callback->WaitForResult();
  78. }
  79. return previous_result;
  80. }
  81. char* source_data() { return source_data_; }
  82. size_t source_data_len() { return source_data_len_; }
  83. char* encoded_data() { return encoded_data_; }
  84. size_t encoded_data_len() { return encoded_data_len_; }
  85. IOBuffer* output_buffer() { return output_buffer_.get(); }
  86. char* output_data() { return output_buffer_->data(); }
  87. size_t output_buffer_size() { return output_buffer_size_; }
  88. MockSourceStream* source() { return source_; }
  89. GzipSourceStream* stream() { return stream_.get(); }
  90. // Reads from |stream_| until an error occurs or the EOF is reached.
  91. // When an error occurs, returns the net error code. When an EOF is reached,
  92. // returns the number of bytes read and appends data read to |output|.
  93. int ReadStream(std::string* output) {
  94. int bytes_read = 0;
  95. while (true) {
  96. TestCompletionCallback callback;
  97. int rv = stream_->Read(output_buffer(), output_buffer_size(),
  98. callback.callback());
  99. if (rv == ERR_IO_PENDING)
  100. rv = CompleteReadsIfAsync(rv, &callback, source());
  101. if (rv == OK)
  102. break;
  103. if (rv < OK)
  104. return rv;
  105. EXPECT_GT(rv, OK);
  106. bytes_read += rv;
  107. output->append(output_data(), rv);
  108. }
  109. return bytes_read;
  110. }
  111. private:
  112. char source_data_[kBigBufferSize];
  113. size_t source_data_len_;
  114. char encoded_data_[kBigBufferSize];
  115. size_t encoded_data_len_;
  116. scoped_refptr<IOBuffer> output_buffer_;
  117. const int output_buffer_size_;
  118. raw_ptr<MockSourceStream> source_;
  119. std::unique_ptr<GzipSourceStream> stream_;
  120. };
  121. INSTANTIATE_TEST_SUITE_P(
  122. GzipSourceStreamTests,
  123. GzipSourceStreamTest,
  124. ::testing::Values(GzipTestParam(kBigBufferSize,
  125. MockSourceStream::SYNC,
  126. ReadResultType::EVERYTHING_AT_ONCE),
  127. GzipTestParam(kSmallBufferSize,
  128. MockSourceStream::SYNC,
  129. ReadResultType::EVERYTHING_AT_ONCE),
  130. GzipTestParam(kBigBufferSize,
  131. MockSourceStream::ASYNC,
  132. ReadResultType::EVERYTHING_AT_ONCE),
  133. GzipTestParam(kSmallBufferSize,
  134. MockSourceStream::ASYNC,
  135. ReadResultType::EVERYTHING_AT_ONCE),
  136. GzipTestParam(kBigBufferSize,
  137. MockSourceStream::SYNC,
  138. ReadResultType::ONE_BYTE_AT_A_TIME),
  139. GzipTestParam(kSmallBufferSize,
  140. MockSourceStream::SYNC,
  141. ReadResultType::ONE_BYTE_AT_A_TIME),
  142. GzipTestParam(kBigBufferSize,
  143. MockSourceStream::ASYNC,
  144. ReadResultType::ONE_BYTE_AT_A_TIME),
  145. GzipTestParam(kSmallBufferSize,
  146. MockSourceStream::ASYNC,
  147. ReadResultType::ONE_BYTE_AT_A_TIME)));
  148. TEST_P(GzipSourceStreamTest, EmptyStream) {
  149. Init(SourceStream::TYPE_DEFLATE);
  150. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  151. TestCompletionCallback callback;
  152. std::string actual_output;
  153. int result = ReadStream(&actual_output);
  154. EXPECT_EQ(OK, result);
  155. EXPECT_EQ("DEFLATE", stream()->Description());
  156. }
  157. TEST_P(GzipSourceStreamTest, DeflateOneBlock) {
  158. Init(SourceStream::TYPE_DEFLATE);
  159. source()->AddReadResult(encoded_data(), encoded_data_len(), OK,
  160. GetParam().mode);
  161. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  162. std::string actual_output;
  163. int rv = ReadStream(&actual_output);
  164. EXPECT_EQ(static_cast<int>(source_data_len()), rv);
  165. EXPECT_EQ(std::string(source_data(), source_data_len()), actual_output);
  166. EXPECT_EQ("DEFLATE", stream()->Description());
  167. }
  168. TEST_P(GzipSourceStreamTest, GzipOneBloc) {
  169. Init(SourceStream::TYPE_GZIP);
  170. source()->AddReadResult(encoded_data(), encoded_data_len(), OK,
  171. GetParam().mode);
  172. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  173. std::string actual_output;
  174. int rv = ReadStream(&actual_output);
  175. EXPECT_EQ(static_cast<int>(source_data_len()), rv);
  176. EXPECT_EQ(std::string(source_data(), source_data_len()), actual_output);
  177. EXPECT_EQ("GZIP", stream()->Description());
  178. }
  179. TEST_P(GzipSourceStreamTest, DeflateTwoReads) {
  180. Init(SourceStream::TYPE_DEFLATE);
  181. source()->AddReadResult(encoded_data(), 10, OK, GetParam().mode);
  182. source()->AddReadResult(encoded_data() + 10, encoded_data_len() - 10, OK,
  183. GetParam().mode);
  184. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  185. std::string actual_output;
  186. int rv = ReadStream(&actual_output);
  187. EXPECT_EQ(static_cast<int>(source_data_len()), rv);
  188. EXPECT_EQ(std::string(source_data(), source_data_len()), actual_output);
  189. EXPECT_EQ("DEFLATE", stream()->Description());
  190. }
  191. // Check that any extra bytes after the end of the gzipped data are silently
  192. // ignored.
  193. TEST_P(GzipSourceStreamTest, IgnoreDataAfterEof) {
  194. Init(SourceStream::TYPE_DEFLATE);
  195. const char kExtraData[] = "Hello, World!";
  196. std::string encoded_data_with_trailing_data(encoded_data(),
  197. encoded_data_len());
  198. encoded_data_with_trailing_data.append(kExtraData, sizeof(kExtraData));
  199. source()->AddReadResult(encoded_data_with_trailing_data.c_str(),
  200. encoded_data_with_trailing_data.length(), OK,
  201. GetParam().mode);
  202. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  203. // Compressed and uncompressed data get returned as separate Read() results,
  204. // so this test has to call Read twice.
  205. std::string actual_output;
  206. int rv = ReadStream(&actual_output);
  207. std::string expected_output(source_data(), source_data_len());
  208. EXPECT_EQ(static_cast<int>(expected_output.size()), rv);
  209. EXPECT_EQ(expected_output, actual_output);
  210. EXPECT_EQ("DEFLATE", stream()->Description());
  211. }
  212. TEST_P(GzipSourceStreamTest, MissingZlibHeader) {
  213. Init(SourceStream::TYPE_DEFLATE);
  214. const size_t kZlibHeaderLen = 2;
  215. source()->AddReadResult(encoded_data() + kZlibHeaderLen,
  216. encoded_data_len() - kZlibHeaderLen, OK,
  217. GetParam().mode);
  218. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  219. std::string actual_output;
  220. int rv = ReadStream(&actual_output);
  221. EXPECT_EQ(static_cast<int>(source_data_len()), rv);
  222. EXPECT_EQ(std::string(source_data(), source_data_len()), actual_output);
  223. EXPECT_EQ("DEFLATE", stream()->Description());
  224. }
  225. TEST_P(GzipSourceStreamTest, CorruptGzipHeader) {
  226. Init(SourceStream::TYPE_GZIP);
  227. encoded_data()[1] = 0;
  228. int read_len = encoded_data_len();
  229. // Needed to a avoid a DCHECK that all reads were consumed.
  230. if (GetParam().read_result_type == ReadResultType::ONE_BYTE_AT_A_TIME)
  231. read_len = 2;
  232. source()->AddReadResult(encoded_data(), read_len, OK, GetParam().mode);
  233. std::string actual_output;
  234. int rv = ReadStream(&actual_output);
  235. EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
  236. EXPECT_EQ("GZIP", stream()->Description());
  237. }
  238. // This test checks that the gzip stream source works correctly on 'golden' data
  239. // as produced by gzip(1).
  240. TEST_P(GzipSourceStreamTest, GzipCorrectness) {
  241. Init(SourceStream::TYPE_GZIP);
  242. const char kDecompressedData[] = "Hello, World!";
  243. const unsigned char kGzipData[] = {
  244. // From:
  245. // echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/ /'
  246. // The footer is the last 8 bytes.
  247. 0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00, 0x03, 0xf3,
  248. 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
  249. 0x51, 0x04, 0x00, 0xd0, 0xc3, 0x4a, 0xec, 0x0d, 0x00, 0x00, 0x00};
  250. source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
  251. sizeof(kGzipData), OK, GetParam().mode);
  252. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  253. std::string actual_output;
  254. int rv = ReadStream(&actual_output);
  255. EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
  256. EXPECT_EQ(kDecompressedData, actual_output);
  257. EXPECT_EQ("GZIP", stream()->Description());
  258. }
  259. // Same as GzipCorrectness except that last 8 bytes are removed to test that the
  260. // implementation can handle missing footer.
  261. TEST_P(GzipSourceStreamTest, GzipCorrectnessWithoutFooter) {
  262. Init(SourceStream::TYPE_GZIP);
  263. const char kDecompressedData[] = "Hello, World!";
  264. const unsigned char kGzipData[] = {
  265. // From:
  266. // echo -n 'Hello, World!' | gzip | xxd -i | sed -e 's/^/ /'
  267. // with the 8 footer bytes removed.
  268. 0x1f, 0x8b, 0x08, 0x00, 0x2b, 0x02, 0x84, 0x55, 0x00,
  269. 0x03, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51, 0x08,
  270. 0xcf, 0x2f, 0xca, 0x49, 0x51, 0x04, 0x00};
  271. source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
  272. sizeof(kGzipData), OK, GetParam().mode);
  273. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  274. std::string actual_output;
  275. int rv = ReadStream(&actual_output);
  276. EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
  277. EXPECT_EQ(kDecompressedData, actual_output);
  278. EXPECT_EQ("GZIP", stream()->Description());
  279. }
  280. // Test with the same compressed data as the above tests, but uses deflate with
  281. // header and checksum. Tests the Z_STREAM_END case in
  282. // STATE_SNIFFING_DEFLATE_HEADER.
  283. TEST_P(GzipSourceStreamTest, DeflateWithAdler32) {
  284. Init(SourceStream::TYPE_DEFLATE);
  285. const char kDecompressedData[] = "Hello, World!";
  286. const unsigned char kGzipData[] = {0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9,
  287. 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
  288. 0x51, 0x04, 0x00, 0x1f, 0x9e, 0x04, 0x6a};
  289. source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
  290. sizeof(kGzipData), OK, GetParam().mode);
  291. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  292. std::string actual_output;
  293. int rv = ReadStream(&actual_output);
  294. EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
  295. EXPECT_EQ(kDecompressedData, actual_output);
  296. EXPECT_EQ("DEFLATE", stream()->Description());
  297. }
  298. TEST_P(GzipSourceStreamTest, DeflateWithBadAdler32) {
  299. Init(SourceStream::TYPE_DEFLATE);
  300. const unsigned char kGzipData[] = {0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9,
  301. 0xd7, 0x51, 0x08, 0xcf, 0x2f, 0xca, 0x49,
  302. 0x51, 0x04, 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
  303. source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
  304. sizeof(kGzipData), OK, GetParam().mode);
  305. std::string actual_output;
  306. int rv = ReadStream(&actual_output);
  307. EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
  308. EXPECT_EQ("DEFLATE", stream()->Description());
  309. }
  310. TEST_P(GzipSourceStreamTest, DeflateWithoutHeaderWithAdler32) {
  311. Init(SourceStream::TYPE_DEFLATE);
  312. const char kDecompressedData[] = "Hello, World!";
  313. const unsigned char kGzipData[] = {0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51,
  314. 0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51, 0x04,
  315. 0x00, 0x1f, 0x9e, 0x04, 0x6a};
  316. source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
  317. sizeof(kGzipData), OK, GetParam().mode);
  318. source()->AddReadResult(nullptr, 0, OK, GetParam().mode);
  319. std::string actual_output;
  320. int rv = ReadStream(&actual_output);
  321. EXPECT_EQ(static_cast<int>(strlen(kDecompressedData)), rv);
  322. EXPECT_EQ(kDecompressedData, actual_output);
  323. EXPECT_EQ("DEFLATE", stream()->Description());
  324. }
  325. TEST_P(GzipSourceStreamTest, DeflateWithoutHeaderWithBadAdler32) {
  326. Init(SourceStream::TYPE_DEFLATE);
  327. const unsigned char kGzipData[] = {0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0xd7, 0x51,
  328. 0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51, 0x04,
  329. 0x00, 0xFF, 0xFF, 0xFF, 0xFF};
  330. source()->AddReadResult(reinterpret_cast<const char*>(kGzipData),
  331. sizeof(kGzipData), OK, GetParam().mode);
  332. std::string actual_output;
  333. int rv = ReadStream(&actual_output);
  334. EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, rv);
  335. EXPECT_EQ("DEFLATE", stream()->Description());
  336. }
  337. } // namespace net