123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- // Copyright 2016 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include <string>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback.h"
- #include "base/files/file_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/path_service.h"
- #include "base/run_loop.h"
- #include "net/base/io_buffer.h"
- #include "net/base/test_completion_callback.h"
- #include "net/filter/brotli_source_stream.h"
- #include "net/filter/mock_source_stream.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/platform_test.h"
- namespace net {
- namespace {
- const size_t kDefaultBufferSize = 4096;
- const size_t kSmallBufferSize = 128;
- } // namespace
- class BrotliSourceStreamTest : public PlatformTest {
- protected:
- void SetUp() override {
- PlatformTest::SetUp();
- // Get the path of data directory.
- base::FilePath data_dir;
- base::PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
- data_dir = data_dir.AppendASCII("net");
- data_dir = data_dir.AppendASCII("data");
- data_dir = data_dir.AppendASCII("filter_unittests");
- // Read data from the original file into buffer.
- base::FilePath file_path;
- file_path = data_dir.AppendASCII("google.txt");
- ASSERT_TRUE(base::ReadFileToString(file_path, &source_data_));
- ASSERT_GE(kDefaultBufferSize, source_data_.size());
- // Read data from the encoded file into buffer.
- base::FilePath encoded_file_path;
- encoded_file_path = data_dir.AppendASCII("google.br");
- ASSERT_TRUE(base::ReadFileToString(encoded_file_path, &encoded_buffer_));
- ASSERT_GE(kDefaultBufferSize, encoded_buffer_.size());
- auto source = std::make_unique<MockSourceStream>();
- source_ = source.get();
- brotli_stream_ = CreateBrotliSourceStream(std::move(source));
- }
- int ReadStream(net::CompletionOnceCallback callback) {
- return brotli_stream_->Read(out_buffer(), out_data_size(),
- std::move(callback));
- }
- IOBuffer* out_buffer() { return out_buffer_.get(); }
- char* out_data() { return out_buffer_->data(); }
- size_t out_data_size() { return out_buffer_->size(); }
- std::string source_data() { return source_data_; }
- size_t source_data_len() { return source_data_.length(); }
- char* encoded_buffer() { return &encoded_buffer_[0]; }
- size_t encoded_len() { return encoded_buffer_.length(); }
- MockSourceStream* source() { return source_; }
- SourceStream* brotli_stream() { return brotli_stream_.get(); }
- scoped_refptr<IOBufferWithSize> out_buffer_;
- private:
- raw_ptr<MockSourceStream> source_;
- std::unique_ptr<SourceStream> brotli_stream_;
- std::unique_ptr<base::RunLoop> loop_;
- std::string source_data_;
- std::string encoded_buffer_;
- };
- // Basic scenario: decoding brotli data with big enough buffer.
- TEST_F(BrotliSourceStreamTest, DecodeBrotliOneBlockSync) {
- source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
- MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- TestCompletionCallback callback;
- int bytes_read = ReadStream(callback.callback());
- EXPECT_EQ(static_cast<int>(source_data_len()), bytes_read);
- EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Regression test for crbug.com/659311. The following example is taken out
- // of the bug report. For this specific example, Brotli will consume the first
- // byte in the 6 available bytes and return 0.
- TEST_F(BrotliSourceStreamTest, IgnoreExtraData) {
- const unsigned char kResponse[] = {0x1A, 0xDF, 0x6E, 0x74, 0x74, 0x68};
- source()->AddReadResult(reinterpret_cast<const char*>(kResponse),
- sizeof(kResponse), OK, MockSourceStream::SYNC);
- // Add an EOF.
- source()->AddReadResult(reinterpret_cast<const char*>(kResponse), 0, OK,
- MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- std::string actual_output;
- TestCompletionCallback callback;
- int bytes_read = ReadStream(callback.callback());
- EXPECT_EQ(0, bytes_read);
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // If there are data after decoding is done, ignore the data. crbug.com/659311.
- TEST_F(BrotliSourceStreamTest, IgnoreExtraDataInOneRead) {
- std::string response_with_extra_data(encoded_buffer(), encoded_len());
- response_with_extra_data.append(1000, 'x');
- source()->AddReadResult(response_with_extra_data.c_str(),
- response_with_extra_data.length(), OK,
- MockSourceStream::SYNC);
- // Add an EOF.
- source()->AddReadResult(response_with_extra_data.c_str(), 0, OK,
- MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- std::string actual_output;
- while (true) {
- TestCompletionCallback callback;
- int bytes_read = ReadStream(callback.callback());
- if (bytes_read == OK)
- break;
- ASSERT_GT(bytes_read, OK);
- actual_output.append(out_data(), bytes_read);
- }
- EXPECT_EQ(source_data_len(), actual_output.size());
- EXPECT_EQ(source_data(), actual_output);
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Same as above but extra data is in a different read.
- TEST_F(BrotliSourceStreamTest, IgnoreExtraDataInDifferentRead) {
- std::string extra_data;
- extra_data.append(1000, 'x');
- source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
- MockSourceStream::SYNC);
- source()->AddReadResult(extra_data.c_str(), extra_data.length(), OK,
- MockSourceStream::SYNC);
- // Add an EOF.
- source()->AddReadResult(extra_data.c_str(), 0, OK, MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- std::string actual_output;
- while (true) {
- TestCompletionCallback callback;
- int bytes_read = ReadStream(callback.callback());
- if (bytes_read == OK)
- break;
- ASSERT_GT(bytes_read, OK);
- actual_output.append(out_data(), bytes_read);
- }
- EXPECT_EQ(source_data_len(), actual_output.size());
- EXPECT_EQ(source_data(), actual_output);
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Basic scenario: decoding brotli data with big enough buffer.
- TEST_F(BrotliSourceStreamTest, DecodeBrotliTwoBlockSync) {
- source()->AddReadResult(encoded_buffer(), 10, OK, MockSourceStream::SYNC);
- source()->AddReadResult(encoded_buffer() + 10, encoded_len() - 10, OK,
- MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- TestCompletionCallback callback;
- int bytes_read = ReadStream(callback.callback());
- EXPECT_EQ(static_cast<int>(source_data_len()), bytes_read);
- EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Basic scenario: decoding brotli data with big enough buffer.
- TEST_F(BrotliSourceStreamTest, DecodeBrotliOneBlockAsync) {
- source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
- MockSourceStream::ASYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- TestCompletionCallback callback;
- int bytes_read = ReadStream(callback.callback());
- EXPECT_EQ(ERR_IO_PENDING, bytes_read);
- source()->CompleteNextRead();
- int rv = callback.WaitForResult();
- EXPECT_EQ(static_cast<int>(source_data_len()), rv);
- EXPECT_EQ(0, memcmp(out_data(), source_data().c_str(), source_data_len()));
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Tests we can call filter repeatedly to get all the data decoded.
- // To do that, we create a filter with a small buffer that can not hold all
- // the input data.
- TEST_F(BrotliSourceStreamTest, DecodeWithSmallBufferSync) {
- source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
- MockSourceStream::SYNC);
- // Add a 0 byte read to signal EOF.
- source()->AddReadResult(encoded_buffer(), 0, OK, MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kSmallBufferSize);
- scoped_refptr<IOBuffer> buffer =
- base::MakeRefCounted<IOBufferWithSize>(source_data_len());
- size_t total_bytes_read = 0;
- int bytes_read = 0;
- do {
- TestCompletionCallback callback;
- bytes_read = ReadStream(callback.callback());
- EXPECT_LE(OK, bytes_read);
- EXPECT_GE(kSmallBufferSize, static_cast<size_t>(bytes_read));
- memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
- total_bytes_read += bytes_read;
- } while (bytes_read > 0);
- EXPECT_EQ(source_data_len(), total_bytes_read);
- EXPECT_EQ(0, memcmp(buffer->data(), source_data().c_str(), total_bytes_read));
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Tests we can call filter repeatedly to get all the data decoded.
- // To do that, we create a filter with a small buffer that can not hold all
- // the input data.
- TEST_F(BrotliSourceStreamTest, DecodeWithSmallBufferAsync) {
- source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
- MockSourceStream::ASYNC);
- // Add a 0 byte read to signal EOF.
- source()->AddReadResult(encoded_buffer(), 0, OK, MockSourceStream::ASYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kSmallBufferSize);
- scoped_refptr<IOBuffer> buffer =
- base::MakeRefCounted<IOBufferWithSize>(source_data_len());
- size_t total_bytes_read = 0;
- int bytes_read = 0;
- do {
- TestCompletionCallback callback;
- bytes_read = ReadStream(callback.callback());
- if (bytes_read == ERR_IO_PENDING) {
- source()->CompleteNextRead();
- bytes_read = callback.WaitForResult();
- }
- EXPECT_GE(static_cast<int>(kSmallBufferSize), bytes_read);
- memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
- total_bytes_read += bytes_read;
- } while (bytes_read > 0);
- EXPECT_EQ(source_data_len(), total_bytes_read);
- EXPECT_EQ(0, memcmp(buffer->data(), source_data().c_str(), total_bytes_read));
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Tests we can still decode with just 1 byte buffer in the filter.
- // The purpose of this test: sometimes the filter will consume input without
- // generating output. Verify filter can handle it correctly.
- TEST_F(BrotliSourceStreamTest, DecodeWithOneByteBuffer) {
- source()->AddReadResult(encoded_buffer(), encoded_len(), OK,
- MockSourceStream::SYNC);
- // Add a 0 byte read to signal EOF.
- source()->AddReadResult(encoded_buffer(), 0, OK, MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(1);
- scoped_refptr<IOBuffer> buffer =
- base::MakeRefCounted<IOBufferWithSize>(source_data_len());
- size_t total_bytes_read = 0;
- int bytes_read = 0;
- do {
- TestCompletionCallback callback;
- bytes_read = ReadStream(callback.callback());
- EXPECT_NE(ERR_IO_PENDING, bytes_read);
- EXPECT_GE(1, bytes_read);
- memcpy(buffer->data() + total_bytes_read, out_data(), bytes_read);
- total_bytes_read += bytes_read;
- } while (bytes_read > 0);
- EXPECT_EQ(source_data_len(), total_bytes_read);
- EXPECT_EQ(0,
- memcmp(buffer->data(), source_data().c_str(), source_data_len()));
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Decoding deflate stream with corrupted data.
- TEST_F(BrotliSourceStreamTest, DecodeCorruptedData) {
- char corrupt_data[kDefaultBufferSize];
- int corrupt_data_len = encoded_len();
- memcpy(corrupt_data, encoded_buffer(), encoded_len());
- int pos = corrupt_data_len / 2;
- corrupt_data[pos] = !corrupt_data[pos];
- source()->AddReadResult(corrupt_data, corrupt_data_len, OK,
- MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- int error = OK;
- do {
- TestCompletionCallback callback;
- error = ReadStream(callback.callback());
- EXPECT_NE(ERR_IO_PENDING, error);
- } while (error > 0);
- // Expect failures
- EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, error);
- // Calling Read again gives the same error.
- TestCompletionCallback callback;
- error = ReadStream(callback.callback());
- EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, error);
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Decoding deflate stream with missing data.
- TEST_F(BrotliSourceStreamTest, DecodeMissingData) {
- char corrupt_data[kDefaultBufferSize];
- int corrupt_data_len = encoded_len();
- memcpy(corrupt_data, encoded_buffer(), encoded_len());
- int pos = corrupt_data_len / 2;
- int len = corrupt_data_len - pos - 1;
- memmove(&corrupt_data[pos], &corrupt_data[pos + 1], len);
- --corrupt_data_len;
- // Decode the corrupted data with filter
- source()->AddReadResult(corrupt_data, corrupt_data_len, OK,
- MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- int error = OK;
- do {
- TestCompletionCallback callback;
- error = ReadStream(callback.callback());
- EXPECT_NE(ERR_IO_PENDING, error);
- } while (error > 0);
- // Expect failures
- EXPECT_EQ(ERR_CONTENT_DECODING_FAILED, error);
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- // Decoding brotli stream with empty output data.
- TEST_F(BrotliSourceStreamTest, DecodeEmptyData) {
- char data[1] = {6}; // WBITS = 16, ISLAST = 1, ISLASTEMPTY = 1
- int data_len = 1;
- source()->AddReadResult(data, data_len, OK, MockSourceStream::SYNC);
- source()->AddReadResult(data, 0, OK, MockSourceStream::SYNC);
- out_buffer_ = base::MakeRefCounted<IOBufferWithSize>(kDefaultBufferSize);
- TestCompletionCallback callback;
- int bytes_read = ReadStream(callback.callback());
- EXPECT_EQ(OK, bytes_read);
- EXPECT_EQ("BROTLI", brotli_stream()->Description());
- }
- } // namespace net
|