Home | History | Annotate | Download | only in base
      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