Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / filter / sdch_filter_unittest.cc
blob88a9c392bd81a69ec8ddde883c8691e34362bd99
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.
5 #include <limits.h>
7 #include <algorithm>
8 #include <string>
9 #include <vector>
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "net/base/io_buffer.h"
14 #include "net/filter/mock_filter_context.h"
15 #include "net/filter/sdch_filter.h"
16 #include "net/url_request/url_request_context.h"
17 #include "net/url_request/url_request_http_job.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/zlib/zlib.h"
21 namespace net {
23 //------------------------------------------------------------------------------
24 // Provide sample data and compression results with a sample VCDIFF dictionary.
25 // Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary.
26 static const char kTestVcdiffDictionary[] = "DictionaryFor"
27 "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
28 // Pre-compression test data. Note that we pad with a lot of highly gzip
29 // compressible content to help to exercise the chaining pipeline. That is why
30 // there are a PILE of zeros at the start and end.
31 // This will ensure that gzip compressed data can be fed to the chain in one
32 // gulp, but (with careful selection of intermediate buffers) that it takes
33 // several sdch buffers worth of data to satisfy the sdch filter. See detailed
34 // CHECK() calls in FilterChaining test for specifics.
35 static const char kTestData[] = "0000000000000000000000000000000000000000000000"
36 "0000000000000000000000000000TestData "
37 "SdchCompression1SdchCompression2SdchCompression3SdchCompression"
38 "00000000000000000000000000000000000000000000000000000000000000000000000000"
39 "000000000000000000000000000000000000000\n";
41 // Note SDCH compressed data will include a reference to the SDCH dictionary.
42 static const char kSdchCompressedTestData[] =
43 "\326\303\304\0\0\001M\0\201S\202\004\0\201E\006\001"
44 "00000000000000000000000000000000000000000000000000000000000000000000000000"
45 "TestData 00000000000000000000000000000000000000000000000000000000000000000"
46 "000000000000000000000000000000000000000000000000\n\001S\023\077\001r\r";
48 //------------------------------------------------------------------------------
50 class SdchFilterTest : public testing::Test {
51 protected:
52 SdchFilterTest()
53 : test_vcdiff_dictionary_(kTestVcdiffDictionary,
54 sizeof(kTestVcdiffDictionary) - 1),
55 vcdiff_compressed_data_(kSdchCompressedTestData,
56 sizeof(kSdchCompressedTestData) - 1),
57 expanded_(kTestData, sizeof(kTestData) - 1),
58 sdch_manager_(new SdchManager),
59 filter_context_(new MockFilterContext) {
60 URLRequestContext* url_request_context =
61 filter_context_->GetModifiableURLRequestContext();
63 url_request_context->set_sdch_manager(sdch_manager_.get());
66 MockFilterContext* filter_context() { return filter_context_.get(); }
68 std::string NewSdchCompressedData(const std::string dictionary);
70 const std::string test_vcdiff_dictionary_;
71 const std::string vcdiff_compressed_data_;
72 const std::string expanded_; // Desired final, decompressed data.
74 scoped_ptr<SdchManager> sdch_manager_;
75 scoped_ptr<MockFilterContext> filter_context_;
78 std::string SdchFilterTest::NewSdchCompressedData(
79 const std::string dictionary) {
80 std::string client_hash;
81 std::string server_hash;
82 SdchManager::GenerateHash(dictionary, &client_hash, &server_hash);
84 // Build compressed data that refers to our dictionary.
85 std::string compressed(server_hash);
86 compressed.append("\0", 1);
87 compressed.append(vcdiff_compressed_data_);
88 return compressed;
91 //------------------------------------------------------------------------------
94 TEST_F(SdchFilterTest, Hashing) {
95 std::string client_hash, server_hash;
96 std::string dictionary("test contents");
97 SdchManager::GenerateHash(dictionary, &client_hash, &server_hash);
99 EXPECT_EQ(client_hash, "lMQBjS3P");
100 EXPECT_EQ(server_hash, "MyciMVll");
104 //------------------------------------------------------------------------------
105 // Provide a generic helper function for trying to filter data.
106 // This function repeatedly calls the filter to process data, until the entire
107 // source is consumed. The return value from the filter is appended to output.
108 // This allows us to vary input and output block sizes in order to test for edge
109 // effects (boundary effects?) during the filtering process.
110 // This function provides data to the filter in blocks of no-more-than the
111 // specified input_block_length. It allows the filter to fill no more than
112 // output_buffer_length in any one call to proccess (a.k.a., Read) data, and
113 // concatenates all these little output blocks into the singular output string.
114 static bool FilterTestData(const std::string& source,
115 size_t input_block_length,
116 const size_t output_buffer_length,
117 Filter* filter, std::string* output) {
118 CHECK_GT(input_block_length, 0u);
119 Filter::FilterStatus status(Filter::FILTER_NEED_MORE_DATA);
120 size_t source_index = 0;
121 scoped_ptr<char[]> output_buffer(new char[output_buffer_length]);
122 size_t input_amount = std::min(input_block_length,
123 static_cast<size_t>(filter->stream_buffer_size()));
125 do {
126 int copy_amount = std::min(input_amount, source.size() - source_index);
127 if (copy_amount > 0 && status == Filter::FILTER_NEED_MORE_DATA) {
128 memcpy(filter->stream_buffer()->data(), source.data() + source_index,
129 copy_amount);
130 filter->FlushStreamBuffer(copy_amount);
131 source_index += copy_amount;
133 int buffer_length = output_buffer_length;
134 status = filter->ReadData(output_buffer.get(), &buffer_length);
135 output->append(output_buffer.get(), buffer_length);
136 if (status == Filter::FILTER_ERROR)
137 return false;
138 // Callers assume that FILTER_OK with no output buffer means FILTER_DONE.
139 if (Filter::FILTER_OK == status && 0 == buffer_length)
140 return true;
141 if (copy_amount == 0 && buffer_length == 0)
142 return true;
143 } while (1);
145 //------------------------------------------------------------------------------
146 static std::string NewSdchDictionary(const std::string& domain) {
147 std::string dictionary;
148 if (!domain.empty()) {
149 dictionary.append("Domain: ");
150 dictionary.append(domain);
151 dictionary.append("\n");
153 dictionary.append("\n");
154 dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
155 return dictionary;
158 //------------------------------------------------------------------------------
160 TEST_F(SdchFilterTest, EmptyInputOk) {
161 std::vector<Filter::FilterType> filter_types;
162 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
163 char output_buffer[20];
164 std::string url_string("http://ignore.com");
165 filter_context()->SetURL(GURL(url_string));
166 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
168 // With no input data, try to read output.
169 int output_bytes_or_buffer_size = sizeof(output_buffer);
170 Filter::FilterStatus status = filter->ReadData(output_buffer,
171 &output_bytes_or_buffer_size);
173 EXPECT_EQ(0, output_bytes_or_buffer_size);
174 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
177 // Make sure that the filter context has everything that might be
178 // nuked from it during URLRequest teardown before the SdchFilter
179 // destructor.
180 TEST_F(SdchFilterTest, SparseContextOk) {
181 std::vector<Filter::FilterType> filter_types;
182 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
183 char output_buffer[20];
184 std::string url_string("http://ignore.com");
185 filter_context()->SetURL(GURL(url_string));
186 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
188 // With no input data, try to read output.
189 int output_bytes_or_buffer_size = sizeof(output_buffer);
190 Filter::FilterStatus status = filter->ReadData(output_buffer,
191 &output_bytes_or_buffer_size);
193 EXPECT_EQ(0, output_bytes_or_buffer_size);
194 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
196 // Partially tear down context. Anything that goes through request()
197 // without checking it for null in the URLRequestJob::HttpFilterContext
198 // implementation is suspect. Everything that does check it for null should
199 // return null. This is to test for incorrectly relying on filter_context()
200 // from the SdchFilter destructor.
201 filter_context()->NukeUnstableInterfaces();
204 TEST_F(SdchFilterTest, PassThroughWhenTentative) {
205 std::vector<Filter::FilterType> filter_types;
206 // Selective a tentative filter (which can fall back to pass through).
207 filter_types.push_back(Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
208 char output_buffer[20];
209 // Response code needs to be 200 to allow a pass through.
210 filter_context()->SetResponseCode(200);
211 std::string url_string("http://ignore.com");
212 filter_context()->SetURL(GURL(url_string));
213 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
215 // Supply enough data to force a pass-through mode..
216 std::string non_gzip_content("not GZIPed data");
218 char* input_buffer = filter->stream_buffer()->data();
219 int input_buffer_size = filter->stream_buffer_size();
221 EXPECT_LT(static_cast<int>(non_gzip_content.size()),
222 input_buffer_size);
223 memcpy(input_buffer, non_gzip_content.data(),
224 non_gzip_content.size());
225 filter->FlushStreamBuffer(non_gzip_content.size());
227 // Try to read output.
228 int output_bytes_or_buffer_size = sizeof(output_buffer);
229 Filter::FilterStatus status = filter->ReadData(output_buffer,
230 &output_bytes_or_buffer_size);
232 EXPECT_EQ(non_gzip_content.size(),
233 static_cast<size_t>(output_bytes_or_buffer_size));
234 ASSERT_GT(sizeof(output_buffer),
235 static_cast<size_t>(output_bytes_or_buffer_size));
236 output_buffer[output_bytes_or_buffer_size] = '\0';
237 EXPECT_TRUE(non_gzip_content == output_buffer);
238 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
241 TEST_F(SdchFilterTest, RefreshBadReturnCode) {
242 std::vector<Filter::FilterType> filter_types;
243 // Selective a tentative filter (which can fall back to pass through).
244 filter_types.push_back(Filter::FILTER_TYPE_SDCH_POSSIBLE);
245 char output_buffer[20];
246 // Response code needs to be 200 to allow a pass through.
247 filter_context()->SetResponseCode(403);
248 // Meta refresh will only appear for html content
249 filter_context()->SetMimeType("text/html");
250 std::string url_string("http://ignore.com");
251 filter_context()->SetURL(GURL(url_string));
252 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
254 // Supply enough data to force a pass-through mode, which means we have
255 // provided more than 9 characters that can't be a dictionary hash.
256 std::string non_sdch_content("This is not SDCH");
258 char* input_buffer = filter->stream_buffer()->data();
259 int input_buffer_size = filter->stream_buffer_size();
261 EXPECT_LT(static_cast<int>(non_sdch_content.size()),
262 input_buffer_size);
263 memcpy(input_buffer, non_sdch_content.data(),
264 non_sdch_content.size());
265 filter->FlushStreamBuffer(non_sdch_content.size());
267 // Try to read output.
268 int output_bytes_or_buffer_size = sizeof(output_buffer);
269 Filter::FilterStatus status = filter->ReadData(output_buffer,
270 &output_bytes_or_buffer_size);
272 // We should have read a long and complicated meta-refresh request.
273 EXPECT_TRUE(sizeof(output_buffer) == output_bytes_or_buffer_size);
274 // Check at least the prefix of the return.
275 EXPECT_EQ(0, strncmp(output_buffer,
276 "<head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\"></head>",
277 sizeof(output_buffer)));
278 EXPECT_EQ(Filter::FILTER_OK, status);
281 TEST_F(SdchFilterTest, ErrorOnBadReturnCode) {
282 std::vector<Filter::FilterType> filter_types;
283 // Selective a tentative filter (which can fall back to pass through).
284 filter_types.push_back(Filter::FILTER_TYPE_SDCH_POSSIBLE);
285 char output_buffer[20];
286 // Response code needs to be 200 to allow a pass through.
287 filter_context()->SetResponseCode(403);
288 // Meta refresh will only appear for html content, so set to something else
289 // to induce an error (we can't meta refresh).
290 filter_context()->SetMimeType("anything");
291 std::string url_string("http://ignore.com");
292 filter_context()->SetURL(GURL(url_string));
293 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
295 // Supply enough data to force a pass-through mode, which means we have
296 // provided more than 9 characters that can't be a dictionary hash.
297 std::string non_sdch_content("This is not SDCH");
299 char* input_buffer = filter->stream_buffer()->data();
300 int input_buffer_size = filter->stream_buffer_size();
302 EXPECT_LT(static_cast<int>(non_sdch_content.size()),
303 input_buffer_size);
304 memcpy(input_buffer, non_sdch_content.data(),
305 non_sdch_content.size());
306 filter->FlushStreamBuffer(non_sdch_content.size());
308 // Try to read output.
309 int output_bytes_or_buffer_size = sizeof(output_buffer);
310 Filter::FilterStatus status = filter->ReadData(output_buffer,
311 &output_bytes_or_buffer_size);
313 EXPECT_EQ(0, output_bytes_or_buffer_size);
314 EXPECT_EQ(Filter::FILTER_ERROR, status);
317 TEST_F(SdchFilterTest, ErrorOnBadReturnCodeWithHtml) {
318 std::vector<Filter::FilterType> filter_types;
319 // Selective a tentative filter (which can fall back to pass through).
320 filter_types.push_back(Filter::FILTER_TYPE_SDCH_POSSIBLE);
321 char output_buffer[20];
322 // Response code needs to be 200 to allow a pass through.
323 filter_context()->SetResponseCode(403);
324 // Meta refresh will only appear for html content
325 filter_context()->SetMimeType("text/html");
326 std::string url_string("http://ignore.com");
327 filter_context()->SetURL(GURL(url_string));
328 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
330 // Supply enough data to force a pass-through mode, which means we have
331 // provided more than 9 characters that can't be a dictionary hash.
332 std::string non_sdch_content("This is not SDCH");
334 char* input_buffer = filter->stream_buffer()->data();
335 int input_buffer_size = filter->stream_buffer_size();
337 EXPECT_LT(static_cast<int>(non_sdch_content.size()),
338 input_buffer_size);
339 memcpy(input_buffer, non_sdch_content.data(),
340 non_sdch_content.size());
341 filter->FlushStreamBuffer(non_sdch_content.size());
343 // Try to read output.
344 int output_bytes_or_buffer_size = sizeof(output_buffer);
345 Filter::FilterStatus status = filter->ReadData(output_buffer,
346 &output_bytes_or_buffer_size);
348 // We should have read a long and complicated meta-refresh request.
349 EXPECT_EQ(sizeof(output_buffer),
350 static_cast<size_t>(output_bytes_or_buffer_size));
351 // Check at least the prefix of the return.
352 EXPECT_EQ(0, strncmp(output_buffer,
353 "<head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\"></head>",
354 sizeof(output_buffer)));
355 EXPECT_EQ(Filter::FILTER_OK, status);
358 TEST_F(SdchFilterTest, BasicBadDictionary) {
359 std::vector<Filter::FilterType> filter_types;
360 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
361 char output_buffer[20];
362 std::string url_string("http://ignore.com");
363 filter_context()->SetURL(GURL(url_string));
364 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
366 // Supply bogus data (which doesn't yet specify a full dictionary hash).
367 // Dictionary hash is 8 characters followed by a null.
368 std::string dictionary_hash_prefix("123");
370 char* input_buffer = filter->stream_buffer()->data();
371 int input_buffer_size = filter->stream_buffer_size();
373 EXPECT_LT(static_cast<int>(dictionary_hash_prefix.size()),
374 input_buffer_size);
375 memcpy(input_buffer, dictionary_hash_prefix.data(),
376 dictionary_hash_prefix.size());
377 filter->FlushStreamBuffer(dictionary_hash_prefix.size());
379 // With less than a dictionary specifier, try to read output.
380 int output_bytes_or_buffer_size = sizeof(output_buffer);
381 Filter::FilterStatus status = filter->ReadData(output_buffer,
382 &output_bytes_or_buffer_size);
384 EXPECT_EQ(0, output_bytes_or_buffer_size);
385 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
387 // Provide enough data to complete *a* hash, but it is bogus, and not in our
388 // list of dictionaries, so the filter should error out immediately.
389 std::string dictionary_hash_postfix("4abcd\0", 6);
391 CHECK_LT(dictionary_hash_postfix.size(),
392 static_cast<size_t>(input_buffer_size));
393 memcpy(input_buffer, dictionary_hash_postfix.data(),
394 dictionary_hash_postfix.size());
395 filter->FlushStreamBuffer(dictionary_hash_postfix.size());
397 // With a non-existant dictionary specifier, try to read output.
398 output_bytes_or_buffer_size = sizeof(output_buffer);
399 status = filter->ReadData(output_buffer, &output_bytes_or_buffer_size);
401 EXPECT_EQ(0, output_bytes_or_buffer_size);
402 EXPECT_EQ(Filter::FILTER_ERROR, status);
404 EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
405 sdch_manager_->ClearBlacklistings();
406 EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
409 TEST_F(SdchFilterTest, DictionaryAddOnce) {
410 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
411 const std::string kSampleDomain = "sdchtest.com";
412 std::string dictionary(NewSdchDictionary(kSampleDomain));
414 std::string url_string = "http://" + kSampleDomain;
415 GURL url(url_string);
416 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
418 // Check we can't add it twice.
419 EXPECT_FALSE(sdch_manager_->AddSdchDictionary(dictionary, url));
421 const std::string kSampleDomain2 = "sdchtest2.com";
423 // Don't test adding a second dictionary if our limits are tight.
424 if (SdchManager::kMaxDictionaryCount > 1) {
425 // Construct a second SDCH dictionary from a VCDIFF dictionary.
426 std::string dictionary2(NewSdchDictionary(kSampleDomain2));
428 std::string url_string2 = "http://" + kSampleDomain2;
429 GURL url2(url_string2);
430 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary2, url2));
434 TEST_F(SdchFilterTest, BasicDictionary) {
435 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
436 const std::string kSampleDomain = "sdchtest.com";
437 std::string dictionary(NewSdchDictionary(kSampleDomain));
439 std::string url_string = "http://" + kSampleDomain;
441 GURL url(url_string);
442 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
444 std::string compressed(NewSdchCompressedData(dictionary));
446 std::vector<Filter::FilterType> filter_types;
447 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
449 filter_context()->SetURL(url);
451 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
453 size_t feed_block_size = 100;
454 size_t output_block_size = 100;
455 std::string output;
456 EXPECT_TRUE(FilterTestData(compressed, feed_block_size, output_block_size,
457 filter.get(), &output));
458 EXPECT_EQ(output, expanded_);
460 // Decode with really small buffers (size 1) to check for edge effects.
461 filter.reset(Filter::Factory(filter_types, *filter_context()));
463 feed_block_size = 1;
464 output_block_size = 1;
465 output.clear();
466 EXPECT_TRUE(FilterTestData(compressed, feed_block_size, output_block_size,
467 filter.get(), &output));
468 EXPECT_EQ(output, expanded_);
471 TEST_F(SdchFilterTest, NoDecodeHttps) {
472 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
473 const std::string kSampleDomain = "sdchtest.com";
474 std::string dictionary(NewSdchDictionary(kSampleDomain));
476 std::string url_string = "http://" + kSampleDomain;
478 GURL url(url_string);
479 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
481 std::string compressed(NewSdchCompressedData(dictionary));
483 std::vector<Filter::FilterType> filter_types;
484 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
486 filter_context()->SetURL(GURL("https://" + kSampleDomain));
487 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
489 const size_t feed_block_size(100);
490 const size_t output_block_size(100);
491 std::string output;
493 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
494 filter.get(), &output));
497 // Current failsafe TODO/hack refuses to decode any content that doesn't use
498 // http as the scheme (see use of DICTIONARY_SELECTED_FOR_NON_HTTP).
499 // The following tests this blockage. Note that blacklisting results, so we
500 // we need separate tests for each of these.
501 TEST_F(SdchFilterTest, NoDecodeFtp) {
502 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
503 const std::string kSampleDomain = "sdchtest.com";
504 std::string dictionary(NewSdchDictionary(kSampleDomain));
506 std::string url_string = "http://" + kSampleDomain;
508 GURL url(url_string);
509 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
511 std::string compressed(NewSdchCompressedData(dictionary));
513 std::vector<Filter::FilterType> filter_types;
514 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
516 filter_context()->SetURL(GURL("ftp://" + kSampleDomain));
517 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
519 const size_t feed_block_size(100);
520 const size_t output_block_size(100);
521 std::string output;
523 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
524 filter.get(), &output));
527 TEST_F(SdchFilterTest, NoDecodeFileColon) {
528 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
529 const std::string kSampleDomain = "sdchtest.com";
530 std::string dictionary(NewSdchDictionary(kSampleDomain));
532 std::string url_string = "http://" + kSampleDomain;
534 GURL url(url_string);
535 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
537 std::string compressed(NewSdchCompressedData(dictionary));
539 std::vector<Filter::FilterType> filter_types;
540 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
542 filter_context()->SetURL(GURL("file://" + kSampleDomain));
543 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
545 const size_t feed_block_size(100);
546 const size_t output_block_size(100);
547 std::string output;
549 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
550 filter.get(), &output));
553 TEST_F(SdchFilterTest, NoDecodeAboutColon) {
554 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
555 const std::string kSampleDomain = "sdchtest.com";
556 std::string dictionary(NewSdchDictionary(kSampleDomain));
558 std::string url_string = "http://" + kSampleDomain;
560 GURL url(url_string);
561 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
563 std::string compressed(NewSdchCompressedData(dictionary));
565 std::vector<Filter::FilterType> filter_types;
566 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
568 filter_context()->SetURL(GURL("about://" + kSampleDomain));
569 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
571 const size_t feed_block_size(100);
572 const size_t output_block_size(100);
573 std::string output;
575 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
576 filter.get(), &output));
579 TEST_F(SdchFilterTest, NoDecodeJavaScript) {
580 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
581 const std::string kSampleDomain = "sdchtest.com";
582 std::string dictionary(NewSdchDictionary(kSampleDomain));
584 std::string url_string = "http://" + kSampleDomain;
586 GURL url(url_string);
587 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
589 std::string compressed(NewSdchCompressedData(dictionary));
591 std::vector<Filter::FilterType> filter_types;
592 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
594 filter_context()->SetURL(GURL("javascript://" + kSampleDomain));
595 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
597 const size_t feed_block_size(100);
598 const size_t output_block_size(100);
599 std::string output;
601 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
602 filter.get(), &output));
605 TEST_F(SdchFilterTest, CanStillDecodeHttp) {
606 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
607 const std::string kSampleDomain = "sdchtest.com";
608 std::string dictionary(NewSdchDictionary(kSampleDomain));
610 std::string url_string = "http://" + kSampleDomain;
612 GURL url(url_string);
613 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
615 std::string compressed(NewSdchCompressedData(dictionary));
617 std::vector<Filter::FilterType> filter_types;
618 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
620 filter_context()->SetURL(GURL("http://" + kSampleDomain));
621 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
623 const size_t feed_block_size(100);
624 const size_t output_block_size(100);
625 std::string output;
627 EXPECT_TRUE(FilterTestData(compressed, feed_block_size, output_block_size,
628 filter.get(), &output));
631 TEST_F(SdchFilterTest, CrossDomainDictionaryUse) {
632 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
633 const std::string kSampleDomain = "sdchtest.com";
634 std::string dictionary(NewSdchDictionary(kSampleDomain));
636 std::string url_string = "http://" + kSampleDomain;
638 GURL url(url_string);
639 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
641 std::string compressed(NewSdchCompressedData(dictionary));
643 std::vector<Filter::FilterType> filter_types;
644 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
646 // Decode with content arriving from the "wrong" domain.
647 // This tests SdchManager::CanSet().
648 GURL wrong_domain_url("http://www.wrongdomain.com");
649 filter_context()->SetURL(wrong_domain_url);
650 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
652 size_t feed_block_size = 100;
653 size_t output_block_size = 100;
654 std::string output;
655 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
656 filter.get(), &output));
657 EXPECT_EQ(output.size(), 0u); // No output written.
659 EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
660 EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
661 sdch_manager_->ClearBlacklistings();
662 EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
665 TEST_F(SdchFilterTest, DictionaryPathValidation) {
666 // Can't test path distinction between dictionaries if we aren't allowed
667 // more than one dictionary.
668 if (SdchManager::kMaxDictionaryCount <= 1)
669 return;
671 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
672 const std::string kSampleDomain = "sdchtest.com";
673 std::string dictionary(NewSdchDictionary(kSampleDomain));
675 std::string url_string = "http://" + kSampleDomain;
677 GURL url(url_string);
678 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
680 // Create a dictionary with a path restriction, by prefixing dictionary.
681 const std::string path("/special_path/bin");
682 std::string dictionary_with_path("Path: " + path + "\n");
683 dictionary_with_path.append(dictionary);
684 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary_with_path, url));
686 std::string compressed_for_path(NewSdchCompressedData(dictionary_with_path));
688 std::vector<Filter::FilterType> filter_types;
689 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
691 // Test decode the path data, arriving from a valid path.
692 filter_context()->SetURL(GURL(url_string + path));
693 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
695 size_t feed_block_size = 100;
696 size_t output_block_size = 100;
697 std::string output;
699 EXPECT_TRUE(FilterTestData(compressed_for_path, feed_block_size,
700 output_block_size, filter.get(), &output));
701 EXPECT_EQ(output, expanded_);
703 // Test decode the path data, arriving from a invalid path.
704 filter_context()->SetURL(GURL(url_string));
705 filter.reset(Filter::Factory(filter_types, *filter_context()));
707 feed_block_size = 100;
708 output_block_size = 100;
709 output.clear();
710 EXPECT_FALSE(FilterTestData(compressed_for_path, feed_block_size,
711 output_block_size, filter.get(), &output));
712 EXPECT_EQ(output.size(), 0u); // No output written.
714 EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
715 sdch_manager_->ClearBlacklistings();
716 EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
719 TEST_F(SdchFilterTest, DictionaryPortValidation) {
720 // Can't test port distinction between dictionaries if we aren't allowed
721 // more than one dictionary.
722 if (SdchManager::kMaxDictionaryCount <= 1)
723 return;
725 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
726 const std::string kSampleDomain = "sdchtest.com";
727 std::string dictionary(NewSdchDictionary(kSampleDomain));
729 std::string url_string = "http://" + kSampleDomain;
731 GURL url(url_string);
732 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
735 // Create a dictionary with a port restriction, by prefixing old dictionary.
736 const std::string port("502");
737 std::string dictionary_with_port("Port: " + port + "\n");
738 dictionary_with_port.append("Port: 80\n"); // Add default port.
739 dictionary_with_port.append(dictionary);
740 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary_with_port,
741 GURL(url_string + ":" + port)));
743 std::string compressed_for_port(NewSdchCompressedData(dictionary_with_port));
745 std::vector<Filter::FilterType> filter_types;
746 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
748 // Test decode the port data, arriving from a valid port.
749 filter_context()->SetURL(GURL(url_string + ":" + port));
750 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
752 size_t feed_block_size = 100;
753 size_t output_block_size = 100;
754 std::string output;
755 EXPECT_TRUE(FilterTestData(compressed_for_port, feed_block_size,
756 output_block_size, filter.get(), &output));
757 EXPECT_EQ(output, expanded_);
759 // Test decode the port data, arriving from a valid (default) port.
760 filter_context()->SetURL(GURL(url_string)); // Default port.
761 filter.reset(Filter::Factory(filter_types, *filter_context()));
763 feed_block_size = 100;
764 output_block_size = 100;
765 output.clear();
766 EXPECT_TRUE(FilterTestData(compressed_for_port, feed_block_size,
767 output_block_size, filter.get(), &output));
768 EXPECT_EQ(output, expanded_);
770 // Test decode the port data, arriving from a invalid port.
771 filter_context()->SetURL(GURL(url_string + ":" + port + "1"));
772 filter.reset(Filter::Factory(filter_types, *filter_context()));
774 feed_block_size = 100;
775 output_block_size = 100;
776 output.clear();
777 EXPECT_FALSE(FilterTestData(compressed_for_port, feed_block_size,
778 output_block_size, filter.get(), &output));
779 EXPECT_EQ(output.size(), 0u); // No output written.
781 EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
782 sdch_manager_->ClearBlacklistings();
783 EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
786 //------------------------------------------------------------------------------
787 // Helper function to perform gzip compression of data.
789 static std::string gzip_compress(const std::string &input) {
790 z_stream zlib_stream;
791 memset(&zlib_stream, 0, sizeof(zlib_stream));
792 int code;
794 // Initialize zlib
795 code = deflateInit2(&zlib_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
796 -MAX_WBITS,
797 8, // DEF_MEM_LEVEL
798 Z_DEFAULT_STRATEGY);
800 CHECK_EQ(Z_OK, code);
802 // Fill in zlib control block
803 zlib_stream.next_in = bit_cast<Bytef*>(input.data());
804 zlib_stream.avail_in = input.size();
806 // Assume we can compress into similar buffer (add 100 bytes to be sure).
807 size_t gzip_compressed_length = zlib_stream.avail_in + 100;
808 scoped_ptr<char[]> gzip_compressed(new char[gzip_compressed_length]);
809 zlib_stream.next_out = bit_cast<Bytef*>(gzip_compressed.get());
810 zlib_stream.avail_out = gzip_compressed_length;
812 // The GZIP header (see RFC 1952):
813 // +---+---+---+---+---+---+---+---+---+---+
814 // |ID1|ID2|CM |FLG| MTIME |XFL|OS |
815 // +---+---+---+---+---+---+---+---+---+---+
816 // ID1 \037
817 // ID2 \213
818 // CM \010 (compression method == DEFLATE)
819 // FLG \000 (special flags that we do not support)
820 // MTIME Unix format modification time (0 means not available)
821 // XFL 2-4? DEFLATE flags
822 // OS ???? Operating system indicator (255 means unknown)
824 // Header value we generate:
825 const char kGZipHeader[] = { '\037', '\213', '\010', '\000', '\000',
826 '\000', '\000', '\000', '\002', '\377' };
827 CHECK_GT(zlib_stream.avail_out, sizeof(kGZipHeader));
828 memcpy(zlib_stream.next_out, kGZipHeader, sizeof(kGZipHeader));
829 zlib_stream.next_out += sizeof(kGZipHeader);
830 zlib_stream.avail_out -= sizeof(kGZipHeader);
832 // Do deflate
833 code = deflate(&zlib_stream, Z_FINISH);
834 gzip_compressed_length -= zlib_stream.avail_out;
835 std::string compressed(gzip_compressed.get(), gzip_compressed_length);
836 deflateEnd(&zlib_stream);
837 return compressed;
840 //------------------------------------------------------------------------------
842 class SdchFilterChainingTest {
843 public:
844 static Filter* Factory(const std::vector<Filter::FilterType>& types,
845 const FilterContext& context, int size) {
846 return Filter::FactoryForTests(types, context, size);
850 // Test that filters can be cascaded (chained) so that the output of one filter
851 // is processed by the next one. This is most critical for SDCH, which is
852 // routinely followed by gzip (during encoding). The filter we'll test for will
853 // do the gzip decoding first, and then decode the SDCH content.
854 TEST_F(SdchFilterTest, FilterChaining) {
855 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
856 const std::string kSampleDomain = "sdchtest.com";
857 std::string dictionary(NewSdchDictionary(kSampleDomain));
859 std::string url_string = "http://" + kSampleDomain;
861 GURL url(url_string);
862 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
864 std::string sdch_compressed(NewSdchCompressedData(dictionary));
866 // Use Gzip to compress the sdch sdch_compressed data.
867 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
869 // Construct a chained filter.
870 std::vector<Filter::FilterType> filter_types;
871 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
872 filter_types.push_back(Filter::FILTER_TYPE_GZIP);
874 // First try with a large buffer (larger than test input, or compressed data).
875 const size_t kLargeInputBufferSize(1000); // Used internally in filters.
876 CHECK_GT(kLargeInputBufferSize, gzip_compressed_sdch.size());
877 CHECK_GT(kLargeInputBufferSize, sdch_compressed.size());
878 CHECK_GT(kLargeInputBufferSize, expanded_.size());
879 filter_context()->SetURL(url);
880 scoped_ptr<Filter> filter(
881 SdchFilterChainingTest::Factory(filter_types, *filter_context(),
882 kLargeInputBufferSize));
883 EXPECT_EQ(static_cast<int>(kLargeInputBufferSize),
884 filter->stream_buffer_size());
886 // Verify that chained filter is waiting for data.
887 char tiny_output_buffer[10];
888 int tiny_output_size = sizeof(tiny_output_buffer);
889 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
890 filter->ReadData(tiny_output_buffer, &tiny_output_size));
892 // Make chain process all data.
893 size_t feed_block_size = kLargeInputBufferSize;
894 size_t output_block_size = kLargeInputBufferSize;
895 std::string output;
896 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
897 output_block_size, filter.get(), &output));
898 EXPECT_EQ(output, expanded_);
900 // Next try with a mid-sized internal buffer size.
901 const size_t kMidSizedInputBufferSize(100);
902 // Buffer should be big enough to swallow whole gzip content.
903 CHECK_GT(kMidSizedInputBufferSize, gzip_compressed_sdch.size());
904 // Buffer should be small enough that entire SDCH content can't fit.
905 // We'll go even further, and force the chain to flush the buffer between the
906 // two filters more than once (that is why we multiply by 2).
907 CHECK_LT(kMidSizedInputBufferSize * 2, sdch_compressed.size());
908 filter_context()->SetURL(url);
909 filter.reset(
910 SdchFilterChainingTest::Factory(filter_types, *filter_context(),
911 kMidSizedInputBufferSize));
912 EXPECT_EQ(static_cast<int>(kMidSizedInputBufferSize),
913 filter->stream_buffer_size());
915 feed_block_size = kMidSizedInputBufferSize;
916 output_block_size = kMidSizedInputBufferSize;
917 output.clear();
918 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
919 output_block_size, filter.get(), &output));
920 EXPECT_EQ(output, expanded_);
922 // Next try with a tiny input and output buffer to cover edge effects.
923 filter.reset(SdchFilterChainingTest::Factory(filter_types, *filter_context(),
924 kLargeInputBufferSize));
925 EXPECT_EQ(static_cast<int>(kLargeInputBufferSize),
926 filter->stream_buffer_size());
928 feed_block_size = 1;
929 output_block_size = 1;
930 output.clear();
931 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
932 output_block_size, filter.get(), &output));
933 EXPECT_EQ(output, expanded_);
936 TEST_F(SdchFilterTest, DefaultGzipIfSdch) {
937 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
938 const std::string kSampleDomain = "sdchtest.com";
939 std::string dictionary(NewSdchDictionary(kSampleDomain));
941 std::string url_string = "http://" + kSampleDomain;
943 GURL url(url_string);
944 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
946 std::string sdch_compressed(NewSdchCompressedData(dictionary));
948 // Use Gzip to compress the sdch sdch_compressed data.
949 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
951 // Only claim to have sdch content, but really use the gzipped sdch content.
952 // System should automatically add the missing (optional) gzip.
953 std::vector<Filter::FilterType> filter_types;
954 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
956 filter_context()->SetMimeType("anything/mime");
957 filter_context()->SetSdchResponse(true);
958 Filter::FixupEncodingTypes(*filter_context(), &filter_types);
959 ASSERT_EQ(filter_types.size(), 2u);
960 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH);
961 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
963 // First try with a large buffer (larger than test input, or compressed data).
964 filter_context()->SetURL(url);
965 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
968 // Verify that chained filter is waiting for data.
969 char tiny_output_buffer[10];
970 int tiny_output_size = sizeof(tiny_output_buffer);
971 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
972 filter->ReadData(tiny_output_buffer, &tiny_output_size));
974 size_t feed_block_size = 100;
975 size_t output_block_size = 100;
976 std::string output;
977 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
978 output_block_size, filter.get(), &output));
979 EXPECT_EQ(output, expanded_);
981 // Next try with a tiny buffer to cover edge effects.
982 filter.reset(Filter::Factory(filter_types, *filter_context()));
984 feed_block_size = 1;
985 output_block_size = 1;
986 output.clear();
987 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
988 output_block_size, filter.get(), &output));
989 EXPECT_EQ(output, expanded_);
992 TEST_F(SdchFilterTest, AcceptGzipSdchIfGzip) {
993 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
994 const std::string kSampleDomain = "sdchtest.com";
995 std::string dictionary(NewSdchDictionary(kSampleDomain));
997 std::string url_string = "http://" + kSampleDomain;
999 GURL url(url_string);
1000 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
1002 std::string sdch_compressed(NewSdchCompressedData(dictionary));
1004 // Use Gzip to compress the sdch sdch_compressed data.
1005 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
1007 // Some proxies strip the content encoding statement down to a mere gzip, but
1008 // pass through the original content (with full sdch,gzip encoding).
1009 // Only claim to have gzip content, but really use the gzipped sdch content.
1010 // System should automatically add the missing (optional) sdch.
1011 std::vector<Filter::FilterType> filter_types;
1012 filter_types.push_back(Filter::FILTER_TYPE_GZIP);
1014 filter_context()->SetMimeType("anything/mime");
1015 filter_context()->SetSdchResponse(true);
1016 Filter::FixupEncodingTypes(*filter_context(), &filter_types);
1017 ASSERT_EQ(filter_types.size(), 3u);
1018 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
1019 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
1020 EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
1022 // First try with a large buffer (larger than test input, or compressed data).
1023 filter_context()->SetURL(url);
1024 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
1027 // Verify that chained filter is waiting for data.
1028 char tiny_output_buffer[10];
1029 int tiny_output_size = sizeof(tiny_output_buffer);
1030 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
1031 filter->ReadData(tiny_output_buffer, &tiny_output_size));
1033 size_t feed_block_size = 100;
1034 size_t output_block_size = 100;
1035 std::string output;
1036 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1037 output_block_size, filter.get(), &output));
1038 EXPECT_EQ(output, expanded_);
1040 // Next try with a tiny buffer to cover edge effects.
1041 filter.reset(Filter::Factory(filter_types, *filter_context()));
1043 feed_block_size = 1;
1044 output_block_size = 1;
1045 output.clear();
1046 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1047 output_block_size, filter.get(), &output));
1048 EXPECT_EQ(output, expanded_);
1051 TEST_F(SdchFilterTest, DefaultSdchGzipIfEmpty) {
1052 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
1053 const std::string kSampleDomain = "sdchtest.com";
1054 std::string dictionary(NewSdchDictionary(kSampleDomain));
1056 std::string url_string = "http://" + kSampleDomain;
1058 GURL url(url_string);
1059 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
1061 std::string sdch_compressed(NewSdchCompressedData(dictionary));
1063 // Use Gzip to compress the sdch sdch_compressed data.
1064 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
1066 // Only claim to have non-encoded content, but really use the gzipped sdch
1067 // content.
1068 // System should automatically add the missing (optional) sdch,gzip.
1069 std::vector<Filter::FilterType> filter_types;
1071 filter_context()->SetMimeType("anything/mime");
1072 filter_context()->SetSdchResponse(true);
1073 Filter::FixupEncodingTypes(*filter_context(), &filter_types);
1074 ASSERT_EQ(filter_types.size(), 2u);
1075 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
1076 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
1078 // First try with a large buffer (larger than test input, or compressed data).
1079 filter_context()->SetURL(url);
1080 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
1083 // Verify that chained filter is waiting for data.
1084 char tiny_output_buffer[10];
1085 int tiny_output_size = sizeof(tiny_output_buffer);
1086 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
1087 filter->ReadData(tiny_output_buffer, &tiny_output_size));
1089 size_t feed_block_size = 100;
1090 size_t output_block_size = 100;
1091 std::string output;
1092 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1093 output_block_size, filter.get(), &output));
1094 EXPECT_EQ(output, expanded_);
1096 // Next try with a tiny buffer to cover edge effects.
1097 filter.reset(Filter::Factory(filter_types, *filter_context()));
1099 feed_block_size = 1;
1100 output_block_size = 1;
1101 output.clear();
1102 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1103 output_block_size, filter.get(), &output));
1104 EXPECT_EQ(output, expanded_);
1107 TEST_F(SdchFilterTest, AcceptGzipGzipSdchIfGzip) {
1108 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
1109 const std::string kSampleDomain = "sdchtest.com";
1110 std::string dictionary(NewSdchDictionary(kSampleDomain));
1112 std::string url_string = "http://" + kSampleDomain;
1114 GURL url(url_string);
1115 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
1117 std::string sdch_compressed(NewSdchCompressedData(dictionary));
1119 // Vodaphone (UK) Mobile Broadband provides double gzipped sdch with a content
1120 // encoding of merely gzip (apparently, only listing the extra level of
1121 // wrapper compression they added, but discarding the actual content encoding.
1122 // Use Gzip to double compress the sdch sdch_compressed data.
1123 std::string double_gzip_compressed_sdch = gzip_compress(gzip_compress(
1124 sdch_compressed));
1126 // Only claim to have gzip content, but really use the double gzipped sdch
1127 // content.
1128 // System should automatically add the missing (optional) sdch, gzip decoders.
1129 std::vector<Filter::FilterType> filter_types;
1130 filter_types.push_back(Filter::FILTER_TYPE_GZIP);
1132 filter_context()->SetMimeType("anything/mime");
1133 filter_context()->SetSdchResponse(true);
1134 Filter::FixupEncodingTypes(*filter_context(), &filter_types);
1135 ASSERT_EQ(filter_types.size(), 3u);
1136 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
1137 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
1138 EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
1140 // First try with a large buffer (larger than test input, or compressed data).
1141 filter_context()->SetURL(url);
1142 scoped_ptr<Filter> filter(Filter::Factory(filter_types, *filter_context()));
1144 // Verify that chained filter is waiting for data.
1145 char tiny_output_buffer[10];
1146 int tiny_output_size = sizeof(tiny_output_buffer);
1147 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
1148 filter->ReadData(tiny_output_buffer, &tiny_output_size));
1150 size_t feed_block_size = 100;
1151 size_t output_block_size = 100;
1152 std::string output;
1153 EXPECT_TRUE(FilterTestData(double_gzip_compressed_sdch, feed_block_size,
1154 output_block_size, filter.get(), &output));
1155 EXPECT_EQ(output, expanded_);
1157 // Next try with a tiny buffer to cover edge effects.
1158 filter.reset(Filter::Factory(filter_types, *filter_context()));
1160 feed_block_size = 1;
1161 output_block_size = 1;
1162 output.clear();
1163 EXPECT_TRUE(FilterTestData(double_gzip_compressed_sdch, feed_block_size,
1164 output_block_size, filter.get(), &output));
1165 EXPECT_EQ(output, expanded_);
1168 } // namespace net