Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / http / http_content_disposition_unittest.cc
1 // Copyright (c) 2012 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/http/http_content_disposition.h"
6
7 #include "base/strings/utf_string_conversions.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9
10 namespace net {
11
12 namespace {
13
14 struct FileNameCDCase {
15   const char* header;
16   const char* referrer_charset;
17   const wchar_t* expected;
18 };
19
20 }  // anonymous namespace
21
22 TEST(HttpContentDispositionTest, Filename) {
23   const FileNameCDCase tests[] = {
24     // Test various forms of C-D header fields emitted by web servers.
25     {"inline; filename=\"abcde.pdf\"", "", L"abcde.pdf"},
26     {"inline; name=\"abcde.pdf\"", "", L"abcde.pdf"},
27     {"attachment; filename=abcde.pdf", "", L"abcde.pdf"},
28     {"attachment; name=abcde.pdf", "", L"abcde.pdf"},
29     {"attachment; filename=abc,de.pdf", "", L"abc,de.pdf"},
30     {"filename=abcde.pdf", "", L"abcde.pdf"},
31     {"filename= abcde.pdf", "", L"abcde.pdf"},
32     {"filename =abcde.pdf", "", L"abcde.pdf"},
33     {"filename = abcde.pdf", "", L"abcde.pdf"},
34     {"filename\t=abcde.pdf", "", L"abcde.pdf"},
35     {"filename \t\t  =abcde.pdf", "", L"abcde.pdf"},
36     {"name=abcde.pdf", "", L"abcde.pdf"},
37     {"inline; filename=\"abc%20de.pdf\"", "",
38      L"abc de.pdf"},
39     // Unbalanced quotation mark
40     {"filename=\"abcdef.pdf", "", L"abcdef.pdf"},
41     // Whitespaces are converted to a space.
42     {"inline; filename=\"abc  \t\nde.pdf\"", "",
43      L"abc    de.pdf"},
44     // %-escaped UTF-8
45     {"attachment; filename=\"%EC%98%88%EC%88%A0%20"
46      "%EC%98%88%EC%88%A0.jpg\"", "", L"\xc608\xc220 \xc608\xc220.jpg"},
47     {"attachment; filename=\"%F0%90%8C%B0%F0%90%8C%B1"
48      "abc.jpg\"", "", L"\U00010330\U00010331abc.jpg"},
49     {"attachment; filename=\"%EC%98%88%EC%88%A0 \n"
50      "%EC%98%88%EC%88%A0.jpg\"", "", L"\xc608\xc220  \xc608\xc220.jpg"},
51     // RFC 2047 with various charsets and Q/B encodings
52     {"attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
53      "D13=2Epng?=\"", "", L"\x82b8\x8853" L"3.png"},
54     {"attachment; filename==?eUc-Kr?b?v7m8+iAzLnBuZw==?=",
55      "", L"\xc608\xc220 3.png"},
56     {"attachment; filename==?utf-8?Q?=E8=8A=B8=E8"
57      "=A1=93_3=2Epng?=", "", L"\x82b8\x8853 3.png"},
58     {"attachment; filename==?utf-8?Q?=F0=90=8C=B0"
59      "_3=2Epng?=", "", L"\U00010330 3.png"},
60     {"inline; filename=\"=?iso88591?Q?caf=e9_=2epng?=\"",
61      "", L"caf\x00e9 .png"},
62     // Space after an encoded word should be removed.
63     {"inline; filename=\"=?iso88591?Q?caf=E9_?= .png\"",
64      "", L"caf\x00e9 .png"},
65     // Two encoded words with different charsets (not very likely to be emitted
66     // by web servers in the wild). Spaces between them are removed.
67     {"inline; filename=\"=?euc-kr?b?v7m8+iAz?="
68      " =?ksc5601?q?=BF=B9=BC=FA=2Epng?=\"", "",
69      L"\xc608\xc220 3\xc608\xc220.png"},
70     {"attachment; filename=\"=?windows-1252?Q?caf=E9?="
71      "  =?iso-8859-7?b?4eI=?= .png\"", "", L"caf\x00e9\x03b1\x03b2.png"},
72     // Non-ASCII string is passed through and treated as UTF-8 as long as
73     // it's valid as UTF-8 and regardless of |referrer_charset|.
74     {"attachment; filename=caf\xc3\xa9.png",
75      "iso-8859-1", L"caf\x00e9.png"},
76     {"attachment; filename=caf\xc3\xa9.png",
77      "", L"caf\x00e9.png"},
78     // Non-ASCII/Non-UTF-8 string. Fall back to the referrer charset.
79     {"attachment; filename=caf\xe5.png",
80      "windows-1253", L"caf\x03b5.png"},
81 #if 0
82     // Non-ASCII/Non-UTF-8 string. Fall back to the native codepage.
83     // TODO(jungshik): We need to set the OS default codepage
84     // to a specific value before testing. On Windows, we can use
85     // SetThreadLocale().
86     {"attachment; filename=\xb0\xa1\xb0\xa2.png",
87      "", L"\xac00\xac01.png"},
88 #endif
89     // Failure cases
90     // Invalid hex-digit "G"
91     {"attachment; filename==?iiso88591?Q?caf=EG?=", "",
92      L""},
93     // Incomplete RFC 2047 encoded-word (missing '='' at the end)
94     {"attachment; filename==?iso88591?Q?caf=E3?", "", L""},
95     // Extra character at the end of an encoded word
96     {"attachment; filename==?iso88591?Q?caf=E3?==",
97      "", L""},
98     // Extra token at the end of an encoded word
99     {"attachment; filename==?iso88591?Q?caf=E3?=?",
100      "", L""},
101     {"attachment; filename==?iso88591?Q?caf=E3?=?=",
102      "",  L""},
103     // Incomplete hex-escaped chars
104     {"attachment; filename==?windows-1252?Q?=63=61=E?=",
105      "", L""},
106     {"attachment; filename=%EC%98%88%EC%88%A", "", L""},
107     // %-escaped non-UTF-8 encoding is an "error"
108     {"attachment; filename=%B7%DD%BD%D1.png", "", L""},
109     // Two RFC 2047 encoded words in a row without a space is an error.
110     {"attachment; filename==?windows-1252?Q?caf=E3?="
111      "=?iso-8859-7?b?4eIucG5nCg==?=", "", L""},
112
113     // RFC 5987 tests with Filename*  : see http://tools.ietf.org/html/rfc5987
114     {"attachment; filename*=foo.html", "", L""},
115     {"attachment; filename*=foo'.html", "", L""},
116     {"attachment; filename*=''foo'.html", "", L""},
117     {"attachment; filename*=''foo.html'", "", L""},
118     {"attachment; filename*=''f\"oo\".html'", "", L""},
119     {"attachment; filename*=bogus_charset''foo.html'",
120      "", L""},
121     {"attachment; filename*='en'foo.html'", "", L""},
122     {"attachment; filename*=iso-8859-1'en'foo.html", "",
123       L"foo.html"},
124     {"attachment; filename*=utf-8'en'foo.html", "",
125       L"foo.html"},
126     // charset cannot be omitted.
127     {"attachment; filename*='es'f\xfa.html'", "", L""},
128     // Non-ASCII bytes are not allowed.
129     {"attachment; filename*=iso-8859-1'es'f\xfa.html", "",
130       L""},
131     {"attachment; filename*=utf-8'es'f\xce\xba.html", "",
132       L""},
133     // TODO(jshin): Space should be %-encoded, but currently, we allow
134     // spaces.
135     {"inline; filename*=iso88591''cafe foo.png", "",
136       L"cafe foo.png"},
137
138     // Filename* tests converted from Q-encoded tests above.
139     {"attachment; filename*=EUC-JP''%B7%DD%BD%D13%2Epng",
140      "", L"\x82b8\x8853" L"3.png"},
141     {"attachment; filename*=utf-8''"
142       "%E8%8A%B8%E8%A1%93%203%2Epng", "", L"\x82b8\x8853 3.png"},
143     {"attachment; filename*=utf-8''%F0%90%8C%B0 3.png", "",
144       L"\U00010330 3.png"},
145     {"inline; filename*=Euc-Kr'ko'%BF%B9%BC%FA%2Epng", "",
146      L"\xc608\xc220.png"},
147     {"attachment; filename*=windows-1252''caf%E9.png", "",
148       L"caf\x00e9.png"},
149
150     // Multiple filename, filename*, name parameters specified.
151     {"attachment; name=\"foo\"; filename=\"bar\"", "", L"bar"},
152     {"attachment; filename=\"bar\"; name=\"foo\"", "", L"bar"},
153     {"attachment; filename=\"bar\"; filename*=utf-8''baz", "", L"baz"},
154
155     // http://greenbytes.de/tech/tc2231/ filename* test cases.
156     // attwithisofn2231iso
157     {"attachment; filename*=iso-8859-1''foo-%E4.html", "",
158       L"foo-\xe4.html"},
159     // attwithfn2231utf8
160     {"attachment; filename*="
161       "UTF-8''foo-%c3%a4-%e2%82%ac.html", "", L"foo-\xe4-\x20ac.html"},
162     // attwithfn2231noc : no encoding specified but UTF-8 is used.
163     {"attachment; filename*=''foo-%c3%a4-%e2%82%ac.html",
164       "", L""},
165     // attwithfn2231utf8comp
166     {"attachment; filename*=UTF-8''foo-a%cc%88.html", "",
167       L"foo-\xe4.html"},
168 #ifdef ICU_SHOULD_FAIL_CONVERSION_ON_INVALID_CHARACTER
169     // This does not work because we treat ISO-8859-1 synonymous with
170     // Windows-1252 per HTML5. For HTTP, in theory, we're not
171     // supposed to.
172     // attwithfn2231utf8-bad
173     {"attachment; filename*="
174       "iso-8859-1''foo-%c3%a4-%e2%82%ac.html", "", L""},
175 #endif
176     // attwithfn2231ws1
177     {"attachment; filename *=UTF-8''foo-%c3%a4.html", "",
178       L""},
179     // attwithfn2231ws2
180     {"attachment; filename*= UTF-8''foo-%c3%a4.html", "",
181       L"foo-\xe4.html"},
182     // attwithfn2231ws3
183     {"attachment; filename* =UTF-8''foo-%c3%a4.html", "",
184       L"foo-\xe4.html"},
185     // attwithfn2231quot
186     {"attachment; filename*=\"UTF-8''foo-%c3%a4.html\"",
187       "", L""},
188     // attfnboth
189     {"attachment; filename=\"foo-ae.html\"; "
190       "filename*=UTF-8''foo-%c3%a4.html", "", L"foo-\xe4.html"},
191     // attfnboth2
192     {"attachment; filename*=UTF-8''foo-%c3%a4.html; "
193       "filename=\"foo-ae.html\"", "", L"foo-\xe4.html"},
194     // attnewandfn
195     {"attachment; foobar=x; filename=\"foo.html\"", "",
196       L"foo.html"},
197   };
198   for (size_t i = 0; i < arraysize(tests); ++i) {
199     HttpContentDisposition header(tests[i].header, tests[i].referrer_charset);
200     EXPECT_EQ(tests[i].expected,
201         base::UTF8ToWide(header.filename()))
202         << "Failed on input: " << tests[i].header;
203   }
204 }
205
206 // Test cases from http://greenbytes.de/tech/tc2231/
207 TEST(HttpContentDispositionTest, tc2231) {
208   const struct FileNameCDCase {
209     const char* header;
210     net::HttpContentDisposition::Type expected_type;
211     const wchar_t* expected_filename;
212   } tests[] = {
213     // http://greenbytes.de/tech/tc2231/#inlonly
214     { "inline",
215       net::HttpContentDisposition::INLINE,
216       L""
217     },
218     // http://greenbytes.de/tech/tc2231/#inlonlyquoted
219     { "\"inline\"",
220       net::HttpContentDisposition::INLINE,
221       L""
222     },
223     // http://greenbytes.de/tech/tc2231/#inlwithasciifilename
224     { "inline; filename=\"foo.html\"",
225       net::HttpContentDisposition::INLINE,
226       L"foo.html"
227     },
228     // http://greenbytes.de/tech/tc2231/#inlwithfnattach
229     { "inline; filename=\"Not an attachment!\"",
230       net::HttpContentDisposition::INLINE,
231       L"Not an attachment!"
232     },
233     // http://greenbytes.de/tech/tc2231/#inlwithasciifilenamepdf
234     { "inline; filename=\"foo.pdf\"",
235       net::HttpContentDisposition::INLINE,
236       L"foo.pdf"
237     },
238     // http://greenbytes.de/tech/tc2231/#attonly
239     { "attachment",
240       net::HttpContentDisposition::ATTACHMENT,
241       L""
242     },
243     // http://greenbytes.de/tech/tc2231/#attonlyquoted
244     { "\"attachment\"",
245       net::HttpContentDisposition::INLINE,
246       L""
247     },
248     // http://greenbytes.de/tech/tc2231/#attonly403
249     // TODO(abarth): This isn't testable in this unit test.
250     // http://greenbytes.de/tech/tc2231/#attonlyucase
251     { "ATTACHMENT",
252       net::HttpContentDisposition::ATTACHMENT,
253       L""
254     },
255     // http://greenbytes.de/tech/tc2231/#attwithasciifilename
256     { "attachment; filename=\"foo.html\"",
257       net::HttpContentDisposition::ATTACHMENT,
258       L"foo.html"
259     },
260     // http://greenbytes.de/tech/tc2231/#attwithasciifnescapedchar
261     { "attachment; filename=\"f\\oo.html\"",
262       net::HttpContentDisposition::ATTACHMENT,
263       L"foo.html"
264     },
265     // http://greenbytes.de/tech/tc2231/#attwithasciifnescapedquote
266     { "attachment; filename=\"\\\"quoting\\\" tested.html\"",
267       net::HttpContentDisposition::ATTACHMENT,
268       L"\"quoting\" tested.html"
269     },
270     // http://greenbytes.de/tech/tc2231/#attwithquotedsemicolon
271     { "attachment; filename=\"Here's a semicolon;.html\"",
272       net::HttpContentDisposition::ATTACHMENT,
273       L"Here's a semicolon;.html"
274     },
275     // http://greenbytes.de/tech/tc2231/#attwithfilenameandextparam
276     { "attachment; foo=\"bar\"; filename=\"foo.html\"",
277       net::HttpContentDisposition::ATTACHMENT,
278       L"foo.html"
279     },
280     // http://greenbytes.de/tech/tc2231/#attwithfilenameandextparamescaped
281     { "attachment; foo=\"\\\"\\\\\";filename=\"foo.html\"",
282       net::HttpContentDisposition::ATTACHMENT,
283       L"foo.html"
284     },
285     // http://greenbytes.de/tech/tc2231/#attwithasciifilenameucase
286     { "attachment; FILENAME=\"foo.html\"",
287       net::HttpContentDisposition::ATTACHMENT,
288       L"foo.html"
289     },
290     // http://greenbytes.de/tech/tc2231/#attwithasciifilenamenq
291     { "attachment; filename=foo.html",
292       net::HttpContentDisposition::ATTACHMENT,
293       L"foo.html"
294     },
295     // http://greenbytes.de/tech/tc2231/#attwithasciifilenamenqs
296     // Note: tc2231 says we should fail to parse this header.
297     { "attachment; filename=foo.html ;",
298       net::HttpContentDisposition::ATTACHMENT,
299       L"foo.html"
300     },
301     // http://greenbytes.de/tech/tc2231/#attemptyparam
302     // Note: tc2231 says we should fail to parse this header.
303     { "attachment; ;filename=foo",
304       net::HttpContentDisposition::ATTACHMENT,
305       L"foo"
306     },
307     // http://greenbytes.de/tech/tc2231/#attwithasciifilenamenqws
308     // Note: tc2231 says we should fail to parse this header.
309     { "attachment; filename=foo bar.html",
310       net::HttpContentDisposition::ATTACHMENT,
311       L"foo bar.html"
312     },
313     // http://greenbytes.de/tech/tc2231/#attwithfntokensq
314     { "attachment; filename='foo.bar'",
315       net::HttpContentDisposition::ATTACHMENT,
316       L"foo.bar"  // Should be L"'foo.bar'"
317     },
318 #ifdef ICU_SHOULD_FAIL_CONVERSION_ON_INVALID_CHARACTER
319     // http://greenbytes.de/tech/tc2231/#attwithisofnplain
320     { "attachment; filename=\"foo-\xE4html\"",
321       net::HttpContentDisposition::ATTACHMENT,
322       L""  // Should be L"foo-\xE4.html"
323     },
324 #endif
325     // http://greenbytes.de/tech/tc2231/#attwithutf8fnplain
326     // Note: We'll UTF-8 decode the file name, even though tc2231 says not to.
327     { "attachment; filename=\"foo-\xC3\xA4.html\"",
328       net::HttpContentDisposition::ATTACHMENT,
329       L"foo-\xE4.html"
330     },
331     // http://greenbytes.de/tech/tc2231/#attwithfnrawpctenca
332     { "attachment; filename=\"foo-%41.html\"",
333       net::HttpContentDisposition::ATTACHMENT,
334       L"foo-A.html"  // Should be L"foo-%41.html"
335     },
336     // http://greenbytes.de/tech/tc2231/#attwithfnusingpct
337     { "attachment; filename=\"50%.html\"",
338       net::HttpContentDisposition::ATTACHMENT,
339       L"50%.html"
340     },
341     // http://greenbytes.de/tech/tc2231/#attwithfnrawpctencaq
342     { "attachment; filename=\"foo-%\\41.html\"",
343       net::HttpContentDisposition::ATTACHMENT,
344       L"foo-A.html"  // Should be L"foo-%41.html"
345     },
346     // http://greenbytes.de/tech/tc2231/#attwithnamepct
347     { "attachment; name=\"foo-%41.html\"",
348       net::HttpContentDisposition::ATTACHMENT,
349       L"foo-A.html"  // Should be L"foo-%41.html"
350     },
351 #ifdef ICU_SHOULD_FAIL_CONVERSION_ON_INVALID_CHARACTER
352     // http://greenbytes.de/tech/tc2231/#attwithfilenamepctandiso
353     { "attachment; filename=\"\xE4-%41.html\"",
354       net::HttpContentDisposition::ATTACHMENT,
355       L""  // Should be L"\xE4-%41.htm"
356     },
357 #endif
358     // http://greenbytes.de/tech/tc2231/#attwithfnrawpctenclong
359     { "attachment; filename=\"foo-%c3%a4-%e2%82%ac.html\"",
360       net::HttpContentDisposition::ATTACHMENT,
361       L"foo-\xE4-\u20AC.html"  // Should be L"foo-%c3%a4-%e2%82%ac.html"
362     },
363     // http://greenbytes.de/tech/tc2231/#attwithasciifilenamews1
364     { "attachment; filename =\"foo.html\"",
365       net::HttpContentDisposition::ATTACHMENT,
366       L"foo.html"
367     },
368     // http://greenbytes.de/tech/tc2231/#attwith2filenames
369     // Note: tc2231 says we should fail to parse this header.
370     { "attachment; filename=\"foo.html\"; filename=\"bar.html\"",
371       net::HttpContentDisposition::ATTACHMENT,
372       L"foo.html"
373     },
374     // http://greenbytes.de/tech/tc2231/#attfnbrokentoken
375     // Note: tc2231 says we should fail to parse this header.
376     { "attachment; filename=foo[1](2).html",
377       net::HttpContentDisposition::ATTACHMENT,
378       L"foo[1](2).html"
379     },
380 #ifdef ICU_SHOULD_FAIL_CONVERSION_ON_INVALID_CHARACTER
381     // http://greenbytes.de/tech/tc2231/#attfnbrokentokeniso
382     // Note: tc2231 says we should fail to parse this header.
383     { "attachment; filename=foo-\xE4.html",
384       net::HttpContentDisposition::ATTACHMENT,
385       L""
386     },
387 #endif
388     // http://greenbytes.de/tech/tc2231/#attfnbrokentokenutf
389     // Note: tc2231 says we should fail to parse this header.
390     { "attachment; filename=foo-\xC3\xA4.html",
391       net::HttpContentDisposition::ATTACHMENT,
392       L"foo-\xE4.html"
393     },
394     // http://greenbytes.de/tech/tc2231/#attmissingdisposition
395     // Note: tc2231 says we should fail to parse this header.
396     { "filename=foo.html",
397       net::HttpContentDisposition::INLINE,
398       L"foo.html"
399     },
400     // http://greenbytes.de/tech/tc2231/#attmissingdisposition2
401     // Note: tc2231 says we should fail to parse this header.
402     { "x=y; filename=foo.html",
403       net::HttpContentDisposition::INLINE,
404       L"foo.html"
405     },
406     // http://greenbytes.de/tech/tc2231/#attmissingdisposition3
407     // Note: tc2231 says we should fail to parse this header.
408     { "\"foo; filename=bar;baz\"; filename=qux",
409       net::HttpContentDisposition::INLINE,
410       L""  // Firefox gets qux
411     },
412     // http://greenbytes.de/tech/tc2231/#attmissingdisposition4
413     // Note: tc2231 says we should fail to parse this header.
414     { "filename=foo.html, filename=bar.html",
415       net::HttpContentDisposition::INLINE,
416       L"foo.html, filename=bar.html"
417     },
418     // http://greenbytes.de/tech/tc2231/#emptydisposition
419     // Note: tc2231 says we should fail to parse this header.
420     { "; filename=foo.html",
421       net::HttpContentDisposition::INLINE,
422       L"foo.html"
423     },
424     // http://greenbytes.de/tech/tc2231/#attandinline
425     // Note: tc2231 says we should fail to parse this header.
426     { "inline; attachment; filename=foo.html",
427       net::HttpContentDisposition::INLINE,
428       L""
429     },
430     // http://greenbytes.de/tech/tc2231/#attandinline2
431     // Note: tc2231 says we should fail to parse this header.
432     { "attachment; inline; filename=foo.html",
433       net::HttpContentDisposition::ATTACHMENT,
434       L""
435     },
436     // http://greenbytes.de/tech/tc2231/#attbrokenquotedfn
437     // Note: tc2231 says we should fail to parse this header.
438     { "attachment; filename=\"foo.html\".txt",
439       net::HttpContentDisposition::ATTACHMENT,
440       L"foo.html\".txt"
441     },
442     // http://greenbytes.de/tech/tc2231/#attbrokenquotedfn2
443     // Note: tc2231 says we should fail to parse this header.
444     { "attachment; filename=\"bar",
445       net::HttpContentDisposition::ATTACHMENT,
446       L"bar"
447     },
448     // http://greenbytes.de/tech/tc2231/#attbrokenquotedfn3
449     // Note: tc2231 says we should fail to parse this header.
450     { "attachment; filename=foo\"bar;baz\"qux",
451       net::HttpContentDisposition::ATTACHMENT,
452       L"foo\"bar;baz\"qux"
453     },
454     // http://greenbytes.de/tech/tc2231/#attmultinstances
455     // Note: tc2231 says we should fail to parse this header.
456     { "attachment; filename=foo.html, attachment; filename=bar.html",
457       net::HttpContentDisposition::ATTACHMENT,
458       L"foo.html, attachment"
459     },
460     // http://greenbytes.de/tech/tc2231/#attmissingdelim
461     { "attachment; foo=foo filename=bar",
462       net::HttpContentDisposition::ATTACHMENT,
463       L""
464     },
465     // http://greenbytes.de/tech/tc2231/#attreversed
466     // Note: tc2231 says we should fail to parse this header.
467     { "filename=foo.html; attachment",
468       net::HttpContentDisposition::INLINE,
469       L"foo.html"
470     },
471     // http://greenbytes.de/tech/tc2231/#attconfusedparam
472     { "attachment; xfilename=foo.html",
473       net::HttpContentDisposition::ATTACHMENT,
474       L""
475     },
476     // http://greenbytes.de/tech/tc2231/#attabspath
477     { "attachment; filename=\"/foo.html\"",
478       net::HttpContentDisposition::ATTACHMENT,
479       L"/foo.html"
480     },
481     // http://greenbytes.de/tech/tc2231/#attabspathwin
482     { "attachment; filename=\"\\\\foo.html\"",
483       net::HttpContentDisposition::ATTACHMENT,
484       L"\\foo.html"
485     },
486     // http://greenbytes.de/tech/tc2231/#dispext
487     { "foobar",
488       net::HttpContentDisposition::ATTACHMENT,
489       L""
490     },
491     // http://greenbytes.de/tech/tc2231/#dispextbadfn
492     { "attachment; example=\"filename=example.txt\"",
493       net::HttpContentDisposition::ATTACHMENT,
494       L""
495     },
496     // http://greenbytes.de/tech/tc2231/#attnewandfn
497     { "attachment; foobar=x; filename=\"foo.html\"",
498       net::HttpContentDisposition::ATTACHMENT,
499       L"foo.html"
500     },
501     // TODO(abarth): Add the filename* tests, but check
502     //              HttpContentDispositionTest.Filename for overlap.
503     // TODO(abarth): http://greenbytes.de/tech/tc2231/#attrfc2047token
504     // TODO(abarth): http://greenbytes.de/tech/tc2231/#attrfc2047quoted
505   };
506   for (size_t i = 0; i < arraysize(tests); ++i) {
507     HttpContentDisposition header(tests[i].header, std::string());
508     EXPECT_EQ(tests[i].expected_type, header.type())
509         << "Failed on input: " << tests[i].header;
510     EXPECT_EQ(tests[i].expected_filename, base::UTF8ToWide(header.filename()))
511         << "Failed on input: " << tests[i].header;
512   }
513 }
514
515 TEST(HttpContentDispositionTest, ParseResult) {
516   const struct ParseResultTestCase {
517     const char* header;
518     int expected_flags;
519   } kTestCases[] = {
520     // Basic feature tests
521     { "", HttpContentDisposition::INVALID },
522     { "example=x", HttpContentDisposition::INVALID },
523     { "attachment; filename=", HttpContentDisposition::HAS_DISPOSITION_TYPE },
524     { "attachment; name=", HttpContentDisposition::HAS_DISPOSITION_TYPE },
525     { "attachment; filename*=", HttpContentDisposition::HAS_DISPOSITION_TYPE },
526     { "attachment; filename==?utf-8?Q?\?=",
527       HttpContentDisposition::HAS_DISPOSITION_TYPE },
528     { "filename=x", HttpContentDisposition::HAS_FILENAME },
529     { "example; filename=x",
530       HttpContentDisposition::HAS_DISPOSITION_TYPE |
531       HttpContentDisposition::HAS_UNKNOWN_DISPOSITION_TYPE |
532       HttpContentDisposition::HAS_FILENAME},
533     { "attachment; filename=x",
534       HttpContentDisposition::HAS_DISPOSITION_TYPE |
535       HttpContentDisposition::HAS_FILENAME },
536     { "attachment; filename=x; name=y",
537       HttpContentDisposition::HAS_DISPOSITION_TYPE |
538       HttpContentDisposition::HAS_FILENAME |
539       HttpContentDisposition::HAS_NAME },
540     { "attachment; name=y; filename*=utf-8''foo; name=x",
541       HttpContentDisposition::HAS_DISPOSITION_TYPE |
542       HttpContentDisposition::HAS_EXT_FILENAME |
543       HttpContentDisposition::HAS_NAME },
544
545     // Feature tests for 'filename' attribute.
546     { "filename=foo\xcc\x88",
547       HttpContentDisposition::HAS_FILENAME |
548       HttpContentDisposition::HAS_NON_ASCII_STRINGS },
549     { "filename=foo%cc%88",
550       HttpContentDisposition::HAS_FILENAME |
551       HttpContentDisposition::HAS_PERCENT_ENCODED_STRINGS },
552     { "filename==?utf-8?Q?foo?=",
553       HttpContentDisposition::HAS_FILENAME |
554       HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS },
555     { "filename=\"=?utf-8?Q?foo?=\"",
556       HttpContentDisposition::HAS_FILENAME |
557       HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS },
558     { "filename==?utf-8?Q?foo?", HttpContentDisposition::INVALID },
559     { "name=foo\xcc\x88",
560       HttpContentDisposition::HAS_NAME },
561
562     // Shouldn't set |has_non_ascii_strings| based on 'name' attribute.
563     { "filename=x; name=foo\xcc\x88",
564       HttpContentDisposition::HAS_FILENAME |
565       HttpContentDisposition::HAS_NAME },
566     { "filename=foo\xcc\x88 foo%cc%88 =?utf-8?Q?foo?=",
567       HttpContentDisposition::HAS_FILENAME |
568       HttpContentDisposition::HAS_NON_ASCII_STRINGS |
569       HttpContentDisposition::HAS_PERCENT_ENCODED_STRINGS |
570       HttpContentDisposition::HAS_RFC2047_ENCODED_STRINGS },
571
572     // If 'filename' attribute is invalid, should set any flags based on it.
573     { "filename=foo\xcc\x88 foo%cc%88 =?utf-8?Q?foo?",
574       HttpContentDisposition::INVALID },
575     { "filename=foo\xcc\x88 foo%cc%88 =?utf-8?Q?foo?; name=x",
576       HttpContentDisposition::HAS_NAME },
577   };
578
579   for (size_t i = 0; i < arraysize(kTestCases); ++i) {
580     const ParseResultTestCase& test_case = kTestCases[i];
581     HttpContentDisposition content_disposition(test_case.header, "utf-8");
582     int result = content_disposition.parse_result_flags();
583
584     SCOPED_TRACE(testing::Message() << "Test case " << i
585                                     << " with header " << test_case.header);
586     EXPECT_EQ(test_case.expected_flags, result);
587   }
588 }
589
590 }  // namespace net