1 // Copyright 2014 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 5 #include <fstream> 6 #include <ostream> 7 8 #include "base/files/file_util.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/path_service.h" 11 #include "net/base/io_buffer.h" 12 #include "net/filter/gzip_filter.h" 13 #include "net/filter/mock_filter_context.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/platform_test.h" 16 #include "third_party/zlib/zlib.h" 17 18 namespace { 19 20 const int kDefaultBufferSize = 4096; 21 const int kSmallBufferSize = 128; 22 23 // The GZIP header (see RFC 1952): 24 // +---+---+---+---+---+---+---+---+---+---+ 25 // |ID1|ID2|CM |FLG| MTIME |XFL|OS | 26 // +---+---+---+---+---+---+---+---+---+---+ 27 // ID1 \037 28 // ID2 \213 29 // CM \010 (compression method == DEFLATE) 30 // FLG \000 (special flags that we do not support) 31 // MTIME Unix format modification time (0 means not available) 32 // XFL 2-4? DEFLATE flags 33 // OS ???? Operating system indicator (255 means unknown) 34 // 35 // Header value we generate: 36 const char kGZipHeader[] = { '\037', '\213', '\010', '\000', '\000', 37 '\000', '\000', '\000', '\002', '\377' }; 38 39 enum EncodeMode { 40 ENCODE_GZIP, // Wrap the deflate with a GZip header. 41 ENCODE_DEFLATE // Raw deflate. 42 }; 43 44 } // namespace 45 46 namespace net { 47 48 // These tests use the path service, which uses autoreleased objects on the 49 // Mac, so this needs to be a PlatformTest. 50 class GZipUnitTest : public PlatformTest { 51 protected: 52 virtual void SetUp() { 53 PlatformTest::SetUp(); 54 55 deflate_encode_buffer_ = NULL; 56 gzip_encode_buffer_ = NULL; 57 58 // Get the path of source data file. 59 base::FilePath file_path; 60 PathService::Get(base::DIR_SOURCE_ROOT, &file_path); 61 file_path = file_path.AppendASCII("net"); 62 file_path = file_path.AppendASCII("data"); 63 file_path = file_path.AppendASCII("filter_unittests"); 64 file_path = file_path.AppendASCII("google.txt"); 65 66 // Read data from the file into buffer. 67 ASSERT_TRUE(base::ReadFileToString(file_path, &source_buffer_)); 68 69 // Encode the data with deflate 70 deflate_encode_buffer_ = new char[kDefaultBufferSize]; 71 ASSERT_TRUE(deflate_encode_buffer_ != NULL); 72 73 deflate_encode_len_ = kDefaultBufferSize; 74 int code = CompressAll(ENCODE_DEFLATE , source_buffer(), source_len(), 75 deflate_encode_buffer_, &deflate_encode_len_); 76 ASSERT_TRUE(code == Z_STREAM_END); 77 ASSERT_GT(deflate_encode_len_, 0); 78 ASSERT_TRUE(deflate_encode_len_ <= kDefaultBufferSize); 79 80 // Encode the data with gzip 81 gzip_encode_buffer_ = new char[kDefaultBufferSize]; 82 ASSERT_TRUE(gzip_encode_buffer_ != NULL); 83 84 gzip_encode_len_ = kDefaultBufferSize; 85 code = CompressAll(ENCODE_GZIP, source_buffer(), source_len(), 86 gzip_encode_buffer_, &gzip_encode_len_); 87 ASSERT_TRUE(code == Z_STREAM_END); 88 ASSERT_GT(gzip_encode_len_, 0); 89 ASSERT_TRUE(gzip_encode_len_ <= kDefaultBufferSize); 90 } 91 92 virtual void TearDown() { 93 delete[] deflate_encode_buffer_; 94 deflate_encode_buffer_ = NULL; 95 96 delete[] gzip_encode_buffer_; 97 gzip_encode_buffer_ = NULL; 98 99 PlatformTest::TearDown(); 100 } 101 102 // Compress the data in source with deflate encoding and write output to the 103 // buffer provided by dest. The function returns Z_OK if success, and returns 104 // other zlib error code if fail. 105 // The parameter mode specifies the encoding mechanism. 106 // The dest buffer should be large enough to hold all the output data. 107 int CompressAll(EncodeMode mode, const char* source, int source_size, 108 char* dest, int* dest_len) { 109 z_stream zlib_stream; 110 memset(&zlib_stream, 0, sizeof(zlib_stream)); 111 int code; 112 113 // Initialize zlib 114 if (mode == ENCODE_GZIP) { 115 code = deflateInit2(&zlib_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 116 -MAX_WBITS, 117 8, // DEF_MEM_LEVEL 118 Z_DEFAULT_STRATEGY); 119 } else { 120 code = deflateInit(&zlib_stream, Z_DEFAULT_COMPRESSION); 121 } 122 123 if (code != Z_OK) 124 return code; 125 126 // Fill in zlib control block 127 zlib_stream.next_in = bit_cast<Bytef*>(source); 128 zlib_stream.avail_in = source_size; 129 zlib_stream.next_out = bit_cast<Bytef*>(dest); 130 zlib_stream.avail_out = *dest_len; 131 132 // Write header if needed 133 if (mode == ENCODE_GZIP) { 134 if (zlib_stream.avail_out < sizeof(kGZipHeader)) 135 return Z_BUF_ERROR; 136 memcpy(zlib_stream.next_out, kGZipHeader, sizeof(kGZipHeader)); 137 zlib_stream.next_out += sizeof(kGZipHeader); 138 zlib_stream.avail_out -= sizeof(kGZipHeader); 139 } 140 141 // Do deflate 142 code = deflate(&zlib_stream, Z_FINISH); 143 *dest_len = *dest_len - zlib_stream.avail_out; 144 145 deflateEnd(&zlib_stream); 146 return code; 147 } 148 149 // Use filter to decode compressed data, and compare the decoding result with 150 // the orginal Data. 151 // Parameters: Source and source_len are original data and its size. 152 // Encoded_source and encoded_source_len are compressed data and its size. 153 // Output_buffer_size specifies the size of buffer to read out data from 154 // filter. 155 void DecodeAndCompareWithFilter(Filter* filter, 156 const char* source, 157 int source_len, 158 const char* encoded_source, 159 int encoded_source_len, 160 int output_buffer_size) { 161 // Make sure we have enough space to hold the decoding output. 162 ASSERT_TRUE(source_len <= kDefaultBufferSize); 163 ASSERT_TRUE(output_buffer_size <= kDefaultBufferSize); 164 165 char decode_buffer[kDefaultBufferSize]; 166 char* decode_next = decode_buffer; 167 int decode_avail_size = kDefaultBufferSize; 168 169 const char* encode_next = encoded_source; 170 int encode_avail_size = encoded_source_len; 171 172 int code = Filter::FILTER_OK; 173 while (code != Filter::FILTER_DONE) { 174 int encode_data_len; 175 encode_data_len = std::min(encode_avail_size, 176 filter->stream_buffer_size()); 177 memcpy(filter->stream_buffer()->data(), encode_next, encode_data_len); 178 filter->FlushStreamBuffer(encode_data_len); 179 encode_next += encode_data_len; 180 encode_avail_size -= encode_data_len; 181 182 while (1) { 183 int decode_data_len = std::min(decode_avail_size, output_buffer_size); 184 185 code = filter->ReadData(decode_next, &decode_data_len); 186 decode_next += decode_data_len; 187 decode_avail_size -= decode_data_len; 188 189 ASSERT_TRUE(code != Filter::FILTER_ERROR); 190 191 if (code == Filter::FILTER_NEED_MORE_DATA || 192 code == Filter::FILTER_DONE) { 193 break; 194 } 195 } 196 } 197 198 // Compare the decoding result with source data 199 int decode_total_data_len = kDefaultBufferSize - decode_avail_size; 200 EXPECT_TRUE(decode_total_data_len == source_len); 201 EXPECT_EQ(memcmp(source, decode_buffer, source_len), 0); 202 } 203 204 // Unsafe function to use filter to decode compressed data. 205 // Parameters: Source and source_len are compressed data and its size. 206 // Dest is the buffer for decoding results. Upon entry, *dest_len is the size 207 // of the dest buffer. Upon exit, *dest_len is the number of chars written 208 // into the buffer. 209 int DecodeAllWithFilter(Filter* filter, const char* source, int source_len, 210 char* dest, int* dest_len) { 211 memcpy(filter->stream_buffer()->data(), source, source_len); 212 filter->FlushStreamBuffer(source_len); 213 return filter->ReadData(dest, dest_len); 214 } 215 216 void InitFilter(Filter::FilterType type) { 217 std::vector<Filter::FilterType> filter_types; 218 filter_types.push_back(type); 219 filter_.reset(Filter::Factory(filter_types, filter_context_)); 220 ASSERT_TRUE(filter_.get()); 221 ASSERT_GE(filter_->stream_buffer_size(), kDefaultBufferSize); 222 } 223 224 void InitFilterWithBufferSize(Filter::FilterType type, int buffer_size) { 225 std::vector<Filter::FilterType> filter_types; 226 filter_types.push_back(type); 227 filter_.reset(Filter::FactoryForTests(filter_types, filter_context_, 228 buffer_size)); 229 ASSERT_TRUE(filter_.get()); 230 } 231 232 const char* source_buffer() const { return source_buffer_.data(); } 233 int source_len() const { return static_cast<int>(source_buffer_.size()); } 234 235 scoped_ptr<Filter> filter_; 236 237 std::string source_buffer_; 238 239 char* deflate_encode_buffer_; 240 int deflate_encode_len_; 241 242 char* gzip_encode_buffer_; 243 int gzip_encode_len_; 244 245 private: 246 MockFilterContext filter_context_; 247 }; 248 249 // Basic scenario: decoding deflate data with big enough buffer. 250 TEST_F(GZipUnitTest, DecodeDeflate) { 251 // Decode the compressed data with filter 252 InitFilter(Filter::FILTER_TYPE_DEFLATE); 253 memcpy(filter_->stream_buffer()->data(), deflate_encode_buffer_, 254 deflate_encode_len_); 255 filter_->FlushStreamBuffer(deflate_encode_len_); 256 257 char deflate_decode_buffer[kDefaultBufferSize]; 258 int deflate_decode_size = kDefaultBufferSize; 259 filter_->ReadData(deflate_decode_buffer, &deflate_decode_size); 260 261 // Compare the decoding result with source data 262 EXPECT_TRUE(deflate_decode_size == source_len()); 263 EXPECT_EQ(memcmp(source_buffer(), deflate_decode_buffer, source_len()), 0); 264 } 265 266 // Basic scenario: decoding gzip data with big enough buffer. 267 TEST_F(GZipUnitTest, DecodeGZip) { 268 // Decode the compressed data with filter 269 InitFilter(Filter::FILTER_TYPE_GZIP); 270 memcpy(filter_->stream_buffer()->data(), gzip_encode_buffer_, 271 gzip_encode_len_); 272 filter_->FlushStreamBuffer(gzip_encode_len_); 273 274 char gzip_decode_buffer[kDefaultBufferSize]; 275 int gzip_decode_size = kDefaultBufferSize; 276 filter_->ReadData(gzip_decode_buffer, &gzip_decode_size); 277 278 // Compare the decoding result with source data 279 EXPECT_TRUE(gzip_decode_size == source_len()); 280 EXPECT_EQ(memcmp(source_buffer(), gzip_decode_buffer, source_len()), 0); 281 } 282 283 // Tests we can call filter repeatedly to get all the data decoded. 284 // To do that, we create a filter with a small buffer that can not hold all 285 // the input data. 286 TEST_F(GZipUnitTest, DecodeWithSmallBuffer) { 287 InitFilterWithBufferSize(Filter::FILTER_TYPE_DEFLATE, kSmallBufferSize); 288 EXPECT_EQ(kSmallBufferSize, filter_->stream_buffer_size()); 289 DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), 290 deflate_encode_buffer_, deflate_encode_len_, 291 kDefaultBufferSize); 292 } 293 294 // Tests we can still decode with just 1 byte buffer in the filter. 295 // The purpose of this tests are two: (1) Verify filter can parse partial GZip 296 // header correctly. (2) Sometimes the filter will consume input without 297 // generating output. Verify filter can handle it correctly. 298 TEST_F(GZipUnitTest, DecodeWithOneByteBuffer) { 299 InitFilterWithBufferSize(Filter::FILTER_TYPE_GZIP, 1); 300 EXPECT_EQ(1, filter_->stream_buffer_size()); 301 DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), 302 gzip_encode_buffer_, gzip_encode_len_, 303 kDefaultBufferSize); 304 } 305 306 // Tests we can decode when caller has small buffer to read out from filter. 307 TEST_F(GZipUnitTest, DecodeWithSmallOutputBuffer) { 308 InitFilter(Filter::FILTER_TYPE_DEFLATE); 309 DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), 310 deflate_encode_buffer_, deflate_encode_len_, 311 kSmallBufferSize); 312 } 313 314 // Tests we can still decode with just 1 byte buffer in the filter and just 1 315 // byte buffer in the caller. 316 TEST_F(GZipUnitTest, DecodeWithOneByteInputAndOutputBuffer) { 317 InitFilterWithBufferSize(Filter::FILTER_TYPE_GZIP, 1); 318 EXPECT_EQ(1, filter_->stream_buffer_size()); 319 DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), 320 gzip_encode_buffer_, gzip_encode_len_, 1); 321 } 322 323 // Decoding deflate stream with corrupted data. 324 TEST_F(GZipUnitTest, DecodeCorruptedData) { 325 char corrupt_data[kDefaultBufferSize]; 326 int corrupt_data_len = deflate_encode_len_; 327 memcpy(corrupt_data, deflate_encode_buffer_, deflate_encode_len_); 328 329 int pos = corrupt_data_len / 2; 330 corrupt_data[pos] = !corrupt_data[pos]; 331 332 // Decode the corrupted data with filter 333 InitFilter(Filter::FILTER_TYPE_DEFLATE); 334 char corrupt_decode_buffer[kDefaultBufferSize]; 335 int corrupt_decode_size = kDefaultBufferSize; 336 337 int code = DecodeAllWithFilter(filter_.get(), corrupt_data, corrupt_data_len, 338 corrupt_decode_buffer, &corrupt_decode_size); 339 340 // Expect failures 341 EXPECT_TRUE(code == Filter::FILTER_ERROR); 342 } 343 344 // Decoding deflate stream with missing data. 345 TEST_F(GZipUnitTest, DecodeMissingData) { 346 char corrupt_data[kDefaultBufferSize]; 347 int corrupt_data_len = deflate_encode_len_; 348 memcpy(corrupt_data, deflate_encode_buffer_, deflate_encode_len_); 349 350 int pos = corrupt_data_len / 2; 351 int len = corrupt_data_len - pos - 1; 352 memmove(&corrupt_data[pos], &corrupt_data[pos+1], len); 353 --corrupt_data_len; 354 355 // Decode the corrupted data with filter 356 InitFilter(Filter::FILTER_TYPE_DEFLATE); 357 char corrupt_decode_buffer[kDefaultBufferSize]; 358 int corrupt_decode_size = kDefaultBufferSize; 359 360 int code = DecodeAllWithFilter(filter_.get(), corrupt_data, corrupt_data_len, 361 corrupt_decode_buffer, &corrupt_decode_size); 362 363 // Expect failures 364 EXPECT_EQ(Filter::FILTER_ERROR, code); 365 } 366 367 // Decoding gzip stream with corrupted header. 368 TEST_F(GZipUnitTest, DecodeCorruptedHeader) { 369 char corrupt_data[kDefaultBufferSize]; 370 int corrupt_data_len = gzip_encode_len_; 371 memcpy(corrupt_data, gzip_encode_buffer_, gzip_encode_len_); 372 373 corrupt_data[2] = !corrupt_data[2]; 374 375 // Decode the corrupted data with filter 376 InitFilter(Filter::FILTER_TYPE_GZIP); 377 char corrupt_decode_buffer[kDefaultBufferSize]; 378 int corrupt_decode_size = kDefaultBufferSize; 379 380 int code = DecodeAllWithFilter(filter_.get(), corrupt_data, corrupt_data_len, 381 corrupt_decode_buffer, &corrupt_decode_size); 382 383 // Expect failures 384 EXPECT_TRUE(code == Filter::FILTER_ERROR); 385 } 386 387 } // namespace net 388