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/filename_util.h"
7 #include "base/file_util.h"
8 #include "base/files/file_path.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/test/test_file_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
24 struct GenerateFilenameCase
{
27 const char* content_disp_header
;
28 const char* referrer_charset
;
29 const char* suggested_filename
;
30 const char* mime_type
;
31 const wchar_t* default_filename
;
32 const wchar_t* expected_filename
;
35 void RunGenerateFileNameTestCase(const GenerateFilenameCase
* test_case
) {
36 std::string
default_filename(base::WideToUTF8(test_case
->default_filename
));
37 base::FilePath file_path
= GenerateFileName(
38 GURL(test_case
->url
), test_case
->content_disp_header
,
39 test_case
->referrer_charset
, test_case
->suggested_filename
,
40 test_case
->mime_type
, default_filename
);
41 EXPECT_EQ(test_case
->expected_filename
,
42 file_util::FilePathAsWString(file_path
))
43 << "test case at line number: " << test_case
->lineno
;
48 static const base::FilePath::CharType
* kSafePortableBasenames
[] = {
49 FILE_PATH_LITERAL("a"),
50 FILE_PATH_LITERAL("a.txt"),
51 FILE_PATH_LITERAL("a b.txt"),
52 FILE_PATH_LITERAL("a-b.txt"),
53 FILE_PATH_LITERAL("My Computer"),
54 FILE_PATH_LITERAL(" Computer"),
57 static const base::FilePath::CharType
* kUnsafePortableBasenames
[] = {
58 FILE_PATH_LITERAL(""),
59 FILE_PATH_LITERAL("."),
60 FILE_PATH_LITERAL(".."),
61 FILE_PATH_LITERAL("..."),
62 FILE_PATH_LITERAL("con"),
63 FILE_PATH_LITERAL("con.zip"),
64 FILE_PATH_LITERAL("NUL"),
65 FILE_PATH_LITERAL("NUL.zip"),
66 FILE_PATH_LITERAL(".a"),
67 FILE_PATH_LITERAL("a."),
68 FILE_PATH_LITERAL("a\"a"),
69 FILE_PATH_LITERAL("a<a"),
70 FILE_PATH_LITERAL("a>a"),
71 FILE_PATH_LITERAL("a?a"),
72 FILE_PATH_LITERAL("a/"),
73 FILE_PATH_LITERAL("a\\"),
74 FILE_PATH_LITERAL("a "),
75 FILE_PATH_LITERAL("a . ."),
76 FILE_PATH_LITERAL("My Computer.{a}"),
77 FILE_PATH_LITERAL("My Computer.{20D04FE0-3AEA-1069-A2D8-08002B30309D}"),
79 FILE_PATH_LITERAL("a\\a"),
83 static const base::FilePath::CharType
* kSafePortableRelativePaths
[] = {
84 FILE_PATH_LITERAL("a/a"),
86 FILE_PATH_LITERAL("a\\a"),
90 TEST(FilenameUtilTest
, IsSafePortablePathComponent
) {
91 for (size_t i
= 0 ; i
< arraysize(kSafePortableBasenames
); ++i
) {
92 EXPECT_TRUE(IsSafePortablePathComponent(base::FilePath(
93 kSafePortableBasenames
[i
]))) << kSafePortableBasenames
[i
];
95 for (size_t i
= 0 ; i
< arraysize(kUnsafePortableBasenames
); ++i
) {
96 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
97 kUnsafePortableBasenames
[i
]))) << kUnsafePortableBasenames
[i
];
99 for (size_t i
= 0 ; i
< arraysize(kSafePortableRelativePaths
); ++i
) {
100 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
101 kSafePortableRelativePaths
[i
]))) << kSafePortableRelativePaths
[i
];
105 TEST(FilenameUtilTest
, IsSafePortableRelativePath
) {
106 base::FilePath
safe_dirname(FILE_PATH_LITERAL("a"));
107 for (size_t i
= 0 ; i
< arraysize(kSafePortableBasenames
); ++i
) {
108 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
109 kSafePortableBasenames
[i
]))) << kSafePortableBasenames
[i
];
110 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname
.Append(base::FilePath(
111 kSafePortableBasenames
[i
])))) << kSafePortableBasenames
[i
];
113 for (size_t i
= 0 ; i
< arraysize(kSafePortableRelativePaths
); ++i
) {
114 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
115 kSafePortableRelativePaths
[i
]))) << kSafePortableRelativePaths
[i
];
116 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname
.Append(base::FilePath(
117 kSafePortableRelativePaths
[i
])))) << kSafePortableRelativePaths
[i
];
119 for (size_t i
= 0 ; i
< arraysize(kUnsafePortableBasenames
); ++i
) {
120 EXPECT_FALSE(IsSafePortableRelativePath(base::FilePath(
121 kUnsafePortableBasenames
[i
]))) << kUnsafePortableBasenames
[i
];
122 if (!base::FilePath::StringType(kUnsafePortableBasenames
[i
]).empty()) {
123 EXPECT_FALSE(IsSafePortableRelativePath(safe_dirname
.Append(
124 base::FilePath(kUnsafePortableBasenames
[i
]))))
125 << kUnsafePortableBasenames
[i
];
130 TEST(FilenameUtilTest
, FileURLConversion
) {
131 // a list of test file names and the corresponding URLs
132 const FileCase round_trip_cases
[] = {
134 {L
"C:\\foo\\bar.txt", "file:///C:/foo/bar.txt"},
135 {L
"\\\\some computer\\foo\\bar.txt",
136 "file://some%20computer/foo/bar.txt"}, // UNC
137 {L
"D:\\Name;with%some symbols*#",
138 "file:///D:/Name%3Bwith%25some%20symbols*%23"},
139 // issue 14153: To be tested with the OS default codepage other than 1252.
140 {L
"D:\\latin1\\caf\x00E9\x00DD.txt",
141 "file:///D:/latin1/caf%C3%A9%C3%9D.txt"},
142 {L
"D:\\otherlatin\\caf\x0119.txt",
143 "file:///D:/otherlatin/caf%C4%99.txt"},
144 {L
"D:\\greek\\\x03B1\x03B2\x03B3.txt",
145 "file:///D:/greek/%CE%B1%CE%B2%CE%B3.txt"},
146 {L
"D:\\Chinese\\\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
147 "file:///D:/Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD%91"
149 {L
"D:\\plane1\\\xD835\xDC00\xD835\xDC01.txt", // Math alphabet "AB"
150 "file:///D:/plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
151 #elif defined(OS_POSIX)
152 {L
"/foo/bar.txt", "file:///foo/bar.txt"},
153 {L
"/foo/BAR.txt", "file:///foo/BAR.txt"},
154 {L
"/C:/foo/bar.txt", "file:///C:/foo/bar.txt"},
155 {L
"/foo/bar?.txt", "file:///foo/bar%3F.txt"},
156 {L
"/some computer/foo/bar.txt", "file:///some%20computer/foo/bar.txt"},
157 {L
"/Name;with%some symbols*#", "file:///Name%3Bwith%25some%20symbols*%23"},
158 {L
"/latin1/caf\x00E9\x00DD.txt", "file:///latin1/caf%C3%A9%C3%9D.txt"},
159 {L
"/otherlatin/caf\x0119.txt", "file:///otherlatin/caf%C4%99.txt"},
160 {L
"/greek/\x03B1\x03B2\x03B3.txt", "file:///greek/%CE%B1%CE%B2%CE%B3.txt"},
161 {L
"/Chinese/\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
162 "file:///Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD"
164 {L
"/plane1/\x1D400\x1D401.txt", // Math alphabet "AB"
165 "file:///plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
169 // First, we'll test that we can round-trip all of the above cases of URLs
170 base::FilePath output
;
171 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(round_trip_cases
); i
++) {
172 // convert to the file URL
173 GURL
file_url(FilePathToFileURL(
174 file_util::WStringAsFilePath(round_trip_cases
[i
].file
)));
175 EXPECT_EQ(round_trip_cases
[i
].url
, file_url
.spec());
177 // Back to the filename.
178 EXPECT_TRUE(FileURLToFilePath(file_url
, &output
));
179 EXPECT_EQ(round_trip_cases
[i
].file
, file_util::FilePathAsWString(output
));
182 // Test that various file: URLs get decoded into the correct file type
183 FileCase url_cases
[] = {
185 {L
"C:\\foo\\bar.txt", "file:c|/foo\\bar.txt"},
186 {L
"C:\\foo\\bar.txt", "file:/c:/foo/bar.txt"},
187 {L
"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
188 {L
"C:\\foo\\bar.txt", "file:///c:/foo/bar.txt"},
189 {L
"\\\\foo\\bar.txt", "file:////foo\\bar.txt"},
190 {L
"\\\\foo\\bar.txt", "file:/foo/bar.txt"},
191 {L
"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
192 {L
"C:\\foo\\bar.txt", "file:\\\\\\c:/foo/bar.txt"},
193 #elif defined(OS_POSIX)
194 {L
"/c:/foo/bar.txt", "file:/c:/foo/bar.txt"},
195 {L
"/c:/foo/bar.txt", "file:///c:/foo/bar.txt"},
196 {L
"/foo/bar.txt", "file:/foo/bar.txt"},
197 {L
"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
198 {L
"/foo/bar.txt", "file:foo/bar.txt"},
199 {L
"/bar.txt", "file://foo/bar.txt"},
200 {L
"/foo/bar.txt", "file:///foo/bar.txt"},
201 {L
"/foo/bar.txt", "file:////foo/bar.txt"},
202 {L
"/foo/bar.txt", "file:////foo//bar.txt"},
203 {L
"/foo/bar.txt", "file:////foo///bar.txt"},
204 {L
"/foo/bar.txt", "file:////foo////bar.txt"},
205 {L
"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
206 {L
"/c:/foo/bar.txt", "file:c:/foo/bar.txt"},
207 // We get these wrong because GURL turns back slashes into forward
209 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
210 //{L"/c|/foo%5Cbar.txt", "file:c|/foo\\bar.txt"},
211 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
212 //{L"/foo%5Cbar.txt", "file:////foo\\bar.txt"},
213 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
216 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(url_cases
); i
++) {
217 FileURLToFilePath(GURL(url_cases
[i
].url
), &output
);
218 EXPECT_EQ(url_cases
[i
].file
, file_util::FilePathAsWString(output
));
221 // Unfortunately, UTF8ToWide discards invalid UTF8 input.
222 #ifdef BUG_878908_IS_FIXED
223 // Test that no conversion happens if the UTF-8 input is invalid, and that
224 // the input is preserved in UTF-8
225 const char invalid_utf8
[] = "file:///d:/Blah/\xff.doc";
226 const wchar_t invalid_wide
[] = L
"D:\\Blah\\\xff.doc";
227 EXPECT_TRUE(FileURLToFilePath(
228 GURL(std::string(invalid_utf8
)), &output
));
229 EXPECT_EQ(std::wstring(invalid_wide
), output
);
232 // Test that if a file URL is malformed, we get a failure
233 EXPECT_FALSE(FileURLToFilePath(GURL("filefoobar"), &output
));
237 #define JPEG_EXT L".jpg"
238 #define HTML_EXT L".htm"
239 #elif defined(OS_MACOSX)
240 #define JPEG_EXT L".jpeg"
241 #define HTML_EXT L".html"
243 #define JPEG_EXT L".jpg"
244 #define HTML_EXT L".html"
246 #define TXT_EXT L".txt"
247 #define TAR_EXT L".tar"
249 TEST(FilenameUtilTest
, GenerateSafeFileName
) {
251 const char* mime_type
;
252 const base::FilePath::CharType
* filename
;
253 const base::FilePath::CharType
* expected_filename
;
258 FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
259 FILE_PATH_LITERAL("C:\\foo\\bar.htm")
263 FILE_PATH_LITERAL("C:\\foo\\bar.html"),
264 FILE_PATH_LITERAL("C:\\foo\\bar.html")
268 FILE_PATH_LITERAL("C:\\foo\\bar"),
269 FILE_PATH_LITERAL("C:\\foo\\bar.htm")
273 FILE_PATH_LITERAL("C:\\bar.html"),
274 FILE_PATH_LITERAL("C:\\bar.html")
278 FILE_PATH_LITERAL("C:\\bar"),
279 FILE_PATH_LITERAL("C:\\bar.png")
283 FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
284 FILE_PATH_LITERAL("C:\\foo\\bar.exe")
288 FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
289 FILE_PATH_LITERAL("C:\\foo\\bar.exe")
293 FILE_PATH_LITERAL("C:\\foo\\google.com"),
294 FILE_PATH_LITERAL("C:\\foo\\google.com")
298 FILE_PATH_LITERAL("C:\\foo\\con.htm"),
299 FILE_PATH_LITERAL("C:\\foo\\_con.htm")
303 FILE_PATH_LITERAL("C:\\foo\\con"),
304 FILE_PATH_LITERAL("C:\\foo\\_con.htm")
308 FILE_PATH_LITERAL("C:\\foo\\harmless.{not-really-this-may-be-a-guid}"),
309 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
313 FILE_PATH_LITERAL("C:\\foo\\harmless.local"),
314 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
318 FILE_PATH_LITERAL("C:\\foo\\harmless.lnk"),
319 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
323 FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-"),
324 FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-")
326 // Allow extension synonyms.
329 FILE_PATH_LITERAL("C:\\foo\\bar.jpg"),
330 FILE_PATH_LITERAL("C:\\foo\\bar.jpg")
334 FILE_PATH_LITERAL("C:\\foo\\bar.jpeg"),
335 FILE_PATH_LITERAL("C:\\foo\\bar.jpeg")
337 #else // !defined(OS_WIN)
340 FILE_PATH_LITERAL("/foo/bar.htm"),
341 FILE_PATH_LITERAL("/foo/bar.htm")
345 FILE_PATH_LITERAL("/foo/bar.html"),
346 FILE_PATH_LITERAL("/foo/bar.html")
350 FILE_PATH_LITERAL("/foo/bar"),
351 FILE_PATH_LITERAL("/foo/bar.html")
355 FILE_PATH_LITERAL("/bar.html"),
356 FILE_PATH_LITERAL("/bar.html")
360 FILE_PATH_LITERAL("/bar"),
361 FILE_PATH_LITERAL("/bar.png")
365 FILE_PATH_LITERAL("/foo/bar.exe"),
366 FILE_PATH_LITERAL("/foo/bar.exe")
370 FILE_PATH_LITERAL("/foo/google.com"),
371 FILE_PATH_LITERAL("/foo/google.com")
375 FILE_PATH_LITERAL("/foo/con.htm"),
376 FILE_PATH_LITERAL("/foo/con.htm")
380 FILE_PATH_LITERAL("/foo/con"),
381 FILE_PATH_LITERAL("/foo/con.html")
383 // Allow extension synonyms.
386 FILE_PATH_LITERAL("/bar.jpg"),
387 FILE_PATH_LITERAL("/bar.jpg")
391 FILE_PATH_LITERAL("/bar.jpeg"),
392 FILE_PATH_LITERAL("/bar.jpeg")
394 #endif // !defined(OS_WIN)
397 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(safe_tests
); ++i
) {
398 base::FilePath
file_path(safe_tests
[i
].filename
);
399 GenerateSafeFileName(safe_tests
[i
].mime_type
, false, &file_path
);
400 EXPECT_EQ(safe_tests
[i
].expected_filename
, file_path
.value())
401 << "Iteration " << i
;
405 TEST(FilenameUtilTest
, GenerateFileName
) {
406 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
407 // This test doesn't run when the locale is not UTF-8 because some of the
408 // string conversions fail. This is OK (we have the default value) but they
409 // don't match our expectations.
410 std::string locale
= setlocale(LC_CTYPE
, NULL
);
411 StringToLowerASCII(&locale
);
412 EXPECT_TRUE(locale
.find("utf-8") != std::string::npos
||
413 locale
.find("utf8") != std::string::npos
)
414 << "Your locale (" << locale
<< ") must be set to UTF-8 "
415 << "for this test to pass!";
418 // Tests whether the correct filename is selected from the the given
419 // parameters and that Content-Disposition headers are properly
420 // handled including failovers when the header is malformed.
421 const GenerateFilenameCase selection_tests
[] = {
424 "http://www.google.com/",
425 "attachment; filename=test.html",
434 "http://www.google.com/",
435 "attachment; filename=\"test.html\"",
444 "http://www.google.com/",
445 "attachment; filename= \"test.html\"",
454 "http://www.google.com/",
455 "attachment; filename = \"test.html\"",
462 { // filename is whitespace. Should failover to URL host
464 "http://www.google.com/",
465 "attachment; filename= ",
474 "http://www.google.com/path/test.html",
484 "http://www.google.com/path/test.html",
494 "http://www.google.com/",
504 "http://www.google.com/test.html",
512 { // Now that we use src/url's ExtractFileName, this case falls back to
513 // the hostname. If this behavior is not desirable, we'd better change
514 // ExtractFileName (in url_parse.cc).
516 "http://www.google.com/path/",
526 "http://www.google.com/path",
546 "file:///path/testfile",
556 "non-standard-scheme:",
564 { // C-D should override default
566 "http://www.google.com/",
567 "attachment; filename =\"test.html\"",
574 { // But the URL shouldn't
576 "http://www.google.com/",
586 "http://www.google.com/",
587 "attachment; filename=\"../test.html\"",
596 "http://www.google.com/",
597 "attachment; filename=\"..\\test.html\"",
606 "http://www.google.com/",
607 "attachment; filename=\"..\\\\test.html\"",
614 { // Filename disappears after leading and trailing periods are removed.
616 "http://www.google.com/",
617 "attachment; filename=\"..\"",
624 { // C-D specified filename disappears. Failover to final filename.
626 "http://www.google.com/test.html",
627 "attachment; filename=\"..\"",
634 // Below is a small subset of cases taken from HttpContentDisposition tests.
637 "http://www.google.com/",
638 "attachment; filename=\"%EC%98%88%EC%88%A0%20"
639 "%EC%98%88%EC%88%A0.jpg\"",
644 L
"\uc608\uc220 \uc608\uc220.jpg"
648 "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
654 L
"\uc608\uc220 \uc608\uc220.jpg"
658 "http://www.google.com/",
663 L
"\uB2E4\uC6B4\uB85C\uB4DC",
664 L
"\uB2E4\uC6B4\uB85C\uB4DC"
668 "http://www.google.com/",
669 "attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
679 "http://www.example.com/images?id=3",
680 "attachment; filename=caf\xc3\xa9.png",
689 "http://www.example.com/images?id=3",
690 "attachment; filename=caf\xe5.png",
699 "http://www.example.com/file?id=3",
700 "attachment; name=\xcf\xc2\xd4\xd8.zip",
707 { // Invalid C-D header. Extracts filename from url.
709 "http://www.google.com/test.html",
710 "attachment; filename==?iiso88591?Q?caf=EG?=",
717 // about: and data: URLs
730 "data:,looks/like/a.path",
740 "data:text/plain;base64,VG8gYmUgb3Igbm90IHRvIGJlLg=",
750 "data:,looks/like/a.path",
755 L
"default_filename_is_given",
756 L
"default_filename_is_given"
760 "data:,looks/like/a.path",
765 L
"\u65e5\u672c\u8a9e", // Japanese Kanji.
766 L
"\u65e5\u672c\u8a9e"
768 { // The filename encoding is specified by the referrer charset.
770 "http://example.com/V%FDvojov%E1%20psychologie.doc",
776 L
"V\u00fdvojov\u00e1 psychologie.doc"
778 { // Suggested filename takes precedence over URL
780 "http://www.google.com/test",
788 { // The content-disposition has higher precedence over the suggested name.
790 "http://www.google.com/test",
791 "attachment; filename=test.html",
799 { // The filename encoding doesn't match the referrer charset, the system
800 // charset, or UTF-8.
801 // TODO(jshin): we need to handle this case.
803 "http://example.com/V%FDvojov%E1%20psychologie.doc",
809 L
"V\u00fdvojov\u00e1 psychologie.doc",
812 // Raw 8bit characters in C-D
815 "http://www.example.com/images?id=3",
816 "attachment; filename=caf\xc3\xa9.png",
825 "http://www.example.com/images?id=3",
826 "attachment; filename=caf\xe5.png",
833 { // No 'filename' keyword in the disposition, use the URL
835 "http://www.evil.com/my_download.txt",
843 { // Spaces in the disposition file name
845 "http://www.frontpagehacker.com/a_download.exe",
846 "filename=My Downloaded File.exe",
849 "application/octet-stream",
851 L
"My Downloaded File.exe"
855 "http://www.examples.com/",
857 "filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
862 L
"\uc608\uc220 \uc608\uc220.jpg"
866 "http://www.examples.com/q.cgi?id=abc",
867 "attachment; name=abc de.pdf",
870 "application/octet-stream",
876 "http://www.example.com/path",
877 "filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
882 L
"\x82b8\x8853" L
"3.png"
884 { // The following two have invalid CD headers and filenames come from the
887 "http://www.example.com/test%20123",
888 "attachment; filename==?iiso88591?Q?caf=EG?=",
897 "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
898 "malformed_disposition",
903 L
"\uc608\uc220 \uc608\uc220.jpg"
905 { // Invalid C-D. No filename from URL. Falls back to 'download'.
907 "http://www.google.com/path1/path2/",
908 "attachment; filename==?iso88591?Q?caf=E3?",
917 // Tests filename generation. Once the correct filename is
918 // selected, they should be passed through the validation steps and
919 // a correct extension should be added if necessary.
920 const GenerateFilenameCase generation_tests
[] = {
921 // Dotfiles. Ensures preceeding period(s) stripped.
924 "http://www.google.com/.test.html",
934 "http://www.google.com/.test",
944 "http://www.google.com/..test",
952 { // Disposition has relative paths, remove directory separators
954 "http://www.evil.com/my_download.txt",
955 "filename=../../../../././../a_file_name.txt",
960 L
"-..-..-..-.-.-..-a_file_name.txt"
962 { // Disposition has parent directories, remove directory separators
964 "http://www.evil.com/my_download.txt",
965 "filename=dir1/dir2/a_file_name.txt",
970 L
"dir1-dir2-a_file_name.txt"
972 { // Disposition has relative paths, remove directory separators
974 "http://www.evil.com/my_download.txt",
975 "filename=..\\..\\..\\..\\.\\.\\..\\a_file_name.txt",
980 L
"-..-..-..-.-.-..-a_file_name.txt"
982 { // Disposition has parent directories, remove directory separators
984 "http://www.evil.com/my_download.txt",
985 "filename=dir1\\dir2\\a_file_name.txt",
990 L
"dir1-dir2-a_file_name.txt"
992 { // No useful information in disposition or URL, use default
994 "http://www.truncated.com/path/",
1002 { // Filename looks like HTML?
1004 "http://www.evil.com/get/malware/here",
1005 "filename=\"<blink>Hello kitty</blink>\"",
1010 L
"-blink-Hello kitty--blink-" TXT_EXT
1012 { // A normal avi should get .avi and not .avi.avi
1014 "https://blah.google.com/misc/2.avi",
1022 { // Extension generation
1024 "http://www.example.com/my-cat",
1034 "http://www.example.com/my-cat",
1044 "http://www.example.com/my-cat",
1052 { // Unknown MIME type
1054 "http://www.example.com/my-cat",
1064 "http://www.example.com/my-cat.jpg",
1065 "filename=my-cat.jpg",
1072 // Windows specific tests
1076 "http://www.goodguy.com/evil.exe",
1077 "filename=evil.exe",
1086 "http://www.goodguy.com/ok.exe",
1090 "binary/octet-stream",
1096 "http://www.goodguy.com/evil.dll",
1097 "filename=evil.dll",
1106 "http://www.goodguy.com/evil.exe",
1110 "application/rss+xml",
1114 // Test truncation of trailing dots and spaces
1117 "http://www.goodguy.com/evil.exe ",
1118 "filename=evil.exe ",
1121 "binary/octet-stream",
1127 "http://www.goodguy.com/evil.exe.",
1128 "filename=evil.exe.",
1131 "binary/octet-stream",
1137 "http://www.goodguy.com/evil.exe. . .",
1138 "filename=evil.exe. . .",
1141 "binary/octet-stream",
1147 "http://www.goodguy.com/evil.",
1151 "binary/octet-stream",
1157 "http://www.goodguy.com/. . . . .",
1158 "filename=. . . . .",
1161 "binary/octet-stream",
1167 "http://www.badguy.com/attachment?name=meh.exe%C2%A0",
1168 "attachment; filename=\"meh.exe\xC2\xA0\"",
1171 "binary/octet-stream",
1178 "http://www.goodguy.com/utils.js",
1179 "filename=utils.js",
1182 "application/x-javascript",
1188 "http://www.goodguy.com/contacts.js",
1189 "filename=contacts.js",
1198 "http://www.goodguy.com/utils.js",
1199 "filename=utils.js",
1208 "http://www.goodguy.com/utils.js",
1209 "filename=utils.js",
1212 "text/javascript;version=2",
1218 "http://www.goodguy.com/utils.js",
1219 "filename=utils.js",
1222 "application/ecmascript",
1228 "http://www.goodguy.com/utils.js",
1229 "filename=utils.js",
1232 "application/ecmascript;version=4",
1238 "http://www.goodguy.com/program.exe",
1239 "filename=program.exe",
1242 "application/foo-bar",
1248 "http://www.evil.com/../foo.txt",
1249 "filename=../foo.txt",
1258 "http://www.evil.com/..\\foo.txt",
1259 "filename=..\\foo.txt",
1268 "http://www.evil.com/.hidden",
1278 "http://www.evil.com/trailing.",
1279 "filename=trailing.",
1292 "http://www.evil.com/trailing.",
1293 "filename=trailing.",
1299 L
"trailing-" TXT_EXT
1306 "http://www.evil.com/.",
1316 "http://www.evil.com/..",
1326 "http://www.evil.com/...",
1334 { // Note that this one doesn't have "filename=" on it.
1336 "http://www.evil.com/",
1342 L
"download" JPEG_EXT
1346 "http://www.evil.com/",
1352 L
"download" JPEG_EXT
1356 "http://www.example.com/simple",
1360 "application/octet-stream",
1364 // Reserved words on Windows
1367 "http://www.goodguy.com/COM1",
1371 "application/foo-bar",
1381 "http://www.goodguy.com/COM4.txt",
1382 "filename=COM4.txt",
1395 "http://www.goodguy.com/lpt1.TXT",
1396 "filename=lpt1.TXT",
1409 "http://www.goodguy.com/clock$.txt",
1410 "filename=clock$.txt",
1421 { // Validation should also apply to sugested name
1423 "http://www.goodguy.com/blah$.txt",
1424 "filename=clock$.txt",
1437 "http://www.goodguy.com/mycom1.foo",
1438 "filename=mycom1.foo",
1447 "http://www.badguy.com/Setup.exe.local",
1448 "filename=Setup.exe.local",
1451 "application/foo-bar",
1454 L
"Setup.exe.download"
1461 "http://www.badguy.com/Setup.exe.local",
1462 "filename=Setup.exe.local.local",
1465 "application/foo-bar",
1468 L
"Setup.exe.local.download"
1470 L
"Setup.exe.local.local"
1475 "http://www.badguy.com/Setup.exe.lnk",
1476 "filename=Setup.exe.lnk",
1479 "application/foo-bar",
1482 L
"Setup.exe.download"
1489 "http://www.badguy.com/Desktop.ini",
1490 "filename=Desktop.ini",
1493 "application/foo-bar",
1503 "http://www.badguy.com/Thumbs.db",
1504 "filename=Thumbs.db",
1507 "application/foo-bar",
1517 "http://www.hotmail.com",
1518 "filename=source.jpg",
1521 "application/x-javascript",
1525 { // http://crbug.com/5772.
1527 "http://www.example.com/foo.tar.gz",
1531 "application/x-tar",
1535 { // http://crbug.com/52250.
1537 "http://www.example.com/foo.tgz",
1541 "application/x-tar",
1545 { // http://crbug.com/7337.
1547 "http://maged.lordaeron.org/blank.reg",
1557 "http://www.example.com/bar.tar",
1561 "application/x-tar",
1567 "http://www.example.com/bar.bogus",
1571 "application/x-tar",
1575 { // http://crbug.com/20337
1577 "http://www.example.com/.download.txt",
1578 "filename=.download.txt",
1585 { // http://crbug.com/56855.
1587 "http://www.example.com/bar.sh",
1595 { // http://crbug.com/61571
1597 "http://www.example.com/npdf.php?fn=foobar.pdf",
1605 { // Shouldn't overwrite C-D specified extension.
1607 "http://www.example.com/npdf.php?fn=foobar.pdf",
1608 "filename=foobar.jpg",
1615 { // http://crbug.com/87719
1617 "http://www.example.com/image.aspx?id=blargh",
1625 #if defined(OS_CHROMEOS)
1626 { // http://crosbug.com/26028
1628 "http://www.example.com/fooa%cc%88.txt",
1639 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(selection_tests
); ++i
)
1640 RunGenerateFileNameTestCase(&selection_tests
[i
]);
1642 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(generation_tests
); ++i
)
1643 RunGenerateFileNameTestCase(&generation_tests
[i
]);
1645 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(generation_tests
); ++i
) {
1646 GenerateFilenameCase test_case
= generation_tests
[i
];
1647 test_case
.referrer_charset
= "GBK";
1648 RunGenerateFileNameTestCase(&test_case
);