| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright 2015 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 "net/filter/brotli_filter.h" |  | 
|    6  |  | 
|    7 #include <memory> |  | 
|    8  |  | 
|    9 #include "base/files/file_util.h" |  | 
|   10 #include "base/path_service.h" |  | 
|   11 #include "net/base/io_buffer.h" |  | 
|   12 #include "net/filter/mock_filter_context.h" |  | 
|   13 #include "testing/gtest/include/gtest/gtest.h" |  | 
|   14 #include "testing/platform_test.h" |  | 
|   15  |  | 
|   16 namespace { |  | 
|   17 const int kDefaultBufferSize = 4096; |  | 
|   18 const int kSmallBufferSize = 128; |  | 
|   19 }  // namespace |  | 
|   20  |  | 
|   21 namespace net { |  | 
|   22  |  | 
|   23 // These tests use the path service, which uses autoreleased objects on the |  | 
|   24 // Mac, so this needs to be a PlatformTest. |  | 
|   25 class BrotliUnitTest : public PlatformTest { |  | 
|   26  protected: |  | 
|   27   void SetUp() override { |  | 
|   28     PlatformTest::SetUp(); |  | 
|   29  |  | 
|   30     // Get the path of data directory. |  | 
|   31     base::FilePath data_dir; |  | 
|   32     PathService::Get(base::DIR_SOURCE_ROOT, &data_dir); |  | 
|   33     data_dir = data_dir.AppendASCII("net"); |  | 
|   34     data_dir = data_dir.AppendASCII("data"); |  | 
|   35     data_dir = data_dir.AppendASCII("filter_unittests"); |  | 
|   36  |  | 
|   37     // Read data from the original file into buffer. |  | 
|   38     base::FilePath file_path; |  | 
|   39     file_path = data_dir.AppendASCII("google.txt"); |  | 
|   40     ASSERT_TRUE(base::ReadFileToString(file_path, &source_buffer_)); |  | 
|   41  |  | 
|   42     // Read data from the encoded file into buffer. |  | 
|   43     base::FilePath encoded_file_path; |  | 
|   44     encoded_file_path = data_dir.AppendASCII("google.br"); |  | 
|   45     ASSERT_TRUE(base::ReadFileToString(encoded_file_path, &encoded_buffer_)); |  | 
|   46     ASSERT_GE(kDefaultBufferSize, static_cast<int>(encoded_buffer_.size())); |  | 
|   47   } |  | 
|   48  |  | 
|   49   // Use filter to decode compressed data, and compare the decoded result with |  | 
|   50   // the orginal data. |  | 
|   51   // Parameters: |source| and |source_len| are original data and its size. |  | 
|   52   // |encoded_source| and |encoded_source_len| are compressed data and its size. |  | 
|   53   // |output_buffer_size| specifies the size of buffer to read out data from |  | 
|   54   // filter. |  | 
|   55   void DecodeAndCompareWithFilter(Filter* filter, |  | 
|   56                                   const char* source, |  | 
|   57                                   int source_len, |  | 
|   58                                   const char* encoded_source, |  | 
|   59                                   int encoded_source_len, |  | 
|   60                                   int output_buffer_size) { |  | 
|   61     // Make sure we have enough space to hold the decoding output. |  | 
|   62     ASSERT_GE(kDefaultBufferSize, source_len); |  | 
|   63     ASSERT_GE(kDefaultBufferSize, output_buffer_size); |  | 
|   64  |  | 
|   65     char decode_buffer[kDefaultBufferSize]; |  | 
|   66     char* decode_next = decode_buffer; |  | 
|   67     int decode_avail_size = kDefaultBufferSize; |  | 
|   68  |  | 
|   69     const char* encode_next = encoded_source; |  | 
|   70     int encode_avail_size = encoded_source_len; |  | 
|   71  |  | 
|   72     int code = Filter::FILTER_OK; |  | 
|   73     while (code != Filter::FILTER_DONE) { |  | 
|   74       int encode_data_len = |  | 
|   75           std::min(encode_avail_size, filter->stream_buffer_size()); |  | 
|   76       memcpy(filter->stream_buffer()->data(), encode_next, encode_data_len); |  | 
|   77       filter->FlushStreamBuffer(encode_data_len); |  | 
|   78       encode_next += encode_data_len; |  | 
|   79       encode_avail_size -= encode_data_len; |  | 
|   80  |  | 
|   81       while (true) { |  | 
|   82         int decode_data_len = std::min(decode_avail_size, output_buffer_size); |  | 
|   83  |  | 
|   84         code = filter->ReadData(decode_next, &decode_data_len); |  | 
|   85         decode_next += decode_data_len; |  | 
|   86         decode_avail_size -= decode_data_len; |  | 
|   87  |  | 
|   88         ASSERT_NE(Filter::FILTER_ERROR, code); |  | 
|   89  |  | 
|   90         if (code == Filter::FILTER_NEED_MORE_DATA || |  | 
|   91             code == Filter::FILTER_DONE) { |  | 
|   92           break; |  | 
|   93         } |  | 
|   94       } |  | 
|   95     } |  | 
|   96  |  | 
|   97     // Compare the decoding result with source data |  | 
|   98     int decode_total_data_len = kDefaultBufferSize - decode_avail_size; |  | 
|   99     EXPECT_EQ(source_len, decode_total_data_len); |  | 
|  100     EXPECT_EQ(memcmp(source, decode_buffer, source_len), 0); |  | 
|  101   } |  | 
|  102  |  | 
|  103   // Unsafe function to use filter to decode compressed data. |  | 
|  104   // Parameters: |source| and |source_len| are compressed data and its size. |  | 
|  105   // |dest| is the buffer for decoding results. Upon entry, |*dest_len| is the |  | 
|  106   // size of the output buffer. Upon exit, |*dest_len| is the number of chars |  | 
|  107   // written into the buffer. |  | 
|  108   int DecodeAllWithFilter(Filter* filter, |  | 
|  109                           const char* source, |  | 
|  110                           int source_len, |  | 
|  111                           char* dest, |  | 
|  112                           int* dest_len) { |  | 
|  113     memcpy(filter->stream_buffer()->data(), source, source_len); |  | 
|  114     filter->FlushStreamBuffer(source_len); |  | 
|  115     return filter->ReadData(dest, dest_len); |  | 
|  116   } |  | 
|  117  |  | 
|  118   void InitFilter() { |  | 
|  119     std::vector<Filter::FilterType> filter_types; |  | 
|  120     filter_types.push_back(Filter::FILTER_TYPE_BROTLI); |  | 
|  121     filter_ = Filter::Factory(filter_types, filter_context_); |  | 
|  122     ASSERT_TRUE(filter_.get()); |  | 
|  123     ASSERT_LE(kDefaultBufferSize, filter_->stream_buffer_size()); |  | 
|  124   } |  | 
|  125  |  | 
|  126   void InitFilterWithBufferSize(int buffer_size) { |  | 
|  127     std::vector<Filter::FilterType> filter_types; |  | 
|  128     filter_types.push_back(Filter::FILTER_TYPE_BROTLI); |  | 
|  129     filter_ = |  | 
|  130         Filter::FactoryForTests(filter_types, filter_context_, buffer_size); |  | 
|  131     ASSERT_TRUE(filter_.get()); |  | 
|  132   } |  | 
|  133  |  | 
|  134   const char* source_buffer() const { return source_buffer_.data(); } |  | 
|  135   int source_len() const { return static_cast<int>(source_buffer_.size()); } |  | 
|  136  |  | 
|  137   const char* encoded_buffer() const { return encoded_buffer_.data(); } |  | 
|  138   int encoded_len() const { return static_cast<int>(encoded_buffer_.size()); } |  | 
|  139  |  | 
|  140   std::unique_ptr<Filter> filter_; |  | 
|  141  |  | 
|  142  private: |  | 
|  143   MockFilterContext filter_context_; |  | 
|  144   std::string source_buffer_; |  | 
|  145   std::string encoded_buffer_; |  | 
|  146 }; |  | 
|  147  |  | 
|  148 // Basic scenario: decoding brotli data with big enough buffer. |  | 
|  149 TEST_F(BrotliUnitTest, DecodeBrotli) { |  | 
|  150   InitFilter(); |  | 
|  151   memcpy(filter_->stream_buffer()->data(), encoded_buffer(), encoded_len()); |  | 
|  152   filter_->FlushStreamBuffer(encoded_len()); |  | 
|  153  |  | 
|  154   ASSERT_GE(kDefaultBufferSize, source_len()); |  | 
|  155   char decode_buffer[kDefaultBufferSize]; |  | 
|  156   int decode_size = kDefaultBufferSize; |  | 
|  157   filter_->ReadData(decode_buffer, &decode_size); |  | 
|  158  |  | 
|  159   // Compare the decoding result with source data |  | 
|  160   EXPECT_EQ(source_len(), decode_size); |  | 
|  161   EXPECT_EQ(memcmp(source_buffer(), decode_buffer, source_len()), 0); |  | 
|  162 } |  | 
|  163  |  | 
|  164 // Tests we can call filter repeatedly to get all the data decoded. |  | 
|  165 // To do that, we create a filter with a small buffer that can not hold all |  | 
|  166 // the input data. |  | 
|  167 TEST_F(BrotliUnitTest, DecodeWithSmallBuffer) { |  | 
|  168   InitFilterWithBufferSize(kSmallBufferSize); |  | 
|  169   EXPECT_EQ(kSmallBufferSize, filter_->stream_buffer_size()); |  | 
|  170   DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), |  | 
|  171                              encoded_buffer(), encoded_len(), |  | 
|  172                              kDefaultBufferSize); |  | 
|  173 } |  | 
|  174  |  | 
|  175 // Tests we can still decode with just 1 byte buffer in the filter. |  | 
|  176 // The purpose of this test: sometimes the filter will consume input without |  | 
|  177 // generating output. Verify filter can handle it correctly. |  | 
|  178 TEST_F(BrotliUnitTest, DecodeWithOneByteBuffer) { |  | 
|  179   InitFilterWithBufferSize(1); |  | 
|  180   EXPECT_EQ(1, filter_->stream_buffer_size()); |  | 
|  181   DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), |  | 
|  182                              encoded_buffer(), encoded_len(), |  | 
|  183                              kDefaultBufferSize); |  | 
|  184 } |  | 
|  185  |  | 
|  186 // Tests we can decode when caller has small buffer to read out from filter. |  | 
|  187 TEST_F(BrotliUnitTest, DecodeWithSmallOutputBuffer) { |  | 
|  188   InitFilter(); |  | 
|  189   DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), |  | 
|  190                              encoded_buffer(), encoded_len(), kSmallBufferSize); |  | 
|  191 } |  | 
|  192  |  | 
|  193 // Tests we can decode when caller has small buffer and input is also broken |  | 
|  194 // into small parts. This may uncover some corner cases that doesn't happen with |  | 
|  195 // one-byte buffers. |  | 
|  196 TEST_F(BrotliUnitTest, DecodeWithSmallInputAndOutputBuffer) { |  | 
|  197   InitFilterWithBufferSize(kSmallBufferSize); |  | 
|  198   DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), |  | 
|  199                              encoded_buffer(), encoded_len(), kSmallBufferSize); |  | 
|  200 } |  | 
|  201  |  | 
|  202 // Tests we can still decode with just 1 byte buffer in the filter and just 1 |  | 
|  203 // byte buffer in the caller. |  | 
|  204 TEST_F(BrotliUnitTest, DecodeWithOneByteInputAndOutputBuffer) { |  | 
|  205   InitFilterWithBufferSize(1); |  | 
|  206   EXPECT_EQ(1, filter_->stream_buffer_size()); |  | 
|  207   DecodeAndCompareWithFilter(filter_.get(), source_buffer(), source_len(), |  | 
|  208                              encoded_buffer(), encoded_len(), 1); |  | 
|  209 } |  | 
|  210  |  | 
|  211 // Decoding deflate stream with corrupted data. |  | 
|  212 TEST_F(BrotliUnitTest, DecodeCorruptedData) { |  | 
|  213   char corrupt_data[kDefaultBufferSize]; |  | 
|  214   int corrupt_data_len = encoded_len(); |  | 
|  215   memcpy(corrupt_data, encoded_buffer(), encoded_len()); |  | 
|  216  |  | 
|  217   int pos = corrupt_data_len / 2; |  | 
|  218   corrupt_data[pos] = !corrupt_data[pos]; |  | 
|  219  |  | 
|  220   // Decode the corrupted data with filter |  | 
|  221   InitFilter(); |  | 
|  222   char corrupt_decode_buffer[kDefaultBufferSize]; |  | 
|  223   int corrupt_decode_size = kDefaultBufferSize; |  | 
|  224  |  | 
|  225   int code = DecodeAllWithFilter(filter_.get(), corrupt_data, corrupt_data_len, |  | 
|  226                                  corrupt_decode_buffer, &corrupt_decode_size); |  | 
|  227  |  | 
|  228   // Expect failures |  | 
|  229   EXPECT_EQ(Filter::FILTER_ERROR, code); |  | 
|  230 } |  | 
|  231  |  | 
|  232 // Decoding deflate stream with missing data. |  | 
|  233 TEST_F(BrotliUnitTest, DecodeMissingData) { |  | 
|  234   char corrupt_data[kDefaultBufferSize]; |  | 
|  235   int corrupt_data_len = encoded_len(); |  | 
|  236   memcpy(corrupt_data, encoded_buffer(), encoded_len()); |  | 
|  237  |  | 
|  238   int pos = corrupt_data_len / 2; |  | 
|  239   int len = corrupt_data_len - pos - 1; |  | 
|  240   memmove(&corrupt_data[pos], &corrupt_data[pos + 1], len); |  | 
|  241   --corrupt_data_len; |  | 
|  242  |  | 
|  243   // Decode the corrupted data with filter |  | 
|  244   InitFilter(); |  | 
|  245   char corrupt_decode_buffer[kDefaultBufferSize]; |  | 
|  246   int corrupt_decode_size = kDefaultBufferSize; |  | 
|  247  |  | 
|  248   int code = DecodeAllWithFilter(filter_.get(), corrupt_data, corrupt_data_len, |  | 
|  249                                  corrupt_decode_buffer, &corrupt_decode_size); |  | 
|  250  |  | 
|  251   // Expect failures |  | 
|  252   EXPECT_EQ(Filter::FILTER_ERROR, code); |  | 
|  253 } |  | 
|  254  |  | 
|  255 // Decoding brotli stream with empty output data. |  | 
|  256 TEST_F(BrotliUnitTest, DecodeEmptyData) { |  | 
|  257   char data[1] = {6};  // WBITS = 16, ISLAST = 1, ISLASTEMPTY = 1 |  | 
|  258   int data_len = 1; |  | 
|  259  |  | 
|  260   InitFilter(); |  | 
|  261   char decode_buffer[kDefaultBufferSize]; |  | 
|  262   int decode_size = kDefaultBufferSize; |  | 
|  263   int code = DecodeAllWithFilter(filter_.get(), data, data_len, decode_buffer, |  | 
|  264                                  &decode_size); |  | 
|  265  |  | 
|  266   // Expect success / empty output. |  | 
|  267   EXPECT_EQ(Filter::FILTER_DONE, code); |  | 
|  268   EXPECT_EQ(0, decode_size); |  | 
|  269 } |  | 
|  270  |  | 
|  271 }  // namespace net |  | 
| OLD | NEW |