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