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/base/net_util.h"
6
7 #include <string.h>
8
9 #include <algorithm>
10
11 #include "base/files/file_path.h"
12 #include "base/format_macros.h"
13 #include "base/scoped_native_library.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/sys_byteorder.h"
20 #include "base/test/test_file_util.h"
21 #include "base/time/time.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "url/gurl.h"
24
25 #if defined(OS_WIN)
26 #include <iphlpapi.h>
27 #include <objbase.h>
28 #include "base/win/windows_version.h"
29 #elif !defined(OS_ANDROID)
30 #include <net/if.h>
31 #endif // OS_WIN
32
33 namespace net {
34
35 namespace {
36
37 static const size_t kNpos = base::string16::npos;
38
39 struct FileCase {
40 const wchar_t* file;
41 const char* url;
42 };
43
44 struct HeaderCase {
45 const char* header_name;
46 const char* expected;
47 };
48
49 struct HeaderParamCase {
50 const char* header_name;
51 const char* param_name;
52 const char* expected;
53 };
54
55 struct FileNameCDCase {
56 const char* header_field;
57 const char* referrer_charset;
58 const wchar_t* expected;
59 };
60
61 const char* kLanguages[] = {
62 "", "en", "zh-CN", "ja", "ko",
63 "he", "ar", "ru", "el", "fr",
64 "de", "pt", "sv", "th", "hi",
65 "de,en", "el,en", "zh-TW,en", "ko,ja", "he,ru,en",
66 "zh,ru,en"
67 };
68
69 struct IDNTestCase {
70 const char* input;
71 const wchar_t* unicode_output;
72 const bool unicode_allowed[arraysize(kLanguages)];
73 };
74
75 // TODO(jungshik) This is just a random sample of languages and is far
76 // from exhaustive. We may have to generate all the combinations
77 // of languages (powerset of a set of all the languages).
78 const IDNTestCase idn_cases[] = {
79 // No IDN
80 {"www.google.com", L"www.google.com",
81 {true, true, true, true, true,
82 true, true, true, true, true,
83 true, true, true, true, true,
84 true, true, true, true, true,
85 true}},
86 {"www.google.com.", L"www.google.com.",
87 {true, true, true, true, true,
88 true, true, true, true, true,
89 true, true, true, true, true,
90 true, true, true, true, true,
91 true}},
92 {".", L".",
93 {true, true, true, true, true,
94 true, true, true, true, true,
95 true, true, true, true, true,
96 true, true, true, true, true,
97 true}},
98 {"", L"",
99 {true, true, true, true, true,
100 true, true, true, true, true,
101 true, true, true, true, true,
102 true, true, true, true, true,
103 true}},
104 // IDN
105 // Hanzi (Traditional Chinese)
106 {"xn--1lq90ic7f1rc.cn", L"\x5317\x4eac\x5927\x5b78.cn",
107 {true, false, true, true, false,
108 false, false, false, false, false,
109 false, false, false, false, false,
110 false, false, true, true, false,
111 true}},
112 // Hanzi ('video' in Simplified Chinese : will pass only in zh-CN,zh)
113 {"xn--cy2a840a.com", L"\x89c6\x9891.com",
114 {true, false, true, false, false,
115 false, false, false, false, false,
116 false, false, false, false, false,
117 false, false, false, false, false,
118 true}},
119 // Hanzi + '123'
120 {"www.xn--123-p18d.com", L"www.\x4e00" L"123.com",
121 {true, false, true, true, false,
122 false, false, false, false, false,
123 false, false, false, false, false,
124 false, false, true, true, false,
125 true}},
126 // Hanzi + Latin : U+56FD is simplified and is regarded
127 // as not supported in zh-TW.
128 {"www.xn--hello-9n1hm04c.com", L"www.hello\x4e2d\x56fd.com",
129 {false, false, true, true, false,
130 false, false, false, false, false,
131 false, false, false, false, false,
132 false, false, false, true, false,
133 true}},
134 // Kanji + Kana (Japanese)
135 {"xn--l8jvb1ey91xtjb.jp", L"\x671d\x65e5\x3042\x3055\x3072.jp",
136 {true, false, false, true, false,
137 false, false, false, false, false,
138 false, false, false, false, false,
139 false, false, false, true, false,
140 false}},
141 // Katakana including U+30FC
142 {"xn--tckm4i2e.jp", L"\x30b3\x30de\x30fc\x30b9.jp",
143 {true, false, false, true, false,
144 false, false, false, false, false,
145 false, false, false, false, false,
146 false, false, false, true, false,
147 }},
148 {"xn--3ck7a7g.jp", L"\u30ce\u30f3\u30bd.jp",
149 {true, false, false, true, false,
150 false, false, false, false, false,
151 false, false, false, false, false,
152 false, false, false, true, false,
153 }},
154 // Katakana + Latin (Japanese)
155 // TODO(jungshik): Change 'false' in the first element to 'true'
156 // after upgrading to ICU 4.2.1 to use new uspoof_* APIs instead
157 // of our IsIDNComponentInSingleScript().
158 {"xn--e-efusa1mzf.jp", L"e\x30b3\x30de\x30fc\x30b9.jp",
159 {false, false, false, true, false,
160 false, false, false, false, false,
161 false, false, false, false, false,
162 false, false, false, true, false,
163 }},
164 {"xn--3bkxe.jp", L"\x30c8\x309a.jp",
165 {false, false, false, true, false,
166 false, false, false, false, false,
167 false, false, false, false, false,
168 false, false, false, true, false,
169 }},
170 // Hangul (Korean)
171 {"www.xn--or3b17p6jjc.kr", L"www.\xc804\xc790\xc815\xbd80.kr",
172 {true, false, false, false, true,
173 false, false, false, false, false,
174 false, false, false, false, false,
175 false, false, false, true, false,
176 false}},
177 // b<u-umlaut>cher (German)
178 {"xn--bcher-kva.de", L"b\x00fc" L"cher.de",
179 {true, false, false, false, false,
180 false, false, false, false, true,
181 true, false, false, false, false,
182 true, false, false, false, false,
183 false}},
184 // a with diaeresis
185 {"www.xn--frgbolaget-q5a.se", L"www.f\x00e4rgbolaget.se",
186 {true, false, false, false, false,
187 false, false, false, false, false,
188 true, false, true, false, false,
189 true, false, false, false, false,
190 false}},
191 // c-cedilla (French)
192 {"www.xn--alliancefranaise-npb.fr", L"www.alliancefran\x00e7" L"aise.fr",
193 {true, false, false, false, false,
194 false, false, false, false, true,
195 false, true, false, false, false,
196 false, false, false, false, false,
197 false}},
198 // caf'e with acute accent' (French)
199 {"xn--caf-dma.fr", L"caf\x00e9.fr",
200 {true, false, false, false, false,
201 false, false, false, false, true,
202 false, true, true, false, false,
203 false, false, false, false, false,
204 false}},
205 // c-cedillla and a with tilde (Portuguese)
206 {"xn--poema-9qae5a.com.br", L"p\x00e3oema\x00e7\x00e3.com.br",
207 {true, false, false, false, false,
208 false, false, false, false, false,
209 false, true, false, false, false,
210 false, false, false, false, false,
211 false}},
212 // s with caron
213 {"xn--achy-f6a.com", L"\x0161" L"achy.com",
214 {true, false, false, false, false,
215 false, false, false, false, false,
216 false, false, false, false, false,
217 false, false, false, false, false,
218 false}},
219 // TODO(jungshik) : Add examples with Cyrillic letters
220 // only used in some languages written in Cyrillic.
221 // Eutopia (Greek)
222 {"xn--kxae4bafwg.gr", L"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1.gr",
223 {true, false, false, false, false,
224 false, false, false, true, false,
225 false, false, false, false, false,
226 false, true, false, false, false,
227 false}},
228 // Eutopia + 123 (Greek)
229 {"xn---123-pldm0haj2bk.gr",
230 L"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1-123.gr",
231 {true, false, false, false, false,
232 false, false, false, true, false,
233 false, false, false, false, false,
234 false, true, false, false, false,
235 false}},
236 // Cyrillic (Russian)
237 {"xn--n1aeec9b.ru", L"\x0442\x043e\x0440\x0442\x044b.ru",
238 {true, false, false, false, false,
239 false, false, true, false, false,
240 false, false, false, false, false,
241 false, false, false, false, true,
242 true}},
243 // Cyrillic + 123 (Russian)
244 {"xn---123-45dmmc5f.ru", L"\x0442\x043e\x0440\x0442\x044b-123.ru",
245 {true, false, false, false, false,
246 false, false, true, false, false,
247 false, false, false, false, false,
248 false, false, false, false, true,
249 true}},
250 // Arabic
251 {"xn--mgba1fmg.ar", L"\x0627\x0641\x0644\x0627\x0645.ar",
252 {true, false, false, false, false,
253 false, true, false, false, false,
254 false, false, false, false, false,
255 false, false, false, false, false,
256 false}},
257 // Hebrew
258 {"xn--4dbib.he", L"\x05d5\x05d0\x05d4.he",
259 {true, false, false, false, false,
260 true, false, false, false, false,
261 false, false, false, false, false,
262 false, false, false, false, true,
263 false}},
264 // Thai
265 {"xn--12c2cc4ag3b4ccu.th",
266 L"\x0e2a\x0e32\x0e22\x0e01\x0e32\x0e23\x0e1a\x0e34\x0e19.th",
267 {true, false, false, false, false,
268 false, false, false, false, false,
269 false, false, false, true, false,
270 false, false, false, false, false,
271 false}},
272 // Devangari (Hindi)
273 {"www.xn--l1b6a9e1b7c.in", L"www.\x0905\x0915\x094b\x0932\x093e.in",
274 {true, false, false, false, false,
275 false, false, false, false, false,
276 false, false, false, false, true,
277 false, false, false, false, false,
278 false}},
279 // Invalid IDN
280 {"xn--hello?world.com", NULL,
281 {false, false, false, false, false,
282 false, false, false, false, false,
283 false, false, false, false, false,
284 false, false, false, false, false,
285 false}},
286 // Unsafe IDNs
287 // "payp<alpha>l.com"
288 {"www.xn--paypl-g9d.com", L"payp\x03b1l.com",
289 {false, false, false, false, false,
290 false, false, false, false, false,
291 false, false, false, false, false,
292 false, false, false, false, false,
293 false}},
294 // google.gr with Greek omicron and epsilon
295 {"xn--ggl-6xc1ca.gr", L"g\x03bf\x03bfgl\x03b5.gr",
296 {false, false, false, false, false,
297 false, false, false, false, false,
298 false, false, false, false, false,
299 false, false, false, false, false,
300 false}},
301 // google.ru with Cyrillic o
302 {"xn--ggl-tdd6ba.ru", L"g\x043e\x043egl\x0435.ru",
303 {false, false, false, false, false,
304 false, false, false, false, false,
305 false, false, false, false, false,
306 false, false, false, false, false,
307 false}},
308 // h<e with acute>llo<China in Han>.cn
309 {"xn--hllo-bpa7979ih5m.cn", L"h\x00e9llo\x4e2d\x56fd.cn",
310 {false, false, false, false, false,
311 false, false, false, false, false,
312 false, false, false, false, false,
313 false, false, false, false, false,
314 false}},
315 // <Greek rho><Cyrillic a><Cyrillic u>.ru
316 {"xn--2xa6t2b.ru", L"\x03c1\x0430\x0443.ru",
317 {false, false, false, false, false,
318 false, false, false, false, false,
319 false, false, false, false, false,
320 false, false, false, false, false,
321 false}},
322 // One that's really long that will force a buffer realloc
323 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
324 "aaaaaaa",
325 L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
326 L"aaaaaaaa",
327 {true, true, true, true, true,
328 true, true, true, true, true,
329 true, true, true, true, true,
330 true, true, true, true, true,
331 true}},
332 // Test cases for characters we blacklisted although allowed in IDN.
333 // Embedded spaces will be turned to %20 in the display.
334 // TODO(jungshik): We need to have more cases. This is a typical
335 // data-driven trap. The following test cases need to be separated
336 // and tested only for a couple of languages.
337 {"xn--osd3820f24c.kr", L"\xac00\xb098\x115f.kr",
338 {false, false, false, false, false,
339 false, false, false, false, false,
340 false, false, false, false, false,
341 false, false, false, false, false,
342 false}},
343 {"www.xn--google-ho0coa.com", L"www.\x2039google\x203a.com",
344 {false, false, false, false, false,
345 false, false, false, false, false,
346 false, false, false, false, false,
347 false, false, false, false, false,
348 }},
349 {"google.xn--comabc-k8d", L"google.com\x0338" L"abc",
350 {false, false, false, false, false,
351 false, false, false, false, false,
352 false, false, false, false, false,
353 false, false, false, false, false,
354 }},
355 {"google.xn--com-oh4ba.evil.jp", L"google.com\x309a\x309a.evil.jp",
356 {false, false, false, false, false,
357 false, false, false, false, false,
358 false, false, false, false, false,
359 false, false, false, false, false,
360 }},
361 {"google.xn--comevil-v04f.jp", L"google.com\x30ce" L"evil.jp",
362 {false, false, false, false, false,
363 false, false, false, false, false,
364 false, false, false, false, false,
365 false, false, false, false, false,
366 }},
367 #if 0
368 // These two cases are special. We need a separate test.
369 // U+3000 and U+3002 are normalized to ASCII space and dot.
370 {"xn-- -kq6ay5z.cn", L"\x4e2d\x56fd\x3000.cn",
371 {false, false, true, false, false,
372 false, false, false, false, false,
373 false, false, false, false, false,
374 false, false, true, false, false,
375 true}},
376 {"xn--fiqs8s.cn", L"\x4e2d\x56fd\x3002" L"cn",
377 {false, false, true, false, false,
378 false, false, false, false, false,
379 false, false, false, false, false,
380 false, false, true, false, false,
381 true}},
382 #endif
383 };
384
385 struct AdjustOffsetCase {
386 size_t input_offset;
387 size_t output_offset;
388 };
389
390 struct CompliantHostCase {
391 const char* host;
392 const char* desired_tld;
393 bool expected_output;
394 };
395
396 struct GenerateFilenameCase {
397 int lineno;
398 const char* url;
399 const char* content_disp_header;
400 const char* referrer_charset;
401 const char* suggested_filename;
402 const char* mime_type;
403 const wchar_t* default_filename;
404 const wchar_t* expected_filename;
405 };
406
407 struct UrlTestData {
408 const char* description;
409 const char* input;
410 const char* languages;
411 FormatUrlTypes format_types;
412 UnescapeRule::Type escape_rules;
413 const wchar_t* output; // Use |wchar_t| to handle Unicode constants easily.
414 size_t prefix_len;
415 };
416
417 // Fills in sockaddr for the given 32-bit address (IPv4.)
418 // |bytes| should be an array of length 4.
MakeIPv4Address(const uint8 * bytes,int port,SockaddrStorage * storage)419 void MakeIPv4Address(const uint8* bytes, int port, SockaddrStorage* storage) {
420 memset(&storage->addr_storage, 0, sizeof(storage->addr_storage));
421 storage->addr_len = sizeof(struct sockaddr_in);
422 struct sockaddr_in* addr4 = reinterpret_cast<sockaddr_in*>(storage->addr);
423 addr4->sin_port = base::HostToNet16(port);
424 addr4->sin_family = AF_INET;
425 memcpy(&addr4->sin_addr, bytes, 4);
426 }
427
428 // Fills in sockaddr for the given 128-bit address (IPv6.)
429 // |bytes| should be an array of length 16.
MakeIPv6Address(const uint8 * bytes,int port,SockaddrStorage * storage)430 void MakeIPv6Address(const uint8* bytes, int port, SockaddrStorage* storage) {
431 memset(&storage->addr_storage, 0, sizeof(storage->addr_storage));
432 storage->addr_len = sizeof(struct sockaddr_in6);
433 struct sockaddr_in6* addr6 = reinterpret_cast<sockaddr_in6*>(storage->addr);
434 addr6->sin6_port = base::HostToNet16(port);
435 addr6->sin6_family = AF_INET6;
436 memcpy(&addr6->sin6_addr, bytes, 16);
437 }
438
439 // A helper for IDN*{Fast,Slow}.
440 // Append "::<language list>" to |expected| and |actual| to make it
441 // easy to tell which sub-case fails without debugging.
AppendLanguagesToOutputs(const char * languages,base::string16 * expected,base::string16 * actual)442 void AppendLanguagesToOutputs(const char* languages,
443 base::string16* expected,
444 base::string16* actual) {
445 base::string16 to_append = ASCIIToUTF16("::") + ASCIIToUTF16(languages);
446 expected->append(to_append);
447 actual->append(to_append);
448 }
449
450 // A pair of helpers for the FormatUrlWithOffsets() test.
VerboseExpect(size_t expected,size_t actual,const std::string & original_url,size_t position,const base::string16 & formatted_url)451 void VerboseExpect(size_t expected,
452 size_t actual,
453 const std::string& original_url,
454 size_t position,
455 const base::string16& formatted_url) {
456 EXPECT_EQ(expected, actual) << "Original URL: " << original_url
457 << " (at char " << position << ")\nFormatted URL: " << formatted_url;
458 }
459
CheckAdjustedOffsets(const std::string & url_string,const std::string & languages,FormatUrlTypes format_types,UnescapeRule::Type unescape_rules,const size_t * output_offsets)460 void CheckAdjustedOffsets(const std::string& url_string,
461 const std::string& languages,
462 FormatUrlTypes format_types,
463 UnescapeRule::Type unescape_rules,
464 const size_t* output_offsets) {
465 GURL url(url_string);
466 size_t url_length = url_string.length();
467 std::vector<size_t> offsets;
468 for (size_t i = 0; i <= url_length + 1; ++i)
469 offsets.push_back(i);
470 offsets.push_back(500000); // Something larger than any input length.
471 offsets.push_back(std::string::npos);
472 base::string16 formatted_url = FormatUrlWithOffsets(url, languages,
473 format_types, unescape_rules, NULL, NULL, &offsets);
474 for (size_t i = 0; i < url_length; ++i)
475 VerboseExpect(output_offsets[i], offsets[i], url_string, i, formatted_url);
476 VerboseExpect(formatted_url.length(), offsets[url_length], url_string,
477 url_length, formatted_url);
478 VerboseExpect(base::string16::npos, offsets[url_length + 1], url_string,
479 500000, formatted_url);
480 VerboseExpect(base::string16::npos, offsets[url_length + 2], url_string,
481 std::string::npos, formatted_url);
482 }
483
484 // Helper to strignize an IP number (used to define expectations).
DumpIPNumber(const IPAddressNumber & v)485 std::string DumpIPNumber(const IPAddressNumber& v) {
486 std::string out;
487 for (size_t i = 0; i < v.size(); ++i) {
488 if (i != 0)
489 out.append(",");
490 out.append(base::IntToString(static_cast<int>(v[i])));
491 }
492 return out;
493 }
494
RunGenerateFileNameTestCase(const GenerateFilenameCase * test_case)495 void RunGenerateFileNameTestCase(const GenerateFilenameCase* test_case) {
496 std::string default_filename(WideToUTF8(test_case->default_filename));
497 base::FilePath file_path = GenerateFileName(
498 GURL(test_case->url), test_case->content_disp_header,
499 test_case->referrer_charset, test_case->suggested_filename,
500 test_case->mime_type, default_filename);
501 EXPECT_EQ(test_case->expected_filename,
502 file_util::FilePathAsWString(file_path))
503 << "test case at line number: " << test_case->lineno;
504 }
505
506 } // anonymous namespace
507
TEST(NetUtilTest,FileURLConversion)508 TEST(NetUtilTest, FileURLConversion) {
509 // a list of test file names and the corresponding URLs
510 const FileCase round_trip_cases[] = {
511 #if defined(OS_WIN)
512 {L"C:\\foo\\bar.txt", "file:///C:/foo/bar.txt"},
513 {L"\\\\some computer\\foo\\bar.txt",
514 "file://some%20computer/foo/bar.txt"}, // UNC
515 {L"D:\\Name;with%some symbols*#",
516 "file:///D:/Name%3Bwith%25some%20symbols*%23"},
517 // issue 14153: To be tested with the OS default codepage other than 1252.
518 {L"D:\\latin1\\caf\x00E9\x00DD.txt",
519 "file:///D:/latin1/caf%C3%A9%C3%9D.txt"},
520 {L"D:\\otherlatin\\caf\x0119.txt",
521 "file:///D:/otherlatin/caf%C4%99.txt"},
522 {L"D:\\greek\\\x03B1\x03B2\x03B3.txt",
523 "file:///D:/greek/%CE%B1%CE%B2%CE%B3.txt"},
524 {L"D:\\Chinese\\\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
525 "file:///D:/Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD%91"
526 "%E9%A1%B5.doc"},
527 {L"D:\\plane1\\\xD835\xDC00\xD835\xDC01.txt", // Math alphabet "AB"
528 "file:///D:/plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
529 #elif defined(OS_POSIX)
530 {L"/foo/bar.txt", "file:///foo/bar.txt"},
531 {L"/foo/BAR.txt", "file:///foo/BAR.txt"},
532 {L"/C:/foo/bar.txt", "file:///C:/foo/bar.txt"},
533 {L"/foo/bar?.txt", "file:///foo/bar%3F.txt"},
534 {L"/some computer/foo/bar.txt", "file:///some%20computer/foo/bar.txt"},
535 {L"/Name;with%some symbols*#", "file:///Name%3Bwith%25some%20symbols*%23"},
536 {L"/latin1/caf\x00E9\x00DD.txt", "file:///latin1/caf%C3%A9%C3%9D.txt"},
537 {L"/otherlatin/caf\x0119.txt", "file:///otherlatin/caf%C4%99.txt"},
538 {L"/greek/\x03B1\x03B2\x03B3.txt", "file:///greek/%CE%B1%CE%B2%CE%B3.txt"},
539 {L"/Chinese/\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
540 "file:///Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD"
541 "%91%E9%A1%B5.doc"},
542 {L"/plane1/\x1D400\x1D401.txt", // Math alphabet "AB"
543 "file:///plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
544 #endif
545 };
546
547 // First, we'll test that we can round-trip all of the above cases of URLs
548 base::FilePath output;
549 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(round_trip_cases); i++) {
550 // convert to the file URL
551 GURL file_url(FilePathToFileURL(
552 file_util::WStringAsFilePath(round_trip_cases[i].file)));
553 EXPECT_EQ(round_trip_cases[i].url, file_url.spec());
554
555 // Back to the filename.
556 EXPECT_TRUE(FileURLToFilePath(file_url, &output));
557 EXPECT_EQ(round_trip_cases[i].file, file_util::FilePathAsWString(output));
558 }
559
560 // Test that various file: URLs get decoded into the correct file type
561 FileCase url_cases[] = {
562 #if defined(OS_WIN)
563 {L"C:\\foo\\bar.txt", "file:c|/foo\\bar.txt"},
564 {L"C:\\foo\\bar.txt", "file:/c:/foo/bar.txt"},
565 {L"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
566 {L"C:\\foo\\bar.txt", "file:///c:/foo/bar.txt"},
567 {L"\\\\foo\\bar.txt", "file:////foo\\bar.txt"},
568 {L"\\\\foo\\bar.txt", "file:/foo/bar.txt"},
569 {L"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
570 {L"C:\\foo\\bar.txt", "file:\\\\\\c:/foo/bar.txt"},
571 #elif defined(OS_POSIX)
572 {L"/c:/foo/bar.txt", "file:/c:/foo/bar.txt"},
573 {L"/c:/foo/bar.txt", "file:///c:/foo/bar.txt"},
574 {L"/foo/bar.txt", "file:/foo/bar.txt"},
575 {L"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
576 {L"/foo/bar.txt", "file:foo/bar.txt"},
577 {L"/bar.txt", "file://foo/bar.txt"},
578 {L"/foo/bar.txt", "file:///foo/bar.txt"},
579 {L"/foo/bar.txt", "file:////foo/bar.txt"},
580 {L"/foo/bar.txt", "file:////foo//bar.txt"},
581 {L"/foo/bar.txt", "file:////foo///bar.txt"},
582 {L"/foo/bar.txt", "file:////foo////bar.txt"},
583 {L"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
584 {L"/c:/foo/bar.txt", "file:c:/foo/bar.txt"},
585 // We get these wrong because GURL turns back slashes into forward
586 // slashes.
587 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
588 //{L"/c|/foo%5Cbar.txt", "file:c|/foo\\bar.txt"},
589 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
590 //{L"/foo%5Cbar.txt", "file:////foo\\bar.txt"},
591 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
592 #endif
593 };
594 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(url_cases); i++) {
595 FileURLToFilePath(GURL(url_cases[i].url), &output);
596 EXPECT_EQ(url_cases[i].file, file_util::FilePathAsWString(output));
597 }
598
599 // Unfortunately, UTF8ToWide discards invalid UTF8 input.
600 #ifdef BUG_878908_IS_FIXED
601 // Test that no conversion happens if the UTF-8 input is invalid, and that
602 // the input is preserved in UTF-8
603 const char invalid_utf8[] = "file:///d:/Blah/\xff.doc";
604 const wchar_t invalid_wide[] = L"D:\\Blah\\\xff.doc";
605 EXPECT_TRUE(FileURLToFilePath(
606 GURL(std::string(invalid_utf8)), &output));
607 EXPECT_EQ(std::wstring(invalid_wide), output);
608 #endif
609
610 // Test that if a file URL is malformed, we get a failure
611 EXPECT_FALSE(FileURLToFilePath(GURL("filefoobar"), &output));
612 }
613
TEST(NetUtilTest,GetIdentityFromURL)614 TEST(NetUtilTest, GetIdentityFromURL) {
615 struct {
616 const char* input_url;
617 const char* expected_username;
618 const char* expected_password;
619 } tests[] = {
620 {
621 "http://username:password@google.com",
622 "username",
623 "password",
624 },
625 { // Test for http://crbug.com/19200
626 "http://username:p@ssword@google.com",
627 "username",
628 "p@ssword",
629 },
630 { // Special URL characters should be unescaped.
631 "http://username:p%3fa%26s%2fs%23@google.com",
632 "username",
633 "p?a&s/s#",
634 },
635 { // Username contains %20.
636 "http://use rname:password@google.com",
637 "use rname",
638 "password",
639 },
640 { // Keep %00 as is.
641 "http://use%00rname:password@google.com",
642 "use%00rname",
643 "password",
644 },
645 { // Use a '+' in the username.
646 "http://use+rname:password@google.com",
647 "use+rname",
648 "password",
649 },
650 { // Use a '&' in the password.
651 "http://username:p&ssword@google.com",
652 "username",
653 "p&ssword",
654 },
655 };
656 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
657 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
658 tests[i].input_url));
659 GURL url(tests[i].input_url);
660
661 base::string16 username, password;
662 GetIdentityFromURL(url, &username, &password);
663
664 EXPECT_EQ(ASCIIToUTF16(tests[i].expected_username), username);
665 EXPECT_EQ(ASCIIToUTF16(tests[i].expected_password), password);
666 }
667 }
668
669 // Try extracting a username which was encoded with UTF8.
TEST(NetUtilTest,GetIdentityFromURL_UTF8)670 TEST(NetUtilTest, GetIdentityFromURL_UTF8) {
671 GURL url(WideToUTF16(L"http://foo:\x4f60\x597d@blah.com"));
672
673 EXPECT_EQ("foo", url.username());
674 EXPECT_EQ("%E4%BD%A0%E5%A5%BD", url.password());
675
676 // Extract the unescaped identity.
677 base::string16 username, password;
678 GetIdentityFromURL(url, &username, &password);
679
680 // Verify that it was decoded as UTF8.
681 EXPECT_EQ(ASCIIToUTF16("foo"), username);
682 EXPECT_EQ(WideToUTF16(L"\x4f60\x597d"), password);
683 }
684
685 // Just a bunch of fake headers.
686 const char* google_headers =
687 "HTTP/1.1 200 OK\n"
688 "Content-TYPE: text/html; charset=utf-8\n"
689 "Content-disposition: attachment; filename=\"download.pdf\"\n"
690 "Content-Length: 378557\n"
691 "X-Google-Google1: 314159265\n"
692 "X-Google-Google2: aaaa2:7783,bbb21:9441\n"
693 "X-Google-Google4: home\n"
694 "Transfer-Encoding: chunked\n"
695 "Set-Cookie: HEHE_AT=6666x66beef666x6-66xx6666x66; Path=/mail\n"
696 "Set-Cookie: HEHE_HELP=owned:0;Path=/\n"
697 "Set-Cookie: S=gmail=Xxx-beefbeefbeef_beefb:gmail_yj=beefbeef000beefbee"
698 "fbee:gmproxy=bee-fbeefbe; Domain=.google.com; Path=/\n"
699 "X-Google-Google2: /one/two/three/four/five/six/seven-height/nine:9411\n"
700 "Server: GFE/1.3\n"
701 "Transfer-Encoding: chunked\n"
702 "Date: Mon, 13 Nov 2006 21:38:09 GMT\n"
703 "Expires: Tue, 14 Nov 2006 19:23:58 GMT\n"
704 "X-Malformed: bla; arg=test\"\n"
705 "X-Malformed2: bla; arg=\n"
706 "X-Test: bla; arg1=val1; arg2=val2";
707
TEST(NetUtilTest,GetSpecificHeader)708 TEST(NetUtilTest, GetSpecificHeader) {
709 const HeaderCase tests[] = {
710 {"content-type", "text/html; charset=utf-8"},
711 {"CONTENT-LENGTH", "378557"},
712 {"Date", "Mon, 13 Nov 2006 21:38:09 GMT"},
713 {"Bad-Header", ""},
714 {"", ""},
715 };
716
717 // Test first with google_headers.
718 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
719 std::string result =
720 GetSpecificHeader(google_headers, tests[i].header_name);
721 EXPECT_EQ(result, tests[i].expected);
722 }
723
724 // Test again with empty headers.
725 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
726 std::string result = GetSpecificHeader(std::string(), tests[i].header_name);
727 EXPECT_EQ(result, std::string());
728 }
729 }
730
TEST(NetUtilTest,IDNToUnicodeFast)731 TEST(NetUtilTest, IDNToUnicodeFast) {
732 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(idn_cases); i++) {
733 for (size_t j = 0; j < arraysize(kLanguages); j++) {
734 // ja || zh-TW,en || ko,ja -> IDNToUnicodeSlow
735 if (j == 3 || j == 17 || j == 18)
736 continue;
737 base::string16 output(IDNToUnicode(idn_cases[i].input, kLanguages[j]));
738 base::string16 expected(idn_cases[i].unicode_allowed[j] ?
739 WideToUTF16(idn_cases[i].unicode_output) :
740 ASCIIToUTF16(idn_cases[i].input));
741 AppendLanguagesToOutputs(kLanguages[j], &expected, &output);
742 EXPECT_EQ(expected, output);
743 }
744 }
745 }
746
TEST(NetUtilTest,IDNToUnicodeSlow)747 TEST(NetUtilTest, IDNToUnicodeSlow) {
748 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(idn_cases); i++) {
749 for (size_t j = 0; j < arraysize(kLanguages); j++) {
750 // !(ja || zh-TW,en || ko,ja) -> IDNToUnicodeFast
751 if (!(j == 3 || j == 17 || j == 18))
752 continue;
753 base::string16 output(IDNToUnicode(idn_cases[i].input, kLanguages[j]));
754 base::string16 expected(idn_cases[i].unicode_allowed[j] ?
755 WideToUTF16(idn_cases[i].unicode_output) :
756 ASCIIToUTF16(idn_cases[i].input));
757 AppendLanguagesToOutputs(kLanguages[j], &expected, &output);
758 EXPECT_EQ(expected, output);
759 }
760 }
761 }
762
TEST(NetUtilTest,CompliantHost)763 TEST(NetUtilTest, CompliantHost) {
764 const CompliantHostCase compliant_host_cases[] = {
765 {"", "", false},
766 {"a", "", true},
767 {"-", "", false},
768 {".", "", false},
769 {"9", "", true},
770 {"9a", "", true},
771 {"a.", "", true},
772 {"a.a", "", true},
773 {"9.a", "", true},
774 {"a.9", "", true},
775 {"_9a", "", false},
776 {"-9a", "", false},
777 {"-9a", "a", true},
778 {"a.a9", "", true},
779 {"a.-a9", "", false},
780 {"a+9a", "", false},
781 {"-a.a9", "", true},
782 {"1-.a-b", "", true},
783 {"1_.a-b", "", false},
784 {"1-2.a_b", "", true},
785 {"a.b.c.d.e", "", true},
786 {"1.2.3.4.5", "", true},
787 {"1.2.3.4.5.", "", true},
788 };
789
790 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(compliant_host_cases); ++i) {
791 EXPECT_EQ(compliant_host_cases[i].expected_output,
792 IsCanonicalizedHostCompliant(compliant_host_cases[i].host,
793 compliant_host_cases[i].desired_tld));
794 }
795 }
796
TEST(NetUtilTest,StripWWW)797 TEST(NetUtilTest, StripWWW) {
798 EXPECT_EQ(base::string16(), StripWWW(base::string16()));
799 EXPECT_EQ(base::string16(), StripWWW(ASCIIToUTF16("www.")));
800 EXPECT_EQ(ASCIIToUTF16("blah"), StripWWW(ASCIIToUTF16("www.blah")));
801 EXPECT_EQ(ASCIIToUTF16("blah"), StripWWW(ASCIIToUTF16("blah")));
802 }
803
804 #if defined(OS_WIN)
805 #define JPEG_EXT L".jpg"
806 #define HTML_EXT L".htm"
807 #elif defined(OS_MACOSX)
808 #define JPEG_EXT L".jpeg"
809 #define HTML_EXT L".html"
810 #else
811 #define JPEG_EXT L".jpg"
812 #define HTML_EXT L".html"
813 #endif
814 #define TXT_EXT L".txt"
815 #define TAR_EXT L".tar"
816
TEST(NetUtilTest,GenerateSafeFileName)817 TEST(NetUtilTest, GenerateSafeFileName) {
818 const struct {
819 const char* mime_type;
820 const base::FilePath::CharType* filename;
821 const base::FilePath::CharType* expected_filename;
822 } safe_tests[] = {
823 #if defined(OS_WIN)
824 {
825 "text/html",
826 FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
827 FILE_PATH_LITERAL("C:\\foo\\bar.htm")
828 },
829 {
830 "text/html",
831 FILE_PATH_LITERAL("C:\\foo\\bar.html"),
832 FILE_PATH_LITERAL("C:\\foo\\bar.html")
833 },
834 {
835 "text/html",
836 FILE_PATH_LITERAL("C:\\foo\\bar"),
837 FILE_PATH_LITERAL("C:\\foo\\bar.htm")
838 },
839 {
840 "image/png",
841 FILE_PATH_LITERAL("C:\\bar.html"),
842 FILE_PATH_LITERAL("C:\\bar.html")
843 },
844 {
845 "image/png",
846 FILE_PATH_LITERAL("C:\\bar"),
847 FILE_PATH_LITERAL("C:\\bar.png")
848 },
849 {
850 "text/html",
851 FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
852 FILE_PATH_LITERAL("C:\\foo\\bar.exe")
853 },
854 {
855 "image/gif",
856 FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
857 FILE_PATH_LITERAL("C:\\foo\\bar.exe")
858 },
859 {
860 "text/html",
861 FILE_PATH_LITERAL("C:\\foo\\google.com"),
862 FILE_PATH_LITERAL("C:\\foo\\google.com")
863 },
864 {
865 "text/html",
866 FILE_PATH_LITERAL("C:\\foo\\con.htm"),
867 FILE_PATH_LITERAL("C:\\foo\\_con.htm")
868 },
869 {
870 "text/html",
871 FILE_PATH_LITERAL("C:\\foo\\con"),
872 FILE_PATH_LITERAL("C:\\foo\\_con.htm")
873 },
874 {
875 "text/html",
876 FILE_PATH_LITERAL("C:\\foo\\harmless.{not-really-this-may-be-a-guid}"),
877 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
878 },
879 {
880 "text/html",
881 FILE_PATH_LITERAL("C:\\foo\\harmless.local"),
882 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
883 },
884 {
885 "text/html",
886 FILE_PATH_LITERAL("C:\\foo\\harmless.lnk"),
887 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
888 },
889 {
890 "text/html",
891 FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-"),
892 FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-")
893 },
894 // Allow extension synonyms.
895 {
896 "image/jpeg",
897 FILE_PATH_LITERAL("C:\\foo\\bar.jpg"),
898 FILE_PATH_LITERAL("C:\\foo\\bar.jpg")
899 },
900 {
901 "image/jpeg",
902 FILE_PATH_LITERAL("C:\\foo\\bar.jpeg"),
903 FILE_PATH_LITERAL("C:\\foo\\bar.jpeg")
904 },
905 #else // !defined(OS_WIN)
906 {
907 "text/html",
908 FILE_PATH_LITERAL("/foo/bar.htm"),
909 FILE_PATH_LITERAL("/foo/bar.htm")
910 },
911 {
912 "text/html",
913 FILE_PATH_LITERAL("/foo/bar.html"),
914 FILE_PATH_LITERAL("/foo/bar.html")
915 },
916 {
917 "text/html",
918 FILE_PATH_LITERAL("/foo/bar"),
919 FILE_PATH_LITERAL("/foo/bar.html")
920 },
921 {
922 "image/png",
923 FILE_PATH_LITERAL("/bar.html"),
924 FILE_PATH_LITERAL("/bar.html")
925 },
926 {
927 "image/png",
928 FILE_PATH_LITERAL("/bar"),
929 FILE_PATH_LITERAL("/bar.png")
930 },
931 {
932 "image/gif",
933 FILE_PATH_LITERAL("/foo/bar.exe"),
934 FILE_PATH_LITERAL("/foo/bar.exe")
935 },
936 {
937 "text/html",
938 FILE_PATH_LITERAL("/foo/google.com"),
939 FILE_PATH_LITERAL("/foo/google.com")
940 },
941 {
942 "text/html",
943 FILE_PATH_LITERAL("/foo/con.htm"),
944 FILE_PATH_LITERAL("/foo/con.htm")
945 },
946 {
947 "text/html",
948 FILE_PATH_LITERAL("/foo/con"),
949 FILE_PATH_LITERAL("/foo/con.html")
950 },
951 // Allow extension synonyms.
952 {
953 "image/jpeg",
954 FILE_PATH_LITERAL("/bar.jpg"),
955 FILE_PATH_LITERAL("/bar.jpg")
956 },
957 {
958 "image/jpeg",
959 FILE_PATH_LITERAL("/bar.jpeg"),
960 FILE_PATH_LITERAL("/bar.jpeg")
961 },
962 #endif // !defined(OS_WIN)
963 };
964
965 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(safe_tests); ++i) {
966 base::FilePath file_path(safe_tests[i].filename);
967 GenerateSafeFileName(safe_tests[i].mime_type, false, &file_path);
968 EXPECT_EQ(safe_tests[i].expected_filename, file_path.value())
969 << "Iteration " << i;
970 }
971 }
972
TEST(NetUtilTest,GenerateFileName)973 TEST(NetUtilTest, GenerateFileName) {
974 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
975 // This test doesn't run when the locale is not UTF-8 because some of the
976 // string conversions fail. This is OK (we have the default value) but they
977 // don't match our expectations.
978 std::string locale = setlocale(LC_CTYPE, NULL);
979 StringToLowerASCII(&locale);
980 EXPECT_TRUE(locale.find("utf-8") != std::string::npos ||
981 locale.find("utf8") != std::string::npos)
982 << "Your locale (" << locale << ") must be set to UTF-8 "
983 << "for this test to pass!";
984 #endif
985
986 // Tests whether the correct filename is selected from the the given
987 // parameters and that Content-Disposition headers are properly
988 // handled including failovers when the header is malformed.
989 const GenerateFilenameCase selection_tests[] = {
990 {
991 __LINE__,
992 "http://www.google.com/",
993 "attachment; filename=test.html",
994 "",
995 "",
996 "",
997 L"",
998 L"test.html"
999 },
1000 {
1001 __LINE__,
1002 "http://www.google.com/",
1003 "attachment; filename=\"test.html\"",
1004 "",
1005 "",
1006 "",
1007 L"",
1008 L"test.html"
1009 },
1010 {
1011 __LINE__,
1012 "http://www.google.com/",
1013 "attachment; filename= \"test.html\"",
1014 "",
1015 "",
1016 "",
1017 L"",
1018 L"test.html"
1019 },
1020 {
1021 __LINE__,
1022 "http://www.google.com/",
1023 "attachment; filename = \"test.html\"",
1024 "",
1025 "",
1026 "",
1027 L"",
1028 L"test.html"
1029 },
1030 { // filename is whitespace. Should failover to URL host
1031 __LINE__,
1032 "http://www.google.com/",
1033 "attachment; filename= ",
1034 "",
1035 "",
1036 "",
1037 L"",
1038 L"www.google.com"
1039 },
1040 { // No filename.
1041 __LINE__,
1042 "http://www.google.com/path/test.html",
1043 "attachment",
1044 "",
1045 "",
1046 "",
1047 L"",
1048 L"test.html"
1049 },
1050 { // Ditto
1051 __LINE__,
1052 "http://www.google.com/path/test.html",
1053 "attachment;",
1054 "",
1055 "",
1056 "",
1057 L"",
1058 L"test.html"
1059 },
1060 { // No C-D
1061 __LINE__,
1062 "http://www.google.com/",
1063 "",
1064 "",
1065 "",
1066 "",
1067 L"",
1068 L"www.google.com"
1069 },
1070 {
1071 __LINE__,
1072 "http://www.google.com/test.html",
1073 "",
1074 "",
1075 "",
1076 "",
1077 L"",
1078 L"test.html"
1079 },
1080 { // Now that we use src/url's ExtractFileName, this case falls back to
1081 // the hostname. If this behavior is not desirable, we'd better change
1082 // ExtractFileName (in url_parse).
1083 __LINE__,
1084 "http://www.google.com/path/",
1085 "",
1086 "",
1087 "",
1088 "",
1089 L"",
1090 L"www.google.com"
1091 },
1092 {
1093 __LINE__,
1094 "http://www.google.com/path",
1095 "",
1096 "",
1097 "",
1098 "",
1099 L"",
1100 L"path"
1101 },
1102 {
1103 __LINE__,
1104 "file:///",
1105 "",
1106 "",
1107 "",
1108 "",
1109 L"",
1110 L"download"
1111 },
1112 {
1113 __LINE__,
1114 "file:///path/testfile",
1115 "",
1116 "",
1117 "",
1118 "",
1119 L"",
1120 L"testfile"
1121 },
1122 {
1123 __LINE__,
1124 "non-standard-scheme:",
1125 "",
1126 "",
1127 "",
1128 "",
1129 L"",
1130 L"download"
1131 },
1132 { // C-D should override default
1133 __LINE__,
1134 "http://www.google.com/",
1135 "attachment; filename =\"test.html\"",
1136 "",
1137 "",
1138 "",
1139 L"download",
1140 L"test.html"
1141 },
1142 { // But the URL shouldn't
1143 __LINE__,
1144 "http://www.google.com/",
1145 "",
1146 "",
1147 "",
1148 "",
1149 L"download",
1150 L"download"
1151 },
1152 {
1153 __LINE__,
1154 "http://www.google.com/",
1155 "attachment; filename=\"../test.html\"",
1156 "",
1157 "",
1158 "",
1159 L"",
1160 L"-test.html"
1161 },
1162 {
1163 __LINE__,
1164 "http://www.google.com/",
1165 "attachment; filename=\"..\\test.html\"",
1166 "",
1167 "",
1168 "",
1169 L"",
1170 L"test.html"
1171 },
1172 {
1173 __LINE__,
1174 "http://www.google.com/",
1175 "attachment; filename=\"..\\\\test.html\"",
1176 "",
1177 "",
1178 "",
1179 L"",
1180 L"-test.html"
1181 },
1182 { // Filename disappears after leading and trailing periods are removed.
1183 __LINE__,
1184 "http://www.google.com/",
1185 "attachment; filename=\"..\"",
1186 "",
1187 "",
1188 "",
1189 L"default",
1190 L"default"
1191 },
1192 { // C-D specified filename disappears. Failover to final filename.
1193 __LINE__,
1194 "http://www.google.com/test.html",
1195 "attachment; filename=\"..\"",
1196 "",
1197 "",
1198 "",
1199 L"default",
1200 L"default"
1201 },
1202 // Below is a small subset of cases taken from HttpContentDisposition tests.
1203 {
1204 __LINE__,
1205 "http://www.google.com/",
1206 "attachment; filename=\"%EC%98%88%EC%88%A0%20"
1207 "%EC%98%88%EC%88%A0.jpg\"",
1208 "",
1209 "",
1210 "",
1211 L"",
1212 L"\uc608\uc220 \uc608\uc220.jpg"
1213 },
1214 {
1215 __LINE__,
1216 "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
1217 "",
1218 "",
1219 "",
1220 "",
1221 L"download",
1222 L"\uc608\uc220 \uc608\uc220.jpg"
1223 },
1224 {
1225 __LINE__,
1226 "http://www.google.com/",
1227 "attachment;",
1228 "",
1229 "",
1230 "",
1231 L"\uB2E4\uC6B4\uB85C\uB4DC",
1232 L"\uB2E4\uC6B4\uB85C\uB4DC"
1233 },
1234 {
1235 __LINE__,
1236 "http://www.google.com/",
1237 "attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
1238 "D13=2Epng?=\"",
1239 "",
1240 "",
1241 "",
1242 L"download",
1243 L"\u82b8\u88533.png"
1244 },
1245 {
1246 __LINE__,
1247 "http://www.example.com/images?id=3",
1248 "attachment; filename=caf\xc3\xa9.png",
1249 "iso-8859-1",
1250 "",
1251 "",
1252 L"",
1253 L"caf\u00e9.png"
1254 },
1255 {
1256 __LINE__,
1257 "http://www.example.com/images?id=3",
1258 "attachment; filename=caf\xe5.png",
1259 "windows-1253",
1260 "",
1261 "",
1262 L"",
1263 L"caf\u03b5.png"
1264 },
1265 {
1266 __LINE__,
1267 "http://www.example.com/file?id=3",
1268 "attachment; name=\xcf\xc2\xd4\xd8.zip",
1269 "GBK",
1270 "",
1271 "",
1272 L"",
1273 L"\u4e0b\u8f7d.zip"
1274 },
1275 { // Invalid C-D header. Extracts filename from url.
1276 __LINE__,
1277 "http://www.google.com/test.html",
1278 "attachment; filename==?iiso88591?Q?caf=EG?=",
1279 "",
1280 "",
1281 "",
1282 L"",
1283 L"test.html"
1284 },
1285 // about: and data: URLs
1286 {
1287 __LINE__,
1288 "about:chrome",
1289 "",
1290 "",
1291 "",
1292 "",
1293 L"",
1294 L"download"
1295 },
1296 {
1297 __LINE__,
1298 "data:,looks/like/a.path",
1299 "",
1300 "",
1301 "",
1302 "",
1303 L"",
1304 L"download"
1305 },
1306 {
1307 __LINE__,
1308 "data:text/plain;base64,VG8gYmUgb3Igbm90IHRvIGJlLg=",
1309 "",
1310 "",
1311 "",
1312 "",
1313 L"",
1314 L"download"
1315 },
1316 {
1317 __LINE__,
1318 "data:,looks/like/a.path",
1319 "",
1320 "",
1321 "",
1322 "",
1323 L"default_filename_is_given",
1324 L"default_filename_is_given"
1325 },
1326 {
1327 __LINE__,
1328 "data:,looks/like/a.path",
1329 "",
1330 "",
1331 "",
1332 "",
1333 L"\u65e5\u672c\u8a9e", // Japanese Kanji.
1334 L"\u65e5\u672c\u8a9e"
1335 },
1336 { // The filename encoding is specified by the referrer charset.
1337 __LINE__,
1338 "http://example.com/V%FDvojov%E1%20psychologie.doc",
1339 "",
1340 "iso-8859-1",
1341 "",
1342 "",
1343 L"",
1344 L"V\u00fdvojov\u00e1 psychologie.doc"
1345 },
1346 { // Suggested filename takes precedence over URL
1347 __LINE__,
1348 "http://www.google.com/test",
1349 "",
1350 "",
1351 "suggested",
1352 "",
1353 L"",
1354 L"suggested"
1355 },
1356 { // The content-disposition has higher precedence over the suggested name.
1357 __LINE__,
1358 "http://www.google.com/test",
1359 "attachment; filename=test.html",
1360 "",
1361 "suggested",
1362 "",
1363 L"",
1364 L"test.html"
1365 },
1366 #if 0
1367 { // The filename encoding doesn't match the referrer charset, the system
1368 // charset, or UTF-8.
1369 // TODO(jshin): we need to handle this case.
1370 __LINE__,
1371 "http://example.com/V%FDvojov%E1%20psychologie.doc",
1372 "",
1373 "utf-8",
1374 "",
1375 "",
1376 L"",
1377 L"V\u00fdvojov\u00e1 psychologie.doc",
1378 },
1379 #endif
1380 // Raw 8bit characters in C-D
1381 {
1382 __LINE__,
1383 "http://www.example.com/images?id=3",
1384 "attachment; filename=caf\xc3\xa9.png",
1385 "iso-8859-1",
1386 "",
1387 "image/png",
1388 L"",
1389 L"caf\u00e9.png"
1390 },
1391 {
1392 __LINE__,
1393 "http://www.example.com/images?id=3",
1394 "attachment; filename=caf\xe5.png",
1395 "windows-1253",
1396 "",
1397 "image/png",
1398 L"",
1399 L"caf\u03b5.png"
1400 },
1401 { // No 'filename' keyword in the disposition, use the URL
1402 __LINE__,
1403 "http://www.evil.com/my_download.txt",
1404 "a_file_name.txt",
1405 "",
1406 "",
1407 "text/plain",
1408 L"download",
1409 L"my_download.txt"
1410 },
1411 { // Spaces in the disposition file name
1412 __LINE__,
1413 "http://www.frontpagehacker.com/a_download.exe",
1414 "filename=My Downloaded File.exe",
1415 "",
1416 "",
1417 "application/octet-stream",
1418 L"download",
1419 L"My Downloaded File.exe"
1420 },
1421 { // % encoded
1422 __LINE__,
1423 "http://www.examples.com/",
1424 "attachment; "
1425 "filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
1426 "",
1427 "",
1428 "image/jpeg",
1429 L"download",
1430 L"\uc608\uc220 \uc608\uc220.jpg"
1431 },
1432 { // name= parameter
1433 __LINE__,
1434 "http://www.examples.com/q.cgi?id=abc",
1435 "attachment; name=abc de.pdf",
1436 "",
1437 "",
1438 "application/octet-stream",
1439 L"download",
1440 L"abc de.pdf"
1441 },
1442 {
1443 __LINE__,
1444 "http://www.example.com/path",
1445 "filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
1446 "",
1447 "",
1448 "image/png",
1449 L"download",
1450 L"\x82b8\x8853" L"3.png"
1451 },
1452 { // The following two have invalid CD headers and filenames come from the
1453 // URL.
1454 __LINE__,
1455 "http://www.example.com/test%20123",
1456 "attachment; filename==?iiso88591?Q?caf=EG?=",
1457 "",
1458 "",
1459 "image/jpeg",
1460 L"download",
1461 L"test 123" JPEG_EXT
1462 },
1463 {
1464 __LINE__,
1465 "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
1466 "malformed_disposition",
1467 "",
1468 "",
1469 "image/jpeg",
1470 L"download",
1471 L"\uc608\uc220 \uc608\uc220.jpg"
1472 },
1473 { // Invalid C-D. No filename from URL. Falls back to 'download'.
1474 __LINE__,
1475 "http://www.google.com/path1/path2/",
1476 "attachment; filename==?iso88591?Q?caf=E3?",
1477 "",
1478 "",
1479 "image/jpeg",
1480 L"download",
1481 L"download" JPEG_EXT
1482 },
1483 };
1484
1485 // Tests filename generation. Once the correct filename is
1486 // selected, they should be passed through the validation steps and
1487 // a correct extension should be added if necessary.
1488 const GenerateFilenameCase generation_tests[] = {
1489 // Dotfiles. Ensures preceeding period(s) stripped.
1490 {
1491 __LINE__,
1492 "http://www.google.com/.test.html",
1493 "",
1494 "",
1495 "",
1496 "",
1497 L"",
1498 L"test.html"
1499 },
1500 {
1501 __LINE__,
1502 "http://www.google.com/.test",
1503 "",
1504 "",
1505 "",
1506 "",
1507 L"",
1508 L"test"
1509 },
1510 {
1511 __LINE__,
1512 "http://www.google.com/..test",
1513 "",
1514 "",
1515 "",
1516 "",
1517 L"",
1518 L"test"
1519 },
1520 { // Disposition has relative paths, remove directory separators
1521 __LINE__,
1522 "http://www.evil.com/my_download.txt",
1523 "filename=../../../../././../a_file_name.txt",
1524 "",
1525 "",
1526 "text/plain",
1527 L"download",
1528 L"-..-..-..-.-.-..-a_file_name.txt"
1529 },
1530 { // Disposition has parent directories, remove directory separators
1531 __LINE__,
1532 "http://www.evil.com/my_download.txt",
1533 "filename=dir1/dir2/a_file_name.txt",
1534 "",
1535 "",
1536 "text/plain",
1537 L"download",
1538 L"dir1-dir2-a_file_name.txt"
1539 },
1540 { // Disposition has relative paths, remove directory separators
1541 __LINE__,
1542 "http://www.evil.com/my_download.txt",
1543 "filename=..\\..\\..\\..\\.\\.\\..\\a_file_name.txt",
1544 "",
1545 "",
1546 "text/plain",
1547 L"download",
1548 L"-..-..-..-.-.-..-a_file_name.txt"
1549 },
1550 { // Disposition has parent directories, remove directory separators
1551 __LINE__,
1552 "http://www.evil.com/my_download.txt",
1553 "filename=dir1\\dir2\\a_file_name.txt",
1554 "",
1555 "",
1556 "text/plain",
1557 L"download",
1558 L"dir1-dir2-a_file_name.txt"
1559 },
1560 { // No useful information in disposition or URL, use default
1561 __LINE__,
1562 "http://www.truncated.com/path/",
1563 "",
1564 "",
1565 "",
1566 "text/plain",
1567 L"download",
1568 L"download" TXT_EXT
1569 },
1570 { // Filename looks like HTML?
1571 __LINE__,
1572 "http://www.evil.com/get/malware/here",
1573 "filename=\"<blink>Hello kitty</blink>\"",
1574 "",
1575 "",
1576 "text/plain",
1577 L"default",
1578 L"-blink-Hello kitty--blink-" TXT_EXT
1579 },
1580 { // A normal avi should get .avi and not .avi.avi
1581 __LINE__,
1582 "https://blah.google.com/misc/2.avi",
1583 "",
1584 "",
1585 "",
1586 "video/x-msvideo",
1587 L"download",
1588 L"2.avi"
1589 },
1590 { // Extension generation
1591 __LINE__,
1592 "http://www.example.com/my-cat",
1593 "filename=my-cat",
1594 "",
1595 "",
1596 "image/jpeg",
1597 L"download",
1598 L"my-cat" JPEG_EXT
1599 },
1600 {
1601 __LINE__,
1602 "http://www.example.com/my-cat",
1603 "filename=my-cat",
1604 "",
1605 "",
1606 "text/plain",
1607 L"download",
1608 L"my-cat.txt"
1609 },
1610 {
1611 __LINE__,
1612 "http://www.example.com/my-cat",
1613 "filename=my-cat",
1614 "",
1615 "",
1616 "text/html",
1617 L"download",
1618 L"my-cat" HTML_EXT
1619 },
1620 { // Unknown MIME type
1621 __LINE__,
1622 "http://www.example.com/my-cat",
1623 "filename=my-cat",
1624 "",
1625 "",
1626 "dance/party",
1627 L"download",
1628 L"my-cat"
1629 },
1630 {
1631 __LINE__,
1632 "http://www.example.com/my-cat.jpg",
1633 "filename=my-cat.jpg",
1634 "",
1635 "",
1636 "text/plain",
1637 L"download",
1638 L"my-cat.jpg"
1639 },
1640 // Windows specific tests
1641 #if defined(OS_WIN)
1642 {
1643 __LINE__,
1644 "http://www.goodguy.com/evil.exe",
1645 "filename=evil.exe",
1646 "",
1647 "",
1648 "image/jpeg",
1649 L"download",
1650 L"evil.exe"
1651 },
1652 {
1653 __LINE__,
1654 "http://www.goodguy.com/ok.exe",
1655 "filename=ok.exe",
1656 "",
1657 "",
1658 "binary/octet-stream",
1659 L"download",
1660 L"ok.exe"
1661 },
1662 {
1663 __LINE__,
1664 "http://www.goodguy.com/evil.dll",
1665 "filename=evil.dll",
1666 "",
1667 "",
1668 "dance/party",
1669 L"download",
1670 L"evil.dll"
1671 },
1672 {
1673 __LINE__,
1674 "http://www.goodguy.com/evil.exe",
1675 "filename=evil",
1676 "",
1677 "",
1678 "application/rss+xml",
1679 L"download",
1680 L"evil"
1681 },
1682 // Test truncation of trailing dots and spaces
1683 {
1684 __LINE__,
1685 "http://www.goodguy.com/evil.exe ",
1686 "filename=evil.exe ",
1687 "",
1688 "",
1689 "binary/octet-stream",
1690 L"download",
1691 L"evil.exe"
1692 },
1693 {
1694 __LINE__,
1695 "http://www.goodguy.com/evil.exe.",
1696 "filename=evil.exe.",
1697 "",
1698 "",
1699 "binary/octet-stream",
1700 L"download",
1701 L"evil.exe-"
1702 },
1703 {
1704 __LINE__,
1705 "http://www.goodguy.com/evil.exe. . .",
1706 "filename=evil.exe. . .",
1707 "",
1708 "",
1709 "binary/octet-stream",
1710 L"download",
1711 L"evil.exe-------"
1712 },
1713 {
1714 __LINE__,
1715 "http://www.goodguy.com/evil.",
1716 "filename=evil.",
1717 "",
1718 "",
1719 "binary/octet-stream",
1720 L"download",
1721 L"evil-"
1722 },
1723 {
1724 __LINE__,
1725 "http://www.goodguy.com/. . . . .",
1726 "filename=. . . . .",
1727 "",
1728 "",
1729 "binary/octet-stream",
1730 L"download",
1731 L"download"
1732 },
1733 {
1734 __LINE__,
1735 "http://www.badguy.com/attachment?name=meh.exe%C2%A0",
1736 "attachment; filename=\"meh.exe\xC2\xA0\"",
1737 "",
1738 "",
1739 "binary/octet-stream",
1740 L"",
1741 L"meh.exe-"
1742 },
1743 #endif // OS_WIN
1744 {
1745 __LINE__,
1746 "http://www.goodguy.com/utils.js",
1747 "filename=utils.js",
1748 "",
1749 "",
1750 "application/x-javascript",
1751 L"download",
1752 L"utils.js"
1753 },
1754 {
1755 __LINE__,
1756 "http://www.goodguy.com/contacts.js",
1757 "filename=contacts.js",
1758 "",
1759 "",
1760 "application/json",
1761 L"download",
1762 L"contacts.js"
1763 },
1764 {
1765 __LINE__,
1766 "http://www.goodguy.com/utils.js",
1767 "filename=utils.js",
1768 "",
1769 "",
1770 "text/javascript",
1771 L"download",
1772 L"utils.js"
1773 },
1774 {
1775 __LINE__,
1776 "http://www.goodguy.com/utils.js",
1777 "filename=utils.js",
1778 "",
1779 "",
1780 "text/javascript;version=2",
1781 L"download",
1782 L"utils.js"
1783 },
1784 {
1785 __LINE__,
1786 "http://www.goodguy.com/utils.js",
1787 "filename=utils.js",
1788 "",
1789 "",
1790 "application/ecmascript",
1791 L"download",
1792 L"utils.js"
1793 },
1794 {
1795 __LINE__,
1796 "http://www.goodguy.com/utils.js",
1797 "filename=utils.js",
1798 "",
1799 "",
1800 "application/ecmascript;version=4",
1801 L"download",
1802 L"utils.js"
1803 },
1804 {
1805 __LINE__,
1806 "http://www.goodguy.com/program.exe",
1807 "filename=program.exe",
1808 "",
1809 "",
1810 "application/foo-bar",
1811 L"download",
1812 L"program.exe"
1813 },
1814 {
1815 __LINE__,
1816 "http://www.evil.com/../foo.txt",
1817 "filename=../foo.txt",
1818 "",
1819 "",
1820 "text/plain",
1821 L"download",
1822 L"-foo.txt"
1823 },
1824 {
1825 __LINE__,
1826 "http://www.evil.com/..\\foo.txt",
1827 "filename=..\\foo.txt",
1828 "",
1829 "",
1830 "text/plain",
1831 L"download",
1832 L"-foo.txt"
1833 },
1834 {
1835 __LINE__,
1836 "http://www.evil.com/.hidden",
1837 "filename=.hidden",
1838 "",
1839 "",
1840 "text/plain",
1841 L"download",
1842 L"hidden" TXT_EXT
1843 },
1844 {
1845 __LINE__,
1846 "http://www.evil.com/trailing.",
1847 "filename=trailing.",
1848 "",
1849 "",
1850 "dance/party",
1851 L"download",
1852 #if defined(OS_WIN)
1853 L"trailing-"
1854 #else
1855 L"trailing"
1856 #endif
1857 },
1858 {
1859 __LINE__,
1860 "http://www.evil.com/trailing.",
1861 "filename=trailing.",
1862 "",
1863 "",
1864 "text/plain",
1865 L"download",
1866 #if defined(OS_WIN)
1867 L"trailing-" TXT_EXT
1868 #else
1869 L"trailing" TXT_EXT
1870 #endif
1871 },
1872 {
1873 __LINE__,
1874 "http://www.evil.com/.",
1875 "filename=.",
1876 "",
1877 "",
1878 "dance/party",
1879 L"download",
1880 L"download"
1881 },
1882 {
1883 __LINE__,
1884 "http://www.evil.com/..",
1885 "filename=..",
1886 "",
1887 "",
1888 "dance/party",
1889 L"download",
1890 L"download"
1891 },
1892 {
1893 __LINE__,
1894 "http://www.evil.com/...",
1895 "filename=...",
1896 "",
1897 "",
1898 "dance/party",
1899 L"download",
1900 L"download"
1901 },
1902 { // Note that this one doesn't have "filename=" on it.
1903 __LINE__,
1904 "http://www.evil.com/",
1905 "a_file_name.txt",
1906 "",
1907 "",
1908 "image/jpeg",
1909 L"download",
1910 L"download" JPEG_EXT
1911 },
1912 {
1913 __LINE__,
1914 "http://www.evil.com/",
1915 "filename=",
1916 "",
1917 "",
1918 "image/jpeg",
1919 L"download",
1920 L"download" JPEG_EXT
1921 },
1922 {
1923 __LINE__,
1924 "http://www.example.com/simple",
1925 "filename=simple",
1926 "",
1927 "",
1928 "application/octet-stream",
1929 L"download",
1930 L"simple"
1931 },
1932 // Reserved words on Windows
1933 {
1934 __LINE__,
1935 "http://www.goodguy.com/COM1",
1936 "filename=COM1",
1937 "",
1938 "",
1939 "application/foo-bar",
1940 L"download",
1941 #if defined(OS_WIN)
1942 L"_COM1"
1943 #else
1944 L"COM1"
1945 #endif
1946 },
1947 {
1948 __LINE__,
1949 "http://www.goodguy.com/COM4.txt",
1950 "filename=COM4.txt",
1951 "",
1952 "",
1953 "text/plain",
1954 L"download",
1955 #if defined(OS_WIN)
1956 L"_COM4.txt"
1957 #else
1958 L"COM4.txt"
1959 #endif
1960 },
1961 {
1962 __LINE__,
1963 "http://www.goodguy.com/lpt1.TXT",
1964 "filename=lpt1.TXT",
1965 "",
1966 "",
1967 "text/plain",
1968 L"download",
1969 #if defined(OS_WIN)
1970 L"_lpt1.TXT"
1971 #else
1972 L"lpt1.TXT"
1973 #endif
1974 },
1975 {
1976 __LINE__,
1977 "http://www.goodguy.com/clock$.txt",
1978 "filename=clock$.txt",
1979 "",
1980 "",
1981 "text/plain",
1982 L"download",
1983 #if defined(OS_WIN)
1984 L"_clock$.txt"
1985 #else
1986 L"clock$.txt"
1987 #endif
1988 },
1989 { // Validation should also apply to sugested name
1990 __LINE__,
1991 "http://www.goodguy.com/blah$.txt",
1992 "filename=clock$.txt",
1993 "",
1994 "clock$.txt",
1995 "text/plain",
1996 L"download",
1997 #if defined(OS_WIN)
1998 L"_clock$.txt"
1999 #else
2000 L"clock$.txt"
2001 #endif
2002 },
2003 {
2004 __LINE__,
2005 "http://www.goodguy.com/mycom1.foo",
2006 "filename=mycom1.foo",
2007 "",
2008 "",
2009 "text/plain",
2010 L"download",
2011 L"mycom1.foo"
2012 },
2013 {
2014 __LINE__,
2015 "http://www.badguy.com/Setup.exe.local",
2016 "filename=Setup.exe.local",
2017 "",
2018 "",
2019 "application/foo-bar",
2020 L"download",
2021 #if defined(OS_WIN)
2022 L"Setup.exe.download"
2023 #else
2024 L"Setup.exe.local"
2025 #endif
2026 },
2027 {
2028 __LINE__,
2029 "http://www.badguy.com/Setup.exe.local",
2030 "filename=Setup.exe.local.local",
2031 "",
2032 "",
2033 "application/foo-bar",
2034 L"download",
2035 #if defined(OS_WIN)
2036 L"Setup.exe.local.download"
2037 #else
2038 L"Setup.exe.local.local"
2039 #endif
2040 },
2041 {
2042 __LINE__,
2043 "http://www.badguy.com/Setup.exe.lnk",
2044 "filename=Setup.exe.lnk",
2045 "",
2046 "",
2047 "application/foo-bar",
2048 L"download",
2049 #if defined(OS_WIN)
2050 L"Setup.exe.download"
2051 #else
2052 L"Setup.exe.lnk"
2053 #endif
2054 },
2055 {
2056 __LINE__,
2057 "http://www.badguy.com/Desktop.ini",
2058 "filename=Desktop.ini",
2059 "",
2060 "",
2061 "application/foo-bar",
2062 L"download",
2063 #if defined(OS_WIN)
2064 L"_Desktop.ini"
2065 #else
2066 L"Desktop.ini"
2067 #endif
2068 },
2069 {
2070 __LINE__,
2071 "http://www.badguy.com/Thumbs.db",
2072 "filename=Thumbs.db",
2073 "",
2074 "",
2075 "application/foo-bar",
2076 L"download",
2077 #if defined(OS_WIN)
2078 L"_Thumbs.db"
2079 #else
2080 L"Thumbs.db"
2081 #endif
2082 },
2083 {
2084 __LINE__,
2085 "http://www.hotmail.com",
2086 "filename=source.jpg",
2087 "",
2088 "",
2089 "application/x-javascript",
2090 L"download",
2091 L"source.jpg"
2092 },
2093 { // http://crbug.com/5772.
2094 __LINE__,
2095 "http://www.example.com/foo.tar.gz",
2096 "",
2097 "",
2098 "",
2099 "application/x-tar",
2100 L"download",
2101 L"foo.tar.gz"
2102 },
2103 { // http://crbug.com/52250.
2104 __LINE__,
2105 "http://www.example.com/foo.tgz",
2106 "",
2107 "",
2108 "",
2109 "application/x-tar",
2110 L"download",
2111 L"foo.tgz"
2112 },
2113 { // http://crbug.com/7337.
2114 __LINE__,
2115 "http://maged.lordaeron.org/blank.reg",
2116 "",
2117 "",
2118 "",
2119 "text/x-registry",
2120 L"download",
2121 L"blank.reg"
2122 },
2123 {
2124 __LINE__,
2125 "http://www.example.com/bar.tar",
2126 "",
2127 "",
2128 "",
2129 "application/x-tar",
2130 L"download",
2131 L"bar.tar"
2132 },
2133 {
2134 __LINE__,
2135 "http://www.example.com/bar.bogus",
2136 "",
2137 "",
2138 "",
2139 "application/x-tar",
2140 L"download",
2141 L"bar.bogus"
2142 },
2143 { // http://crbug.com/20337
2144 __LINE__,
2145 "http://www.example.com/.download.txt",
2146 "filename=.download.txt",
2147 "",
2148 "",
2149 "text/plain",
2150 L"-download",
2151 L"download.txt"
2152 },
2153 { // http://crbug.com/56855.
2154 __LINE__,
2155 "http://www.example.com/bar.sh",
2156 "",
2157 "",
2158 "",
2159 "application/x-sh",
2160 L"download",
2161 L"bar.sh"
2162 },
2163 { // http://crbug.com/61571
2164 __LINE__,
2165 "http://www.example.com/npdf.php?fn=foobar.pdf",
2166 "",
2167 "",
2168 "",
2169 "text/plain",
2170 L"download",
2171 L"npdf" TXT_EXT
2172 },
2173 { // Shouldn't overwrite C-D specified extension.
2174 __LINE__,
2175 "http://www.example.com/npdf.php?fn=foobar.pdf",
2176 "filename=foobar.jpg",
2177 "",
2178 "",
2179 "text/plain",
2180 L"download",
2181 L"foobar.jpg"
2182 },
2183 { // http://crbug.com/87719
2184 __LINE__,
2185 "http://www.example.com/image.aspx?id=blargh",
2186 "",
2187 "",
2188 "",
2189 "image/jpeg",
2190 L"download",
2191 L"image" JPEG_EXT
2192 },
2193 #if defined(OS_CHROMEOS)
2194 { // http://crosbug.com/26028
2195 __LINE__,
2196 "http://www.example.com/fooa%cc%88.txt",
2197 "",
2198 "",
2199 "",
2200 "image/jpeg",
2201 L"foo\xe4",
2202 L"foo\xe4.txt"
2203 },
2204 #endif
2205 };
2206
2207 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(selection_tests); ++i)
2208 RunGenerateFileNameTestCase(&selection_tests[i]);
2209
2210 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(generation_tests); ++i)
2211 RunGenerateFileNameTestCase(&generation_tests[i]);
2212
2213 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(generation_tests); ++i) {
2214 GenerateFilenameCase test_case = generation_tests[i];
2215 test_case.referrer_charset = "GBK";
2216 RunGenerateFileNameTestCase(&test_case);
2217 }
2218 }
2219
2220 // This is currently a windows specific function.
2221 #if defined(OS_WIN)
2222 namespace {
2223
2224 struct GetDirectoryListingEntryCase {
2225 const wchar_t* name;
2226 const char* raw_bytes;
2227 bool is_dir;
2228 int64 filesize;
2229 base::Time time;
2230 const char* expected;
2231 };
2232
2233 } // namespace
TEST(NetUtilTest,GetDirectoryListingEntry)2234 TEST(NetUtilTest, GetDirectoryListingEntry) {
2235 const GetDirectoryListingEntryCase test_cases[] = {
2236 {L"Foo",
2237 "",
2238 false,
2239 10000,
2240 base::Time(),
2241 "<script>addRow(\"Foo\",\"Foo\",0,\"9.8 kB\",\"\");</script>\n"},
2242 {L"quo\"tes",
2243 "",
2244 false,
2245 10000,
2246 base::Time(),
2247 "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
2248 "\n"},
2249 {L"quo\"tes",
2250 "quo\"tes",
2251 false,
2252 10000,
2253 base::Time(),
2254 "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
2255 "\n"},
2256 // U+D55C0 U+AE00. raw_bytes is empty (either a local file with
2257 // UTF-8/UTF-16 encoding or a remote file on an ftp server using UTF-8
2258 {L"\xD55C\xAE00.txt",
2259 "",
2260 false,
2261 10000,
2262 base::Time(),
2263 "<script>addRow(\"\xED\x95\x9C\xEA\xB8\x80.txt\","
2264 "\"%ED%95%9C%EA%B8%80.txt\",0,\"9.8 kB\",\"\");</script>\n"},
2265 // U+D55C0 U+AE00. raw_bytes is the corresponding EUC-KR sequence:
2266 // a local or remote file in EUC-KR.
2267 {L"\xD55C\xAE00.txt",
2268 "\xC7\xD1\xB1\xDB.txt",
2269 false,
2270 10000,
2271 base::Time(),
2272 "<script>addRow(\"\xED\x95\x9C\xEA\xB8\x80.txt\",\"%C7%D1%B1%DB.txt\""
2273 ",0,\"9.8 kB\",\"\");</script>\n"},
2274 };
2275
2276 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
2277 const std::string results = GetDirectoryListingEntry(
2278 WideToUTF16(test_cases[i].name),
2279 test_cases[i].raw_bytes,
2280 test_cases[i].is_dir,
2281 test_cases[i].filesize,
2282 test_cases[i].time);
2283 EXPECT_EQ(test_cases[i].expected, results);
2284 }
2285 }
2286
2287 #endif
2288
TEST(NetUtilTest,ParseHostAndPort)2289 TEST(NetUtilTest, ParseHostAndPort) {
2290 const struct {
2291 const char* input;
2292 bool success;
2293 const char* expected_host;
2294 int expected_port;
2295 } tests[] = {
2296 // Valid inputs:
2297 {"foo:10", true, "foo", 10},
2298 {"foo", true, "foo", -1},
2299 {
2300 "[1080:0:0:0:8:800:200C:4171]:11",
2301 true,
2302 "[1080:0:0:0:8:800:200C:4171]",
2303 11,
2304 },
2305 // Invalid inputs:
2306 {"foo:bar", false, "", -1},
2307 {"foo:", false, "", -1},
2308 {":", false, "", -1},
2309 {":80", false, "", -1},
2310 {"", false, "", -1},
2311 {"porttoolong:300000", false, "", -1},
2312 {"usrname@host", false, "", -1},
2313 {"usrname:password@host", false, "", -1},
2314 {":password@host", false, "", -1},
2315 {":password@host:80", false, "", -1},
2316 {":password@host", false, "", -1},
2317 {"@host", false, "", -1},
2318 };
2319
2320 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2321 std::string host;
2322 int port;
2323 bool ok = ParseHostAndPort(tests[i].input, &host, &port);
2324
2325 EXPECT_EQ(tests[i].success, ok);
2326
2327 if (tests[i].success) {
2328 EXPECT_EQ(tests[i].expected_host, host);
2329 EXPECT_EQ(tests[i].expected_port, port);
2330 }
2331 }
2332 }
2333
TEST(NetUtilTest,GetHostAndPort)2334 TEST(NetUtilTest, GetHostAndPort) {
2335 const struct {
2336 GURL url;
2337 const char* expected_host_and_port;
2338 } tests[] = {
2339 { GURL("http://www.foo.com/x"), "www.foo.com:80"},
2340 { GURL("http://www.foo.com:21/x"), "www.foo.com:21"},
2341
2342 // For IPv6 literals should always include the brackets.
2343 { GURL("http://[1::2]/x"), "[1::2]:80"},
2344 { GURL("http://[::a]:33/x"), "[::a]:33"},
2345 };
2346 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2347 std::string host_and_port = GetHostAndPort(tests[i].url);
2348 EXPECT_EQ(std::string(tests[i].expected_host_and_port), host_and_port);
2349 }
2350 }
2351
TEST(NetUtilTest,GetHostAndOptionalPort)2352 TEST(NetUtilTest, GetHostAndOptionalPort) {
2353 const struct {
2354 GURL url;
2355 const char* expected_host_and_port;
2356 } tests[] = {
2357 { GURL("http://www.foo.com/x"), "www.foo.com"},
2358 { GURL("http://www.foo.com:21/x"), "www.foo.com:21"},
2359
2360 // For IPv6 literals should always include the brackets.
2361 { GURL("http://[1::2]/x"), "[1::2]"},
2362 { GURL("http://[::a]:33/x"), "[::a]:33"},
2363 };
2364 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2365 std::string host_and_port = GetHostAndOptionalPort(tests[i].url);
2366 EXPECT_EQ(std::string(tests[i].expected_host_and_port), host_and_port);
2367 }
2368 }
2369
TEST(NetUtilTest,IPAddressToString)2370 TEST(NetUtilTest, IPAddressToString) {
2371 uint8 addr1[4] = {0, 0, 0, 0};
2372 EXPECT_EQ("0.0.0.0", IPAddressToString(addr1, sizeof(addr1)));
2373
2374 uint8 addr2[4] = {192, 168, 0, 1};
2375 EXPECT_EQ("192.168.0.1", IPAddressToString(addr2, sizeof(addr2)));
2376
2377 uint8 addr3[16] = {0xFE, 0xDC, 0xBA, 0x98};
2378 EXPECT_EQ("fedc:ba98::", IPAddressToString(addr3, sizeof(addr3)));
2379 }
2380
TEST(NetUtilTest,IPAddressToStringWithPort)2381 TEST(NetUtilTest, IPAddressToStringWithPort) {
2382 uint8 addr1[4] = {0, 0, 0, 0};
2383 EXPECT_EQ("0.0.0.0:3", IPAddressToStringWithPort(addr1, sizeof(addr1), 3));
2384
2385 uint8 addr2[4] = {192, 168, 0, 1};
2386 EXPECT_EQ("192.168.0.1:99",
2387 IPAddressToStringWithPort(addr2, sizeof(addr2), 99));
2388
2389 uint8 addr3[16] = {0xFE, 0xDC, 0xBA, 0x98};
2390 EXPECT_EQ("[fedc:ba98::]:8080",
2391 IPAddressToStringWithPort(addr3, sizeof(addr3), 8080));
2392 }
2393
TEST(NetUtilTest,NetAddressToString_IPv4)2394 TEST(NetUtilTest, NetAddressToString_IPv4) {
2395 const struct {
2396 uint8 addr[4];
2397 const char* result;
2398 } tests[] = {
2399 {{0, 0, 0, 0}, "0.0.0.0"},
2400 {{127, 0, 0, 1}, "127.0.0.1"},
2401 {{192, 168, 0, 1}, "192.168.0.1"},
2402 };
2403
2404 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2405 SockaddrStorage storage;
2406 MakeIPv4Address(tests[i].addr, 80, &storage);
2407 std::string result = NetAddressToString(storage.addr, storage.addr_len);
2408 EXPECT_EQ(std::string(tests[i].result), result);
2409 }
2410 }
2411
TEST(NetUtilTest,NetAddressToString_IPv6)2412 TEST(NetUtilTest, NetAddressToString_IPv6) {
2413 const struct {
2414 uint8 addr[16];
2415 const char* result;
2416 } tests[] = {
2417 {{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA,
2418 0x98, 0x76, 0x54, 0x32, 0x10},
2419 "fedc:ba98:7654:3210:fedc:ba98:7654:3210"},
2420 };
2421
2422 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2423 SockaddrStorage storage;
2424 MakeIPv6Address(tests[i].addr, 80, &storage);
2425 EXPECT_EQ(std::string(tests[i].result),
2426 NetAddressToString(storage.addr, storage.addr_len));
2427 }
2428 }
2429
TEST(NetUtilTest,NetAddressToStringWithPort_IPv4)2430 TEST(NetUtilTest, NetAddressToStringWithPort_IPv4) {
2431 uint8 addr[] = {127, 0, 0, 1};
2432 SockaddrStorage storage;
2433 MakeIPv4Address(addr, 166, &storage);
2434 std::string result = NetAddressToStringWithPort(storage.addr,
2435 storage.addr_len);
2436 EXPECT_EQ("127.0.0.1:166", result);
2437 }
2438
TEST(NetUtilTest,NetAddressToStringWithPort_IPv6)2439 TEST(NetUtilTest, NetAddressToStringWithPort_IPv6) {
2440 uint8 addr[] = {
2441 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA,
2442 0x98, 0x76, 0x54, 0x32, 0x10
2443 };
2444 SockaddrStorage storage;
2445 MakeIPv6Address(addr, 361, &storage);
2446 std::string result = NetAddressToStringWithPort(storage.addr,
2447 storage.addr_len);
2448
2449 // May fail on systems that don't support IPv6.
2450 if (!result.empty())
2451 EXPECT_EQ("[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:361", result);
2452 }
2453
TEST(NetUtilTest,GetHostName)2454 TEST(NetUtilTest, GetHostName) {
2455 // We can't check the result of GetHostName() directly, since the result
2456 // will differ across machines. Our goal here is to simply exercise the
2457 // code path, and check that things "look about right".
2458 std::string hostname = GetHostName();
2459 EXPECT_FALSE(hostname.empty());
2460 }
2461
TEST(NetUtilTest,FormatUrl)2462 TEST(NetUtilTest, FormatUrl) {
2463 FormatUrlTypes default_format_type = kFormatUrlOmitUsernamePassword;
2464 const UrlTestData tests[] = {
2465 {"Empty URL", "", "", default_format_type, UnescapeRule::NORMAL, L"", 0},
2466
2467 {"Simple URL",
2468 "http://www.google.com/", "", default_format_type, UnescapeRule::NORMAL,
2469 L"http://www.google.com/", 7},
2470
2471 {"With a port number and a reference",
2472 "http://www.google.com:8080/#\xE3\x82\xB0", "", default_format_type,
2473 UnescapeRule::NORMAL,
2474 L"http://www.google.com:8080/#\x30B0", 7},
2475
2476 // -------- IDN tests --------
2477 {"Japanese IDN with ja",
2478 "http://xn--l8jvb1ey91xtjb.jp", "ja", default_format_type,
2479 UnescapeRule::NORMAL, L"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
2480
2481 {"Japanese IDN with en",
2482 "http://xn--l8jvb1ey91xtjb.jp", "en", default_format_type,
2483 UnescapeRule::NORMAL, L"http://xn--l8jvb1ey91xtjb.jp/", 7},
2484
2485 {"Japanese IDN without any languages",
2486 "http://xn--l8jvb1ey91xtjb.jp", "", default_format_type,
2487 UnescapeRule::NORMAL,
2488 // Single script is safe for empty languages.
2489 L"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
2490
2491 {"mailto: with Japanese IDN",
2492 "mailto:foo@xn--l8jvb1ey91xtjb.jp", "ja", default_format_type,
2493 UnescapeRule::NORMAL,
2494 // GURL doesn't assume an email address's domain part as a host name.
2495 L"mailto:foo@xn--l8jvb1ey91xtjb.jp", 7},
2496
2497 {"file: with Japanese IDN",
2498 "file://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type,
2499 UnescapeRule::NORMAL,
2500 L"file://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 7},
2501
2502 {"ftp: with Japanese IDN",
2503 "ftp://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type,
2504 UnescapeRule::NORMAL,
2505 L"ftp://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 6},
2506
2507 // -------- omit_username_password flag tests --------
2508 {"With username and password, omit_username_password=false",
2509 "http://user:passwd@example.com/foo", "",
2510 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2511 L"http://user:passwd@example.com/foo", 19},
2512
2513 {"With username and password, omit_username_password=true",
2514 "http://user:passwd@example.com/foo", "", default_format_type,
2515 UnescapeRule::NORMAL, L"http://example.com/foo", 7},
2516
2517 {"With username and no password",
2518 "http://user@example.com/foo", "", default_format_type,
2519 UnescapeRule::NORMAL, L"http://example.com/foo", 7},
2520
2521 {"Just '@' without username and password",
2522 "http://@example.com/foo", "", default_format_type, UnescapeRule::NORMAL,
2523 L"http://example.com/foo", 7},
2524
2525 // GURL doesn't think local-part of an email address is username for URL.
2526 {"mailto:, omit_username_password=true",
2527 "mailto:foo@example.com", "", default_format_type, UnescapeRule::NORMAL,
2528 L"mailto:foo@example.com", 7},
2529
2530 // -------- unescape flag tests --------
2531 {"Do not unescape",
2532 "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
2533 "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
2534 "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type,
2535 UnescapeRule::NONE,
2536 // GURL parses %-encoded hostnames into Punycode.
2537 L"http://xn--qcka1pmc.jp/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
2538 L"?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", 7},
2539
2540 {"Unescape normally",
2541 "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
2542 "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
2543 "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type,
2544 UnescapeRule::NORMAL,
2545 L"http://xn--qcka1pmc.jp/\x30B0\x30FC\x30B0\x30EB"
2546 L"?q=\x30B0\x30FC\x30B0\x30EB", 7},
2547
2548 {"Unescape normally including unescape spaces",
2549 "http://www.google.com/search?q=Hello%20World", "en", default_format_type,
2550 UnescapeRule::SPACES, L"http://www.google.com/search?q=Hello World", 7},
2551
2552 /*
2553 {"unescape=true with some special characters",
2554 "http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", "",
2555 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2556 L"http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", 25},
2557 */
2558 // Disabled: the resultant URL becomes "...user%253A:%2540passwd...".
2559
2560 // -------- omit http: --------
2561 {"omit http with user name",
2562 "http://user@example.com/foo", "", kFormatUrlOmitAll,
2563 UnescapeRule::NORMAL, L"example.com/foo", 0},
2564
2565 {"omit http",
2566 "http://www.google.com/", "en", kFormatUrlOmitHTTP,
2567 UnescapeRule::NORMAL, L"www.google.com/",
2568 0},
2569
2570 {"omit http with https",
2571 "https://www.google.com/", "en", kFormatUrlOmitHTTP,
2572 UnescapeRule::NORMAL, L"https://www.google.com/",
2573 8},
2574
2575 {"omit http starts with ftp.",
2576 "http://ftp.google.com/", "en", kFormatUrlOmitHTTP,
2577 UnescapeRule::NORMAL, L"http://ftp.google.com/",
2578 7},
2579
2580 // -------- omit trailing slash on bare hostname --------
2581 {"omit slash when it's the entire path",
2582 "http://www.google.com/", "en",
2583 kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
2584 L"http://www.google.com", 7},
2585 {"omit slash when there's a ref",
2586 "http://www.google.com/#ref", "en",
2587 kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
2588 L"http://www.google.com/#ref", 7},
2589 {"omit slash when there's a query",
2590 "http://www.google.com/?", "en",
2591 kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
2592 L"http://www.google.com/?", 7},
2593 {"omit slash when it's not the entire path",
2594 "http://www.google.com/foo", "en",
2595 kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
2596 L"http://www.google.com/foo", 7},
2597 {"omit slash for nonstandard URLs",
2598 "data:/", "en", kFormatUrlOmitTrailingSlashOnBareHostname,
2599 UnescapeRule::NORMAL, L"data:/", 5},
2600 {"omit slash for file URLs",
2601 "file:///", "en", kFormatUrlOmitTrailingSlashOnBareHostname,
2602 UnescapeRule::NORMAL, L"file:///", 7},
2603
2604 // -------- view-source: --------
2605 {"view-source",
2606 "view-source:http://xn--qcka1pmc.jp/", "ja", default_format_type,
2607 UnescapeRule::NORMAL, L"view-source:http://\x30B0\x30FC\x30B0\x30EB.jp/",
2608 19},
2609
2610 {"view-source of view-source",
2611 "view-source:view-source:http://xn--qcka1pmc.jp/", "ja",
2612 default_format_type, UnescapeRule::NORMAL,
2613 L"view-source:view-source:http://xn--qcka1pmc.jp/", 12},
2614
2615 // view-source should omit http and trailing slash where non-view-source
2616 // would.
2617 {"view-source omit http",
2618 "view-source:http://a.b/c", "en", kFormatUrlOmitAll,
2619 UnescapeRule::NORMAL, L"view-source:a.b/c",
2620 12},
2621 {"view-source omit http starts with ftp.",
2622 "view-source:http://ftp.b/c", "en", kFormatUrlOmitAll,
2623 UnescapeRule::NORMAL, L"view-source:http://ftp.b/c",
2624 19},
2625 {"view-source omit slash when it's the entire path",
2626 "view-source:http://a.b/", "en", kFormatUrlOmitAll,
2627 UnescapeRule::NORMAL, L"view-source:a.b",
2628 12},
2629 };
2630
2631 for (size_t i = 0; i < arraysize(tests); ++i) {
2632 size_t prefix_len;
2633 base::string16 formatted = FormatUrl(
2634 GURL(tests[i].input), tests[i].languages, tests[i].format_types,
2635 tests[i].escape_rules, NULL, &prefix_len, NULL);
2636 EXPECT_EQ(WideToUTF16(tests[i].output), formatted) << tests[i].description;
2637 EXPECT_EQ(tests[i].prefix_len, prefix_len) << tests[i].description;
2638 }
2639 }
2640
TEST(NetUtilTest,FormatUrlParsed)2641 TEST(NetUtilTest, FormatUrlParsed) {
2642 // No unescape case.
2643 url_parse::Parsed parsed;
2644 base::string16 formatted = FormatUrl(
2645 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2646 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2647 "ja", kFormatUrlOmitNothing, UnescapeRule::NONE, &parsed, NULL,
2648 NULL);
2649 EXPECT_EQ(WideToUTF16(
2650 L"http://%E3%82%B0:%E3%83%BC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
2651 L"/%E3%82%B0/?q=%E3%82%B0#\x30B0"), formatted);
2652 EXPECT_EQ(WideToUTF16(L"%E3%82%B0"),
2653 formatted.substr(parsed.username.begin, parsed.username.len));
2654 EXPECT_EQ(WideToUTF16(L"%E3%83%BC"),
2655 formatted.substr(parsed.password.begin, parsed.password.len));
2656 EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
2657 formatted.substr(parsed.host.begin, parsed.host.len));
2658 EXPECT_EQ(WideToUTF16(L"8080"),
2659 formatted.substr(parsed.port.begin, parsed.port.len));
2660 EXPECT_EQ(WideToUTF16(L"/%E3%82%B0/"),
2661 formatted.substr(parsed.path.begin, parsed.path.len));
2662 EXPECT_EQ(WideToUTF16(L"q=%E3%82%B0"),
2663 formatted.substr(parsed.query.begin, parsed.query.len));
2664 EXPECT_EQ(WideToUTF16(L"\x30B0"),
2665 formatted.substr(parsed.ref.begin, parsed.ref.len));
2666
2667 // Unescape case.
2668 formatted = FormatUrl(
2669 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2670 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2671 "ja", kFormatUrlOmitNothing, UnescapeRule::NORMAL, &parsed, NULL,
2672 NULL);
2673 EXPECT_EQ(WideToUTF16(L"http://\x30B0:\x30FC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
2674 L"/\x30B0/?q=\x30B0#\x30B0"), formatted);
2675 EXPECT_EQ(WideToUTF16(L"\x30B0"),
2676 formatted.substr(parsed.username.begin, parsed.username.len));
2677 EXPECT_EQ(WideToUTF16(L"\x30FC"),
2678 formatted.substr(parsed.password.begin, parsed.password.len));
2679 EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
2680 formatted.substr(parsed.host.begin, parsed.host.len));
2681 EXPECT_EQ(WideToUTF16(L"8080"),
2682 formatted.substr(parsed.port.begin, parsed.port.len));
2683 EXPECT_EQ(WideToUTF16(L"/\x30B0/"),
2684 formatted.substr(parsed.path.begin, parsed.path.len));
2685 EXPECT_EQ(WideToUTF16(L"q=\x30B0"),
2686 formatted.substr(parsed.query.begin, parsed.query.len));
2687 EXPECT_EQ(WideToUTF16(L"\x30B0"),
2688 formatted.substr(parsed.ref.begin, parsed.ref.len));
2689
2690 // Omit_username_password + unescape case.
2691 formatted = FormatUrl(
2692 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2693 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2694 "ja", kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, &parsed,
2695 NULL, NULL);
2696 EXPECT_EQ(WideToUTF16(L"http://\x30B0\x30FC\x30B0\x30EB.jp:8080"
2697 L"/\x30B0/?q=\x30B0#\x30B0"), formatted);
2698 EXPECT_FALSE(parsed.username.is_valid());
2699 EXPECT_FALSE(parsed.password.is_valid());
2700 EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
2701 formatted.substr(parsed.host.begin, parsed.host.len));
2702 EXPECT_EQ(WideToUTF16(L"8080"),
2703 formatted.substr(parsed.port.begin, parsed.port.len));
2704 EXPECT_EQ(WideToUTF16(L"/\x30B0/"),
2705 formatted.substr(parsed.path.begin, parsed.path.len));
2706 EXPECT_EQ(WideToUTF16(L"q=\x30B0"),
2707 formatted.substr(parsed.query.begin, parsed.query.len));
2708 EXPECT_EQ(WideToUTF16(L"\x30B0"),
2709 formatted.substr(parsed.ref.begin, parsed.ref.len));
2710
2711 // View-source case.
2712 formatted =
2713 FormatUrl(GURL("view-source:http://user:passwd@host:81/path?query#ref"),
2714 std::string(),
2715 kFormatUrlOmitUsernamePassword,
2716 UnescapeRule::NORMAL,
2717 &parsed,
2718 NULL,
2719 NULL);
2720 EXPECT_EQ(WideToUTF16(L"view-source:http://host:81/path?query#ref"),
2721 formatted);
2722 EXPECT_EQ(WideToUTF16(L"view-source:http"),
2723 formatted.substr(parsed.scheme.begin, parsed.scheme.len));
2724 EXPECT_FALSE(parsed.username.is_valid());
2725 EXPECT_FALSE(parsed.password.is_valid());
2726 EXPECT_EQ(WideToUTF16(L"host"),
2727 formatted.substr(parsed.host.begin, parsed.host.len));
2728 EXPECT_EQ(WideToUTF16(L"81"),
2729 formatted.substr(parsed.port.begin, parsed.port.len));
2730 EXPECT_EQ(WideToUTF16(L"/path"),
2731 formatted.substr(parsed.path.begin, parsed.path.len));
2732 EXPECT_EQ(WideToUTF16(L"query"),
2733 formatted.substr(parsed.query.begin, parsed.query.len));
2734 EXPECT_EQ(WideToUTF16(L"ref"),
2735 formatted.substr(parsed.ref.begin, parsed.ref.len));
2736
2737 // omit http case.
2738 formatted = FormatUrl(GURL("http://host:8000/a?b=c#d"),
2739 std::string(),
2740 kFormatUrlOmitHTTP,
2741 UnescapeRule::NORMAL,
2742 &parsed,
2743 NULL,
2744 NULL);
2745 EXPECT_EQ(WideToUTF16(L"host:8000/a?b=c#d"), formatted);
2746 EXPECT_FALSE(parsed.scheme.is_valid());
2747 EXPECT_FALSE(parsed.username.is_valid());
2748 EXPECT_FALSE(parsed.password.is_valid());
2749 EXPECT_EQ(WideToUTF16(L"host"),
2750 formatted.substr(parsed.host.begin, parsed.host.len));
2751 EXPECT_EQ(WideToUTF16(L"8000"),
2752 formatted.substr(parsed.port.begin, parsed.port.len));
2753 EXPECT_EQ(WideToUTF16(L"/a"),
2754 formatted.substr(parsed.path.begin, parsed.path.len));
2755 EXPECT_EQ(WideToUTF16(L"b=c"),
2756 formatted.substr(parsed.query.begin, parsed.query.len));
2757 EXPECT_EQ(WideToUTF16(L"d"),
2758 formatted.substr(parsed.ref.begin, parsed.ref.len));
2759
2760 // omit http starts with ftp case.
2761 formatted = FormatUrl(GURL("http://ftp.host:8000/a?b=c#d"),
2762 std::string(),
2763 kFormatUrlOmitHTTP,
2764 UnescapeRule::NORMAL,
2765 &parsed,
2766 NULL,
2767 NULL);
2768 EXPECT_EQ(WideToUTF16(L"http://ftp.host:8000/a?b=c#d"), formatted);
2769 EXPECT_TRUE(parsed.scheme.is_valid());
2770 EXPECT_FALSE(parsed.username.is_valid());
2771 EXPECT_FALSE(parsed.password.is_valid());
2772 EXPECT_EQ(WideToUTF16(L"http"),
2773 formatted.substr(parsed.scheme.begin, parsed.scheme.len));
2774 EXPECT_EQ(WideToUTF16(L"ftp.host"),
2775 formatted.substr(parsed.host.begin, parsed.host.len));
2776 EXPECT_EQ(WideToUTF16(L"8000"),
2777 formatted.substr(parsed.port.begin, parsed.port.len));
2778 EXPECT_EQ(WideToUTF16(L"/a"),
2779 formatted.substr(parsed.path.begin, parsed.path.len));
2780 EXPECT_EQ(WideToUTF16(L"b=c"),
2781 formatted.substr(parsed.query.begin, parsed.query.len));
2782 EXPECT_EQ(WideToUTF16(L"d"),
2783 formatted.substr(parsed.ref.begin, parsed.ref.len));
2784
2785 // omit http starts with 'f' case.
2786 formatted = FormatUrl(GURL("http://f/"),
2787 std::string(),
2788 kFormatUrlOmitHTTP,
2789 UnescapeRule::NORMAL,
2790 &parsed,
2791 NULL,
2792 NULL);
2793 EXPECT_EQ(WideToUTF16(L"f/"), formatted);
2794 EXPECT_FALSE(parsed.scheme.is_valid());
2795 EXPECT_FALSE(parsed.username.is_valid());
2796 EXPECT_FALSE(parsed.password.is_valid());
2797 EXPECT_FALSE(parsed.port.is_valid());
2798 EXPECT_TRUE(parsed.path.is_valid());
2799 EXPECT_FALSE(parsed.query.is_valid());
2800 EXPECT_FALSE(parsed.ref.is_valid());
2801 EXPECT_EQ(WideToUTF16(L"f"),
2802 formatted.substr(parsed.host.begin, parsed.host.len));
2803 EXPECT_EQ(WideToUTF16(L"/"),
2804 formatted.substr(parsed.path.begin, parsed.path.len));
2805 }
2806
2807 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2808 // results in the original GURL, for each ASCII character in the path.
TEST(NetUtilTest,FormatUrlRoundTripPathASCII)2809 TEST(NetUtilTest, FormatUrlRoundTripPathASCII) {
2810 for (unsigned char test_char = 32; test_char < 128; ++test_char) {
2811 GURL url(std::string("http://www.google.com/") +
2812 static_cast<char>(test_char));
2813 size_t prefix_len;
2814 base::string16 formatted = FormatUrl(url,
2815 std::string(),
2816 kFormatUrlOmitUsernamePassword,
2817 UnescapeRule::NORMAL,
2818 NULL,
2819 &prefix_len,
2820 NULL);
2821 EXPECT_EQ(url.spec(), GURL(formatted).spec());
2822 }
2823 }
2824
2825 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2826 // results in the original GURL, for each escaped ASCII character in the path.
TEST(NetUtilTest,FormatUrlRoundTripPathEscaped)2827 TEST(NetUtilTest, FormatUrlRoundTripPathEscaped) {
2828 for (unsigned char test_char = 32; test_char < 128; ++test_char) {
2829 std::string original_url("http://www.google.com/");
2830 original_url.push_back('%');
2831 original_url.append(base::HexEncode(&test_char, 1));
2832
2833 GURL url(original_url);
2834 size_t prefix_len;
2835 base::string16 formatted = FormatUrl(url,
2836 std::string(),
2837 kFormatUrlOmitUsernamePassword,
2838 UnescapeRule::NORMAL,
2839 NULL,
2840 &prefix_len,
2841 NULL);
2842 EXPECT_EQ(url.spec(), GURL(formatted).spec());
2843 }
2844 }
2845
2846 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2847 // results in the original GURL, for each ASCII character in the query.
TEST(NetUtilTest,FormatUrlRoundTripQueryASCII)2848 TEST(NetUtilTest, FormatUrlRoundTripQueryASCII) {
2849 for (unsigned char test_char = 32; test_char < 128; ++test_char) {
2850 GURL url(std::string("http://www.google.com/?") +
2851 static_cast<char>(test_char));
2852 size_t prefix_len;
2853 base::string16 formatted = FormatUrl(url,
2854 std::string(),
2855 kFormatUrlOmitUsernamePassword,
2856 UnescapeRule::NORMAL,
2857 NULL,
2858 &prefix_len,
2859 NULL);
2860 EXPECT_EQ(url.spec(), GURL(formatted).spec());
2861 }
2862 }
2863
2864 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2865 // only results in a different GURL for certain characters.
TEST(NetUtilTest,FormatUrlRoundTripQueryEscaped)2866 TEST(NetUtilTest, FormatUrlRoundTripQueryEscaped) {
2867 // A full list of characters which FormatURL should unescape and GURL should
2868 // not escape again, when they appear in a query string.
2869 const char* kUnescapedCharacters =
2870 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~";
2871 for (unsigned char test_char = 0; test_char < 128; ++test_char) {
2872 std::string original_url("http://www.google.com/?");
2873 original_url.push_back('%');
2874 original_url.append(base::HexEncode(&test_char, 1));
2875
2876 GURL url(original_url);
2877 size_t prefix_len;
2878 base::string16 formatted = FormatUrl(url,
2879 std::string(),
2880 kFormatUrlOmitUsernamePassword,
2881 UnescapeRule::NORMAL,
2882 NULL,
2883 &prefix_len,
2884 NULL);
2885
2886 if (test_char &&
2887 strchr(kUnescapedCharacters, static_cast<char>(test_char))) {
2888 EXPECT_NE(url.spec(), GURL(formatted).spec());
2889 } else {
2890 EXPECT_EQ(url.spec(), GURL(formatted).spec());
2891 }
2892 }
2893 }
2894
TEST(NetUtilTest,FormatUrlWithOffsets)2895 TEST(NetUtilTest, FormatUrlWithOffsets) {
2896 CheckAdjustedOffsets(std::string(), "en", kFormatUrlOmitNothing,
2897 UnescapeRule::NORMAL, NULL);
2898
2899 const size_t basic_offsets[] = {
2900 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2901 21, 22, 23, 24, 25
2902 };
2903 CheckAdjustedOffsets("http://www.google.com/foo/", "en",
2904 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2905 basic_offsets);
2906
2907 const size_t omit_auth_offsets_1[] = {
2908 0, 1, 2, 3, 4, 5, 6, 7, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 7,
2909 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
2910 };
2911 CheckAdjustedOffsets("http://foo:bar@www.google.com/", "en",
2912 kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
2913 omit_auth_offsets_1);
2914
2915 const size_t omit_auth_offsets_2[] = {
2916 0, 1, 2, 3, 4, 5, 6, 7, kNpos, kNpos, kNpos, 7, 8, 9, 10, 11, 12, 13, 14,
2917 15, 16, 17, 18, 19, 20, 21
2918 };
2919 CheckAdjustedOffsets("http://foo@www.google.com/", "en",
2920 kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
2921 omit_auth_offsets_2);
2922
2923 const size_t dont_omit_auth_offsets[] = {
2924 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos,
2925 kNpos, kNpos, 11, 12, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos,
2926 kNpos, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
2927 30, 31
2928 };
2929 // Unescape to "http://foo\x30B0:\x30B0bar@www.google.com".
2930 CheckAdjustedOffsets("http://foo%E3%82%B0:%E3%82%B0bar@www.google.com/", "en",
2931 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2932 dont_omit_auth_offsets);
2933
2934 const size_t view_source_offsets[] = {
2935 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, kNpos,
2936 kNpos, kNpos, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
2937 };
2938 CheckAdjustedOffsets("view-source:http://foo@www.google.com/", "en",
2939 kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
2940 view_source_offsets);
2941
2942 const size_t idn_hostname_offsets_1[] = {
2943 0, 1, 2, 3, 4, 5, 6, 7, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos,
2944 kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 12,
2945 13, 14, 15, 16, 17, 18, 19
2946 };
2947 // Convert punycode to "http://\x671d\x65e5\x3042\x3055\x3072.jp/foo/".
2948 CheckAdjustedOffsets("http://xn--l8jvb1ey91xtjb.jp/foo/", "ja",
2949 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2950 idn_hostname_offsets_1);
2951
2952 const size_t idn_hostname_offsets_2[] = {
2953 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kNpos, kNpos, kNpos, kNpos, kNpos,
2954 kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 14, 15, kNpos, kNpos, kNpos,
2955 kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos,
2956 kNpos, 19, 20, 21, 22, 23, 24
2957 };
2958 // Convert punycode to
2959 // "http://test.\x89c6\x9891.\x5317\x4eac\x5927\x5b78.test/".
2960 CheckAdjustedOffsets("http://test.xn--cy2a840a.xn--1lq90ic7f1rc.test/",
2961 "zh-CN", kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2962 idn_hostname_offsets_2);
2963
2964 const size_t unescape_offsets[] = {
2965 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2966 21, 22, 23, 24, 25, kNpos, kNpos, 26, 27, 28, 29, 30, kNpos, kNpos, kNpos,
2967 kNpos, kNpos, kNpos, kNpos, kNpos, 31, kNpos, kNpos, kNpos, kNpos, kNpos,
2968 kNpos, kNpos, kNpos, 32, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos,
2969 kNpos, 33, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos
2970 };
2971 // Unescape to "http://www.google.com/foo bar/\x30B0\x30FC\x30B0\x30EB".
2972 CheckAdjustedOffsets(
2973 "http://www.google.com/foo%20bar/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB",
2974 "en", kFormatUrlOmitNothing, UnescapeRule::SPACES, unescape_offsets);
2975
2976 const size_t ref_offsets[] = {
2977 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2978 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, kNpos, kNpos, 32, kNpos, kNpos,
2979 33
2980 };
2981 // Unescape to "http://www.google.com/foo.html#\x30B0\x30B0z".
2982 CheckAdjustedOffsets(
2983 "http://www.google.com/foo.html#\xE3\x82\xB0\xE3\x82\xB0z", "en",
2984 kFormatUrlOmitNothing, UnescapeRule::NORMAL, ref_offsets);
2985
2986 const size_t omit_http_offsets[] = {
2987 0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
2988 10, 11, 12, 13, 14
2989 };
2990 CheckAdjustedOffsets("http://www.google.com/", "en", kFormatUrlOmitHTTP,
2991 UnescapeRule::NORMAL, omit_http_offsets);
2992
2993 const size_t omit_http_start_with_ftp_offsets[] = {
2994 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
2995 };
2996 CheckAdjustedOffsets("http://ftp.google.com/", "en", kFormatUrlOmitHTTP,
2997 UnescapeRule::NORMAL, omit_http_start_with_ftp_offsets);
2998
2999 const size_t omit_all_offsets[] = {
3000 0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0, kNpos, kNpos, kNpos, kNpos,
3001 0, 1, 2, 3, 4, 5, 6, 7
3002 };
3003 CheckAdjustedOffsets("http://user@foo.com/", "en", kFormatUrlOmitAll,
3004 UnescapeRule::NORMAL, omit_all_offsets);
3005 }
3006
TEST(NetUtilTest,SimplifyUrlForRequest)3007 TEST(NetUtilTest, SimplifyUrlForRequest) {
3008 struct {
3009 const char* input_url;
3010 const char* expected_simplified_url;
3011 } tests[] = {
3012 {
3013 // Reference section should be stripped.
3014 "http://www.google.com:78/foobar?query=1#hash",
3015 "http://www.google.com:78/foobar?query=1",
3016 },
3017 {
3018 // Reference section can itself contain #.
3019 "http://192.168.0.1?query=1#hash#10#11#13#14",
3020 "http://192.168.0.1?query=1",
3021 },
3022 { // Strip username/password.
3023 "http://user:pass@google.com",
3024 "http://google.com/",
3025 },
3026 { // Strip both the reference and the username/password.
3027 "http://user:pass@google.com:80/sup?yo#X#X",
3028 "http://google.com/sup?yo",
3029 },
3030 { // Try an HTTPS URL -- strip both the reference and the username/password.
3031 "https://user:pass@google.com:80/sup?yo#X#X",
3032 "https://google.com:80/sup?yo",
3033 },
3034 { // Try an FTP URL -- strip both the reference and the username/password.
3035 "ftp://user:pass@google.com:80/sup?yo#X#X",
3036 "ftp://google.com:80/sup?yo",
3037 },
3038 { // Try a nonstandard URL
3039 "foobar://user:pass@google.com:80/sup?yo#X#X",
3040 "foobar://user:pass@google.com:80/sup?yo",
3041 },
3042 };
3043 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
3044 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
3045 tests[i].input_url));
3046 GURL input_url(GURL(tests[i].input_url));
3047 GURL expected_url(GURL(tests[i].expected_simplified_url));
3048 EXPECT_EQ(expected_url, SimplifyUrlForRequest(input_url));
3049 }
3050 }
3051
TEST(NetUtilTest,SetExplicitlyAllowedPortsTest)3052 TEST(NetUtilTest, SetExplicitlyAllowedPortsTest) {
3053 std::string invalid[] = { "1,2,a", "'1','2'", "1, 2, 3", "1 0,11,12" };
3054 std::string valid[] = { "", "1", "1,2", "1,2,3", "10,11,12,13" };
3055
3056 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(invalid); ++i) {
3057 SetExplicitlyAllowedPorts(invalid[i]);
3058 EXPECT_EQ(0, static_cast<int>(GetCountOfExplicitlyAllowedPorts()));
3059 }
3060
3061 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(valid); ++i) {
3062 SetExplicitlyAllowedPorts(valid[i]);
3063 EXPECT_EQ(i, GetCountOfExplicitlyAllowedPorts());
3064 }
3065 }
3066
TEST(NetUtilTest,GetHostOrSpecFromURL)3067 TEST(NetUtilTest, GetHostOrSpecFromURL) {
3068 EXPECT_EQ("example.com",
3069 GetHostOrSpecFromURL(GURL("http://example.com/test")));
3070 EXPECT_EQ("example.com",
3071 GetHostOrSpecFromURL(GURL("http://example.com./test")));
3072 EXPECT_EQ("file:///tmp/test.html",
3073 GetHostOrSpecFromURL(GURL("file:///tmp/test.html")));
3074 }
3075
TEST(NetUtilTest,GetAddressFamily)3076 TEST(NetUtilTest, GetAddressFamily) {
3077 IPAddressNumber number;
3078 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number));
3079 EXPECT_EQ(ADDRESS_FAMILY_IPV4, GetAddressFamily(number));
3080 EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number));
3081 EXPECT_EQ(ADDRESS_FAMILY_IPV6, GetAddressFamily(number));
3082 }
3083
3084 // Test that invalid IP literals fail to parse.
TEST(NetUtilTest,ParseIPLiteralToNumber_FailParse)3085 TEST(NetUtilTest, ParseIPLiteralToNumber_FailParse) {
3086 IPAddressNumber number;
3087
3088 EXPECT_FALSE(ParseIPLiteralToNumber("bad value", &number));
3089 EXPECT_FALSE(ParseIPLiteralToNumber("bad:value", &number));
3090 EXPECT_FALSE(ParseIPLiteralToNumber(std::string(), &number));
3091 EXPECT_FALSE(ParseIPLiteralToNumber("192.168.0.1:30", &number));
3092 EXPECT_FALSE(ParseIPLiteralToNumber(" 192.168.0.1 ", &number));
3093 EXPECT_FALSE(ParseIPLiteralToNumber("[::1]", &number));
3094 }
3095
3096 // Test parsing an IPv4 literal.
TEST(NetUtilTest,ParseIPLiteralToNumber_IPv4)3097 TEST(NetUtilTest, ParseIPLiteralToNumber_IPv4) {
3098 IPAddressNumber number;
3099 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number));
3100 EXPECT_EQ("192,168,0,1", DumpIPNumber(number));
3101 EXPECT_EQ("192.168.0.1", IPAddressToString(number));
3102 }
3103
3104 // Test parsing an IPv6 literal.
TEST(NetUtilTest,ParseIPLiteralToNumber_IPv6)3105 TEST(NetUtilTest, ParseIPLiteralToNumber_IPv6) {
3106 IPAddressNumber number;
3107 EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number));
3108 EXPECT_EQ("0,1,171,205,0,0,0,0,0,0,0,3,0,4,0,255", DumpIPNumber(number));
3109 EXPECT_EQ("1:abcd::3:4:ff", IPAddressToString(number));
3110 }
3111
3112 // Test mapping an IPv4 address to an IPv6 address.
TEST(NetUtilTest,ConvertIPv4NumberToIPv6Number)3113 TEST(NetUtilTest, ConvertIPv4NumberToIPv6Number) {
3114 IPAddressNumber ipv4_number;
3115 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &ipv4_number));
3116
3117 IPAddressNumber ipv6_number =
3118 ConvertIPv4NumberToIPv6Number(ipv4_number);
3119
3120 // ::ffff:192.168.0.1
3121 EXPECT_EQ("0,0,0,0,0,0,0,0,0,0,255,255,192,168,0,1",
3122 DumpIPNumber(ipv6_number));
3123 EXPECT_EQ("::ffff:c0a8:1", IPAddressToString(ipv6_number));
3124 }
3125
TEST(NetUtilTest,IsIPv4Mapped)3126 TEST(NetUtilTest, IsIPv4Mapped) {
3127 IPAddressNumber ipv4_number;
3128 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &ipv4_number));
3129 EXPECT_FALSE(IsIPv4Mapped(ipv4_number));
3130
3131 IPAddressNumber ipv6_number;
3132 EXPECT_TRUE(ParseIPLiteralToNumber("::1", &ipv4_number));
3133 EXPECT_FALSE(IsIPv4Mapped(ipv6_number));
3134
3135 IPAddressNumber ipv4mapped_number;
3136 EXPECT_TRUE(ParseIPLiteralToNumber("::ffff:0101:1", &ipv4mapped_number));
3137 EXPECT_TRUE(IsIPv4Mapped(ipv4mapped_number));
3138 }
3139
TEST(NetUtilTest,ConvertIPv4MappedToIPv4)3140 TEST(NetUtilTest, ConvertIPv4MappedToIPv4) {
3141 IPAddressNumber ipv4mapped_number;
3142 EXPECT_TRUE(ParseIPLiteralToNumber("::ffff:0101:1", &ipv4mapped_number));
3143 IPAddressNumber expected;
3144 EXPECT_TRUE(ParseIPLiteralToNumber("1.1.0.1", &expected));
3145 IPAddressNumber result = ConvertIPv4MappedToIPv4(ipv4mapped_number);
3146 EXPECT_EQ(expected, result);
3147 }
3148
3149 // Test parsing invalid CIDR notation literals.
TEST(NetUtilTest,ParseCIDRBlock_Invalid)3150 TEST(NetUtilTest, ParseCIDRBlock_Invalid) {
3151 const char* bad_literals[] = {
3152 "foobar",
3153 "",
3154 "192.168.0.1",
3155 "::1",
3156 "/",
3157 "/1",
3158 "1",
3159 "192.168.1.1/-1",
3160 "192.168.1.1/33",
3161 "::1/-3",
3162 "a::3/129",
3163 "::1/x",
3164 "192.168.0.1//11"
3165 };
3166
3167 for (size_t i = 0; i < arraysize(bad_literals); ++i) {
3168 IPAddressNumber ip_number;
3169 size_t prefix_length_in_bits;
3170
3171 EXPECT_FALSE(ParseCIDRBlock(bad_literals[i],
3172 &ip_number,
3173 &prefix_length_in_bits));
3174 }
3175 }
3176
3177 // Test parsing a valid CIDR notation literal.
TEST(NetUtilTest,ParseCIDRBlock_Valid)3178 TEST(NetUtilTest, ParseCIDRBlock_Valid) {
3179 IPAddressNumber ip_number;
3180 size_t prefix_length_in_bits;
3181
3182 EXPECT_TRUE(ParseCIDRBlock("192.168.0.1/11",
3183 &ip_number,
3184 &prefix_length_in_bits));
3185
3186 EXPECT_EQ("192,168,0,1", DumpIPNumber(ip_number));
3187 EXPECT_EQ(11u, prefix_length_in_bits);
3188 }
3189
TEST(NetUtilTest,IPNumberMatchesPrefix)3190 TEST(NetUtilTest, IPNumberMatchesPrefix) {
3191 struct {
3192 const char* cidr_literal;
3193 const char* ip_literal;
3194 bool expected_to_match;
3195 } tests[] = {
3196 // IPv4 prefix with IPv4 inputs.
3197 {
3198 "10.10.1.32/27",
3199 "10.10.1.44",
3200 true
3201 },
3202 {
3203 "10.10.1.32/27",
3204 "10.10.1.90",
3205 false
3206 },
3207 {
3208 "10.10.1.32/27",
3209 "10.10.1.90",
3210 false
3211 },
3212
3213 // IPv6 prefix with IPv6 inputs.
3214 {
3215 "2001:db8::/32",
3216 "2001:DB8:3:4::5",
3217 true
3218 },
3219 {
3220 "2001:db8::/32",
3221 "2001:c8::",
3222 false
3223 },
3224
3225 // IPv6 prefix with IPv4 inputs.
3226 {
3227 "2001:db8::/33",
3228 "192.168.0.1",
3229 false
3230 },
3231 {
3232 "::ffff:192.168.0.1/112",
3233 "192.168.33.77",
3234 true
3235 },
3236
3237 // IPv4 prefix with IPv6 inputs.
3238 {
3239 "10.11.33.44/16",
3240 "::ffff:0a0b:89",
3241 true
3242 },
3243 {
3244 "10.11.33.44/16",
3245 "::ffff:10.12.33.44",
3246 false
3247 },
3248 };
3249 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
3250 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s, %s", i,
3251 tests[i].cidr_literal,
3252 tests[i].ip_literal));
3253
3254 IPAddressNumber ip_number;
3255 EXPECT_TRUE(ParseIPLiteralToNumber(tests[i].ip_literal, &ip_number));
3256
3257 IPAddressNumber ip_prefix;
3258 size_t prefix_length_in_bits;
3259
3260 EXPECT_TRUE(ParseCIDRBlock(tests[i].cidr_literal,
3261 &ip_prefix,
3262 &prefix_length_in_bits));
3263
3264 EXPECT_EQ(tests[i].expected_to_match,
3265 IPNumberMatchesPrefix(ip_number,
3266 ip_prefix,
3267 prefix_length_in_bits));
3268 }
3269 }
3270
TEST(NetUtilTest,IsLocalhost)3271 TEST(NetUtilTest, IsLocalhost) {
3272 EXPECT_TRUE(net::IsLocalhost("localhost"));
3273 EXPECT_TRUE(net::IsLocalhost("localhost.localdomain"));
3274 EXPECT_TRUE(net::IsLocalhost("localhost6"));
3275 EXPECT_TRUE(net::IsLocalhost("localhost6.localdomain6"));
3276 EXPECT_TRUE(net::IsLocalhost("127.0.0.1"));
3277 EXPECT_TRUE(net::IsLocalhost("127.0.1.0"));
3278 EXPECT_TRUE(net::IsLocalhost("127.1.0.0"));
3279 EXPECT_TRUE(net::IsLocalhost("127.0.0.255"));
3280 EXPECT_TRUE(net::IsLocalhost("127.0.255.0"));
3281 EXPECT_TRUE(net::IsLocalhost("127.255.0.0"));
3282 EXPECT_TRUE(net::IsLocalhost("::1"));
3283 EXPECT_TRUE(net::IsLocalhost("0:0:0:0:0:0:0:1"));
3284
3285 EXPECT_FALSE(net::IsLocalhost("localhostx"));
3286 EXPECT_FALSE(net::IsLocalhost("foo.localdomain"));
3287 EXPECT_FALSE(net::IsLocalhost("localhost6x"));
3288 EXPECT_FALSE(net::IsLocalhost("localhost.localdomain6"));
3289 EXPECT_FALSE(net::IsLocalhost("localhost6.localdomain"));
3290 EXPECT_FALSE(net::IsLocalhost("127.0.0.1.1"));
3291 EXPECT_FALSE(net::IsLocalhost(".127.0.0.255"));
3292 EXPECT_FALSE(net::IsLocalhost("::2"));
3293 EXPECT_FALSE(net::IsLocalhost("::1:1"));
3294 EXPECT_FALSE(net::IsLocalhost("0:0:0:0:1:0:0:1"));
3295 EXPECT_FALSE(net::IsLocalhost("::1:1"));
3296 EXPECT_FALSE(net::IsLocalhost("0:0:0:0:0:0:0:0:1"));
3297 }
3298
3299 // Verify GetNetworkList().
TEST(NetUtilTest,GetNetworkList)3300 TEST(NetUtilTest, GetNetworkList) {
3301 NetworkInterfaceList list;
3302 ASSERT_TRUE(GetNetworkList(&list));
3303 for (NetworkInterfaceList::iterator it = list.begin();
3304 it != list.end(); ++it) {
3305 // Verify that the name is not empty.
3306 EXPECT_FALSE(it->name.empty());
3307
3308 // Verify that the address is correct.
3309 EXPECT_TRUE(it->address.size() == kIPv4AddressSize ||
3310 it->address.size() == kIPv6AddressSize)
3311 << "Invalid address of size " << it->address.size();
3312 bool all_zeroes = true;
3313 for (size_t i = 0; i < it->address.size(); ++i) {
3314 if (it->address[i] != 0) {
3315 all_zeroes = false;
3316 break;
3317 }
3318 }
3319 EXPECT_FALSE(all_zeroes);
3320 EXPECT_GT(it->network_prefix, 1u);
3321 EXPECT_LE(it->network_prefix, it->address.size() * 8);
3322
3323 #if defined(OS_WIN)
3324 // On Windows |name| is NET_LUID.
3325 base::ScopedNativeLibrary phlpapi_lib(
3326 base::FilePath(FILE_PATH_LITERAL("iphlpapi.dll")));
3327 ASSERT_TRUE(phlpapi_lib.is_valid());
3328 typedef NETIO_STATUS (WINAPI* ConvertInterfaceIndexToLuid)(NET_IFINDEX,
3329 PNET_LUID);
3330 ConvertInterfaceIndexToLuid interface_to_luid =
3331 reinterpret_cast<ConvertInterfaceIndexToLuid>(
3332 phlpapi_lib.GetFunctionPointer("ConvertInterfaceIndexToLuid"));
3333
3334 typedef NETIO_STATUS (WINAPI* ConvertInterfaceLuidToGuid)(NET_LUID*,
3335 GUID*);
3336 ConvertInterfaceLuidToGuid luid_to_guid =
3337 reinterpret_cast<ConvertInterfaceLuidToGuid>(
3338 phlpapi_lib.GetFunctionPointer("ConvertInterfaceLuidToGuid"));
3339
3340 if (interface_to_luid && luid_to_guid) {
3341 NET_LUID luid;
3342 EXPECT_EQ(interface_to_luid(it->interface_index, &luid), NO_ERROR);
3343 GUID guid;
3344 EXPECT_EQ(luid_to_guid(&luid, &guid), NO_ERROR);
3345 LPOLESTR name;
3346 StringFromCLSID(guid, &name);
3347 EXPECT_STREQ(UTF8ToWide(it->name).c_str(), name);
3348 CoTaskMemFree(name);
3349 continue;
3350 } else {
3351 EXPECT_LT(base::win::GetVersion(), base::win::VERSION_VISTA);
3352 EXPECT_LT(it->interface_index, 1u << 24u); // Must fit 0.x.x.x.
3353 EXPECT_NE(it->interface_index, 0u); // 0 means to use default.
3354 }
3355 #elif !defined(OS_ANDROID)
3356 char name[IF_NAMESIZE];
3357 EXPECT_TRUE(if_indextoname(it->interface_index, name));
3358 EXPECT_STREQ(it->name.c_str(), name);
3359 #endif
3360 }
3361 }
3362
3363 static const base::FilePath::CharType* kSafePortableBasenames[] = {
3364 FILE_PATH_LITERAL("a"),
3365 FILE_PATH_LITERAL("a.txt"),
3366 FILE_PATH_LITERAL("a b.txt"),
3367 FILE_PATH_LITERAL("a-b.txt"),
3368 FILE_PATH_LITERAL("My Computer"),
3369 FILE_PATH_LITERAL(" Computer"),
3370 };
3371
3372 static const base::FilePath::CharType* kUnsafePortableBasenames[] = {
3373 FILE_PATH_LITERAL(""),
3374 FILE_PATH_LITERAL("."),
3375 FILE_PATH_LITERAL(".."),
3376 FILE_PATH_LITERAL("..."),
3377 FILE_PATH_LITERAL("con"),
3378 FILE_PATH_LITERAL("con.zip"),
3379 FILE_PATH_LITERAL("NUL"),
3380 FILE_PATH_LITERAL("NUL.zip"),
3381 FILE_PATH_LITERAL(".a"),
3382 FILE_PATH_LITERAL("a."),
3383 FILE_PATH_LITERAL("a\"a"),
3384 FILE_PATH_LITERAL("a<a"),
3385 FILE_PATH_LITERAL("a>a"),
3386 FILE_PATH_LITERAL("a?a"),
3387 FILE_PATH_LITERAL("a/"),
3388 FILE_PATH_LITERAL("a\\"),
3389 FILE_PATH_LITERAL("a "),
3390 FILE_PATH_LITERAL("a . ."),
3391 FILE_PATH_LITERAL("My Computer.{a}"),
3392 FILE_PATH_LITERAL("My Computer.{20D04FE0-3AEA-1069-A2D8-08002B30309D}"),
3393 #if !defined(OS_WIN)
3394 FILE_PATH_LITERAL("a\\a"),
3395 #endif
3396 };
3397
3398 static const base::FilePath::CharType* kSafePortableRelativePaths[] = {
3399 FILE_PATH_LITERAL("a/a"),
3400 #if defined(OS_WIN)
3401 FILE_PATH_LITERAL("a\\a"),
3402 #endif
3403 };
3404
TEST(NetUtilTest,IsSafePortablePathComponent)3405 TEST(NetUtilTest, IsSafePortablePathComponent) {
3406 for (size_t i = 0 ; i < arraysize(kSafePortableBasenames); ++i) {
3407 EXPECT_TRUE(IsSafePortablePathComponent(base::FilePath(
3408 kSafePortableBasenames[i]))) << kSafePortableBasenames[i];
3409 }
3410 for (size_t i = 0 ; i < arraysize(kUnsafePortableBasenames); ++i) {
3411 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
3412 kUnsafePortableBasenames[i]))) << kUnsafePortableBasenames[i];
3413 }
3414 for (size_t i = 0 ; i < arraysize(kSafePortableRelativePaths); ++i) {
3415 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
3416 kSafePortableRelativePaths[i]))) << kSafePortableRelativePaths[i];
3417 }
3418 }
3419
TEST(NetUtilTest,IsSafePortableRelativePath)3420 TEST(NetUtilTest, IsSafePortableRelativePath) {
3421 base::FilePath safe_dirname(FILE_PATH_LITERAL("a"));
3422 for (size_t i = 0 ; i < arraysize(kSafePortableBasenames); ++i) {
3423 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
3424 kSafePortableBasenames[i]))) << kSafePortableBasenames[i];
3425 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname.Append(base::FilePath(
3426 kSafePortableBasenames[i])))) << kSafePortableBasenames[i];
3427 }
3428 for (size_t i = 0 ; i < arraysize(kSafePortableRelativePaths); ++i) {
3429 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
3430 kSafePortableRelativePaths[i]))) << kSafePortableRelativePaths[i];
3431 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname.Append(base::FilePath(
3432 kSafePortableRelativePaths[i])))) << kSafePortableRelativePaths[i];
3433 }
3434 for (size_t i = 0 ; i < arraysize(kUnsafePortableBasenames); ++i) {
3435 EXPECT_FALSE(IsSafePortableRelativePath(base::FilePath(
3436 kUnsafePortableBasenames[i]))) << kUnsafePortableBasenames[i];
3437 if (!base::FilePath::StringType(kUnsafePortableBasenames[i]).empty()) {
3438 EXPECT_FALSE(IsSafePortableRelativePath(safe_dirname.Append(
3439 base::FilePath(kUnsafePortableBasenames[i]))))
3440 << kUnsafePortableBasenames[i];
3441 }
3442 }
3443 }
3444
3445 struct NonUniqueNameTestData {
3446 bool is_unique;
3447 const char* hostname;
3448 };
3449
3450 // Google Test pretty-printer.
PrintTo(const NonUniqueNameTestData & data,std::ostream * os)3451 void PrintTo(const NonUniqueNameTestData& data, std::ostream* os) {
3452 ASSERT_TRUE(data.hostname);
3453 *os << " hostname: " << testing::PrintToString(data.hostname)
3454 << "; is_unique: " << testing::PrintToString(data.is_unique);
3455 }
3456
3457 const NonUniqueNameTestData kNonUniqueNameTestData[] = {
3458 // Domains under ICANN-assigned domains.
3459 { true, "google.com" },
3460 { true, "google.co.uk" },
3461 // Domains under private registries.
3462 { true, "appspot.com" },
3463 { true, "test.appspot.com" },
3464 // Unreserved IPv4 addresses (in various forms).
3465 { true, "8.8.8.8" },
3466 { true, "99.64.0.0" },
3467 { true, "212.15.0.0" },
3468 { true, "212.15" },
3469 { true, "212.15.0" },
3470 { true, "3557752832" },
3471 // Reserved IPv4 addresses (in various forms).
3472 { false, "192.168.0.0" },
3473 { false, "192.168.0.6" },
3474 { false, "10.0.0.5" },
3475 { false, "10.0" },
3476 { false, "10.0.0" },
3477 { false, "3232235526" },
3478 // Unreserved IPv6 addresses.
3479 { true, "FFC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
3480 { true, "2000:ba98:7654:2301:EFCD:BA98:7654:3210" },
3481 // Reserved IPv6 addresses.
3482 { false, "::192.9.5.5" },
3483 { false, "FEED::BEEF" },
3484 { false, "FEC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
3485 // 'internal'/non-IANA assigned domains.
3486 { false, "intranet" },
3487 { false, "intranet." },
3488 { false, "intranet.example" },
3489 { false, "host.intranet.example" },
3490 // gTLDs under discussion, but not yet assigned.
3491 { false, "intranet.corp" },
3492 { false, "example.tech" },
3493 { false, "intranet.internal" },
3494 // Invalid host names are treated as unique - but expected to be
3495 // filtered out before then.
3496 { true, "junk)(£)$*!@~#" },
3497 { true, "w$w.example.com" },
3498 { true, "nocolonsallowed:example" },
3499 { true, "[::4.5.6.9]" },
3500 };
3501
3502 class NetUtilNonUniqueNameTest
3503 : public testing::TestWithParam<NonUniqueNameTestData> {
3504 public:
~NetUtilNonUniqueNameTest()3505 virtual ~NetUtilNonUniqueNameTest() {}
3506
3507 protected:
IsUnique(const std::string & hostname)3508 bool IsUnique(const std::string& hostname) {
3509 return !IsHostnameNonUnique(hostname);
3510 }
3511 };
3512
3513 // Test that internal/non-unique names are properly identified as such, but
3514 // that IP addresses and hosts beneath registry-controlled domains are flagged
3515 // as unique names.
TEST_P(NetUtilNonUniqueNameTest,IsHostnameNonUnique)3516 TEST_P(NetUtilNonUniqueNameTest, IsHostnameNonUnique) {
3517 const NonUniqueNameTestData& test_data = GetParam();
3518
3519 EXPECT_EQ(test_data.is_unique, IsUnique(test_data.hostname));
3520 }
3521
3522 INSTANTIATE_TEST_CASE_P(, NetUtilNonUniqueNameTest,
3523 testing::ValuesIn(kNonUniqueNameTestData));
3524
3525 } // namespace net
3526