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 "net/base/io_buffer.h"
6 #include "net/filter/filter.h"
7 #include "net/filter/mock_filter_context.h"
8 #include "testing/gtest/include/gtest/gtest.h"
14 class PassThroughFilter
: public Filter
{
16 PassThroughFilter() : Filter(FILTER_TYPE_UNSUPPORTED
) {}
18 FilterStatus
ReadFilteredData(char* dest_buffer
, int* dest_len
) override
{
19 return CopyOut(dest_buffer
, dest_len
);
22 DISALLOW_COPY_AND_ASSIGN(PassThroughFilter
);
27 TEST(FilterTest
, ContentTypeId
) {
28 // Check for basic translation of Content-Encoding, including case variations.
29 EXPECT_EQ(Filter::FILTER_TYPE_DEFLATE
,
30 Filter::ConvertEncodingToType("deflate"));
31 EXPECT_EQ(Filter::FILTER_TYPE_DEFLATE
,
32 Filter::ConvertEncodingToType("deflAte"));
33 EXPECT_EQ(Filter::FILTER_TYPE_GZIP
,
34 Filter::ConvertEncodingToType("gzip"));
35 EXPECT_EQ(Filter::FILTER_TYPE_GZIP
,
36 Filter::ConvertEncodingToType("GzIp"));
37 EXPECT_EQ(Filter::FILTER_TYPE_GZIP
,
38 Filter::ConvertEncodingToType("x-gzip"));
39 EXPECT_EQ(Filter::FILTER_TYPE_GZIP
,
40 Filter::ConvertEncodingToType("X-GzIp"));
41 EXPECT_EQ(Filter::FILTER_TYPE_SDCH
,
42 Filter::ConvertEncodingToType("sdch"));
43 EXPECT_EQ(Filter::FILTER_TYPE_SDCH
,
44 Filter::ConvertEncodingToType("sDcH"));
45 EXPECT_EQ(Filter::FILTER_TYPE_UNSUPPORTED
,
46 Filter::ConvertEncodingToType("weird"));
47 EXPECT_EQ(Filter::FILTER_TYPE_UNSUPPORTED
,
48 Filter::ConvertEncodingToType("strange"));
51 TEST(FilterTest
, SdchEncoding
) {
52 // Handle content encodings including SDCH.
53 const std::string
kTextHtmlMime("text/html");
54 MockFilterContext filter_context
;
55 // Empty handle indicates to filter that SDCH is active.
56 filter_context
.SetSdchResponse(
57 SdchManager::CreateEmptyDictionarySetForTesting().Pass());
59 std::vector
<Filter::FilterType
> encoding_types
;
61 // Check for most common encoding, and verify it survives unchanged.
62 encoding_types
.clear();
63 encoding_types
.push_back(Filter::FILTER_TYPE_SDCH
);
64 encoding_types
.push_back(Filter::FILTER_TYPE_GZIP
);
65 filter_context
.SetMimeType(kTextHtmlMime
);
66 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
67 ASSERT_EQ(2U, encoding_types
.size());
68 EXPECT_EQ(Filter::FILTER_TYPE_SDCH
, encoding_types
[0]);
69 EXPECT_EQ(Filter::FILTER_TYPE_GZIP
, encoding_types
[1]);
71 // Unchanged even with other mime types.
72 encoding_types
.clear();
73 encoding_types
.push_back(Filter::FILTER_TYPE_SDCH
);
74 encoding_types
.push_back(Filter::FILTER_TYPE_GZIP
);
75 filter_context
.SetMimeType("other/type");
76 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
77 ASSERT_EQ(2U, encoding_types
.size());
78 EXPECT_EQ(Filter::FILTER_TYPE_SDCH
, encoding_types
[0]);
79 EXPECT_EQ(Filter::FILTER_TYPE_GZIP
, encoding_types
[1]);
81 // Solo SDCH is extended to include optional gunzip.
82 encoding_types
.clear();
83 encoding_types
.push_back(Filter::FILTER_TYPE_SDCH
);
84 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
85 ASSERT_EQ(2U, encoding_types
.size());
86 EXPECT_EQ(Filter::FILTER_TYPE_SDCH
, encoding_types
[0]);
87 EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH
, encoding_types
[1]);
90 TEST(FilterTest
, MissingSdchEncoding
) {
91 // Handle interesting case where entire SDCH encoding assertion "got lost."
92 const std::string
kTextHtmlMime("text/html");
93 MockFilterContext filter_context
;
94 filter_context
.SetSdchResponse(
95 SdchManager::CreateEmptyDictionarySetForTesting().Pass());
97 std::vector
<Filter::FilterType
> encoding_types
;
99 // Loss of encoding, but it was an SDCH response with html type.
100 encoding_types
.clear();
101 filter_context
.SetMimeType(kTextHtmlMime
);
102 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
103 ASSERT_EQ(2U, encoding_types
.size());
104 EXPECT_EQ(Filter::FILTER_TYPE_SDCH_POSSIBLE
, encoding_types
[0]);
105 EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH
, encoding_types
[1]);
107 // Loss of encoding, but it was an SDCH response with a prefix that says it
108 // was an html type. Note that it *should* be the case that a precise match
109 // with "text/html" we be collected by GetMimeType() and passed in, but we
110 // coded the fixup defensively (scanning for a prefix of "text/html", so this
111 // is an example which could survive such confusion in the caller).
112 encoding_types
.clear();
113 filter_context
.SetMimeType("text/html; charset=UTF-8");
114 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
115 ASSERT_EQ(2U, encoding_types
.size());
116 EXPECT_EQ(Filter::FILTER_TYPE_SDCH_POSSIBLE
, encoding_types
[0]);
117 EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH
, encoding_types
[1]);
119 // No encoding, but it was an SDCH response with non-html type.
120 encoding_types
.clear();
121 filter_context
.SetMimeType("other/mime");
122 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
123 ASSERT_EQ(2U, encoding_types
.size());
124 EXPECT_EQ(Filter::FILTER_TYPE_SDCH_POSSIBLE
, encoding_types
[0]);
125 EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH
, encoding_types
[1]);
128 // FixupEncodingTypes() should leave gzip encoding intact.
129 TEST(FilterTest
, Gzip
) {
130 const std::string
kUrl("http://example.com/foo");
131 MockFilterContext filter_context
;
132 std::vector
<Filter::FilterType
> encoding_types
;
133 filter_context
.SetURL(GURL(kUrl
));
135 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
136 EXPECT_EQ(0U, encoding_types
.size());
138 encoding_types
.clear();
139 encoding_types
.push_back(Filter::FILTER_TYPE_GZIP
);
140 Filter::FixupEncodingTypes(filter_context
, &encoding_types
);
141 ASSERT_EQ(1U, encoding_types
.size());
142 EXPECT_EQ(Filter::FILTER_TYPE_GZIP
, encoding_types
.front());
145 // Make sure a series of three pass-through filters copies the data cleanly.
146 // Regression test for http://crbug.com/418975.
147 TEST(FilterTest
, ThreeFilterChain
) {
148 scoped_ptr
<PassThroughFilter
> filter1(new PassThroughFilter
);
149 scoped_ptr
<PassThroughFilter
> filter2(new PassThroughFilter
);
150 scoped_ptr
<PassThroughFilter
> filter3(new PassThroughFilter
);
152 filter1
->InitBuffer(32 * 1024);
153 filter2
->InitBuffer(32 * 1024);
154 filter3
->InitBuffer(32 * 1024);
156 filter2
->next_filter_
= filter3
.Pass();
157 filter1
->next_filter_
= filter2
.Pass();
159 // Initialize the input array with a varying byte sequence.
160 const size_t input_array_size
= 64 * 1024;
161 char input_array
[input_array_size
];
162 size_t read_array_index
= 0;
163 for (size_t i
= 0; i
< input_array_size
; i
++) {
164 input_array
[i
] = i
% 113;
167 const size_t output_array_size
= 4 * 1024;
168 char output_array
[output_array_size
];
170 size_t compare_array_index
= 0;
173 // Read data from the filter chain.
174 int amount_read
= output_array_size
;
175 Filter::FilterStatus status
= filter1
->ReadData(output_array
, &amount_read
);
176 EXPECT_NE(Filter::FILTER_ERROR
, status
);
177 EXPECT_EQ(0, memcmp(output_array
, input_array
+ compare_array_index
,
179 compare_array_index
+= amount_read
;
181 // Detect the various indications that data transfer along the chain is
183 if (Filter::FILTER_DONE
== status
|| Filter::FILTER_ERROR
== status
||
184 (Filter::FILTER_OK
== status
&& amount_read
== 0) ||
185 (Filter::FILTER_NEED_MORE_DATA
== status
&&
186 read_array_index
== input_array_size
))
189 if (Filter::FILTER_OK
== status
)
192 // Write needed data into the filter chain.
193 ASSERT_EQ(Filter::FILTER_NEED_MORE_DATA
, status
);
194 ASSERT_NE(0, filter1
->stream_buffer_size());
195 size_t amount_to_copy
= std::min(
196 static_cast<size_t>(filter1
->stream_buffer_size()),
197 input_array_size
- read_array_index
);
198 memcpy(filter1
->stream_buffer()->data(),
199 input_array
+ read_array_index
,
201 filter1
->FlushStreamBuffer(amount_to_copy
);
202 read_array_index
+= amount_to_copy
;
205 EXPECT_EQ(read_array_index
, input_array_size
);
206 EXPECT_EQ(compare_array_index
, input_array_size
);