OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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 <string> | |
6 | |
7 #include "base/logging.h" | |
8 #include "chrome/browser/download_manager.h" | |
9 #include "chrome/browser/download_util.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 | |
12 class DownloadManagerTest : public testing::Test { | |
13 public: | |
14 DownloadManagerTest() { | |
15 download_manager_ = new DownloadManager(); | |
16 download_util::InitializeExeTypes(&download_manager_->exe_types_); | |
17 } | |
18 | |
19 void GetGeneratedFilename(const std::string& content_disposition, | |
20 const std::wstring& url, | |
21 const std::string& mime_type, | |
22 std::wstring* generated_name) { | |
23 DownloadCreateInfo info; | |
24 info.content_disposition = content_disposition; | |
25 info.url = url; | |
26 info.mime_type = mime_type; | |
27 download_manager_->GenerateFilename(&info, generated_name); | |
28 } | |
29 | |
30 protected: | |
31 scoped_refptr<DownloadManager> download_manager_; | |
32 MessageLoopForUI message_loop_; | |
33 | |
34 DISALLOW_EVIL_CONSTRUCTORS(DownloadManagerTest); | |
35 }; | |
36 | |
37 static const struct { | |
38 const char* disposition; | |
39 const wchar_t* url; | |
40 const char* mime_type; | |
41 const wchar_t* expected_name; | |
42 } kGeneratedFiles[] = { | |
43 // No 'filename' keyword in the disposition, use the URL | |
44 {"a_file_name.txt", | |
45 L"http://www.evil.com/my_download.txt", | |
46 "text/plain", | |
47 L"my_download.txt"}, | |
48 | |
49 // Disposition has relative paths, remove them | |
50 {"filename=../../../../././../a_file_name.txt", | |
51 L"http://www.evil.com/my_download.txt", | |
52 "text/plain", | |
53 L"a_file_name.txt"}, | |
54 | |
55 // Disposition has parent directories, remove them | |
56 {"filename=dir1/dir2/a_file_name.txt", | |
57 L"http://www.evil.com/my_download.txt", | |
58 "text/plain", | |
59 L"a_file_name.txt"}, | |
60 | |
61 // No useful information in disposition or URL, use default | |
62 {"", L"http://www.truncated.com/path/", "text/plain", L"download.txt"}, | |
63 | |
64 // Spaces in the disposition file name | |
65 {"filename=My Downloaded File.exe", | |
66 L"http://www.frontpagehacker.com/a_download.exe", | |
67 "application/octet-stream", | |
68 L"My Downloaded File.exe"}, | |
69 | |
70 {"filename=my-cat", | |
71 L"http://www.example.com/my-cat", | |
72 "image/jpeg", | |
73 L"my-cat.jpg"}, | |
74 | |
75 {"filename=my-cat", | |
76 L"http://www.example.com/my-cat", | |
77 "text/plain", | |
78 L"my-cat.txt"}, | |
79 | |
80 {"filename=my-cat", | |
81 L"http://www.example.com/my-cat", | |
82 "text/html", | |
83 L"my-cat.htm"}, | |
84 | |
85 {"filename=my-cat", | |
86 L"http://www.example.com/my-cat", | |
87 "dance/party", | |
88 L"my-cat"}, | |
89 | |
90 {"filename=my-cat.jpg", | |
91 L"http://www.example.com/my-cat.jpg", | |
92 "text/plain", | |
93 L"my-cat.jpg"}, | |
94 | |
95 {"filename=evil.exe", | |
96 L"http://www.goodguy.com/evil.exe", | |
97 "image/jpeg", | |
98 L"evil.jpg"}, | |
99 | |
100 {"filename=evil.exe.exe", | |
101 L"http://www.goodguy.com/evil.exe.exe", | |
102 "dance/party", | |
103 L"evil.exe.download"}, | |
104 | |
105 {"filename=evil.exe", | |
106 L"http://www.goodguy.com/evil.exe", | |
107 "application/xml", | |
108 L"evil.xml"}, | |
109 | |
110 {"filename=evil.exe", | |
111 L"http://www.goodguy.com/evil.exe", | |
112 "application/html+xml", | |
113 L"evil.download"}, | |
114 | |
115 {"filename=evil.exe", | |
116 L"http://www.goodguy.com/evil.exe", | |
117 "application/rss+xml", | |
118 L"evil.download"}, | |
119 | |
120 {"filename=utils.js", | |
121 L"http://www.goodguy.com/utils.js", | |
122 "application/x-javascript", | |
123 L"utils.js"}, | |
124 | |
125 {"filename=contacts.js", | |
126 L"http://www.goodguy.com/contacts.js", | |
127 "application/json", | |
128 L"contacts.js"}, | |
129 | |
130 {"filename=utils.js", | |
131 L"http://www.goodguy.com/utils.js", | |
132 "text/javascript", | |
133 L"utils.js"}, | |
134 | |
135 {"filename=utils.js", | |
136 L"http://www.goodguy.com/utils.js", | |
137 "text/javascript;version=2", | |
138 L"utils.js"}, | |
139 | |
140 {"filename=utils.js", | |
141 L"http://www.goodguy.com/utils.js", | |
142 "application/ecmascript", | |
143 L"utils.js"}, | |
144 | |
145 {"filename=utils.js", | |
146 L"http://www.goodguy.com/utils.js", | |
147 "application/ecmascript;version=4", | |
148 L"utils.js"}, | |
149 | |
150 {"filename=program.exe", | |
151 L"http://www.goodguy.com/program.exe", | |
152 "application/foo-bar", | |
153 L"program.exe"}, | |
154 | |
155 {"filename=../foo.txt", | |
156 L"http://www.evil.com/../foo.txt", | |
157 "text/plain", | |
158 L"foo.txt"}, | |
159 | |
160 {"filename=..\\foo.txt", | |
161 L"http://www.evil.com/..\\foo.txt", | |
162 "text/plain", | |
163 L"foo.txt"}, | |
164 | |
165 {"filename=.hidden", | |
166 L"http://www.evil.com/.hidden", | |
167 "text/plain", | |
168 L"hidden.txt"}, | |
169 | |
170 {"filename=trailing.", | |
171 L"http://www.evil.com/trailing.", | |
172 "dance/party", | |
173 L"trailing"}, | |
174 | |
175 {"filename=trailing.", | |
176 L"http://www.evil.com/trailing.", | |
177 "text/plain", | |
178 L"trailing.txt"}, | |
179 | |
180 {"filename=.", | |
181 L"http://www.evil.com/.", | |
182 "dance/party", | |
183 L"download"}, | |
184 | |
185 {"filename=..", | |
186 L"http://www.evil.com/..", | |
187 "dance/party", | |
188 L"download"}, | |
189 | |
190 {"filename=...", | |
191 L"http://www.evil.com/...", | |
192 "dance/party", | |
193 L"download"}, | |
194 | |
195 {"a_file_name.txt", | |
196 L"http://www.evil.com/", | |
197 "image/jpeg", | |
198 L"download.jpg"}, | |
199 | |
200 {"filename=", | |
201 L"http://www.evil.com/", | |
202 "image/jpeg", | |
203 L"download.jpg"}, | |
204 | |
205 {"filename=simple", | |
206 L"http://www.example.com/simple", | |
207 "application/octet-stream", | |
208 L"simple"}, | |
209 | |
210 {"filename=COM1", | |
211 L"http://www.goodguy.com/COM1", | |
212 "application/foo-bar", | |
213 L"_COM1"}, | |
214 | |
215 {"filename=COM4.txt", | |
216 L"http://www.goodguy.com/COM4.txt", | |
217 "text/plain", | |
218 L"_COM4.txt"}, | |
219 | |
220 {"filename=lpt1.TXT", | |
221 L"http://www.goodguy.com/lpt1.TXT", | |
222 "text/plain", | |
223 L"_lpt1.TXT"}, | |
224 | |
225 {"filename=clock$.txt", | |
226 L"http://www.goodguy.com/clock$.txt", | |
227 "text/plain", | |
228 L"_clock$.txt"}, | |
229 | |
230 {"filename=mycom1.foo", | |
231 L"http://www.goodguy.com/mycom1.foo", | |
232 "text/plain", | |
233 L"mycom1.foo"}, | |
234 | |
235 {"filename=Setup.exe.local", | |
236 L"http://www.badguy.com/Setup.exe.local", | |
237 "application/foo-bar", | |
238 L"Setup.exe.download"}, | |
239 | |
240 {"filename=Setup.exe.local.local", | |
241 L"http://www.badguy.com/Setup.exe.local", | |
242 "application/foo-bar", | |
243 L"Setup.exe.local.download"}, | |
244 | |
245 {"filename=Setup.exe.lnk", | |
246 L"http://www.badguy.com/Setup.exe.lnk", | |
247 "application/foo-bar", | |
248 L"Setup.exe.download"}, | |
249 | |
250 {"filename=Desktop.ini", | |
251 L"http://www.badguy.com/Desktop.ini", | |
252 "application/foo-bar", | |
253 L"_Desktop.ini"}, | |
254 | |
255 {"filename=Thumbs.db", | |
256 L"http://www.badguy.com/Thumbs.db", | |
257 "application/foo-bar", | |
258 L"_Thumbs.db"}, | |
259 | |
260 {"filename=source.srf", | |
261 L"http://www.hotmail.com", | |
262 "image/jpeg", | |
263 L"source.srf.jpg"}, | |
264 | |
265 {"filename=source.jpg", | |
266 L"http://www.hotmail.com", | |
267 "application/x-javascript", | |
268 L"source.jpg"}, | |
269 | |
270 // NetUtilTest.{GetSuggestedFilename, GetFileNameFromCD} test these | |
271 // more thoroughly. Tested below are a small set of samples. | |
272 {"attachment; filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"", | |
273 L"http://www.examples.com/", | |
274 "image/jpeg", | |
275 L"\uc608\uc220 \uc608\uc220.jpg"}, | |
276 | |
277 {"attachment; name=abc de.pdf", | |
278 L"http://www.examples.com/q.cgi?id=abc", | |
279 "application/octet-stream", | |
280 L"abc de.pdf"}, | |
281 | |
282 {"filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"", | |
283 L"http://www.example.com/path", | |
284 "image/png", | |
285 L"\x82b8\x8853" L"3.png"}, | |
286 | |
287 // The following two have invalid CD headers and filenames come | |
288 // from the URL. | |
289 {"attachment; filename==?iiso88591?Q?caf=EG?=", | |
290 L"http://www.example.com/test%20123", | |
291 "image/jpeg", | |
292 L"test 123.jpg"}, | |
293 | |
294 {"malformed_disposition", | |
295 L"http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg", | |
296 "image/jpeg", | |
297 L"\uc608\uc220 \uc608\uc220.jpg"}, | |
298 | |
299 // Invalid C-D. No filename from URL. Falls back to 'download'. | |
300 {"attachment; filename==?iso88591?Q?caf=E3?", | |
301 L"http://www.google.com/path1/path2/", | |
302 "image/jpeg", | |
303 L"download.jpg"}, | |
304 | |
305 // TODO(darin): Add some raw 8-bit Content-Disposition tests. | |
306 }; | |
307 | |
308 // Tests to ensure that the file names we generate from hints from the server | |
309 // (content-disposition, URL name, etc) don't cause security holes. | |
310 TEST_F(DownloadManagerTest, TestDownloadFilename) { | |
311 for (int i = 0; i < arraysize(kGeneratedFiles); ++i) { | |
312 std::wstring file_name; | |
313 GetGeneratedFilename(kGeneratedFiles[i].disposition, | |
314 kGeneratedFiles[i].url, | |
315 kGeneratedFiles[i].mime_type, | |
316 &file_name); | |
317 EXPECT_EQ(kGeneratedFiles[i].expected_name, file_name); | |
318 } | |
319 } | |
320 | |
OLD | NEW |