Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1129)

Side by Side Diff: chrome/browser/download/download_util_unittest.cc

Issue 7300005: Move filename determination to net_util (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: " Created 9 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/download/download_util.cc ('k') | chrome/chrome_tests.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010 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 "chrome/browser/download/download_util.h"
6
7 #if defined(OS_POSIX) && !defined(OS_MACOSX)
8 #include <locale.h>
9 #endif
10
11 #include "base/string_util.h"
12 #include "base/test/test_file_util.h"
13 #include "googleurl/src/gurl.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 #if defined(OS_WIN)
17 #define JPEG_EXT L".jpg"
18 #define HTML_EXT L".htm"
19 #define TXT_EXT L".txt"
20 #define TAR_EXT L".tar"
21 #elif defined(OS_MACOSX)
22 #define JPEG_EXT L".jpeg"
23 #define HTML_EXT L".html"
24 #define TXT_EXT L".txt"
25 #define TAR_EXT L".tar"
26 #else
27 #define JPEG_EXT L".jpg"
28 #define HTML_EXT L".html"
29 #define TXT_EXT L".txt"
30 #define TAR_EXT L".tar"
31 #endif
32
33 namespace {
34
35 const struct {
36 const char* disposition;
37 const char* url;
38 const char* mime_type;
39 const wchar_t* expected_name;
40 } kGenerateFileNameTestCases[] = {
41 // No 'filename' keyword in the disposition, use the URL
42 {"a_file_name.txt",
43 "http://www.evil.com/my_download.txt",
44 "text/plain",
45 L"my_download.txt"},
46
47 // Disposition has relative paths, remove directory separators
48 {"filename=../../../../././../a_file_name.txt",
49 "http://www.evil.com/my_download.txt",
50 "text/plain",
51 L"_.._.._.._._._.._a_file_name.txt"},
52
53 // Disposition has parent directories, remove directory separators
54 {"filename=dir1/dir2/a_file_name.txt",
55 "http://www.evil.com/my_download.txt",
56 "text/plain",
57 L"dir1_dir2_a_file_name.txt"},
58
59 // Disposition has relative paths, remove directory separators
60 {"filename=..\\..\\..\\..\\.\\.\\..\\a_file_name.txt",
61 "http://www.evil.com/my_download.txt",
62 "text/plain",
63 L"_.._.._.._._._.._a_file_name.txt"},
64
65 // Disposition has parent directories, remove directory separators
66 {"filename=dir1\\dir2\\a_file_name.txt",
67 "http://www.evil.com/my_download.txt",
68 "text/plain",
69 L"dir1_dir2_a_file_name.txt"},
70
71 // No useful information in disposition or URL, use default
72 {"", "http://www.truncated.com/path/", "text/plain",
73 L"download" TXT_EXT
74 },
75
76 // A normal avi should get .avi and not .avi.avi
77 {"", "https://blah.google.com/misc/2.avi", "video/x-msvideo", L"2.avi"},
78
79 // Spaces in the disposition file name
80 {"filename=My Downloaded File.exe",
81 "http://www.frontpagehacker.com/a_download.exe",
82 "application/octet-stream",
83 L"My Downloaded File.exe"},
84
85 {"filename=my-cat",
86 "http://www.example.com/my-cat",
87 "image/jpeg",
88 L"my-cat" JPEG_EXT
89 },
90
91 {"filename=my-cat",
92 "http://www.example.com/my-cat",
93 "text/plain",
94 L"my-cat.txt"},
95
96 {"filename=my-cat",
97 "http://www.example.com/my-cat",
98 "text/html",
99 L"my-cat" HTML_EXT
100 },
101
102 {"filename=my-cat",
103 "http://www.example.com/my-cat",
104 "dance/party",
105 L"my-cat"},
106
107 {"filename=my-cat.jpg",
108 "http://www.example.com/my-cat.jpg",
109 "text/plain",
110 L"my-cat.jpg"},
111
112 // .exe tests.
113 #if defined(OS_WIN)
114 {"filename=evil.exe",
115 "http://www.goodguy.com/evil.exe",
116 "image/jpeg",
117 L"evil.exe"},
118
119 {"filename=ok.exe",
120 "http://www.goodguy.com/ok.exe",
121 "binary/octet-stream",
122 L"ok.exe"},
123
124 {"filename=evil.dll",
125 "http://www.goodguy.com/evil.dll",
126 "dance/party",
127 L"evil.dll"},
128
129 {"filename=evil",
130 "http://www.goodguy.com/evil.exe",
131 "application/rss+xml",
132 L"evil"},
133
134 // Test truncation of trailing dots and spaces
135 {"filename=evil.exe ",
136 "http://www.goodguy.com/evil.exe ",
137 "binary/octet-stream",
138 L"evil.exe"},
139
140 {"filename=evil.exe.",
141 "http://www.goodguy.com/evil.exe.",
142 "binary/octet-stream",
143 L"evil.exe"},
144
145 {"filename=evil.exe. . .",
146 "http://www.goodguy.com/evil.exe. . .",
147 "binary/octet-stream",
148 L"evil.exe"},
149
150 {"filename=evil.",
151 "http://www.goodguy.com/evil.",
152 "binary/octet-stream",
153 L"evil"},
154
155 {"filename=. . . . .",
156 "http://www.goodguy.com/. . . . .",
157 "binary/octet-stream",
158 L"download"},
159
160 #endif // OS_WIN
161
162 {"filename=utils.js",
163 "http://www.goodguy.com/utils.js",
164 "application/x-javascript",
165 L"utils.js"},
166
167 {"filename=contacts.js",
168 "http://www.goodguy.com/contacts.js",
169 "application/json",
170 L"contacts.js"},
171
172 {"filename=utils.js",
173 "http://www.goodguy.com/utils.js",
174 "text/javascript",
175 L"utils.js"},
176
177 {"filename=utils.js",
178 "http://www.goodguy.com/utils.js",
179 "text/javascript;version=2",
180 L"utils.js"},
181
182 {"filename=utils.js",
183 "http://www.goodguy.com/utils.js",
184 "application/ecmascript",
185 L"utils.js"},
186
187 {"filename=utils.js",
188 "http://www.goodguy.com/utils.js",
189 "application/ecmascript;version=4",
190 L"utils.js"},
191
192 {"filename=program.exe",
193 "http://www.goodguy.com/program.exe",
194 "application/foo-bar",
195 L"program.exe"},
196
197 {"filename=../foo.txt",
198 "http://www.evil.com/../foo.txt",
199 "text/plain",
200 L"_foo.txt"},
201
202 {"filename=..\\foo.txt",
203 "http://www.evil.com/..\\foo.txt",
204 "text/plain",
205 L"_foo.txt"
206 },
207
208 {"filename=.hidden",
209 "http://www.evil.com/.hidden",
210 "text/plain",
211 L"hidden" TXT_EXT
212 },
213
214 {"filename=trailing.",
215 "http://www.evil.com/trailing.",
216 "dance/party",
217 L"trailing"
218 },
219
220 {"filename=trailing.",
221 "http://www.evil.com/trailing.",
222 "text/plain",
223 L"trailing" TXT_EXT
224 },
225
226 {"filename=.",
227 "http://www.evil.com/.",
228 "dance/party",
229 L"download"},
230
231 {"filename=..",
232 "http://www.evil.com/..",
233 "dance/party",
234 L"download"},
235
236 {"filename=...",
237 "http://www.evil.com/...",
238 "dance/party",
239 L"download"},
240
241 // Note that this one doesn't have "filename=" on it.
242 {"a_file_name.txt",
243 "http://www.evil.com/",
244 "image/jpeg",
245 L"download" JPEG_EXT
246 },
247
248 {"filename=",
249 "http://www.evil.com/",
250 "image/jpeg",
251 L"download" JPEG_EXT
252 },
253
254 {"filename=simple",
255 "http://www.example.com/simple",
256 "application/octet-stream",
257 L"simple"},
258
259 {"filename=COM1",
260 "http://www.goodguy.com/COM1",
261 "application/foo-bar",
262 #if defined(OS_WIN)
263 L"_COM1"
264 #else
265 L"COM1"
266 #endif
267 },
268
269 {"filename=COM4.txt",
270 "http://www.goodguy.com/COM4.txt",
271 "text/plain",
272 #if defined(OS_WIN)
273 L"_COM4.txt"
274 #else
275 L"COM4.txt"
276 #endif
277 },
278
279 {"filename=lpt1.TXT",
280 "http://www.goodguy.com/lpt1.TXT",
281 "text/plain",
282 #if defined(OS_WIN)
283 L"_lpt1.TXT"
284 #else
285 L"lpt1.TXT"
286 #endif
287 },
288
289 {"filename=clock$.txt",
290 "http://www.goodguy.com/clock$.txt",
291 "text/plain",
292 #if defined(OS_WIN)
293 L"_clock$.txt"
294 #else
295 L"clock$.txt"
296 #endif
297 },
298
299 {"filename=mycom1.foo",
300 "http://www.goodguy.com/mycom1.foo",
301 "text/plain",
302 L"mycom1.foo"},
303
304 {"filename=Setup.exe.local",
305 "http://www.badguy.com/Setup.exe.local",
306 "application/foo-bar",
307 #if defined(OS_WIN)
308 L"Setup.exe.download"
309 #else
310 L"Setup.exe.local"
311 #endif
312 },
313
314 {"filename=Setup.exe.local.local",
315 "http://www.badguy.com/Setup.exe.local",
316 "application/foo-bar",
317 #if defined(OS_WIN)
318 L"Setup.exe.local.download"
319 #else
320 L"Setup.exe.local.local"
321 #endif
322 },
323
324 {"filename=Setup.exe.lnk",
325 "http://www.badguy.com/Setup.exe.lnk",
326 "application/foo-bar",
327 #if defined(OS_WIN)
328 L"Setup.exe.download"
329 #else
330 L"Setup.exe.lnk"
331 #endif
332 },
333
334 {"filename=Desktop.ini",
335 "http://www.badguy.com/Desktop.ini",
336 "application/foo-bar",
337 #if defined(OS_WIN)
338 L"_Desktop.ini"
339 #else
340 L"Desktop.ini"
341 #endif
342 },
343
344 {"filename=Thumbs.db",
345 "http://www.badguy.com/Thumbs.db",
346 "application/foo-bar",
347 #if defined(OS_WIN)
348 L"_Thumbs.db"
349 #else
350 L"Thumbs.db"
351 #endif
352 },
353
354 {"filename=source.jpg",
355 "http://www.hotmail.com",
356 "application/x-javascript",
357 L"source.jpg"
358 },
359
360 // NetUtilTest.{GetSuggestedFilename, GetFileNameFromCD} test these
361 // more thoroughly. Tested below are a small set of samples.
362 {"attachment; filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
363 "http://www.examples.com/",
364 "image/jpeg",
365 L"\uc608\uc220 \uc608\uc220.jpg"},
366
367 {"attachment; name=abc de.pdf",
368 "http://www.examples.com/q.cgi?id=abc",
369 "application/octet-stream",
370 L"abc de.pdf"},
371
372 {"filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
373 "http://www.example.com/path",
374 "image/png",
375 L"\x82b8\x8853" L"3.png"},
376
377 // The following two have invalid CD headers and filenames come
378 // from the URL.
379 {"attachment; filename==?iiso88591?Q?caf=EG?=",
380 "http://www.example.com/test%20123",
381 "image/jpeg",
382 L"test 123" JPEG_EXT
383 },
384
385 {"malformed_disposition",
386 "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
387 "image/jpeg",
388 L"\uc608\uc220 \uc608\uc220.jpg"},
389
390 // Invalid C-D. No filename from URL. Falls back to 'download'.
391 {"attachment; filename==?iso88591?Q?caf=E3?",
392 "http://www.google.com/path1/path2/",
393 "image/jpeg",
394 L"download" JPEG_EXT
395 },
396
397 // Issue=5772.
398 {"",
399 "http://www.example.com/foo.tar.gz",
400 "application/x-tar",
401 L"foo.tar.gz"},
402
403 // Issue=52250.
404 {"",
405 "http://www.example.com/foo.tgz",
406 "application/x-tar",
407 L"foo.tgz"},
408
409 // Issue=7337.
410 {"",
411 "http://maged.lordaeron.org/blank.reg",
412 "text/x-registry",
413 L"blank.reg"},
414
415 {"",
416 "http://www.example.com/bar.tar",
417 "application/x-tar",
418 L"bar.tar"},
419
420 {"",
421 "http://www.example.com/bar.bogus",
422 "application/x-tar",
423 L"bar.bogus"
424 },
425
426 // http://code.google.com/p/chromium/issues/detail?id=20337
427 {"filename=.download.txt",
428 "http://www.example.com/.download.txt",
429 "text/plain",
430 L"download.txt"},
431
432 // Issue=56855.
433 {"",
434 "http://www.example.com/bar.sh",
435 "application/x-sh",
436 L"bar.sh"
437 },
438 };
439
440 // Tests to ensure that the file names we generate from hints from the server
441 // (content-disposition, URL name, etc) don't cause security holes.
442 TEST(DownloadUtilTest, GenerateFileName) {
443 #if defined(OS_POSIX) && !defined(OS_MACOSX)
444 // This test doesn't run when the locale is not UTF-8 because some of the
445 // string conversions fail. This is OK (we have the default value) but they
446 // don't match our expectations.
447 std::string locale = setlocale(LC_CTYPE, NULL);
448 StringToLowerASCII(&locale);
449 EXPECT_NE(std::string::npos, locale.find("utf-8"))
450 << "Your locale (" << locale << ") must be set to UTF-8 "
451 << "for this test to pass!";
452 #endif
453
454 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGenerateFileNameTestCases); ++i) {
455 FilePath generated_name;
456 download_util::GenerateFileName(GURL(kGenerateFileNameTestCases[i].url),
457 kGenerateFileNameTestCases[i].disposition,
458 "",
459 kGenerateFileNameTestCases[i].mime_type,
460 &generated_name);
461 EXPECT_EQ(kGenerateFileNameTestCases[i].expected_name,
462 file_util::FilePathAsWString(generated_name)) << i;
463 }
464
465 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kGenerateFileNameTestCases); ++i) {
466 FilePath generated_name;
467 download_util::GenerateFileName(GURL(kGenerateFileNameTestCases[i].url),
468 kGenerateFileNameTestCases[i].disposition,
469 "GBK",
470 kGenerateFileNameTestCases[i].mime_type,
471 &generated_name);
472 EXPECT_EQ(kGenerateFileNameTestCases[i].expected_name,
473 file_util::FilePathAsWString(generated_name)) << i;
474 }
475
476 // A couple of cases with raw 8bit characters in C-D.
477 {
478 FilePath generated_name;
479 download_util::GenerateFileName(GURL("http://www.example.com/images?id=3"),
480 "attachment; filename=caf\xc3\xa9.png",
481 "iso-8859-1",
482 "image/png",
483 &generated_name);
484 EXPECT_EQ(L"caf\u00e9.png", file_util::FilePathAsWString(generated_name));
485 }
486
487 {
488 FilePath generated_name;
489 download_util::GenerateFileName(GURL("http://www.example.com/images?id=3"),
490 "attachment; filename=caf\xe5.png",
491 "windows-1253",
492 "image/png",
493 &generated_name);
494 EXPECT_EQ(L"caf\u03b5.png", file_util::FilePathAsWString(generated_name));
495 }
496 }
497
498 const struct {
499 const FilePath::CharType* path;
500 const char* mime_type;
501 const FilePath::CharType* expected_path;
502 } kSafeFilenameCases[] = {
503 #if defined(OS_WIN)
504 { FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
505 "text/html",
506 FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
507 { FILE_PATH_LITERAL("C:\\foo\\bar.html"),
508 "text/html",
509 FILE_PATH_LITERAL("C:\\foo\\bar.html") },
510 { FILE_PATH_LITERAL("C:\\foo\\bar"),
511 "text/html",
512 FILE_PATH_LITERAL("C:\\foo\\bar.htm") },
513
514 { FILE_PATH_LITERAL("C:\\bar.html"),
515 "image/png",
516 FILE_PATH_LITERAL("C:\\bar.html") },
517 { FILE_PATH_LITERAL("C:\\bar"),
518 "image/png",
519 FILE_PATH_LITERAL("C:\\bar.png") },
520
521 { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
522 "text/html",
523 FILE_PATH_LITERAL("C:\\foo\\bar.exe") },
524 { FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
525 "image/gif",
526 FILE_PATH_LITERAL("C:\\foo\\bar.exe") },
527
528 { FILE_PATH_LITERAL("C:\\foo\\google.com"),
529 "text/html",
530 FILE_PATH_LITERAL("C:\\foo\\google.com") },
531
532 { FILE_PATH_LITERAL("C:\\foo\\con.htm"),
533 "text/html",
534 FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
535 { FILE_PATH_LITERAL("C:\\foo\\con"),
536 "text/html",
537 FILE_PATH_LITERAL("C:\\foo\\_con.htm") },
538 #else // !defined(OS_WIN)
539 { FILE_PATH_LITERAL("/foo/bar.htm"),
540 "text/html",
541 FILE_PATH_LITERAL("/foo/bar.htm") },
542 { FILE_PATH_LITERAL("/foo/bar.html"),
543 "text/html",
544 FILE_PATH_LITERAL("/foo/bar.html") },
545 { FILE_PATH_LITERAL("/foo/bar"),
546 "text/html",
547 FILE_PATH_LITERAL("/foo/bar.html") },
548
549 { FILE_PATH_LITERAL("/bar.html"),
550 "image/png",
551 FILE_PATH_LITERAL("/bar.html") },
552 { FILE_PATH_LITERAL("/bar"),
553 "image/png",
554 FILE_PATH_LITERAL("/bar.png") },
555
556 { FILE_PATH_LITERAL("/foo/bar.exe"),
557 "image/gif",
558 FILE_PATH_LITERAL("/foo/bar.exe") },
559
560 { FILE_PATH_LITERAL("/foo/google.com"),
561 "text/html",
562 FILE_PATH_LITERAL("/foo/google.com") },
563
564 { FILE_PATH_LITERAL("/foo/con.htm"),
565 "text/html",
566 FILE_PATH_LITERAL("/foo/con.htm") },
567 { FILE_PATH_LITERAL("/foo/con"),
568 "text/html",
569 FILE_PATH_LITERAL("/foo/con.html") },
570 #endif // !defined(OS_WIN)
571 };
572
573 TEST(DownloadUtilTest, GenerateSafeFileName) {
574 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kSafeFilenameCases); ++i) {
575 FilePath path(kSafeFilenameCases[i].path);
576 download_util::GenerateSafeFileName(kSafeFilenameCases[i].mime_type, &path);
577 EXPECT_EQ(kSafeFilenameCases[i].expected_path, path.value()) << i;
578 }
579 }
580
581 } // namespace
582
OLDNEW
« no previous file with comments | « chrome/browser/download/download_util.cc ('k') | chrome/chrome_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698