Blink roll 173193:173208
[chromium-blink-merge.git] / net / filter / sdch_filter_unittest.cc
blob37f48866707bfece16ba4c183b33f7d3f603d43c
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_http_job.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/zlib/zlib.h"
20 namespace net {
22 //------------------------------------------------------------------------------
23 // Provide sample data and compression results with a sample VCDIFF dictionary.
24 // Note an SDCH dictionary has extra meta-data before the VCDIFF dictionary.
25 static const char kTestVcdiffDictionary[] = "DictionaryFor"
26 "SdchCompression1SdchCompression2SdchCompression3SdchCompression\n";
27 // Pre-compression test data. Note that we pad with a lot of highly gzip
28 // compressible content to help to exercise the chaining pipeline. That is why
29 // there are a PILE of zeros at the start and end.
30 // This will ensure that gzip compressed data can be fed to the chain in one
31 // gulp, but (with careful selection of intermediate buffers) that it takes
32 // several sdch buffers worth of data to satisfy the sdch filter. See detailed
33 // CHECK() calls in FilterChaining test for specifics.
34 static const char kTestData[] = "0000000000000000000000000000000000000000000000"
35 "0000000000000000000000000000TestData "
36 "SdchCompression1SdchCompression2SdchCompression3SdchCompression"
37 "00000000000000000000000000000000000000000000000000000000000000000000000000"
38 "000000000000000000000000000000000000000\n";
40 // Note SDCH compressed data will include a reference to the SDCH dictionary.
41 static const char kSdchCompressedTestData[] =
42 "\326\303\304\0\0\001M\0\201S\202\004\0\201E\006\001"
43 "00000000000000000000000000000000000000000000000000000000000000000000000000"
44 "TestData 00000000000000000000000000000000000000000000000000000000000000000"
45 "000000000000000000000000000000000000000000000000\n\001S\023\077\001r\r";
47 //------------------------------------------------------------------------------
49 class SdchFilterTest : public testing::Test {
50 protected:
51 SdchFilterTest()
52 : test_vcdiff_dictionary_(kTestVcdiffDictionary,
53 sizeof(kTestVcdiffDictionary) - 1),
54 vcdiff_compressed_data_(kSdchCompressedTestData,
55 sizeof(kSdchCompressedTestData) - 1),
56 expanded_(kTestData, sizeof(kTestData) - 1),
57 sdch_manager_(new SdchManager) {
60 std::string NewSdchCompressedData(const std::string dictionary);
62 const std::string test_vcdiff_dictionary_;
63 const std::string vcdiff_compressed_data_;
64 const std::string expanded_; // Desired final, decompressed data.
66 scoped_ptr<SdchManager> sdch_manager_; // A singleton database.
69 std::string SdchFilterTest::NewSdchCompressedData(
70 const std::string dictionary) {
71 std::string client_hash;
72 std::string server_hash;
73 SdchManager::GenerateHash(dictionary, &client_hash, &server_hash);
75 // Build compressed data that refers to our dictionary.
76 std::string compressed(server_hash);
77 compressed.append("\0", 1);
78 compressed.append(vcdiff_compressed_data_);
79 return compressed;
82 //------------------------------------------------------------------------------
85 TEST_F(SdchFilterTest, Hashing) {
86 std::string client_hash, server_hash;
87 std::string dictionary("test contents");
88 SdchManager::GenerateHash(dictionary, &client_hash, &server_hash);
90 EXPECT_EQ(client_hash, "lMQBjS3P");
91 EXPECT_EQ(server_hash, "MyciMVll");
95 //------------------------------------------------------------------------------
96 // Provide a generic helper function for trying to filter data.
97 // This function repeatedly calls the filter to process data, until the entire
98 // source is consumed. The return value from the filter is appended to output.
99 // This allows us to vary input and output block sizes in order to test for edge
100 // effects (boundary effects?) during the filtering process.
101 // This function provides data to the filter in blocks of no-more-than the
102 // specified input_block_length. It allows the filter to fill no more than
103 // output_buffer_length in any one call to proccess (a.k.a., Read) data, and
104 // concatenates all these little output blocks into the singular output string.
105 static bool FilterTestData(const std::string& source,
106 size_t input_block_length,
107 const size_t output_buffer_length,
108 Filter* filter, std::string* output) {
109 CHECK_GT(input_block_length, 0u);
110 Filter::FilterStatus status(Filter::FILTER_NEED_MORE_DATA);
111 size_t source_index = 0;
112 scoped_ptr<char[]> output_buffer(new char[output_buffer_length]);
113 size_t input_amount = std::min(input_block_length,
114 static_cast<size_t>(filter->stream_buffer_size()));
116 do {
117 int copy_amount = std::min(input_amount, source.size() - source_index);
118 if (copy_amount > 0 && status == Filter::FILTER_NEED_MORE_DATA) {
119 memcpy(filter->stream_buffer()->data(), source.data() + source_index,
120 copy_amount);
121 filter->FlushStreamBuffer(copy_amount);
122 source_index += copy_amount;
124 int buffer_length = output_buffer_length;
125 status = filter->ReadData(output_buffer.get(), &buffer_length);
126 output->append(output_buffer.get(), buffer_length);
127 if (status == Filter::FILTER_ERROR)
128 return false;
129 // Callers assume that FILTER_OK with no output buffer means FILTER_DONE.
130 if (Filter::FILTER_OK == status && 0 == buffer_length)
131 return true;
132 if (copy_amount == 0 && buffer_length == 0)
133 return true;
134 } while (1);
136 //------------------------------------------------------------------------------
137 static std::string NewSdchDictionary(const std::string& domain) {
138 std::string dictionary;
139 if (!domain.empty()) {
140 dictionary.append("Domain: ");
141 dictionary.append(domain);
142 dictionary.append("\n");
144 dictionary.append("\n");
145 dictionary.append(kTestVcdiffDictionary, sizeof(kTestVcdiffDictionary) - 1);
146 return dictionary;
149 //------------------------------------------------------------------------------
151 TEST_F(SdchFilterTest, EmptyInputOk) {
152 std::vector<Filter::FilterType> filter_types;
153 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
154 char output_buffer[20];
155 MockFilterContext filter_context;
156 std::string url_string("http://ignore.com");
157 filter_context.SetURL(GURL(url_string));
158 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
161 // With no input data, try to read output.
162 int output_bytes_or_buffer_size = sizeof(output_buffer);
163 Filter::FilterStatus status = filter->ReadData(output_buffer,
164 &output_bytes_or_buffer_size);
166 EXPECT_EQ(0, output_bytes_or_buffer_size);
167 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
170 TEST_F(SdchFilterTest, PassThroughWhenTentative) {
171 std::vector<Filter::FilterType> filter_types;
172 // Selective a tentative filter (which can fall back to pass through).
173 filter_types.push_back(Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
174 char output_buffer[20];
175 MockFilterContext filter_context;
176 // Response code needs to be 200 to allow a pass through.
177 filter_context.SetResponseCode(200);
178 std::string url_string("http://ignore.com");
179 filter_context.SetURL(GURL(url_string));
180 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
182 // Supply enough data to force a pass-through mode..
183 std::string non_gzip_content("not GZIPed data");
185 char* input_buffer = filter->stream_buffer()->data();
186 int input_buffer_size = filter->stream_buffer_size();
188 EXPECT_LT(static_cast<int>(non_gzip_content.size()),
189 input_buffer_size);
190 memcpy(input_buffer, non_gzip_content.data(),
191 non_gzip_content.size());
192 filter->FlushStreamBuffer(non_gzip_content.size());
194 // Try to read output.
195 int output_bytes_or_buffer_size = sizeof(output_buffer);
196 Filter::FilterStatus status = filter->ReadData(output_buffer,
197 &output_bytes_or_buffer_size);
199 EXPECT_EQ(non_gzip_content.size(),
200 static_cast<size_t>(output_bytes_or_buffer_size));
201 ASSERT_GT(sizeof(output_buffer),
202 static_cast<size_t>(output_bytes_or_buffer_size));
203 output_buffer[output_bytes_or_buffer_size] = '\0';
204 EXPECT_TRUE(non_gzip_content == output_buffer);
205 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
208 TEST_F(SdchFilterTest, RefreshBadReturnCode) {
209 std::vector<Filter::FilterType> filter_types;
210 // Selective a tentative filter (which can fall back to pass through).
211 filter_types.push_back(Filter::FILTER_TYPE_SDCH_POSSIBLE);
212 char output_buffer[20];
213 MockFilterContext filter_context;
214 // Response code needs to be 200 to allow a pass through.
215 filter_context.SetResponseCode(403);
216 // Meta refresh will only appear for html content
217 filter_context.SetMimeType("text/html");
218 std::string url_string("http://ignore.com");
219 filter_context.SetURL(GURL(url_string));
220 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
222 // Supply enough data to force a pass-through mode, which means we have
223 // provided more than 9 characters that can't be a dictionary hash.
224 std::string non_sdch_content("This is not SDCH");
226 char* input_buffer = filter->stream_buffer()->data();
227 int input_buffer_size = filter->stream_buffer_size();
229 EXPECT_LT(static_cast<int>(non_sdch_content.size()),
230 input_buffer_size);
231 memcpy(input_buffer, non_sdch_content.data(),
232 non_sdch_content.size());
233 filter->FlushStreamBuffer(non_sdch_content.size());
235 // Try to read output.
236 int output_bytes_or_buffer_size = sizeof(output_buffer);
237 Filter::FilterStatus status = filter->ReadData(output_buffer,
238 &output_bytes_or_buffer_size);
240 // We should have read a long and complicated meta-refresh request.
241 EXPECT_TRUE(sizeof(output_buffer) == output_bytes_or_buffer_size);
242 // Check at least the prefix of the return.
243 EXPECT_EQ(0, strncmp(output_buffer,
244 "<head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\"></head>",
245 sizeof(output_buffer)));
246 EXPECT_EQ(Filter::FILTER_OK, status);
249 TEST_F(SdchFilterTest, ErrorOnBadReturnCode) {
250 std::vector<Filter::FilterType> filter_types;
251 // Selective a tentative filter (which can fall back to pass through).
252 filter_types.push_back(Filter::FILTER_TYPE_SDCH_POSSIBLE);
253 char output_buffer[20];
254 MockFilterContext filter_context;
255 // Response code needs to be 200 to allow a pass through.
256 filter_context.SetResponseCode(403);
257 // Meta refresh will only appear for html content, so set to something else
258 // to induce an error (we can't meta refresh).
259 filter_context.SetMimeType("anything");
260 std::string url_string("http://ignore.com");
261 filter_context.SetURL(GURL(url_string));
262 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
264 // Supply enough data to force a pass-through mode, which means we have
265 // provided more than 9 characters that can't be a dictionary hash.
266 std::string non_sdch_content("This is not SDCH");
268 char* input_buffer = filter->stream_buffer()->data();
269 int input_buffer_size = filter->stream_buffer_size();
271 EXPECT_LT(static_cast<int>(non_sdch_content.size()),
272 input_buffer_size);
273 memcpy(input_buffer, non_sdch_content.data(),
274 non_sdch_content.size());
275 filter->FlushStreamBuffer(non_sdch_content.size());
277 // Try to read output.
278 int output_bytes_or_buffer_size = sizeof(output_buffer);
279 Filter::FilterStatus status = filter->ReadData(output_buffer,
280 &output_bytes_or_buffer_size);
282 EXPECT_EQ(0, output_bytes_or_buffer_size);
283 EXPECT_EQ(Filter::FILTER_ERROR, status);
286 TEST_F(SdchFilterTest, ErrorOnBadReturnCodeWithHtml) {
287 std::vector<Filter::FilterType> filter_types;
288 // Selective a tentative filter (which can fall back to pass through).
289 filter_types.push_back(Filter::FILTER_TYPE_SDCH_POSSIBLE);
290 char output_buffer[20];
291 MockFilterContext filter_context;
292 // Response code needs to be 200 to allow a pass through.
293 filter_context.SetResponseCode(403);
294 // Meta refresh will only appear for html content
295 filter_context.SetMimeType("text/html");
296 std::string url_string("http://ignore.com");
297 filter_context.SetURL(GURL(url_string));
298 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
300 // Supply enough data to force a pass-through mode, which means we have
301 // provided more than 9 characters that can't be a dictionary hash.
302 std::string non_sdch_content("This is not SDCH");
304 char* input_buffer = filter->stream_buffer()->data();
305 int input_buffer_size = filter->stream_buffer_size();
307 EXPECT_LT(static_cast<int>(non_sdch_content.size()),
308 input_buffer_size);
309 memcpy(input_buffer, non_sdch_content.data(),
310 non_sdch_content.size());
311 filter->FlushStreamBuffer(non_sdch_content.size());
313 // Try to read output.
314 int output_bytes_or_buffer_size = sizeof(output_buffer);
315 Filter::FilterStatus status = filter->ReadData(output_buffer,
316 &output_bytes_or_buffer_size);
318 // We should have read a long and complicated meta-refresh request.
319 EXPECT_EQ(sizeof(output_buffer),
320 static_cast<size_t>(output_bytes_or_buffer_size));
321 // Check at least the prefix of the return.
322 EXPECT_EQ(0, strncmp(output_buffer,
323 "<head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0\"></head>",
324 sizeof(output_buffer)));
325 EXPECT_EQ(Filter::FILTER_OK, status);
328 TEST_F(SdchFilterTest, BasicBadDictionary) {
329 std::vector<Filter::FilterType> filter_types;
330 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
331 char output_buffer[20];
332 MockFilterContext filter_context;
333 std::string url_string("http://ignore.com");
334 filter_context.SetURL(GURL(url_string));
335 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
337 // Supply bogus data (which doesn't yet specify a full dictionary hash).
338 // Dictionary hash is 8 characters followed by a null.
339 std::string dictionary_hash_prefix("123");
341 char* input_buffer = filter->stream_buffer()->data();
342 int input_buffer_size = filter->stream_buffer_size();
344 EXPECT_LT(static_cast<int>(dictionary_hash_prefix.size()),
345 input_buffer_size);
346 memcpy(input_buffer, dictionary_hash_prefix.data(),
347 dictionary_hash_prefix.size());
348 filter->FlushStreamBuffer(dictionary_hash_prefix.size());
350 // With less than a dictionary specifier, try to read output.
351 int output_bytes_or_buffer_size = sizeof(output_buffer);
352 Filter::FilterStatus status = filter->ReadData(output_buffer,
353 &output_bytes_or_buffer_size);
355 EXPECT_EQ(0, output_bytes_or_buffer_size);
356 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA, status);
358 // Provide enough data to complete *a* hash, but it is bogus, and not in our
359 // list of dictionaries, so the filter should error out immediately.
360 std::string dictionary_hash_postfix("4abcd\0", 6);
362 CHECK_LT(dictionary_hash_postfix.size(),
363 static_cast<size_t>(input_buffer_size));
364 memcpy(input_buffer, dictionary_hash_postfix.data(),
365 dictionary_hash_postfix.size());
366 filter->FlushStreamBuffer(dictionary_hash_postfix.size());
368 // With a non-existant dictionary specifier, try to read output.
369 output_bytes_or_buffer_size = sizeof(output_buffer);
370 status = filter->ReadData(output_buffer, &output_bytes_or_buffer_size);
372 EXPECT_EQ(0, output_bytes_or_buffer_size);
373 EXPECT_EQ(Filter::FILTER_ERROR, status);
375 EXPECT_FALSE(SdchManager::Global()->IsInSupportedDomain(GURL(url_string)));
376 SdchManager::ClearBlacklistings();
377 EXPECT_TRUE(SdchManager::Global()->IsInSupportedDomain(GURL(url_string)));
380 TEST_F(SdchFilterTest, DictionaryAddOnce) {
381 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
382 const std::string kSampleDomain = "sdchtest.com";
383 std::string dictionary(NewSdchDictionary(kSampleDomain));
385 std::string url_string = "http://" + kSampleDomain;
386 GURL url(url_string);
387 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
389 // Check we can't add it twice.
390 EXPECT_FALSE(sdch_manager_->AddSdchDictionary(dictionary, url));
392 const std::string kSampleDomain2 = "sdchtest2.com";
394 // Construct a second SDCH dictionary from a VCDIFF dictionary.
395 std::string dictionary2(NewSdchDictionary(kSampleDomain2));
397 std::string url_string2 = "http://" + kSampleDomain2;
398 GURL url2(url_string2);
399 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary2, url2));
402 TEST_F(SdchFilterTest, BasicDictionary) {
403 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
404 const std::string kSampleDomain = "sdchtest.com";
405 std::string dictionary(NewSdchDictionary(kSampleDomain));
407 std::string url_string = "http://" + kSampleDomain;
409 GURL url(url_string);
410 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
412 std::string compressed(NewSdchCompressedData(dictionary));
414 std::vector<Filter::FilterType> filter_types;
415 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
417 MockFilterContext filter_context;
418 filter_context.SetURL(url);
420 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
422 size_t feed_block_size = 100;
423 size_t output_block_size = 100;
424 std::string output;
425 EXPECT_TRUE(FilterTestData(compressed, feed_block_size, output_block_size,
426 filter.get(), &output));
427 EXPECT_EQ(output, expanded_);
429 // Decode with really small buffers (size 1) to check for edge effects.
430 filter.reset(Filter::Factory(filter_types, filter_context));
432 feed_block_size = 1;
433 output_block_size = 1;
434 output.clear();
435 EXPECT_TRUE(FilterTestData(compressed, feed_block_size, output_block_size,
436 filter.get(), &output));
437 EXPECT_EQ(output, expanded_);
440 TEST_F(SdchFilterTest, NoDecodeHttps) {
441 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
442 const std::string kSampleDomain = "sdchtest.com";
443 std::string dictionary(NewSdchDictionary(kSampleDomain));
445 std::string url_string = "http://" + kSampleDomain;
447 GURL url(url_string);
448 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
450 std::string compressed(NewSdchCompressedData(dictionary));
452 std::vector<Filter::FilterType> filter_types;
453 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
455 MockFilterContext filter_context;
456 filter_context.SetURL(GURL("https://" + kSampleDomain));
457 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
459 const size_t feed_block_size(100);
460 const size_t output_block_size(100);
461 std::string output;
463 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
464 filter.get(), &output));
467 // Current failsafe TODO/hack refuses to decode any content that doesn't use
468 // http as the scheme (see use of DICTIONARY_SELECTED_FOR_NON_HTTP).
469 // The following tests this blockage. Note that blacklisting results, so we
470 // we need separate tests for each of these.
471 TEST_F(SdchFilterTest, NoDecodeFtp) {
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 MockFilterContext filter_context;
487 filter_context.SetURL(GURL("ftp://" + kSampleDomain));
488 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
490 const size_t feed_block_size(100);
491 const size_t output_block_size(100);
492 std::string output;
494 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
495 filter.get(), &output));
498 TEST_F(SdchFilterTest, NoDecodeFileColon) {
499 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
500 const std::string kSampleDomain = "sdchtest.com";
501 std::string dictionary(NewSdchDictionary(kSampleDomain));
503 std::string url_string = "http://" + kSampleDomain;
505 GURL url(url_string);
506 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
508 std::string compressed(NewSdchCompressedData(dictionary));
510 std::vector<Filter::FilterType> filter_types;
511 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
513 MockFilterContext filter_context;
514 filter_context.SetURL(GURL("file://" + kSampleDomain));
515 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
517 const size_t feed_block_size(100);
518 const size_t output_block_size(100);
519 std::string output;
521 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
522 filter.get(), &output));
525 TEST_F(SdchFilterTest, NoDecodeAboutColon) {
526 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
527 const std::string kSampleDomain = "sdchtest.com";
528 std::string dictionary(NewSdchDictionary(kSampleDomain));
530 std::string url_string = "http://" + kSampleDomain;
532 GURL url(url_string);
533 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
535 std::string compressed(NewSdchCompressedData(dictionary));
537 std::vector<Filter::FilterType> filter_types;
538 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
540 MockFilterContext filter_context;
541 filter_context.SetURL(GURL("about://" + kSampleDomain));
542 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
544 const size_t feed_block_size(100);
545 const size_t output_block_size(100);
546 std::string output;
548 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
549 filter.get(), &output));
552 TEST_F(SdchFilterTest, NoDecodeJavaScript) {
553 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
554 const std::string kSampleDomain = "sdchtest.com";
555 std::string dictionary(NewSdchDictionary(kSampleDomain));
557 std::string url_string = "http://" + kSampleDomain;
559 GURL url(url_string);
560 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
562 std::string compressed(NewSdchCompressedData(dictionary));
564 std::vector<Filter::FilterType> filter_types;
565 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
567 MockFilterContext filter_context;
568 filter_context.SetURL(GURL("javascript://" + 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, CanStillDecodeHttp) {
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 MockFilterContext filter_context;
595 filter_context.SetURL(GURL("http://" + kSampleDomain));
596 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
598 const size_t feed_block_size(100);
599 const size_t output_block_size(100);
600 std::string output;
602 EXPECT_TRUE(FilterTestData(compressed, feed_block_size, output_block_size,
603 filter.get(), &output));
606 TEST_F(SdchFilterTest, CrossDomainDictionaryUse) {
607 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
608 const std::string kSampleDomain = "sdchtest.com";
609 std::string dictionary(NewSdchDictionary(kSampleDomain));
611 std::string url_string = "http://" + kSampleDomain;
613 GURL url(url_string);
614 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
616 std::string compressed(NewSdchCompressedData(dictionary));
618 std::vector<Filter::FilterType> filter_types;
619 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
621 // Decode with content arriving from the "wrong" domain.
622 // This tests SdchManager::CanSet().
623 MockFilterContext filter_context;
624 GURL wrong_domain_url("http://www.wrongdomain.com");
625 filter_context.SetURL(wrong_domain_url);
626 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
628 size_t feed_block_size = 100;
629 size_t output_block_size = 100;
630 std::string output;
631 EXPECT_FALSE(FilterTestData(compressed, feed_block_size, output_block_size,
632 filter.get(), &output));
633 EXPECT_EQ(output.size(), 0u); // No output written.
635 EXPECT_TRUE(SdchManager::Global()->IsInSupportedDomain(GURL(url_string)));
636 EXPECT_FALSE(SdchManager::Global()->IsInSupportedDomain(wrong_domain_url));
637 SdchManager::ClearBlacklistings();
638 EXPECT_TRUE(SdchManager::Global()->IsInSupportedDomain(wrong_domain_url));
641 TEST_F(SdchFilterTest, DictionaryPathValidation) {
642 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
643 const std::string kSampleDomain = "sdchtest.com";
644 std::string dictionary(NewSdchDictionary(kSampleDomain));
646 std::string url_string = "http://" + kSampleDomain;
648 GURL url(url_string);
649 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
651 // Create a dictionary with a path restriction, by prefixing dictionary.
652 const std::string path("/special_path/bin");
653 std::string dictionary_with_path("Path: " + path + "\n");
654 dictionary_with_path.append(dictionary);
655 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary_with_path, url));
657 std::string compressed_for_path(NewSdchCompressedData(dictionary_with_path));
659 std::vector<Filter::FilterType> filter_types;
660 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
662 // Test decode the path data, arriving from a valid path.
663 MockFilterContext filter_context;
664 filter_context.SetURL(GURL(url_string + path));
665 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
667 size_t feed_block_size = 100;
668 size_t output_block_size = 100;
669 std::string output;
671 EXPECT_TRUE(FilterTestData(compressed_for_path, feed_block_size,
672 output_block_size, filter.get(), &output));
673 EXPECT_EQ(output, expanded_);
675 // Test decode the path data, arriving from a invalid path.
676 filter_context.SetURL(GURL(url_string));
677 filter.reset(Filter::Factory(filter_types, filter_context));
679 feed_block_size = 100;
680 output_block_size = 100;
681 output.clear();
682 EXPECT_FALSE(FilterTestData(compressed_for_path, feed_block_size,
683 output_block_size, filter.get(), &output));
684 EXPECT_EQ(output.size(), 0u); // No output written.
686 EXPECT_FALSE(SdchManager::Global()->IsInSupportedDomain(GURL(url_string)));
687 SdchManager::ClearBlacklistings();
688 EXPECT_TRUE(SdchManager::Global()->IsInSupportedDomain(GURL(url_string)));
691 TEST_F(SdchFilterTest, DictionaryPortValidation) {
692 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
693 const std::string kSampleDomain = "sdchtest.com";
694 std::string dictionary(NewSdchDictionary(kSampleDomain));
696 std::string url_string = "http://" + kSampleDomain;
698 GURL url(url_string);
699 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
702 // Create a dictionary with a port restriction, by prefixing old dictionary.
703 const std::string port("502");
704 std::string dictionary_with_port("Port: " + port + "\n");
705 dictionary_with_port.append("Port: 80\n"); // Add default port.
706 dictionary_with_port.append(dictionary);
707 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary_with_port,
708 GURL(url_string + ":" + port)));
710 std::string compressed_for_port(NewSdchCompressedData(dictionary_with_port));
712 std::vector<Filter::FilterType> filter_types;
713 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
715 // Test decode the port data, arriving from a valid port.
716 MockFilterContext filter_context;
717 filter_context.SetURL(GURL(url_string + ":" + port));
718 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
720 size_t feed_block_size = 100;
721 size_t output_block_size = 100;
722 std::string output;
723 EXPECT_TRUE(FilterTestData(compressed_for_port, feed_block_size,
724 output_block_size, filter.get(), &output));
725 EXPECT_EQ(output, expanded_);
727 // Test decode the port data, arriving from a valid (default) port.
728 filter_context.SetURL(GURL(url_string)); // Default port.
729 filter.reset(Filter::Factory(filter_types, filter_context));
731 feed_block_size = 100;
732 output_block_size = 100;
733 output.clear();
734 EXPECT_TRUE(FilterTestData(compressed_for_port, feed_block_size,
735 output_block_size, filter.get(), &output));
736 EXPECT_EQ(output, expanded_);
738 // Test decode the port data, arriving from a invalid port.
739 filter_context.SetURL(GURL(url_string + ":" + port + "1"));
740 filter.reset(Filter::Factory(filter_types, filter_context));
742 feed_block_size = 100;
743 output_block_size = 100;
744 output.clear();
745 EXPECT_FALSE(FilterTestData(compressed_for_port, feed_block_size,
746 output_block_size, filter.get(), &output));
747 EXPECT_EQ(output.size(), 0u); // No output written.
749 EXPECT_FALSE(SdchManager::Global()->IsInSupportedDomain(GURL(url_string)));
750 SdchManager::ClearBlacklistings();
751 EXPECT_TRUE(SdchManager::Global()->IsInSupportedDomain(GURL(url_string)));
754 //------------------------------------------------------------------------------
755 // Helper function to perform gzip compression of data.
757 static std::string gzip_compress(const std::string &input) {
758 z_stream zlib_stream;
759 memset(&zlib_stream, 0, sizeof(zlib_stream));
760 int code;
762 // Initialize zlib
763 code = deflateInit2(&zlib_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
764 -MAX_WBITS,
765 8, // DEF_MEM_LEVEL
766 Z_DEFAULT_STRATEGY);
768 CHECK_EQ(Z_OK, code);
770 // Fill in zlib control block
771 zlib_stream.next_in = bit_cast<Bytef*>(input.data());
772 zlib_stream.avail_in = input.size();
774 // Assume we can compress into similar buffer (add 100 bytes to be sure).
775 size_t gzip_compressed_length = zlib_stream.avail_in + 100;
776 scoped_ptr<char[]> gzip_compressed(new char[gzip_compressed_length]);
777 zlib_stream.next_out = bit_cast<Bytef*>(gzip_compressed.get());
778 zlib_stream.avail_out = gzip_compressed_length;
780 // The GZIP header (see RFC 1952):
781 // +---+---+---+---+---+---+---+---+---+---+
782 // |ID1|ID2|CM |FLG| MTIME |XFL|OS |
783 // +---+---+---+---+---+---+---+---+---+---+
784 // ID1 \037
785 // ID2 \213
786 // CM \010 (compression method == DEFLATE)
787 // FLG \000 (special flags that we do not support)
788 // MTIME Unix format modification time (0 means not available)
789 // XFL 2-4? DEFLATE flags
790 // OS ???? Operating system indicator (255 means unknown)
792 // Header value we generate:
793 const char kGZipHeader[] = { '\037', '\213', '\010', '\000', '\000',
794 '\000', '\000', '\000', '\002', '\377' };
795 CHECK_GT(zlib_stream.avail_out, sizeof(kGZipHeader));
796 memcpy(zlib_stream.next_out, kGZipHeader, sizeof(kGZipHeader));
797 zlib_stream.next_out += sizeof(kGZipHeader);
798 zlib_stream.avail_out -= sizeof(kGZipHeader);
800 // Do deflate
801 code = deflate(&zlib_stream, Z_FINISH);
802 gzip_compressed_length -= zlib_stream.avail_out;
803 std::string compressed(gzip_compressed.get(), gzip_compressed_length);
804 deflateEnd(&zlib_stream);
805 return compressed;
808 //------------------------------------------------------------------------------
810 class SdchFilterChainingTest {
811 public:
812 static Filter* Factory(const std::vector<Filter::FilterType>& types,
813 const FilterContext& context, int size) {
814 return Filter::FactoryForTests(types, context, size);
818 // Test that filters can be cascaded (chained) so that the output of one filter
819 // is processed by the next one. This is most critical for SDCH, which is
820 // routinely followed by gzip (during encoding). The filter we'll test for will
821 // do the gzip decoding first, and then decode the SDCH content.
822 TEST_F(SdchFilterTest, FilterChaining) {
823 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
824 const std::string kSampleDomain = "sdchtest.com";
825 std::string dictionary(NewSdchDictionary(kSampleDomain));
827 std::string url_string = "http://" + kSampleDomain;
829 GURL url(url_string);
830 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
832 std::string sdch_compressed(NewSdchCompressedData(dictionary));
834 // Use Gzip to compress the sdch sdch_compressed data.
835 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
837 // Construct a chained filter.
838 std::vector<Filter::FilterType> filter_types;
839 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
840 filter_types.push_back(Filter::FILTER_TYPE_GZIP);
842 // First try with a large buffer (larger than test input, or compressed data).
843 const size_t kLargeInputBufferSize(1000); // Used internally in filters.
844 CHECK_GT(kLargeInputBufferSize, gzip_compressed_sdch.size());
845 CHECK_GT(kLargeInputBufferSize, sdch_compressed.size());
846 CHECK_GT(kLargeInputBufferSize, expanded_.size());
847 MockFilterContext filter_context;
848 filter_context.SetURL(url);
849 scoped_ptr<Filter> filter(
850 SdchFilterChainingTest::Factory(filter_types, filter_context,
851 kLargeInputBufferSize));
852 EXPECT_EQ(static_cast<int>(kLargeInputBufferSize),
853 filter->stream_buffer_size());
855 // Verify that chained filter is waiting for data.
856 char tiny_output_buffer[10];
857 int tiny_output_size = sizeof(tiny_output_buffer);
858 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
859 filter->ReadData(tiny_output_buffer, &tiny_output_size));
861 // Make chain process all data.
862 size_t feed_block_size = kLargeInputBufferSize;
863 size_t output_block_size = kLargeInputBufferSize;
864 std::string output;
865 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
866 output_block_size, filter.get(), &output));
867 EXPECT_EQ(output, expanded_);
869 // Next try with a mid-sized internal buffer size.
870 const size_t kMidSizedInputBufferSize(100);
871 // Buffer should be big enough to swallow whole gzip content.
872 CHECK_GT(kMidSizedInputBufferSize, gzip_compressed_sdch.size());
873 // Buffer should be small enough that entire SDCH content can't fit.
874 // We'll go even further, and force the chain to flush the buffer between the
875 // two filters more than once (that is why we multiply by 2).
876 CHECK_LT(kMidSizedInputBufferSize * 2, sdch_compressed.size());
877 filter_context.SetURL(url);
878 filter.reset(
879 SdchFilterChainingTest::Factory(filter_types, filter_context,
880 kMidSizedInputBufferSize));
881 EXPECT_EQ(static_cast<int>(kMidSizedInputBufferSize),
882 filter->stream_buffer_size());
884 feed_block_size = kMidSizedInputBufferSize;
885 output_block_size = kMidSizedInputBufferSize;
886 output.clear();
887 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
888 output_block_size, filter.get(), &output));
889 EXPECT_EQ(output, expanded_);
891 // Next try with a tiny input and output buffer to cover edge effects.
892 filter.reset(SdchFilterChainingTest::Factory(filter_types, filter_context,
893 kLargeInputBufferSize));
894 EXPECT_EQ(static_cast<int>(kLargeInputBufferSize),
895 filter->stream_buffer_size());
897 feed_block_size = 1;
898 output_block_size = 1;
899 output.clear();
900 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
901 output_block_size, filter.get(), &output));
902 EXPECT_EQ(output, expanded_);
905 TEST_F(SdchFilterTest, DefaultGzipIfSdch) {
906 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
907 const std::string kSampleDomain = "sdchtest.com";
908 std::string dictionary(NewSdchDictionary(kSampleDomain));
910 std::string url_string = "http://" + kSampleDomain;
912 GURL url(url_string);
913 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
915 std::string sdch_compressed(NewSdchCompressedData(dictionary));
917 // Use Gzip to compress the sdch sdch_compressed data.
918 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
920 // Only claim to have sdch content, but really use the gzipped sdch content.
921 // System should automatically add the missing (optional) gzip.
922 std::vector<Filter::FilterType> filter_types;
923 filter_types.push_back(Filter::FILTER_TYPE_SDCH);
925 MockFilterContext filter_context;
926 filter_context.SetMimeType("anything/mime");
927 filter_context.SetSdchResponse(true);
928 Filter::FixupEncodingTypes(filter_context, &filter_types);
929 ASSERT_EQ(filter_types.size(), 2u);
930 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH);
931 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
933 // First try with a large buffer (larger than test input, or compressed data).
934 filter_context.SetURL(url);
935 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
938 // Verify that chained filter is waiting for data.
939 char tiny_output_buffer[10];
940 int tiny_output_size = sizeof(tiny_output_buffer);
941 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
942 filter->ReadData(tiny_output_buffer, &tiny_output_size));
944 size_t feed_block_size = 100;
945 size_t output_block_size = 100;
946 std::string output;
947 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
948 output_block_size, filter.get(), &output));
949 EXPECT_EQ(output, expanded_);
951 // Next try with a tiny buffer to cover edge effects.
952 filter.reset(Filter::Factory(filter_types, filter_context));
954 feed_block_size = 1;
955 output_block_size = 1;
956 output.clear();
957 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
958 output_block_size, filter.get(), &output));
959 EXPECT_EQ(output, expanded_);
962 TEST_F(SdchFilterTest, AcceptGzipSdchIfGzip) {
963 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
964 const std::string kSampleDomain = "sdchtest.com";
965 std::string dictionary(NewSdchDictionary(kSampleDomain));
967 std::string url_string = "http://" + kSampleDomain;
969 GURL url(url_string);
970 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
972 std::string sdch_compressed(NewSdchCompressedData(dictionary));
974 // Use Gzip to compress the sdch sdch_compressed data.
975 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
977 // Some proxies strip the content encoding statement down to a mere gzip, but
978 // pass through the original content (with full sdch,gzip encoding).
979 // Only claim to have gzip content, but really use the gzipped sdch content.
980 // System should automatically add the missing (optional) sdch.
981 std::vector<Filter::FilterType> filter_types;
982 filter_types.push_back(Filter::FILTER_TYPE_GZIP);
984 MockFilterContext filter_context;
985 filter_context.SetMimeType("anything/mime");
986 filter_context.SetSdchResponse(true);
987 Filter::FixupEncodingTypes(filter_context, &filter_types);
988 ASSERT_EQ(filter_types.size(), 3u);
989 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
990 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
991 EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
993 // First try with a large buffer (larger than test input, or compressed data).
994 filter_context.SetURL(url);
995 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
998 // Verify that chained filter is waiting for data.
999 char tiny_output_buffer[10];
1000 int tiny_output_size = sizeof(tiny_output_buffer);
1001 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
1002 filter->ReadData(tiny_output_buffer, &tiny_output_size));
1004 size_t feed_block_size = 100;
1005 size_t output_block_size = 100;
1006 std::string output;
1007 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1008 output_block_size, filter.get(), &output));
1009 EXPECT_EQ(output, expanded_);
1011 // Next try with a tiny buffer to cover edge effects.
1012 filter.reset(Filter::Factory(filter_types, filter_context));
1014 feed_block_size = 1;
1015 output_block_size = 1;
1016 output.clear();
1017 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1018 output_block_size, filter.get(), &output));
1019 EXPECT_EQ(output, expanded_);
1022 TEST_F(SdchFilterTest, DefaultSdchGzipIfEmpty) {
1023 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
1024 const std::string kSampleDomain = "sdchtest.com";
1025 std::string dictionary(NewSdchDictionary(kSampleDomain));
1027 std::string url_string = "http://" + kSampleDomain;
1029 GURL url(url_string);
1030 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
1032 std::string sdch_compressed(NewSdchCompressedData(dictionary));
1034 // Use Gzip to compress the sdch sdch_compressed data.
1035 std::string gzip_compressed_sdch = gzip_compress(sdch_compressed);
1037 // Only claim to have non-encoded content, but really use the gzipped sdch
1038 // content.
1039 // System should automatically add the missing (optional) sdch,gzip.
1040 std::vector<Filter::FilterType> filter_types;
1042 MockFilterContext filter_context;
1043 filter_context.SetMimeType("anything/mime");
1044 filter_context.SetSdchResponse(true);
1045 Filter::FixupEncodingTypes(filter_context, &filter_types);
1046 ASSERT_EQ(filter_types.size(), 2u);
1047 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
1048 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
1050 // First try with a large buffer (larger than test input, or compressed data).
1051 filter_context.SetURL(url);
1052 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
1055 // Verify that chained filter is waiting for data.
1056 char tiny_output_buffer[10];
1057 int tiny_output_size = sizeof(tiny_output_buffer);
1058 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
1059 filter->ReadData(tiny_output_buffer, &tiny_output_size));
1061 size_t feed_block_size = 100;
1062 size_t output_block_size = 100;
1063 std::string output;
1064 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1065 output_block_size, filter.get(), &output));
1066 EXPECT_EQ(output, expanded_);
1068 // Next try with a tiny buffer to cover edge effects.
1069 filter.reset(Filter::Factory(filter_types, filter_context));
1071 feed_block_size = 1;
1072 output_block_size = 1;
1073 output.clear();
1074 EXPECT_TRUE(FilterTestData(gzip_compressed_sdch, feed_block_size,
1075 output_block_size, filter.get(), &output));
1076 EXPECT_EQ(output, expanded_);
1079 TEST_F(SdchFilterTest, AcceptGzipGzipSdchIfGzip) {
1080 // Construct a valid SDCH dictionary from a VCDIFF dictionary.
1081 const std::string kSampleDomain = "sdchtest.com";
1082 std::string dictionary(NewSdchDictionary(kSampleDomain));
1084 std::string url_string = "http://" + kSampleDomain;
1086 GURL url(url_string);
1087 EXPECT_TRUE(sdch_manager_->AddSdchDictionary(dictionary, url));
1089 std::string sdch_compressed(NewSdchCompressedData(dictionary));
1091 // Vodaphone (UK) Mobile Broadband provides double gzipped sdch with a content
1092 // encoding of merely gzip (apparently, only listing the extra level of
1093 // wrapper compression they added, but discarding the actual content encoding.
1094 // Use Gzip to double compress the sdch sdch_compressed data.
1095 std::string double_gzip_compressed_sdch = gzip_compress(gzip_compress(
1096 sdch_compressed));
1098 // Only claim to have gzip content, but really use the double gzipped sdch
1099 // content.
1100 // System should automatically add the missing (optional) sdch, gzip decoders.
1101 std::vector<Filter::FilterType> filter_types;
1102 filter_types.push_back(Filter::FILTER_TYPE_GZIP);
1104 MockFilterContext filter_context;
1105 filter_context.SetMimeType("anything/mime");
1106 filter_context.SetSdchResponse(true);
1107 Filter::FixupEncodingTypes(filter_context, &filter_types);
1108 ASSERT_EQ(filter_types.size(), 3u);
1109 EXPECT_EQ(filter_types[0], Filter::FILTER_TYPE_SDCH_POSSIBLE);
1110 EXPECT_EQ(filter_types[1], Filter::FILTER_TYPE_GZIP_HELPING_SDCH);
1111 EXPECT_EQ(filter_types[2], Filter::FILTER_TYPE_GZIP);
1113 // First try with a large buffer (larger than test input, or compressed data).
1114 filter_context.SetURL(url);
1115 scoped_ptr<Filter> filter(Filter::Factory(filter_types, filter_context));
1117 // Verify that chained filter is waiting for data.
1118 char tiny_output_buffer[10];
1119 int tiny_output_size = sizeof(tiny_output_buffer);
1120 EXPECT_EQ(Filter::FILTER_NEED_MORE_DATA,
1121 filter->ReadData(tiny_output_buffer, &tiny_output_size));
1123 size_t feed_block_size = 100;
1124 size_t output_block_size = 100;
1125 std::string output;
1126 EXPECT_TRUE(FilterTestData(double_gzip_compressed_sdch, feed_block_size,
1127 output_block_size, filter.get(), &output));
1128 EXPECT_EQ(output, expanded_);
1130 // Next try with a tiny buffer to cover edge effects.
1131 filter.reset(Filter::Factory(filter_types, filter_context));
1133 feed_block_size = 1;
1134 output_block_size = 1;
1135 output.clear();
1136 EXPECT_TRUE(FilterTestData(double_gzip_compressed_sdch, feed_block_size,
1137 output_block_size, filter.get(), &output));
1138 EXPECT_EQ(output, expanded_);
1141 } // namespace net