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.
4
5#include "net/filter/filter.h"
6#include "net/filter/mock_filter_context.h"
7#include "testing/gtest/include/gtest/gtest.h"
8
9namespace net {
10
11class FilterTest : public testing::Test {
12};
13
14TEST(FilterTest, ContentTypeId) {
15  // Check for basic translation of Content-Encoding, including case variations.
16  EXPECT_EQ(Filter::FILTER_TYPE_DEFLATE,
17            Filter::ConvertEncodingToType("deflate"));
18  EXPECT_EQ(Filter::FILTER_TYPE_DEFLATE,
19            Filter::ConvertEncodingToType("deflAte"));
20  EXPECT_EQ(Filter::FILTER_TYPE_GZIP,
21            Filter::ConvertEncodingToType("gzip"));
22  EXPECT_EQ(Filter::FILTER_TYPE_GZIP,
23            Filter::ConvertEncodingToType("GzIp"));
24  EXPECT_EQ(Filter::FILTER_TYPE_GZIP,
25            Filter::ConvertEncodingToType("x-gzip"));
26  EXPECT_EQ(Filter::FILTER_TYPE_GZIP,
27            Filter::ConvertEncodingToType("X-GzIp"));
28  EXPECT_EQ(Filter::FILTER_TYPE_SDCH,
29            Filter::ConvertEncodingToType("sdch"));
30  EXPECT_EQ(Filter::FILTER_TYPE_SDCH,
31            Filter::ConvertEncodingToType("sDcH"));
32  EXPECT_EQ(Filter::FILTER_TYPE_UNSUPPORTED,
33            Filter::ConvertEncodingToType("weird"));
34  EXPECT_EQ(Filter::FILTER_TYPE_UNSUPPORTED,
35            Filter::ConvertEncodingToType("strange"));
36}
37
38// Check various fixups that modify content encoding lists.
39TEST(FilterTest, ApacheGzip) {
40  MockFilterContext filter_context;
41  filter_context.SetSdchResponse(false);
42
43  // Check that redundant gzip mime type removes only solo gzip encoding.
44  const std::string kGzipMime1("application/x-gzip");
45  const std::string kGzipMime2("application/gzip");
46  const std::string kGzipMime3("application/x-gunzip");
47  std::vector<Filter::FilterType> encoding_types;
48
49  // First show it removes the gzip, given any gzip style mime type.
50  encoding_types.clear();
51  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
52  filter_context.SetMimeType(kGzipMime1);
53  Filter::FixupEncodingTypes(filter_context, &encoding_types);
54  EXPECT_TRUE(encoding_types.empty());
55
56  encoding_types.clear();
57  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
58  filter_context.SetMimeType(kGzipMime2);
59  Filter::FixupEncodingTypes(filter_context, &encoding_types);
60  EXPECT_TRUE(encoding_types.empty());
61
62  encoding_types.clear();
63  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
64  filter_context.SetMimeType(kGzipMime3);
65  Filter::FixupEncodingTypes(filter_context, &encoding_types);
66  EXPECT_TRUE(encoding_types.empty());
67
68  // Check to be sure it doesn't remove everything when it has such a type.
69  encoding_types.clear();
70  encoding_types.push_back(Filter::FILTER_TYPE_SDCH);
71  filter_context.SetMimeType(kGzipMime1);
72  Filter::FixupEncodingTypes(filter_context, &encoding_types);
73  ASSERT_EQ(1U, encoding_types.size());
74  EXPECT_EQ(Filter::FILTER_TYPE_SDCH, encoding_types.front());
75
76  // Check to be sure that gzip can survive with other mime types.
77  encoding_types.clear();
78  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
79  filter_context.SetMimeType("other/mime");
80  Filter::FixupEncodingTypes(filter_context, &encoding_types);
81  ASSERT_EQ(1U, encoding_types.size());
82  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
83}
84
85TEST(FilterTest, GzipContentDispositionFilename) {
86  MockFilterContext filter_context;
87  filter_context.SetSdchResponse(false);
88
89  const std::string kGzipMime("application/x-tar");
90  const std::string kContentDisposition("attachment; filename=\"foo.tgz\"");
91  const std::string kURL("http://foo.com/getfoo.php");
92  std::vector<Filter::FilterType> encoding_types;
93
94  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
95  filter_context.SetMimeType(kGzipMime);
96  filter_context.SetURL(GURL(kURL));
97  filter_context.SetContentDisposition(kContentDisposition);
98  Filter::FixupEncodingTypes(filter_context, &encoding_types);
99  ASSERT_EQ(0U, encoding_types.size());
100}
101
102TEST(FilterTest, SdchEncoding) {
103  // Handle content encodings including SDCH.
104  const std::string kTextHtmlMime("text/html");
105  MockFilterContext filter_context;
106  filter_context.SetSdchResponse(true);
107
108  std::vector<Filter::FilterType> encoding_types;
109
110  // Check for most common encoding, and verify it survives unchanged.
111  encoding_types.clear();
112  encoding_types.push_back(Filter::FILTER_TYPE_SDCH);
113  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
114  filter_context.SetMimeType(kTextHtmlMime);
115  Filter::FixupEncodingTypes(filter_context, &encoding_types);
116  ASSERT_EQ(2U, encoding_types.size());
117  EXPECT_EQ(Filter::FILTER_TYPE_SDCH, encoding_types[0]);
118  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types[1]);
119
120  // Unchanged even with other mime types.
121  encoding_types.clear();
122  encoding_types.push_back(Filter::FILTER_TYPE_SDCH);
123  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
124  filter_context.SetMimeType("other/type");
125  Filter::FixupEncodingTypes(filter_context, &encoding_types);
126  ASSERT_EQ(2U, encoding_types.size());
127  EXPECT_EQ(Filter::FILTER_TYPE_SDCH, encoding_types[0]);
128  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types[1]);
129
130  // Solo SDCH is extended to include optional gunzip.
131  encoding_types.clear();
132  encoding_types.push_back(Filter::FILTER_TYPE_SDCH);
133  Filter::FixupEncodingTypes(filter_context, &encoding_types);
134  ASSERT_EQ(2U, encoding_types.size());
135  EXPECT_EQ(Filter::FILTER_TYPE_SDCH, encoding_types[0]);
136  EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH, encoding_types[1]);
137}
138
139TEST(FilterTest, MissingSdchEncoding) {
140  // Handle interesting case where entire SDCH encoding assertion "got lost."
141  const std::string kTextHtmlMime("text/html");
142  MockFilterContext filter_context;
143  filter_context.SetSdchResponse(true);
144
145  std::vector<Filter::FilterType> encoding_types;
146
147  // Loss of encoding, but it was an SDCH response with html type.
148  encoding_types.clear();
149  filter_context.SetMimeType(kTextHtmlMime);
150  Filter::FixupEncodingTypes(filter_context, &encoding_types);
151  ASSERT_EQ(2U, encoding_types.size());
152  EXPECT_EQ(Filter::FILTER_TYPE_SDCH_POSSIBLE, encoding_types[0]);
153  EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH, encoding_types[1]);
154
155  // Loss of encoding, but it was an SDCH response with a prefix that says it
156  // was an html type.  Note that it *should* be the case that a precise match
157  // with "text/html" we be collected by GetMimeType() and passed in, but we
158  // coded the fixup defensively (scanning for a prefix of "text/html", so this
159  // is an example which could survive such confusion in the caller).
160  encoding_types.clear();
161  filter_context.SetMimeType("text/html; charset=UTF-8");
162  Filter::FixupEncodingTypes(filter_context, &encoding_types);
163  ASSERT_EQ(2U, encoding_types.size());
164  EXPECT_EQ(Filter::FILTER_TYPE_SDCH_POSSIBLE, encoding_types[0]);
165  EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH, encoding_types[1]);
166
167  // No encoding, but it was an SDCH response with non-html type.
168  encoding_types.clear();
169  filter_context.SetMimeType("other/mime");
170  Filter::FixupEncodingTypes(filter_context, &encoding_types);
171  ASSERT_EQ(2U, encoding_types.size());
172  EXPECT_EQ(Filter::FILTER_TYPE_SDCH_POSSIBLE, encoding_types[0]);
173  EXPECT_EQ(Filter::FILTER_TYPE_GZIP_HELPING_SDCH, encoding_types[1]);
174}
175
176TEST(FilterTest, Svgz) {
177  MockFilterContext filter_context;
178
179  // Check that svgz files are only decompressed when not downloading.
180  const std::string kSvgzMime("image/svg+xml");
181  const std::string kSvgzUrl("http://ignore.com/foo.svgz");
182  const std::string kSvgUrl("http://ignore.com/foo.svg");
183  std::vector<Filter::FilterType> encoding_types;
184
185  // Test svgz extension
186  encoding_types.clear();
187  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
188  filter_context.SetDownload(false);
189  filter_context.SetMimeType(kSvgzMime);
190  filter_context.SetURL(GURL(kSvgzUrl));
191  Filter::FixupEncodingTypes(filter_context, &encoding_types);
192  ASSERT_EQ(1U, encoding_types.size());
193  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
194
195  encoding_types.clear();
196  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
197  filter_context.SetDownload(true);
198  filter_context.SetMimeType(kSvgzMime);
199  filter_context.SetURL(GURL(kSvgzUrl));
200  Filter::FixupEncodingTypes(filter_context, &encoding_types);
201  EXPECT_TRUE(encoding_types.empty());
202
203  // Test svg extension
204  encoding_types.clear();
205  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
206  filter_context.SetDownload(false);
207  filter_context.SetMimeType(kSvgzMime);
208  filter_context.SetURL(GURL(kSvgUrl));
209  Filter::FixupEncodingTypes(filter_context, &encoding_types);
210  ASSERT_EQ(1U, encoding_types.size());
211  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
212
213  encoding_types.clear();
214  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
215  filter_context.SetDownload(true);
216  filter_context.SetMimeType(kSvgzMime);
217  filter_context.SetURL(GURL(kSvgUrl));
218  Filter::FixupEncodingTypes(filter_context, &encoding_types);
219  ASSERT_EQ(1U, encoding_types.size());
220  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
221}
222
223TEST(FilterTest, UnsupportedMimeGzip) {
224  // From issue 8170 - handling files with Content-Encoding: x-gzip
225  MockFilterContext filter_context;
226  std::vector<Filter::FilterType> encoding_types;
227  const std::string kTarMime("application/x-tar");
228  const std::string kCpioMime("application/x-cpio");
229  const std::string kTarUrl("http://ignore.com/foo.tar");
230  const std::string kTargzUrl("http://ignore.com/foo.tar.gz");
231  const std::string kTgzUrl("http://ignore.com/foo.tgz");
232  const std::string kBadTgzUrl("http://ignore.com/foo.targz");
233  const std::string kUrl("http://ignore.com/foo");
234
235  // Firefox 3 does not decompress when we have unsupported mime types for
236  // certain filenames.
237  encoding_types.clear();
238  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
239  filter_context.SetDownload(false);
240  filter_context.SetMimeType(kTarMime);
241  filter_context.SetURL(GURL(kTargzUrl));
242  Filter::FixupEncodingTypes(filter_context, &encoding_types);
243  EXPECT_TRUE(encoding_types.empty());
244
245  encoding_types.clear();
246  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
247  filter_context.SetDownload(false);
248  filter_context.SetMimeType(kTarMime);
249  filter_context.SetURL(GURL(kTgzUrl));
250  Filter::FixupEncodingTypes(filter_context, &encoding_types);
251  EXPECT_TRUE(encoding_types.empty());
252
253  encoding_types.clear();
254  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
255  filter_context.SetDownload(false);
256  filter_context.SetMimeType(kCpioMime);
257  filter_context.SetURL(GURL(kTgzUrl));
258  Filter::FixupEncodingTypes(filter_context, &encoding_types);
259  EXPECT_TRUE(encoding_types.empty());
260
261  // Same behavior for downloads.
262  encoding_types.clear();
263  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
264  filter_context.SetDownload(true);
265  filter_context.SetMimeType(kCpioMime);
266  filter_context.SetURL(GURL(kTgzUrl));
267  Filter::FixupEncodingTypes(filter_context, &encoding_types);
268  EXPECT_TRUE(encoding_types.empty());
269
270  // Unsupported mime type with wrong file name, decompressed.
271  encoding_types.clear();
272  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
273  filter_context.SetDownload(false);
274  filter_context.SetMimeType(kTarMime);
275  filter_context.SetURL(GURL(kUrl));
276  Filter::FixupEncodingTypes(filter_context, &encoding_types);
277  ASSERT_EQ(1U, encoding_types.size());
278  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
279
280  encoding_types.clear();
281  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
282  filter_context.SetDownload(false);
283  filter_context.SetMimeType(kTarMime);
284  filter_context.SetURL(GURL(kTarUrl));
285  Filter::FixupEncodingTypes(filter_context, &encoding_types);
286  ASSERT_EQ(1U, encoding_types.size());
287  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
288
289  encoding_types.clear();
290  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
291  filter_context.SetDownload(false);
292  filter_context.SetMimeType(kTarMime);
293  filter_context.SetURL(GURL(kBadTgzUrl));
294  Filter::FixupEncodingTypes(filter_context, &encoding_types);
295  ASSERT_EQ(1U, encoding_types.size());
296  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
297
298  // Same behavior for downloads.
299  encoding_types.clear();
300  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
301  filter_context.SetDownload(true);
302  filter_context.SetMimeType(kTarMime);
303  filter_context.SetURL(GURL(kBadTgzUrl));
304  Filter::FixupEncodingTypes(filter_context, &encoding_types);
305  ASSERT_EQ(1U, encoding_types.size());
306  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
307}
308
309TEST(FilterTest, SupportedMimeGzip) {
310  // From issue 16430 - Files with supported mime types should be decompressed,
311  // even though these files end in .gz/.tgz.
312  MockFilterContext filter_context;
313  std::vector<Filter::FilterType> encoding_types;
314  const std::string kGzUrl("http://ignore.com/foo.gz");
315  const std::string kUrl("http://ignore.com/foo");
316  const std::string kHtmlMime("text/html");
317  const std::string kJavascriptMime("text/javascript");
318
319  // For files that does not end in .gz/.tgz, we always decompress.
320  encoding_types.clear();
321  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
322  filter_context.SetDownload(false);
323  filter_context.SetMimeType(kHtmlMime);
324  filter_context.SetURL(GURL(kUrl));
325  Filter::FixupEncodingTypes(filter_context, &encoding_types);
326  ASSERT_EQ(1U, encoding_types.size());
327  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
328
329  encoding_types.clear();
330  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
331  filter_context.SetDownload(true);
332  filter_context.SetMimeType(kHtmlMime);
333  filter_context.SetURL(GURL(kUrl));
334  Filter::FixupEncodingTypes(filter_context, &encoding_types);
335  ASSERT_EQ(1U, encoding_types.size());
336  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
337
338  // And also decompress files that end in .gz/.tgz.
339  encoding_types.clear();
340  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
341  filter_context.SetDownload(false);
342  filter_context.SetMimeType(kHtmlMime);
343  filter_context.SetURL(GURL(kGzUrl));
344  Filter::FixupEncodingTypes(filter_context, &encoding_types);
345  ASSERT_EQ(1U, encoding_types.size());
346  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
347
348  encoding_types.clear();
349  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
350  filter_context.SetDownload(false);
351  filter_context.SetMimeType(kJavascriptMime);
352  filter_context.SetURL(GURL(kGzUrl));
353  Filter::FixupEncodingTypes(filter_context, &encoding_types);
354  ASSERT_EQ(1U, encoding_types.size());
355  EXPECT_EQ(Filter::FILTER_TYPE_GZIP, encoding_types.front());
356
357  // Except on downloads, where they just get saved.
358  encoding_types.clear();
359  encoding_types.push_back(Filter::FILTER_TYPE_GZIP);
360  filter_context.SetDownload(true);
361  filter_context.SetMimeType(kHtmlMime);
362  filter_context.SetURL(GURL(kGzUrl));
363  Filter::FixupEncodingTypes(filter_context, &encoding_types);
364  EXPECT_TRUE(encoding_types.empty());
365}
366
367}  // namespace net
368