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