| Index: net/filter/sdch_filter_unittest.cc
|
| diff --git a/net/filter/sdch_filter_unittest.cc b/net/filter/sdch_filter_unittest.cc
|
| index 79b567369d2d7dafb4e34e10b5c81a9b706eb1c6..be9790d643d4600049dd7622fec98e5e794709e4 100644
|
| --- a/net/filter/sdch_filter_unittest.cc
|
| +++ b/net/filter/sdch_filter_unittest.cc
|
| @@ -10,6 +10,7 @@
|
|
|
| #include "base/logging.h"
|
| #include "base/memory/scoped_ptr.h"
|
| +#include "base/test/simple_test_clock.h"
|
| #include "net/base/io_buffer.h"
|
| #include "net/filter/mock_filter_context.h"
|
| #include "net/filter/sdch_filter.h"
|
| @@ -25,12 +26,12 @@ namespace net {
|
| // Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary.
|
| static const char kTestVcdiffDictionary[] = "DictionaryFor"
|
| "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
|
| -// Pre-compression test data. Note that we pad with a lot of highly gzip
|
| -// compressible content to help to exercise the chaining pipeline. That is why
|
| +// Pre-compression test data. Note that we pad with a lot of highly gzip
|
| +// compressible content to help to exercise the chaining pipeline. That is why
|
| // there are a PILE of zeros at the start and end.
|
| // This will ensure that gzip compressed data can be fed to the chain in one
|
| // gulp, but (with careful selection of intermediate buffers) that it takes
|
| -// several sdch buffers worth of data to satisfy the sdch filter. See detailed
|
| +// several sdch buffers worth of data to satisfy the sdch filter. See detailed
|
| // CHECK() calls in FilterChaining test for specifics.
|
| static const char kTestData[] = "0000000000000000000000000000000000000000000000"
|
| "0000000000000000000000000000TestData "
|
| @@ -63,8 +64,8 @@ class SdchFilterTest : public testing::Test {
|
| url_request_context->set_sdch_manager(sdch_manager_.get());
|
| }
|
|
|
| - // Attempt to add a dictionary to the manager; returns whether or not
|
| - // the attempt succeeded.
|
| + // Attempt to add a dictionary to the manager and probe for success or
|
| + // failure.
|
| bool AddSdchDictionary(const std::string& dictionary_text,
|
| const GURL& gurl) {
|
| return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
|
| @@ -72,6 +73,13 @@ class SdchFilterTest : public testing::Test {
|
|
|
| MockFilterContext* filter_context() { return filter_context_.get(); }
|
|
|
| + // Sets both the GURL and the SDCH response for a filter context.
|
| + void SetupFilterContextWithGURL(GURL url) {
|
| + filter_context_->SetURL(url);
|
| + filter_context_->SetSdchResponse(
|
| + sdch_manager_->GetDictionarySet(url).Pass());
|
| + }
|
| +
|
| std::string NewSdchCompressedData(const std::string dictionary) {
|
| std::string client_hash;
|
| std::string server_hash;
|
| @@ -108,11 +116,11 @@ TEST_F(SdchFilterTest, Hashing) {
|
| //------------------------------------------------------------------------------
|
| // Provide a generic helper function for trying to filter data.
|
| // This function repeatedly calls the filter to process data, until the entire
|
| -// source is consumed. The return value from the filter is appended to output.
|
| +// source is consumed. The return value from the filter is appended to output.
|
| // This allows us to vary input and output block sizes in order to test for edge
|
| // effects (boundary effects?) during the filtering process.
|
| // This function provides data to the filter in blocks of no-more-than the
|
| -// specified input_block_length. It allows the filter to fill no more than
|
| +// specified input_block_length. It allows the filter to fill no more than
|
| // output_buffer_length in any one call to proccess (a.k.a., Read) data, and
|
| // concatenates all these little output blocks into the singular output string.
|
| static bool FilterTestData(const std::string& source,
|
| @@ -159,6 +167,19 @@ static std::string NewSdchDictionary(const std::string& domain) {
|
| return dictionary;
|
| }
|
|
|
| +static std::string NewSdchExpiredDictionary(const std::string& domain) {
|
| + std::string dictionary;
|
| + if (!domain.empty()) {
|
| + dictionary.append("Domain: ");
|
| + dictionary.append(domain);
|
| + dictionary.append("\n");
|
| + }
|
| + dictionary.append("Max-Age: 0\n");
|
| + dictionary.append("\n");
|
| + dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
|
| + return dictionary;
|
| +}
|
| +
|
| //------------------------------------------------------------------------------
|
|
|
| TEST_F(SdchFilterTest, EmptyInputOk) {
|
| @@ -197,10 +218,10 @@ TEST_F(SdchFilterTest, SparseContextOk) {
|
| EXPECT_EQ(0, output_bytes_or_buffer_size);
|
| EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
|
|
|
| - // Partially tear down context. Anything that goes through request()
|
| + // Partially tear down context. Anything that goes through request()
|
| // without checking it for null in the URLRequestJob::HttpFilterContext
|
| - // implementation is suspect. Everything that does check it for null should
|
| - // return null. This is to test for incorrectly relying on filter_context()
|
| + // implementation is suspect. Everything that does check it for null should
|
| + // return null. This is to test for incorrectly relying on filter_context()
|
| // from the SdchFilter destructor.
|
| filter_context()->NukeUnstableInterfaces();
|
| }
|
| @@ -451,7 +472,7 @@ TEST_F(SdchFilterTest, BasicDictionary) {
|
| std::vector<Filter::FilterType> filter_types;
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| - filter_context()->SetURL(url);
|
| + SetupFilterContextWithGURL(url);
|
|
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| @@ -488,7 +509,8 @@ TEST_F(SdchFilterTest, NoDecodeHttps) {
|
| std::vector<Filter::FilterType> filter_types;
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| - filter_context()->SetURL(GURL("https://" + kSampleDomain));
|
| + GURL filter_context_gurl("https://" + kSampleDomain);
|
| + SetupFilterContextWithGURL(GURL("https://" + kSampleDomain));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| const size_t feed_block_size(100);
|
| @@ -501,7 +523,7 @@ TEST_F(SdchFilterTest, NoDecodeHttps) {
|
|
|
| // Current failsafe TODO/hack refuses to decode any content that doesn't use
|
| // http as the scheme (see use of DICTIONARY_SELECTED_FOR_NON_HTTP).
|
| -// The following tests this blockage. Note that blacklisting results, so we
|
| +// The following tests this blockage. Note that blacklisting results, so we
|
| // we need separate tests for each of these.
|
| TEST_F(SdchFilterTest, NoDecodeFtp) {
|
| // Construct a valid SDCH dictionary from a VCDIFF dictionary.
|
| @@ -518,7 +540,7 @@ TEST_F(SdchFilterTest, NoDecodeFtp) {
|
| std::vector<Filter::FilterType> filter_types;
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| - filter_context()->SetURL(GURL("ftp://" + kSampleDomain));
|
| + SetupFilterContextWithGURL(GURL("ftp://" + kSampleDomain));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| const size_t feed_block_size(100);
|
| @@ -544,7 +566,7 @@ TEST_F(SdchFilterTest, NoDecodeFileColon) {
|
| std::vector<Filter::FilterType> filter_types;
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| - filter_context()->SetURL(GURL("file://" + kSampleDomain));
|
| + SetupFilterContextWithGURL(GURL("file://" + kSampleDomain));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| const size_t feed_block_size(100);
|
| @@ -570,7 +592,7 @@ TEST_F(SdchFilterTest, NoDecodeAboutColon) {
|
| std::vector<Filter::FilterType> filter_types;
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| - filter_context()->SetURL(GURL("about://" + kSampleDomain));
|
| + SetupFilterContextWithGURL(GURL("about://" + kSampleDomain));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| const size_t feed_block_size(100);
|
| @@ -596,7 +618,7 @@ TEST_F(SdchFilterTest, NoDecodeJavaScript) {
|
| std::vector<Filter::FilterType> filter_types;
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| - filter_context()->SetURL(GURL("javascript://" + kSampleDomain));
|
| + SetupFilterContextWithGURL(GURL("javascript://" + kSampleDomain));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| const size_t feed_block_size(100);
|
| @@ -622,7 +644,7 @@ TEST_F(SdchFilterTest, CanStillDecodeHttp) {
|
| std::vector<Filter::FilterType> filter_types;
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| - filter_context()->SetURL(GURL("http://" + kSampleDomain));
|
| + SetupFilterContextWithGURL(GURL("http://" + kSampleDomain));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| const size_t feed_block_size(100);
|
| @@ -651,7 +673,7 @@ TEST_F(SdchFilterTest, CrossDomainDictionaryUse) {
|
| // Decode with content arriving from the "wrong" domain.
|
| // This tests SdchManager::CanSet().
|
| GURL wrong_domain_url("http://www.wrongdomain.com");
|
| - filter_context()->SetURL(wrong_domain_url);
|
| + SetupFilterContextWithGURL(wrong_domain_url);
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| size_t feed_block_size = 100;
|
| @@ -696,7 +718,7 @@ TEST_F(SdchFilterTest, DictionaryPathValidation) {
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| // Test decode the path data, arriving from a valid path.
|
| - filter_context()->SetURL(GURL(url_string + path));
|
| + SetupFilterContextWithGURL(GURL(url_string + path));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| size_t feed_block_size = 100;
|
| @@ -708,7 +730,7 @@ TEST_F(SdchFilterTest, DictionaryPathValidation) {
|
| EXPECT_EQ(output, expanded_);
|
|
|
| // Test decode the path data, arriving from a invalid path.
|
| - filter_context()->SetURL(GURL(url_string));
|
| + SetupFilterContextWithGURL(GURL(url_string));
|
| filter.reset(Filter::Factory(filter_types, *filter_context()));
|
|
|
| feed_block_size = 100;
|
| @@ -753,7 +775,7 @@ TEST_F(SdchFilterTest, DictionaryPortValidation) {
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| // Test decode the port data, arriving from a valid port.
|
| - filter_context()->SetURL(GURL(url_string + ":" + port));
|
| + SetupFilterContextWithGURL(GURL(url_string + ":" + port));
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| size_t feed_block_size = 100;
|
| @@ -764,7 +786,7 @@ TEST_F(SdchFilterTest, DictionaryPortValidation) {
|
| EXPECT_EQ(output, expanded_);
|
|
|
| // Test decode the port data, arriving from a valid (default) port.
|
| - filter_context()->SetURL(GURL(url_string)); // Default port.
|
| + SetupFilterContextWithGURL(GURL(url_string)); // Default port.
|
| filter.reset(Filter::Factory(filter_types, *filter_context()));
|
|
|
| feed_block_size = 100;
|
| @@ -775,7 +797,7 @@ TEST_F(SdchFilterTest, DictionaryPortValidation) {
|
| EXPECT_EQ(output, expanded_);
|
|
|
| // Test decode the port data, arriving from a invalid port.
|
| - filter_context()->SetURL(GURL(url_string + ":" + port + "1"));
|
| + SetupFilterContextWithGURL(GURL(url_string + ":" + port + "1"));
|
| filter.reset(Filter::Factory(filter_types, *filter_context()));
|
|
|
| feed_block_size = 100;
|
| @@ -856,8 +878,8 @@ class SdchFilterChainingTest {
|
| };
|
|
|
| // Test that filters can be cascaded (chained) so that the output of one filter
|
| -// is processed by the next one. This is most critical for SDCH, which is
|
| -// routinely followed by gzip (during encoding). The filter we'll test for will
|
| +// is processed by the next one. This is most critical for SDCH, which is
|
| +// routinely followed by gzip (during encoding). The filter we'll test for will
|
| // do the gzip decoding first, and then decode the SDCH content.
|
| TEST_F(SdchFilterTest, FilterChaining) {
|
| // Construct a valid SDCH dictionary from a VCDIFF dictionary.
|
| @@ -884,7 +906,7 @@ TEST_F(SdchFilterTest, FilterChaining) {
|
| CHECK_GT(kLargeInputBufferSize, gzip_compressed_sdch.size());
|
| CHECK_GT(kLargeInputBufferSize, sdch_compressed.size());
|
| CHECK_GT(kLargeInputBufferSize, expanded_.size());
|
| - filter_context()->SetURL(url);
|
| + SetupFilterContextWithGURL(url);
|
| scoped_ptr<Filter> filter(
|
| SdchFilterChainingTest::Factory(filter_types, *filter_context(),
|
| kLargeInputBufferSize));
|
| @@ -962,16 +984,15 @@ TEST_F(SdchFilterTest, DefaultGzipIfSdch) {
|
| filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
|
|
| filter_context()->SetMimeType("anything/mime");
|
| - filter_context()->SetSdchResponse(true);
|
| + SetupFilterContextWithGURL(url);
|
| +
|
| Filter::FixupEncodingTypes(*filter_context(), &filter_types);
|
| ASSERT_EQ(filter_types.size(), 2u);
|
| EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH);
|
| EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
|
|
|
| // First try with a large buffer (larger than test input, or compressed data).
|
| - filter_context()->SetURL(url);
|
| - scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
| -
|
| + scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| // Verify that chained filter is waiting for data.
|
| char tiny_output_buffer[10];
|
| @@ -1020,7 +1041,7 @@ TEST_F(SdchFilterTest, AcceptGzipSdchIfGzip) {
|
| filter_types.push_back(Filter::FILTER_TYPE_GZIP);
|
|
|
| filter_context()->SetMimeType("anything/mime");
|
| - filter_context()->SetSdchResponse(true);
|
| + SetupFilterContextWithGURL(url);
|
| Filter::FixupEncodingTypes(*filter_context(), &filter_types);
|
| ASSERT_EQ(filter_types.size(), 3u);
|
| EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
|
| @@ -1028,10 +1049,8 @@ TEST_F(SdchFilterTest, AcceptGzipSdchIfGzip) {
|
| EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
|
|
|
| // First try with a large buffer (larger than test input, or compressed data).
|
| - filter_context()->SetURL(url);
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| -
|
| // Verify that chained filter is waiting for data.
|
| char tiny_output_buffer[10];
|
| int tiny_output_size = sizeof(tiny_output_buffer);
|
| @@ -1077,17 +1096,15 @@ TEST_F(SdchFilterTest, DefaultSdchGzipIfEmpty) {
|
| std::vector<Filter::FilterType> filter_types;
|
|
|
| filter_context()->SetMimeType("anything/mime");
|
| - filter_context()->SetSdchResponse(true);
|
| + SetupFilterContextWithGURL(url);
|
| Filter::FixupEncodingTypes(*filter_context(), &filter_types);
|
| ASSERT_EQ(filter_types.size(), 2u);
|
| EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
|
| EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
|
|
|
| // First try with a large buffer (larger than test input, or compressed data).
|
| - filter_context()->SetURL(url);
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| -
|
| // Verify that chained filter is waiting for data.
|
| char tiny_output_buffer[10];
|
| int tiny_output_size = sizeof(tiny_output_buffer);
|
| @@ -1138,7 +1155,7 @@ TEST_F(SdchFilterTest, AcceptGzipGzipSdchIfGzip) {
|
| filter_types.push_back(Filter::FILTER_TYPE_GZIP);
|
|
|
| filter_context()->SetMimeType("anything/mime");
|
| - filter_context()->SetSdchResponse(true);
|
| + SetupFilterContextWithGURL(url);
|
| Filter::FixupEncodingTypes(*filter_context(), &filter_types);
|
| ASSERT_EQ(filter_types.size(), 3u);
|
| EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
|
| @@ -1146,7 +1163,6 @@ TEST_F(SdchFilterTest, AcceptGzipGzipSdchIfGzip) {
|
| EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
|
|
|
| // First try with a large buffer (larger than test input, or compressed data).
|
| - filter_context()->SetURL(url);
|
| scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
|
|
| // Verify that chained filter is waiting for data.
|
| @@ -1173,4 +1189,58 @@ TEST_F(SdchFilterTest, AcceptGzipGzipSdchIfGzip) {
|
| EXPECT_EQ(output, expanded_);
|
| }
|
|
|
| +// Test to make sure we decode properly with an unexpected dictionary.
|
| +TEST_F(SdchFilterTest, UnexpectedDictionary) {
|
| + // Setup a dictionary, add it to the filter context, and create a filter
|
| + // based on that dictionary.
|
| + const std::string kSampleDomain = "sdchtest.com";
|
| + std::string dictionary(NewSdchDictionary(kSampleDomain));
|
| + std::string url_string = "http://" + kSampleDomain;
|
| + GURL url(url_string);
|
| + EXPECT_TRUE(AddSdchDictionary(dictionary, url));
|
| +
|
| + SetupFilterContextWithGURL(url);
|
| +
|
| + std::vector<Filter::FilterType> filter_types;
|
| + filter_types.push_back(Filter::FILTER_TYPE_SDCH);
|
| + scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
|
| +
|
| + // Setup another dictionary, expired. Don't add it to the filter context.
|
| + // Delete stored dictionaries first to handle platforms which only
|
| + // have room for a single dictionary.
|
| + sdch_manager_->ClearData();
|
| + std::string expired_dictionary(NewSdchExpiredDictionary(kSampleDomain));
|
| +
|
| + // Don't use the Helper function since its insertion check is indeterminate
|
| + // for a Max-Age: 0 dictionary.
|
| + sdch_manager_->AddSdchDictionary(expired_dictionary, url);
|
| +
|
| + std::string client_hash;
|
| + std::string server_hash;
|
| + SdchManager::GenerateHash(expired_dictionary, &client_hash, &server_hash);
|
| +
|
| + // Make sure Max-Age: 0 shows up as expired.
|
| + scoped_ptr<base::SimpleTestClock> clock(new base::SimpleTestClock);
|
| + clock->SetNow(base::Time::Now());
|
| + clock->Advance(base::TimeDelta::FromMinutes(5));
|
| + SdchProblemCode problem_code;
|
| + scoped_ptr<SdchManager::DictionarySet> hash_set(
|
| + sdch_manager_->GetDictionarySetByHash(
|
| + url, server_hash, &problem_code).Pass());
|
| + ASSERT_TRUE(hash_set);
|
| + ASSERT_EQ(SDCH_OK, problem_code);
|
| +
|
| + const_cast<SdchManager::Dictionary*>(
|
| + hash_set->GetDictionary(server_hash))->SetClockForTesting(
|
| + clock.Pass());
|
| +
|
| + // Encode output with the second dictionary.
|
| + std::string sdch_compressed(NewSdchCompressedData(expired_dictionary));
|
| +
|
| + // See if the filter decodes it.
|
| + std::string output;
|
| + EXPECT_TRUE(FilterTestData(sdch_compressed, 100, 100, filter.get(), &output));
|
| + EXPECT_EQ(expanded_, output);
|
| +}
|
| +
|
| } // namespace net
|
|
|