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