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