net_util_unittest.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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 "base/file_path.h"
8#include "base/format_macros.h"
9#include "base/string_number_conversions.h"
10#include "base/string_util.h"
11#include "base/stringprintf.h"
12#include "base/sys_string_conversions.h"
13#include "base/test/test_file_util.h"
14#include "base/time.h"
15#include "base/utf_string_conversions.h"
16#include "googleurl/src/gurl.h"
17#include "net/base/sys_addrinfo.h"
18#include "testing/gtest/include/gtest/gtest.h"
19
20namespace {
21
22class NetUtilTest : public testing::Test {
23};
24
25struct FileCase {
26  const wchar_t* file;
27  const char* url;
28};
29
30struct HeaderCase {
31  const wchar_t* header_name;
32  const wchar_t* expected;
33};
34
35struct HeaderParamCase {
36  const wchar_t* header_name;
37  const wchar_t* param_name;
38  const wchar_t* expected;
39};
40
41struct FileNameCDCase {
42  const char* header_field;
43  const char* referrer_charset;
44  const wchar_t* expected;
45};
46
47const wchar_t* kLanguages[] = {
48  L"",      L"en",    L"zh-CN",       L"ja",    L"ko",
49  L"he",    L"ar",    L"ru",          L"el",    L"fr",
50  L"de",    L"pt",    L"sv",          L"th",    L"hi",
51  L"de,en", L"el,en", L"zh-TW,en",    L"ko,ja", L"he,ru,en",
52  L"zh,ru,en"
53};
54
55struct IDNTestCase {
56  const char* input;
57  const wchar_t* unicode_output;
58  const bool unicode_allowed[arraysize(kLanguages)];
59};
60
61// TODO(jungshik) This is just a random sample of languages and is far
62// from exhaustive.  We may have to generate all the combinations
63// of languages (powerset of a set of all the languages).
64const IDNTestCase idn_cases[] = {
65  // No IDN
66  {"www.google.com", L"www.google.com",
67   {true,  true,  true,  true,  true,
68    true,  true,  true,  true,  true,
69    true,  true,  true,  true,  true,
70    true,  true,  true,  true,  true,
71    true}},
72  {"www.google.com.", L"www.google.com.",
73   {true,  true,  true,  true,  true,
74    true,  true,  true,  true,  true,
75    true,  true,  true,  true,  true,
76    true,  true,  true,  true,  true,
77    true}},
78  {".", L".",
79   {true,  true,  true,  true,  true,
80    true,  true,  true,  true,  true,
81    true,  true,  true,  true,  true,
82    true,  true,  true,  true,  true,
83    true}},
84  {"", L"",
85   {true,  true,  true,  true,  true,
86    true,  true,  true,  true,  true,
87    true,  true,  true,  true,  true,
88    true,  true,  true,  true,  true,
89    true}},
90  // IDN
91  // Hanzi (Traditional Chinese)
92  {"xn--1lq90ic7f1rc.cn", L"\x5317\x4eac\x5927\x5b78.cn",
93   {true,  false, true,  true,  false,
94    false, false, false, false, false,
95    false, false, false, false, false,
96    false, false, true,  true,  false,
97    true}},
98  // Hanzi ('video' in Simplified Chinese : will pass only in zh-CN,zh)
99  {"xn--cy2a840a.com", L"\x89c6\x9891.com",
100   {true,  false, true,  false,  false,
101    false, false, false, false, false,
102    false, false, false, false, false,
103    false, false, false, false,  false,
104    true}},
105  // Hanzi + '123'
106  {"www.xn--123-p18d.com", L"www.\x4e00" L"123.com",
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 + Latin : U+56FD is simplified and is regarded
113  // as not supported in zh-TW.
114  {"www.xn--hello-9n1hm04c.com", L"www.hello\x4e2d\x56fd.com",
115   {false, false, true,  true,  false,
116    false, false, false, false, false,
117    false, false, false, false, false,
118    false, false, false, true,  false,
119    true}},
120  // Kanji + Kana (Japanese)
121  {"xn--l8jvb1ey91xtjb.jp", L"\x671d\x65e5\x3042\x3055\x3072.jp",
122   {true,  false, false, true,  false,
123    false, false, false, false, false,
124    false, false, false, false, false,
125    false, false, false, true,  false,
126    false}},
127  // Katakana including U+30FC
128  {"xn--tckm4i2e.jp", L"\x30b3\x30de\x30fc\x30b9.jp",
129   {true, false, false, true,  false,
130    false, false, false, false, false,
131    false, false, false, false, false,
132    false, false, false, true, false,
133    }},
134  {"xn--3ck7a7g.jp", L"\u30ce\u30f3\u30bd.jp",
135   {true, false, false, true,  false,
136    false, false, false, false, false,
137    false, false, false, false, false,
138    false, false, false, true, false,
139    }},
140  // Katakana + Latin (Japanese)
141  // TODO(jungshik): Change 'false' in the first element to 'true'
142  // after upgrading to ICU 4.2.1 to use new uspoof_* APIs instead
143  // of our IsIDNComponentInSingleScript().
144  {"xn--e-efusa1mzf.jp", L"e\x30b3\x30de\x30fc\x30b9.jp",
145   {false, false, false, true,  false,
146    false, false, false, false, false,
147    false, false, false, false, false,
148    false, false, false, true, false,
149    }},
150  {"xn--3bkxe.jp", L"\x30c8\x309a.jp",
151   {false, false, false, true,  false,
152    false, false, false, false, false,
153    false, false, false, false, false,
154    false, false, false, true, false,
155    }},
156  // Hangul (Korean)
157  {"www.xn--or3b17p6jjc.kr", L"www.\xc804\xc790\xc815\xbd80.kr",
158   {true,  false, false, false, true,
159    false, false, false, false, false,
160    false, false, false, false, false,
161    false, false, false, true,  false,
162    false}},
163  // b<u-umlaut>cher (German)
164  {"xn--bcher-kva.de", L"b\x00fc" L"cher.de",
165   {true,  false, false, false, false,
166    false, false, false, false, true,
167    true,  false,  false, false, false,
168    true,  false, false, false, false,
169    false}},
170  // a with diaeresis
171  {"www.xn--frgbolaget-q5a.se", L"www.f\x00e4rgbolaget.se",
172   {true,  false, false, false, false,
173    false, false, false, false, false,
174    true,  false, true, false, false,
175    true,  false, false, false, false,
176    false}},
177  // c-cedilla (French)
178  {"www.xn--alliancefranaise-npb.fr", L"www.alliancefran\x00e7" L"aise.fr",
179   {true,  false, false, false, false,
180    false, false, false, false, true,
181    false, true,  false, false, false,
182    false, false, false, false, false,
183    false}},
184  // caf'e with acute accent' (French)
185  {"xn--caf-dma.fr", L"caf\x00e9.fr",
186   {true,  false, false, false, false,
187    false, false, false, false, true,
188    false, true,  true,  false, false,
189    false, false, false, false, false,
190    false}},
191  // c-cedillla and a with tilde (Portuguese)
192  {"xn--poema-9qae5a.com.br", L"p\x00e3oema\x00e7\x00e3.com.br",
193   {true,  false, false, false, false,
194    false, false, false, false, false,
195    false, true,  false, false, false,
196    false, false, false, false, false,
197    false}},
198  // s with caron
199  {"xn--achy-f6a.com", L"\x0161" L"achy.com",
200   {true,  false, false, false, false,
201    false, false, false, false, false,
202    false, false, false, false, false,
203    false, false, false, false, false,
204    false}},
205  // TODO(jungshik) : Add examples with Cyrillic letters
206  // only used in some languages written in Cyrillic.
207  // Eutopia (Greek)
208  {"xn--kxae4bafwg.gr", L"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1.gr",
209   {true,  false, false, false, false,
210    false, false, false, true,  false,
211    false, false, false, false, false,
212    false, true,  false, false, false,
213    false}},
214  // Eutopia + 123 (Greek)
215  {"xn---123-pldm0haj2bk.gr",
216   L"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1-123.gr",
217   {true,  false, false, false, false,
218    false, false, false, true,  false,
219    false, false, false, false, false,
220    false, true,  false, false, false,
221    false}},
222  // Cyrillic (Russian)
223  {"xn--n1aeec9b.ru", L"\x0442\x043e\x0440\x0442\x044b.ru",
224   {true,  false, false, false, false,
225    false, false, true,  false, false,
226    false, false, false, false, false,
227    false, false, false, false, true,
228    true}},
229  // Cyrillic + 123 (Russian)
230  {"xn---123-45dmmc5f.ru", L"\x0442\x043e\x0440\x0442\x044b-123.ru",
231   {true,  false, false, false, false,
232    false, false, true,  false, false,
233    false, false, false, false, false,
234    false, false, false, false, true,
235    true}},
236  // Arabic
237  {"xn--mgba1fmg.ar", L"\x0627\x0641\x0644\x0627\x0645.ar",
238   {true,  false, false, false, false,
239    false, true,  false, false, false,
240    false, false, false, false, false,
241    false, false, false, false, false,
242    false}},
243  // Hebrew
244  {"xn--4dbib.he", L"\x05d5\x05d0\x05d4.he",
245   {true,  false, false, false, false,
246    true,  false, false, false, false,
247    false, false, false, false, false,
248    false, false, false, false, true,
249    false}},
250  // Thai
251  {"xn--12c2cc4ag3b4ccu.th",
252   L"\x0e2a\x0e32\x0e22\x0e01\x0e32\x0e23\x0e1a\x0e34\x0e19.th",
253   {true,  false, false, false, false,
254    false, false, false, false, false,
255    false, false, false, true,  false,
256    false, false, false, false, false,
257    false}},
258  // Devangari (Hindi)
259  {"www.xn--l1b6a9e1b7c.in", L"www.\x0905\x0915\x094b\x0932\x093e.in",
260   {true,  false, false, false, false,
261    false, false, false, false, false,
262    false, false, false, false, true,
263    false, false, false, false, false,
264    false}},
265  // Invalid IDN
266  {"xn--hello?world.com", NULL,
267   {false, false, false, false, false,
268    false, false, false, false, false,
269    false, false, false, false, false,
270    false, false, false, false, false,
271    false}},
272  // Unsafe IDNs
273  // "payp<alpha>l.com"
274  {"www.xn--paypl-g9d.com", L"payp\x03b1l.com",
275   {false, false, false, false, false,
276    false, false, false, false, false,
277    false, false, false, false, false,
278    false, false, false, false, false,
279    false}},
280  // google.gr with Greek omicron and epsilon
281  {"xn--ggl-6xc1ca.gr", L"g\x03bf\x03bfgl\x03b5.gr",
282   {false, false, false, false, false,
283    false, false, false, false, false,
284    false, false, false, false, false,
285    false, false, false, false, false,
286    false}},
287  // google.ru with Cyrillic o
288  {"xn--ggl-tdd6ba.ru", L"g\x043e\x043egl\x0435.ru",
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  // h<e with acute>llo<China in Han>.cn
295  {"xn--hllo-bpa7979ih5m.cn", L"h\x00e9llo\x4e2d\x56fd.cn",
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  // <Greek rho><Cyrillic a><Cyrillic u>.ru
302  {"xn--2xa6t2b.ru", L"\x03c1\x0430\x0443.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  // One that's really long that will force a buffer realloc
309  {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
310       "aaaaaaa",
311   L"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
312       L"aaaaaaaa",
313   {true,  true,  true,  true,  true,
314    true,  true,  true,  true,  true,
315    true,  true,  true,  true,  true,
316    true,  true,  true,  true,  true,
317    true}},
318  // Test cases for characters we blacklisted although allowed in IDN.
319  // Embedded spaces will be turned to %20 in the display.
320  // TODO(jungshik): We need to have more cases. This is a typical
321  // data-driven trap. The following test cases need to be separated
322  // and tested only for a couple of languages.
323  {"xn--osd3820f24c.kr", L"\xac00\xb098\x115f.kr",
324    {false, false, false, false, false,
325     false, false, false, false, false,
326     false, false, false, false, false,
327     false, false, false, false, false,
328     false}},
329  {"www.xn--google-ho0coa.com", L"www.\x2039google\x203a.com",
330    {false, false, false, false, false,
331     false, false, false, false, false,
332     false, false, false, false, false,
333     false, false, false, false, false,
334  }},
335  {"google.xn--comabc-k8d", L"google.com\x0338" L"abc",
336    {false, false, false, false, false,
337     false, false, false, false, false,
338     false, false, false, false, false,
339     false, false, false, false, false,
340  }},
341  {"google.xn--com-oh4ba.evil.jp", L"google.com\x309a\x309a.evil.jp",
342    {false, false, false, false, false,
343     false, false, false, false, false,
344     false, false, false, false, false,
345     false, false, false, false, false,
346  }},
347  {"google.xn--comevil-v04f.jp", L"google.com\x30ce" L"evil.jp",
348    {false, false, false, false, false,
349     false, false, false, false, false,
350     false, false, false, false, false,
351     false, false, false, false, false,
352  }},
353#if 0
354  // These two cases are special. We need a separate test.
355  // U+3000 and U+3002 are normalized to ASCII space and dot.
356  {"xn-- -kq6ay5z.cn", L"\x4e2d\x56fd\x3000.cn",
357    {false, false, true,  false, false,
358     false, false, false, false, false,
359     false, false, false, false, false,
360     false, false, true,  false, false,
361     true}},
362  {"xn--fiqs8s.cn", L"\x4e2d\x56fd\x3002" L"cn",
363    {false, false, true,  false, false,
364     false, false, false, false, false,
365     false, false, false, false, false,
366     false, false, true,  false, false,
367     true}},
368#endif
369};
370
371struct AdjustOffsetCase {
372  size_t input_offset;
373  size_t output_offset;
374};
375
376struct CompliantHostCase {
377  const char* host;
378  const char* desired_tld;
379  bool expected_output;
380};
381
382struct SuggestedFilenameCase {
383  const char* url;
384  const char* content_disp_header;
385  const char* referrer_charset;
386  const wchar_t* default_filename;
387  const wchar_t* expected_filename;
388};
389
390struct UrlTestData {
391  const char* description;
392  const char* input;
393  const char* languages;
394  net::FormatUrlTypes format_types;
395  UnescapeRule::Type escape_rules;
396  const wchar_t* output;  // Use |wchar_t| to handle Unicode constants easily.
397  size_t prefix_len;
398};
399
400// Returns an addrinfo for the given 32-bit address (IPv4.)
401// The result lives in static storage, so don't delete it.
402// |bytes| should be an array of length 4.
403const struct addrinfo* GetIPv4Address(const uint8* bytes, int port) {
404  static struct addrinfo static_ai;
405  static struct sockaddr_in static_addr4;
406
407  struct addrinfo* ai = &static_ai;
408  ai->ai_socktype = SOCK_STREAM;
409  memset(ai, 0, sizeof(static_ai));
410
411  ai->ai_family = AF_INET;
412  ai->ai_addrlen = sizeof(static_addr4);
413
414  struct sockaddr_in* addr4 = &static_addr4;
415  memset(addr4, 0, sizeof(static_addr4));
416  addr4->sin_port = htons(port);
417  addr4->sin_family = ai->ai_family;
418  memcpy(&addr4->sin_addr, bytes, 4);
419
420  ai->ai_addr = (sockaddr*)addr4;
421  return ai;
422}
423
424// Returns a addrinfo for the given 128-bit address (IPv6.)
425// The result lives in static storage, so don't delete it.
426// |bytes| should be an array of length 16.
427const struct addrinfo* GetIPv6Address(const uint8* bytes, int port) {
428  static struct addrinfo static_ai;
429  static struct sockaddr_in6 static_addr6;
430
431  struct addrinfo* ai = &static_ai;
432  ai->ai_socktype = SOCK_STREAM;
433  memset(ai, 0, sizeof(static_ai));
434
435  ai->ai_family = AF_INET6;
436  ai->ai_addrlen = sizeof(static_addr6);
437
438  struct sockaddr_in6* addr6 = &static_addr6;
439  memset(addr6, 0, sizeof(static_addr6));
440  addr6->sin6_port = htons(port);
441  addr6->sin6_family = ai->ai_family;
442  memcpy(&addr6->sin6_addr, bytes, 16);
443
444  ai->ai_addr = (sockaddr*)addr6;
445  return ai;
446}
447
448// A helper for IDN*{Fast,Slow}.
449// Append "::<language list>" to |expected| and |actual| to make it
450// easy to tell which sub-case fails without debugging.
451void AppendLanguagesToOutputs(const wchar_t* languages,
452                              std::wstring* expected,
453                              std::wstring* actual) {
454  expected->append(L"::");
455  expected->append(languages);
456  actual->append(L"::");
457  actual->append(languages);
458}
459
460// Helper to strignize an IP number (used to define expectations).
461std::string DumpIPNumber(const net::IPAddressNumber& v) {
462  std::string out;
463  for (size_t i = 0; i < v.size(); ++i) {
464    if (i != 0)
465      out.append(",");
466    out.append(base::IntToString(static_cast<int>(v[i])));
467  }
468  return out;
469}
470
471}  // anonymous namespace
472
473TEST(NetUtilTest, FileURLConversion) {
474  // a list of test file names and the corresponding URLs
475  const FileCase round_trip_cases[] = {
476#if defined(OS_WIN)
477    {L"C:\\foo\\bar.txt", "file:///C:/foo/bar.txt"},
478    {L"\\\\some computer\\foo\\bar.txt",
479     "file://some%20computer/foo/bar.txt"}, // UNC
480    {L"D:\\Name;with%some symbols*#",
481     "file:///D:/Name%3Bwith%25some%20symbols*%23"},
482    // issue 14153: To be tested with the OS default codepage other than 1252.
483    {L"D:\\latin1\\caf\x00E9\x00DD.txt",
484     "file:///D:/latin1/caf%C3%A9%C3%9D.txt"},
485    {L"D:\\otherlatin\\caf\x0119.txt",
486     "file:///D:/otherlatin/caf%C4%99.txt"},
487    {L"D:\\greek\\\x03B1\x03B2\x03B3.txt",
488     "file:///D:/greek/%CE%B1%CE%B2%CE%B3.txt"},
489    {L"D:\\Chinese\\\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
490     "file:///D:/Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD%91"
491         "%E9%A1%B5.doc"},
492    {L"D:\\plane1\\\xD835\xDC00\xD835\xDC01.txt",  // Math alphabet "AB"
493     "file:///D:/plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
494#elif defined(OS_POSIX)
495    {L"/foo/bar.txt", "file:///foo/bar.txt"},
496    {L"/foo/BAR.txt", "file:///foo/BAR.txt"},
497    {L"/C:/foo/bar.txt", "file:///C:/foo/bar.txt"},
498    {L"/some computer/foo/bar.txt", "file:///some%20computer/foo/bar.txt"},
499    {L"/Name;with%some symbols*#", "file:///Name%3Bwith%25some%20symbols*%23"},
500    {L"/latin1/caf\x00E9\x00DD.txt", "file:///latin1/caf%C3%A9%C3%9D.txt"},
501    {L"/otherlatin/caf\x0119.txt", "file:///otherlatin/caf%C4%99.txt"},
502    {L"/greek/\x03B1\x03B2\x03B3.txt", "file:///greek/%CE%B1%CE%B2%CE%B3.txt"},
503    {L"/Chinese/\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
504     "file:///Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD"
505         "%91%E9%A1%B5.doc"},
506    {L"/plane1/\x1D400\x1D401.txt",  // Math alphabet "AB"
507     "file:///plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
508#endif
509  };
510
511  // First, we'll test that we can round-trip all of the above cases of URLs
512  FilePath output;
513  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(round_trip_cases); i++) {
514    // convert to the file URL
515    GURL file_url(net::FilePathToFileURL(
516        FilePath::FromWStringHack(round_trip_cases[i].file)));
517    EXPECT_EQ(round_trip_cases[i].url, file_url.spec());
518
519    // Back to the filename.
520    EXPECT_TRUE(net::FileURLToFilePath(file_url, &output));
521    EXPECT_EQ(round_trip_cases[i].file, file_util::FilePathAsWString(output));
522  }
523
524  // Test that various file: URLs get decoded into the correct file type
525  FileCase url_cases[] = {
526#if defined(OS_WIN)
527    {L"C:\\foo\\bar.txt", "file:c|/foo\\bar.txt"},
528    {L"C:\\foo\\bar.txt", "file:/c:/foo/bar.txt"},
529    {L"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
530    {L"C:\\foo\\bar.txt", "file:///c:/foo/bar.txt"},
531    {L"\\\\foo\\bar.txt", "file:////foo\\bar.txt"},
532    {L"\\\\foo\\bar.txt", "file:/foo/bar.txt"},
533    {L"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
534    {L"C:\\foo\\bar.txt", "file:\\\\\\c:/foo/bar.txt"},
535#elif defined(OS_POSIX)
536    {L"/c:/foo/bar.txt", "file:/c:/foo/bar.txt"},
537    {L"/c:/foo/bar.txt", "file:///c:/foo/bar.txt"},
538    {L"/foo/bar.txt", "file:/foo/bar.txt"},
539    {L"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
540    {L"/foo/bar.txt", "file:foo/bar.txt"},
541    {L"/bar.txt", "file://foo/bar.txt"},
542    {L"/foo/bar.txt", "file:///foo/bar.txt"},
543    {L"/foo/bar.txt", "file:////foo/bar.txt"},
544    {L"/foo/bar.txt", "file:////foo//bar.txt"},
545    {L"/foo/bar.txt", "file:////foo///bar.txt"},
546    {L"/foo/bar.txt", "file:////foo////bar.txt"},
547    {L"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
548    {L"/c:/foo/bar.txt", "file:c:/foo/bar.txt"},
549    // We get these wrong because GURL turns back slashes into forward
550    // slashes.
551    //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
552    //{L"/c|/foo%5Cbar.txt", "file:c|/foo\\bar.txt"},
553    //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
554    //{L"/foo%5Cbar.txt", "file:////foo\\bar.txt"},
555    //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
556#endif
557  };
558  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(url_cases); i++) {
559    net::FileURLToFilePath(GURL(url_cases[i].url), &output);
560    EXPECT_EQ(url_cases[i].file, file_util::FilePathAsWString(output));
561  }
562
563  // Unfortunately, UTF8ToWide discards invalid UTF8 input.
564#ifdef BUG_878908_IS_FIXED
565  // Test that no conversion happens if the UTF-8 input is invalid, and that
566  // the input is preserved in UTF-8
567  const char invalid_utf8[] = "file:///d:/Blah/\xff.doc";
568  const wchar_t invalid_wide[] = L"D:\\Blah\\\xff.doc";
569  EXPECT_TRUE(net::FileURLToFilePath(
570      GURL(std::string(invalid_utf8)), &output));
571  EXPECT_EQ(std::wstring(invalid_wide), output);
572#endif
573
574  // Test that if a file URL is malformed, we get a failure
575  EXPECT_FALSE(net::FileURLToFilePath(GURL("filefoobar"), &output));
576}
577
578TEST(NetUtilTest, GetIdentityFromURL) {
579  struct {
580    const char* input_url;
581    const char* expected_username;
582    const char* expected_password;
583  } tests[] = {
584    {
585      "http://username:password@google.com",
586      "username",
587      "password",
588    },
589    { // Test for http://crbug.com/19200
590      "http://username:p@ssword@google.com",
591      "username",
592      "p@ssword",
593    },
594    { // Special URL characters should be unescaped.
595      "http://username:p%3fa%26s%2fs%23@google.com",
596      "username",
597      "p?a&s/s#",
598    },
599    { // Username contains %20.
600      "http://use rname:password@google.com",
601      "use rname",
602      "password",
603    },
604    { // Keep %00 as is.
605      "http://use%00rname:password@google.com",
606      "use%00rname",
607      "password",
608    },
609    { // Use a '+' in the username.
610      "http://use+rname:password@google.com",
611      "use+rname",
612      "password",
613    },
614    { // Use a '&' in the password.
615      "http://username:p&ssword@google.com",
616      "username",
617      "p&ssword",
618    },
619  };
620  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
621    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
622                                    tests[i].input_url));
623    GURL url(tests[i].input_url);
624
625    string16 username, password;
626    net::GetIdentityFromURL(url, &username, &password);
627
628    EXPECT_EQ(ASCIIToUTF16(tests[i].expected_username), username);
629    EXPECT_EQ(ASCIIToUTF16(tests[i].expected_password), password);
630  }
631}
632
633// Try extracting a username which was encoded with UTF8.
634TEST(NetUtilTest, GetIdentityFromURL_UTF8) {
635  GURL url(WideToUTF16(L"http://foo:\x4f60\x597d@blah.com"));
636
637  EXPECT_EQ("foo", url.username());
638  EXPECT_EQ("%E4%BD%A0%E5%A5%BD", url.password());
639
640  // Extract the unescaped identity.
641  string16 username, password;
642  net::GetIdentityFromURL(url, &username, &password);
643
644  // Verify that it was decoded as UTF8.
645  EXPECT_EQ(ASCIIToUTF16("foo"), username);
646  EXPECT_EQ(WideToUTF16(L"\x4f60\x597d"), password);
647}
648
649// Just a bunch of fake headers.
650const wchar_t* google_headers =
651    L"HTTP/1.1 200 OK\n"
652    L"Content-TYPE: text/html; charset=utf-8\n"
653    L"Content-disposition: attachment; filename=\"download.pdf\"\n"
654    L"Content-Length: 378557\n"
655    L"X-Google-Google1: 314159265\n"
656    L"X-Google-Google2: aaaa2:7783,bbb21:9441\n"
657    L"X-Google-Google4: home\n"
658    L"Transfer-Encoding: chunked\n"
659    L"Set-Cookie: HEHE_AT=6666x66beef666x6-66xx6666x66; Path=/mail\n"
660    L"Set-Cookie: HEHE_HELP=owned:0;Path=/\n"
661    L"Set-Cookie: S=gmail=Xxx-beefbeefbeef_beefb:gmail_yj=beefbeef000beefbee"
662        L"fbee:gmproxy=bee-fbeefbe; Domain=.google.com; Path=/\n"
663    L"X-Google-Google2: /one/two/three/four/five/six/seven-height/nine:9411\n"
664    L"Server: GFE/1.3\n"
665    L"Transfer-Encoding: chunked\n"
666    L"Date: Mon, 13 Nov 2006 21:38:09 GMT\n"
667    L"Expires: Tue, 14 Nov 2006 19:23:58 GMT\n"
668    L"X-Malformed: bla; arg=test\"\n"
669    L"X-Malformed2: bla; arg=\n"
670    L"X-Test: bla; arg1=val1; arg2=val2";
671
672TEST(NetUtilTest, GetSpecificHeader) {
673  const HeaderCase tests[] = {
674    {L"content-type", L"text/html; charset=utf-8"},
675    {L"CONTENT-LENGTH", L"378557"},
676    {L"Date", L"Mon, 13 Nov 2006 21:38:09 GMT"},
677    {L"Bad-Header", L""},
678    {L"", L""},
679  };
680
681  // Test first with google_headers.
682  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
683    std::wstring result = net::GetSpecificHeader(google_headers,
684                                                 tests[i].header_name);
685    EXPECT_EQ(result, tests[i].expected);
686  }
687
688  // Test again with empty headers.
689  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
690    std::wstring result = net::GetSpecificHeader(L"", tests[i].header_name);
691    EXPECT_EQ(result, std::wstring());
692  }
693}
694
695TEST(NetUtilTest, GetHeaderParamValue) {
696  const HeaderParamCase tests[] = {
697    {L"Content-type", L"charset", L"utf-8"},
698    {L"content-disposition", L"filename", L"download.pdf"},
699    {L"Content-Type", L"badparam", L""},
700    {L"X-Malformed", L"arg", L"test\""},
701    {L"X-Malformed2", L"arg", L""},
702    {L"X-Test", L"arg1", L"val1"},
703    {L"X-Test", L"arg2", L"val2"},
704    {L"Bad-Header", L"badparam", L""},
705    {L"Bad-Header", L"", L""},
706    {L"", L"badparam", L""},
707    {L"", L"", L""},
708  };
709  // TODO(mpcomplete): add tests for other formats of headers.
710
711  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
712    std::wstring header_value =
713        net::GetSpecificHeader(google_headers, tests[i].header_name);
714    std::wstring result =
715        net::GetHeaderParamValue(header_value, tests[i].param_name,
716                                 net::QuoteRule::REMOVE_OUTER_QUOTES);
717    EXPECT_EQ(result, tests[i].expected);
718  }
719
720  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
721    std::wstring header_value =
722        net::GetSpecificHeader(L"", tests[i].header_name);
723    std::wstring result =
724        net::GetHeaderParamValue(header_value, tests[i].param_name,
725                                 net::QuoteRule::REMOVE_OUTER_QUOTES);
726    EXPECT_EQ(result, std::wstring());
727  }
728}
729
730TEST(NetUtilTest, GetHeaderParamValueQuotes) {
731  struct {
732    const char* header;
733    const char* expected_with_quotes;
734    const char* expected_without_quotes;
735  } tests[] = {
736    {"filename=foo", "foo", "foo"},
737    {"filename=\"foo\"", "\"foo\"", "foo"},
738    {"filename=foo\"", "foo\"", "foo\""},
739    {"filename=fo\"o", "fo\"o", "fo\"o"},
740  };
741
742  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
743    std::string actual_with_quotes =
744        net::GetHeaderParamValue(tests[i].header, "filename",
745                                 net::QuoteRule::KEEP_OUTER_QUOTES);
746    std::string actual_without_quotes =
747        net::GetHeaderParamValue(tests[i].header, "filename",
748                                 net::QuoteRule::REMOVE_OUTER_QUOTES);
749    EXPECT_EQ(tests[i].expected_with_quotes, actual_with_quotes)
750        << "Failed while processing: " << tests[i].header;
751    EXPECT_EQ(tests[i].expected_without_quotes, actual_without_quotes)
752        << "Failed while processing: " << tests[i].header;
753  }
754}
755
756TEST(NetUtilTest, GetFileNameFromCD) {
757  const FileNameCDCase tests[] = {
758    // Test various forms of C-D header fields emitted by web servers.
759    {"content-disposition: inline; filename=\"abcde.pdf\"", "", L"abcde.pdf"},
760    {"content-disposition: inline; name=\"abcde.pdf\"", "", L"abcde.pdf"},
761    {"content-disposition: attachment; filename=abcde.pdf", "", L"abcde.pdf"},
762    {"content-disposition: attachment; name=abcde.pdf", "", L"abcde.pdf"},
763    {"content-disposition: attachment; filename=abc,de.pdf", "", L"abc,de.pdf"},
764    {"content-disposition: filename=abcde.pdf", "", L"abcde.pdf"},
765    {"content-disposition: filename= abcde.pdf", "", L"abcde.pdf"},
766    {"content-disposition: filename =abcde.pdf", "", L"abcde.pdf"},
767    {"content-disposition: filename = abcde.pdf", "", L"abcde.pdf"},
768    {"content-disposition: filename\t=abcde.pdf", "", L"abcde.pdf"},
769    {"content-disposition: filename \t\t  =abcde.pdf", "", L"abcde.pdf"},
770    {"content-disposition: name=abcde.pdf", "", L"abcde.pdf"},
771    {"content-disposition: inline; filename=\"abc%20de.pdf\"", "",
772     L"abc de.pdf"},
773    // Whitespaces are converted to a space.
774    {"content-disposition: inline; filename=\"abc  \t\nde.pdf\"", "",
775     L"abc    de.pdf"},
776    // %-escaped UTF-8
777    {"Content-Disposition: attachment; filename=\"%EC%98%88%EC%88%A0%20"
778     "%EC%98%88%EC%88%A0.jpg\"", "", L"\xc608\xc220 \xc608\xc220.jpg"},
779    {"Content-Disposition: attachment; filename=\"%F0%90%8C%B0%F0%90%8C%B1"
780     "abc.jpg\"", "", L"\U00010330\U00010331abc.jpg"},
781    {"Content-Disposition: attachment; filename=\"%EC%98%88%EC%88%A0 \n"
782     "%EC%98%88%EC%88%A0.jpg\"", "", L"\xc608\xc220  \xc608\xc220.jpg"},
783    // RFC 2047 with various charsets and Q/B encodings
784    {"Content-Disposition: attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
785     "D13=2Epng?=\"", "", L"\x82b8\x8853" L"3.png"},
786    {"Content-Disposition: attachment; filename==?eUc-Kr?b?v7m8+iAzLnBuZw==?=",
787     "", L"\xc608\xc220 3.png"},
788    {"Content-Disposition: attachment; filename==?utf-8?Q?=E8=8A=B8=E8"
789     "=A1=93_3=2Epng?=", "", L"\x82b8\x8853 3.png"},
790    {"Content-Disposition: attachment; filename==?utf-8?Q?=F0=90=8C=B0"
791     "_3=2Epng?=", "", L"\U00010330 3.png"},
792    {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=e9_=2epng?=\"",
793     "", L"caf\x00e9 .png"},
794    // Space after an encoded word should be removed.
795    {"Content-Disposition: inline; filename=\"=?iso88591?Q?caf=E9_?= .png\"",
796     "", L"caf\x00e9 .png"},
797    // Two encoded words with different charsets (not very likely to be emitted
798    // by web servers in the wild). Spaces between them are removed.
799    {"Content-Disposition: inline; filename=\"=?euc-kr?b?v7m8+iAz?="
800     " =?ksc5601?q?=BF=B9=BC=FA=2Epng?=\"", "",
801     L"\xc608\xc220 3\xc608\xc220.png"},
802    {"Content-Disposition: attachment; filename=\"=?windows-1252?Q?caf=E9?="
803     "  =?iso-8859-7?b?4eI=?= .png\"", "", L"caf\x00e9\x03b1\x03b2.png"},
804    // Non-ASCII string is passed through and treated as UTF-8 as long as
805    // it's valid as UTF-8 and regardless of |referrer_charset|.
806    {"Content-Disposition: attachment; filename=caf\xc3\xa9.png",
807     "iso-8859-1", L"caf\x00e9.png"},
808    {"Content-Disposition: attachment; filename=caf\xc3\xa9.png",
809     "", L"caf\x00e9.png"},
810    // Non-ASCII/Non-UTF-8 string. Fall back to the referrer charset.
811    {"Content-Disposition: attachment; filename=caf\xe5.png",
812     "windows-1253", L"caf\x03b5.png"},
813#if 0
814    // Non-ASCII/Non-UTF-8 string. Fall back to the native codepage.
815    // TODO(jungshik): We need to set the OS default codepage
816    // to a specific value before testing. On Windows, we can use
817    // SetThreadLocale().
818    {"Content-Disposition: attachment; filename=\xb0\xa1\xb0\xa2.png",
819     "", L"\xac00\xac01.png"},
820#endif
821    // Failure cases
822    // Invalid hex-digit "G"
823    {"Content-Disposition: attachment; filename==?iiso88591?Q?caf=EG?=", "",
824     L""},
825    // Incomplete RFC 2047 encoded-word (missing '='' at the end)
826    {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?", "", L""},
827    // Extra character at the end of an encoded word
828    {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?==",
829     "", L""},
830    // Extra token at the end of an encoded word
831    {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?=?",
832     "", L""},
833    {"Content-Disposition: attachment; filename==?iso88591?Q?caf=E3?=?=",
834     "",  L""},
835    // Incomplete hex-escaped chars
836    {"Content-Disposition: attachment; filename==?windows-1252?Q?=63=61=E?=",
837     "", L""},
838    {"Content-Disposition: attachment; filename=%EC%98%88%EC%88%A", "", L""},
839    // %-escaped non-UTF-8 encoding is an "error"
840    {"Content-Disposition: attachment; filename=%B7%DD%BD%D1.png", "", L""},
841    // Two RFC 2047 encoded words in a row without a space is an error.
842    {"Content-Disposition: attachment; filename==?windows-1252?Q?caf=E3?="
843     "=?iso-8859-7?b?4eIucG5nCg==?=", "", L""},
844
845    // RFC 5987 tests with Filename*  : see http://tools.ietf.org/html/rfc5987
846    {"Content-Disposition: attachment; filename*=foo.html", "", L""},
847    {"Content-Disposition: attachment; filename*=foo'.html", "", L""},
848    {"Content-Disposition: attachment; filename*=''foo'.html", "", L""},
849    {"Content-Disposition: attachment; filename*=''foo.html'", "", L""},
850    {"Content-Disposition: attachment; filename*=''f\"oo\".html'", "", L""},
851    {"Content-Disposition: attachment; filename*=bogus_charset''foo.html'",
852     "", L""},
853    {"Content-Disposition: attachment; filename*='en'foo.html'", "", L""},
854    {"Content-Disposition: attachment; filename*=iso-8859-1'en'foo.html", "",
855      L"foo.html"},
856    {"Content-Disposition: attachment; filename*=utf-8'en'foo.html", "",
857      L"foo.html"},
858    // charset cannot be omitted.
859    {"Content-Disposition: attachment; filename*='es'f\xfa.html'", "", L""},
860    // Non-ASCII bytes are not allowed.
861    {"Content-Disposition: attachment; filename*=iso-8859-1'es'f\xfa.html", "",
862      L""},
863    {"Content-Disposition: attachment; filename*=utf-8'es'f\xce\xba.html", "",
864      L""},
865    // TODO(jshin): Space should be %-encoded, but currently, we allow
866    // spaces.
867    {"Content-Disposition: inline; filename*=iso88591''cafe foo.png", "",
868      L"cafe foo.png"},
869
870    // Filename* tests converted from Q-encoded tests above.
871    {"Content-Disposition: attachment; filename*=EUC-JP''%B7%DD%BD%D13%2Epng",
872     "", L"\x82b8\x8853" L"3.png"},
873    {"Content-Disposition: attachment; filename*=utf-8''"
874      "%E8%8A%B8%E8%A1%93%203%2Epng", "", L"\x82b8\x8853 3.png"},
875    {"Content-Disposition: attachment; filename*=utf-8''%F0%90%8C%B0 3.png", "",
876      L"\U00010330 3.png"},
877    {"Content-Disposition: inline; filename*=Euc-Kr'ko'%BF%B9%BC%FA%2Epng", "",
878     L"\xc608\xc220.png"},
879    {"Content-Disposition: attachment; filename*=windows-1252''caf%E9.png", "",
880      L"caf\x00e9.png"},
881
882    // http://greenbytes.de/tech/tc2231/ filename* test cases.
883    // attwithisofn2231iso
884    {"Content-Disposition: attachment; filename*=iso-8859-1''foo-%E4.html", "",
885      L"foo-\xe4.html"},
886    // attwithfn2231utf8
887    {"Content-Disposition: attachment; filename*="
888      "UTF-8''foo-%c3%a4-%e2%82%ac.html", "", L"foo-\xe4-\x20ac.html"},
889    // attwithfn2231noc : no encoding specified but UTF-8 is used.
890    {"Content-Disposition: attachment; filename*=''foo-%c3%a4-%e2%82%ac.html",
891      "", L""},
892    // attwithfn2231utf8comp
893    {"Content-Disposition: attachment; filename*=UTF-8''foo-a%cc%88.html", "",
894      L"foo-\xe4.html"},
895#ifdef ICU_SHOULD_FAIL_CONVERSION_ON_INVALID_CHARACTER
896    // This does not work because we treat ISO-8859-1 synonymous with
897    // Windows-1252 per HTML5. For HTTP, in theory, we're not
898    // supposed to.
899    // attwithfn2231utf8-bad
900    {"Content-Disposition: attachment; filename*="
901      "iso-8859-1''foo-%c3%a4-%e2%82%ac.html", "", L""},
902#endif
903    // attwithfn2231ws1
904    {"Content-Disposition: attachment; filename *=UTF-8''foo-%c3%a4.html", "",
905      L""},
906    // attwithfn2231ws2
907    {"Content-Disposition: attachment; filename*= UTF-8''foo-%c3%a4.html", "",
908      L"foo-\xe4.html"},
909    // attwithfn2231ws3
910    {"Content-Disposition: attachment; filename* =UTF-8''foo-%c3%a4.html", "",
911      L"foo-\xe4.html"},
912    // attwithfn2231quot
913    {"Content-Disposition: attachment; filename*=\"UTF-8''foo-%c3%a4.html\"",
914      "", L""},
915    // attfnboth
916    {"Content-Disposition: attachment; filename=\"foo-ae.html\"; "
917      "filename*=UTF-8''foo-%c3%a4.html", "", L"foo-\xe4.html"},
918    // attfnboth2
919    {"Content-Disposition: attachment; filename*=UTF-8''foo-%c3%a4.html; "
920      "filename=\"foo-ae.html\"", "", L"foo-\xe4.html"},
921    // attnewandfn
922    {"Content-Disposition: attachment; foobar=x; filename=\"foo.html\"", "",
923      L"foo.html"},
924  };
925  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
926    EXPECT_EQ(tests[i].expected,
927              UTF8ToWide(net::GetFileNameFromCD(tests[i].header_field,
928                                                tests[i].referrer_charset)))
929        << "Failed on input: " << tests[i].header_field;
930  }
931}
932
933TEST(NetUtilTest, IDNToUnicodeFast) {
934  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(idn_cases); i++) {
935    for (size_t j = 0; j < arraysize(kLanguages); j++) {
936      // ja || zh-TW,en || ko,ja -> IDNToUnicodeSlow
937      if (j == 3 || j == 17 || j == 18)
938        continue;
939      std::wstring output(net::IDNToUnicode(idn_cases[i].input,
940          strlen(idn_cases[i].input), kLanguages[j], NULL));
941      std::wstring expected(idn_cases[i].unicode_allowed[j] ?
942          idn_cases[i].unicode_output : ASCIIToWide(idn_cases[i].input));
943      AppendLanguagesToOutputs(kLanguages[j], &expected, &output);
944      EXPECT_EQ(expected, output);
945    }
946  }
947}
948
949TEST(NetUtilTest, IDNToUnicodeSlow) {
950  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(idn_cases); i++) {
951    for (size_t j = 0; j < arraysize(kLanguages); j++) {
952      // !(ja || zh-TW,en || ko,ja) -> IDNToUnicodeFast
953      if (!(j == 3 || j == 17 || j == 18))
954        continue;
955      std::wstring output(net::IDNToUnicode(idn_cases[i].input,
956          strlen(idn_cases[i].input), kLanguages[j], NULL));
957      std::wstring expected(idn_cases[i].unicode_allowed[j] ?
958          idn_cases[i].unicode_output : ASCIIToWide(idn_cases[i].input));
959      AppendLanguagesToOutputs(kLanguages[j], &expected, &output);
960      EXPECT_EQ(expected, output);
961    }
962  }
963}
964
965TEST(NetUtilTest, IDNToUnicodeAdjustOffset) {
966  const AdjustOffsetCase adjust_cases[] = {
967    {0, 0},
968    {2, 2},
969    {4, 4},
970    {5, 5},
971    {6, string16::npos},
972    {16, string16::npos},
973    {17, 7},
974    {18, 8},
975    {19, string16::npos},
976    {25, string16::npos},
977    {34, 12},
978    {35, 13},
979    {38, 16},
980    {39, string16::npos},
981    {string16::npos, string16::npos},
982  };
983  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(adjust_cases); ++i) {
984    size_t offset = adjust_cases[i].input_offset;
985    // "test.\x89c6\x9891.\x5317\x4eac\x5927\x5b78.test"
986    net::IDNToUnicode("test.xn--cy2a840a.xn--1lq90ic7f1rc.test", 39, L"zh-CN",
987                      &offset);
988    EXPECT_EQ(adjust_cases[i].output_offset, offset);
989  }
990}
991
992TEST(NetUtilTest, CompliantHost) {
993  const CompliantHostCase compliant_host_cases[] = {
994    {"", "", false},
995    {"a", "", true},
996    {"-", "", false},
997    {".", "", false},
998    {"9", "", false},
999    {"9", "a", true},
1000    {"9a", "", false},
1001    {"9a", "a", true},
1002    {"a.", "", true},
1003    {"a.a", "", true},
1004    {"9.a", "", true},
1005    {"a.9", "", false},
1006    {"_9a", "", false},
1007    {"a.a9", "", true},
1008    {"a.9a", "", false},
1009    {"a+9a", "", false},
1010    {"1-.a-b", "", false},
1011    {"1-2.a_b", "", true},
1012    {"a.b.c.d.e", "", true},
1013    {"1.2.3.4.e", "", true},
1014    {"a.b.c.d.5", "", false},
1015    {"1.2.3.4.e.", "", true},
1016    {"a.b.c.d.5.", "", false},
1017  };
1018
1019  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(compliant_host_cases); ++i) {
1020    EXPECT_EQ(compliant_host_cases[i].expected_output,
1021        net::IsCanonicalizedHostCompliant(compliant_host_cases[i].host,
1022                                          compliant_host_cases[i].desired_tld));
1023  }
1024}
1025
1026TEST(NetUtilTest, StripWWW) {
1027  EXPECT_EQ(string16(), net::StripWWW(string16()));
1028  EXPECT_EQ(string16(), net::StripWWW(ASCIIToUTF16("www.")));
1029  EXPECT_EQ(ASCIIToUTF16("blah"), net::StripWWW(ASCIIToUTF16("www.blah")));
1030  EXPECT_EQ(ASCIIToUTF16("blah"), net::StripWWW(ASCIIToUTF16("blah")));
1031}
1032
1033TEST(NetUtilTest, GetSuggestedFilename) {
1034  const SuggestedFilenameCase test_cases[] = {
1035    {"http://www.google.com/",
1036     "Content-disposition: attachment; filename=test.html",
1037     "",
1038     L"",
1039     L"test.html"},
1040    {"http://www.google.com/",
1041     "Content-disposition: attachment; filename=\"test.html\"",
1042     "",
1043     L"",
1044     L"test.html"},
1045    {"http://www.google.com/path/test.html",
1046     "Content-disposition: attachment",
1047     "",
1048     L"",
1049     L"test.html"},
1050    {"http://www.google.com/path/test.html",
1051     "Content-disposition: attachment;",
1052     "",
1053     L"",
1054     L"test.html"},
1055    {"http://www.google.com/",
1056     "",
1057     "",
1058     L"",
1059     L"www.google.com"},
1060    {"http://www.google.com/test.html",
1061     "",
1062     "",
1063     L"",
1064     L"test.html"},
1065    // Now that we use googleurl's ExtractFileName, this case falls back
1066    // to the hostname. If this behavior is not desirable, we'd better
1067    // change ExtractFileName (in url_parse).
1068    {"http://www.google.com/path/",
1069     "",
1070     "",
1071     L"",
1072     L"www.google.com"},
1073    {"http://www.google.com/path",
1074     "",
1075     "",
1076     L"",
1077     L"path"},
1078    {"file:///",
1079     "",
1080     "",
1081     L"",
1082     L"download"},
1083    {"non-standard-scheme:",
1084     "",
1085     "",
1086     L"",
1087     L"download"},
1088    {"http://www.google.com/",
1089     "Content-disposition: attachment; filename =\"test.html\"",
1090     "",
1091     L"download",
1092     L"test.html"},
1093    {"http://www.google.com/",
1094     "",
1095     "",
1096     L"download",
1097     L"download"},
1098    {"http://www.google.com/",
1099     "Content-disposition: attachment; filename=\"../test.html\"",
1100     "",
1101     L"",
1102     L"_test.html"},
1103    {"http://www.google.com/",
1104     "Content-disposition: attachment; filename=\"..\\test.html\"",
1105     "",
1106     L"",
1107     L"_test.html"},
1108    {"http://www.google.com/",
1109     "Content-disposition: attachment; filename=\"..\"",
1110     "",
1111     L"download",
1112     L"download"},
1113    {"http://www.google.com/test.html",
1114     "Content-disposition: attachment; filename=\"..\"",
1115     "",
1116     L"download",
1117     L"test.html"},
1118    // Below is a small subset of cases taken from GetFileNameFromCD test above.
1119    {"http://www.google.com/",
1120     "Content-Disposition: attachment; filename=\"%EC%98%88%EC%88%A0%20"
1121     "%EC%98%88%EC%88%A0.jpg\"",
1122     "",
1123     L"",
1124     L"\uc608\uc220 \uc608\uc220.jpg"},
1125    {"http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
1126     "",
1127     "",
1128     L"download",
1129     L"\uc608\uc220 \uc608\uc220.jpg"},
1130    {"http://www.google.com/",
1131     "Content-disposition: attachment;",
1132     "",
1133     L"\uB2E4\uC6B4\uB85C\uB4DC",
1134     L"\uB2E4\uC6B4\uB85C\uB4DC"},
1135    {"http://www.google.com/",
1136     "Content-Disposition: attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
1137     "D13=2Epng?=\"",
1138     "",
1139     L"download",
1140     L"\u82b8\u88533.png"},
1141    {"http://www.example.com/images?id=3",
1142     "Content-Disposition: attachment; filename=caf\xc3\xa9.png",
1143     "iso-8859-1",
1144     L"",
1145     L"caf\u00e9.png"},
1146    {"http://www.example.com/images?id=3",
1147     "Content-Disposition: attachment; filename=caf\xe5.png",
1148     "windows-1253",
1149     L"",
1150     L"caf\u03b5.png"},
1151    {"http://www.example.com/file?id=3",
1152     "Content-Disposition: attachment; name=\xcf\xc2\xd4\xd8.zip",
1153     "GBK",
1154     L"",
1155     L"\u4e0b\u8f7d.zip"},
1156    // Invalid C-D header. Extracts filename from url.
1157    {"http://www.google.com/test.html",
1158     "Content-Disposition: attachment; filename==?iiso88591?Q?caf=EG?=",
1159     "",
1160     L"",
1161     L"test.html"},
1162    // about: and data: URLs
1163    {"about:chrome",
1164     "",
1165     "",
1166     L"",
1167     L"download"},
1168    {"data:,looks/like/a.path",
1169     "",
1170     "",
1171     L"",
1172     L"download"},
1173    {"data:text/plain;base64,VG8gYmUgb3Igbm90IHRvIGJlLg=",
1174     "",
1175     "",
1176     L"",
1177     L"download"},
1178    {"data:,looks/like/a.path",
1179     "",
1180     "",
1181     L"default_filename_is_given",
1182     L"default_filename_is_given"},
1183    {"data:,looks/like/a.path",
1184     "",
1185     "",
1186     L"\u65e5\u672c\u8a9e",  // Japanese Kanji.
1187     L"\u65e5\u672c\u8a9e"},
1188    // Dotfiles. Ensures preceeding period(s) stripped.
1189    {"http://www.google.com/.test.html",
1190    "",
1191    "",
1192    L"",
1193    L"test.html"},
1194    {"http://www.google.com/.test",
1195    "",
1196    "",
1197    L"",
1198    L"test"},
1199    {"http://www.google.com/..test",
1200    "",
1201    "",
1202    L"",
1203    L"test"},
1204    // The filename encoding is specified by the referrer charset.
1205    {"http://example.com/V%FDvojov%E1%20psychologie.doc",
1206     "",
1207     "iso-8859-1",
1208     L"",
1209     L"V\u00fdvojov\u00e1 psychologie.doc"},
1210    // The filename encoding doesn't match the referrer charset, the
1211    // system charset, or UTF-8.
1212    // TODO(jshin): we need to handle this case.
1213#if 0
1214    {"http://example.com/V%FDvojov%E1%20psychologie.doc",
1215     "",
1216     "utf-8",
1217     L"",
1218     L"V\u00fdvojov\u00e1 psychologie.doc",
1219    },
1220#endif
1221  };
1222  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
1223    std::wstring default_name = test_cases[i].default_filename;
1224    string16 filename = net::GetSuggestedFilename(
1225        GURL(test_cases[i].url), test_cases[i].content_disp_header,
1226        test_cases[i].referrer_charset, WideToUTF16(default_name));
1227    EXPECT_EQ(std::wstring(test_cases[i].expected_filename),
1228              UTF16ToWide(filename))
1229      << "Iteration " << i << ": " << test_cases[i].url;
1230  }
1231}
1232
1233// This is currently a windows specific function.
1234#if defined(OS_WIN)
1235namespace {
1236
1237struct GetDirectoryListingEntryCase {
1238  const wchar_t* name;
1239  const char* raw_bytes;
1240  bool is_dir;
1241  int64 filesize;
1242  base::Time time;
1243  const char* expected;
1244};
1245
1246}  // namespace
1247TEST(NetUtilTest, GetDirectoryListingEntry) {
1248  const GetDirectoryListingEntryCase test_cases[] = {
1249    {L"Foo",
1250     "",
1251     false,
1252     10000,
1253     base::Time(),
1254     "<script>addRow(\"Foo\",\"Foo\",0,\"9.8 kB\",\"\");</script>\n"},
1255    {L"quo\"tes",
1256     "",
1257     false,
1258     10000,
1259     base::Time(),
1260     "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
1261         "\n"},
1262    {L"quo\"tes",
1263     "quo\"tes",
1264     false,
1265     10000,
1266     base::Time(),
1267     "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
1268         "\n"},
1269    // U+D55C0 U+AE00. raw_bytes is empty (either a local file with
1270    // UTF-8/UTF-16 encoding or a remote file on an ftp server using UTF-8
1271    {L"\xD55C\xAE00.txt",
1272     "",
1273     false,
1274     10000,
1275     base::Time(),
1276     "<script>addRow(\"\\uD55C\\uAE00.txt\",\"%ED%95%9C%EA%B8%80.txt\""
1277         ",0,\"9.8 kB\",\"\");</script>\n"},
1278    // U+D55C0 U+AE00. raw_bytes is the corresponding EUC-KR sequence:
1279    // a local or remote file in EUC-KR.
1280    {L"\xD55C\xAE00.txt",
1281     "\xC7\xD1\xB1\xDB.txt",
1282     false,
1283     10000,
1284     base::Time(),
1285     "<script>addRow(\"\\uD55C\\uAE00.txt\",\"%C7%D1%B1%DB.txt\""
1286         ",0,\"9.8 kB\",\"\");</script>\n"},
1287  };
1288
1289  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
1290    const std::string results = net::GetDirectoryListingEntry(
1291        WideToUTF16(test_cases[i].name),
1292        test_cases[i].raw_bytes,
1293        test_cases[i].is_dir,
1294        test_cases[i].filesize,
1295        test_cases[i].time);
1296    EXPECT_EQ(test_cases[i].expected, results);
1297  }
1298}
1299
1300#endif
1301
1302TEST(NetUtilTest, ParseHostAndPort) {
1303  const struct {
1304    const char* input;
1305    bool success;
1306    const char* expected_host;
1307    int expected_port;
1308  } tests[] = {
1309    // Valid inputs:
1310    {"foo:10", true, "foo", 10},
1311    {"foo", true, "foo", -1},
1312    {
1313      "[1080:0:0:0:8:800:200C:4171]:11",
1314      true,
1315      "[1080:0:0:0:8:800:200C:4171]",
1316      11,
1317    },
1318    // Invalid inputs:
1319    {"foo:bar", false, "", -1},
1320    {"foo:", false, "", -1},
1321    {":", false, "", -1},
1322    {":80", false, "", -1},
1323    {"", false, "", -1},
1324    {"porttoolong:300000", false, "", -1},
1325    {"usrname@host", false, "", -1},
1326    {"usrname:password@host", false, "", -1},
1327    {":password@host", false, "", -1},
1328    {":password@host:80", false, "", -1},
1329    {":password@host", false, "", -1},
1330    {"@host", false, "", -1},
1331  };
1332
1333  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1334    std::string host;
1335    int port;
1336    bool ok = net::ParseHostAndPort(tests[i].input, &host, &port);
1337
1338    EXPECT_EQ(tests[i].success, ok);
1339
1340    if (tests[i].success) {
1341      EXPECT_EQ(tests[i].expected_host, host);
1342      EXPECT_EQ(tests[i].expected_port, port);
1343    }
1344  }
1345}
1346
1347TEST(NetUtilTest, GetHostAndPort) {
1348  const struct {
1349    GURL url;
1350    const char* expected_host_and_port;
1351  } tests[] = {
1352    { GURL("http://www.foo.com/x"), "www.foo.com:80"},
1353    { GURL("http://www.foo.com:21/x"), "www.foo.com:21"},
1354
1355    // For IPv6 literals should always include the brackets.
1356    { GURL("http://[1::2]/x"), "[1::2]:80"},
1357    { GURL("http://[::a]:33/x"), "[::a]:33"},
1358  };
1359  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1360    std::string host_and_port = net::GetHostAndPort(tests[i].url);
1361    EXPECT_EQ(std::string(tests[i].expected_host_and_port), host_and_port);
1362  }
1363}
1364
1365TEST(NetUtilTest, GetHostAndOptionalPort) {
1366  const struct {
1367    GURL url;
1368    const char* expected_host_and_port;
1369  } tests[] = {
1370    { GURL("http://www.foo.com/x"), "www.foo.com"},
1371    { GURL("http://www.foo.com:21/x"), "www.foo.com:21"},
1372
1373    // For IPv6 literals should always include the brackets.
1374    { GURL("http://[1::2]/x"), "[1::2]"},
1375    { GURL("http://[::a]:33/x"), "[::a]:33"},
1376  };
1377  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1378    std::string host_and_port = net::GetHostAndOptionalPort(tests[i].url);
1379    EXPECT_EQ(std::string(tests[i].expected_host_and_port), host_and_port);
1380  }
1381}
1382
1383
1384TEST(NetUtilTest, NetAddressToString_IPv4) {
1385  const struct {
1386    uint8 addr[4];
1387    const char* result;
1388  } tests[] = {
1389    {{0, 0, 0, 0}, "0.0.0.0"},
1390    {{127, 0, 0, 1}, "127.0.0.1"},
1391    {{192, 168, 0, 1}, "192.168.0.1"},
1392  };
1393
1394  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1395    const addrinfo* ai = GetIPv4Address(tests[i].addr, 80);
1396    std::string result = net::NetAddressToString(ai);
1397    EXPECT_EQ(std::string(tests[i].result), result);
1398  }
1399}
1400
1401TEST(NetUtilTest, NetAddressToString_IPv6) {
1402  const struct {
1403    uint8 addr[16];
1404    const char* result;
1405  } tests[] = {
1406    {{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA,
1407      0x98, 0x76, 0x54, 0x32, 0x10},
1408     "fedc:ba98:7654:3210:fedc:ba98:7654:3210"},
1409  };
1410
1411  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1412    const addrinfo* ai = GetIPv6Address(tests[i].addr, 80);
1413    std::string result = net::NetAddressToString(ai);
1414    // Allow NetAddressToString() to fail, in case the system doesn't
1415    // support IPv6.
1416    if (!result.empty())
1417      EXPECT_EQ(std::string(tests[i].result), result);
1418  }
1419}
1420
1421TEST(NetUtilTest, NetAddressToStringWithPort_IPv4) {
1422  uint8 addr[] = {127, 0, 0, 1};
1423  const addrinfo* ai = GetIPv4Address(addr, 166);
1424  std::string result = net::NetAddressToStringWithPort(ai);
1425  EXPECT_EQ("127.0.0.1:166", result);
1426}
1427
1428TEST(NetUtilTest, NetAddressToStringWithPort_IPv6) {
1429  uint8 addr[] = {
1430      0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA,
1431      0x98, 0x76, 0x54, 0x32, 0x10
1432  };
1433  const addrinfo* ai = GetIPv6Address(addr, 361);
1434  std::string result = net::NetAddressToStringWithPort(ai);
1435
1436  // May fail on systems that don't support IPv6.
1437  if (!result.empty())
1438    EXPECT_EQ("[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:361", result);
1439}
1440
1441TEST(NetUtilTest, GetHostName) {
1442  // We can't check the result of GetHostName() directly, since the result
1443  // will differ across machines. Our goal here is to simply exercise the
1444  // code path, and check that things "look about right".
1445  std::string hostname = net::GetHostName();
1446  EXPECT_FALSE(hostname.empty());
1447}
1448
1449TEST(NetUtilTest, FormatUrl) {
1450  net::FormatUrlTypes default_format_type = net::kFormatUrlOmitUsernamePassword;
1451  const UrlTestData tests[] = {
1452    {"Empty URL", "", "", default_format_type, UnescapeRule::NORMAL, L"", 0},
1453
1454    {"Simple URL",
1455     "http://www.google.com/", "", default_format_type, UnescapeRule::NORMAL,
1456     L"http://www.google.com/", 7},
1457
1458    {"With a port number and a reference",
1459     "http://www.google.com:8080/#\xE3\x82\xB0", "", default_format_type,
1460     UnescapeRule::NORMAL,
1461     L"http://www.google.com:8080/#\x30B0", 7},
1462
1463    // -------- IDN tests --------
1464    {"Japanese IDN with ja",
1465     "http://xn--l8jvb1ey91xtjb.jp", "ja", default_format_type,
1466     UnescapeRule::NORMAL, L"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
1467
1468    {"Japanese IDN with en",
1469     "http://xn--l8jvb1ey91xtjb.jp", "en", default_format_type,
1470     UnescapeRule::NORMAL, L"http://xn--l8jvb1ey91xtjb.jp/", 7},
1471
1472    {"Japanese IDN without any languages",
1473     "http://xn--l8jvb1ey91xtjb.jp", "", default_format_type,
1474     UnescapeRule::NORMAL,
1475     // Single script is safe for empty languages.
1476     L"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
1477
1478    {"mailto: with Japanese IDN",
1479     "mailto:foo@xn--l8jvb1ey91xtjb.jp", "ja", default_format_type,
1480     UnescapeRule::NORMAL,
1481     // GURL doesn't assume an email address's domain part as a host name.
1482     L"mailto:foo@xn--l8jvb1ey91xtjb.jp", 7},
1483
1484    {"file: with Japanese IDN",
1485     "file://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type,
1486     UnescapeRule::NORMAL,
1487     L"file://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 7},
1488
1489    {"ftp: with Japanese IDN",
1490     "ftp://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type,
1491     UnescapeRule::NORMAL,
1492     L"ftp://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 6},
1493
1494    // -------- omit_username_password flag tests --------
1495    {"With username and password, omit_username_password=false",
1496     "http://user:passwd@example.com/foo", "",
1497     net::kFormatUrlOmitNothing, UnescapeRule::NORMAL,
1498     L"http://user:passwd@example.com/foo", 19},
1499
1500    {"With username and password, omit_username_password=true",
1501     "http://user:passwd@example.com/foo", "", default_format_type,
1502     UnescapeRule::NORMAL, L"http://example.com/foo", 7},
1503
1504    {"With username and no password",
1505     "http://user@example.com/foo", "", default_format_type,
1506     UnescapeRule::NORMAL, L"http://example.com/foo", 7},
1507
1508    {"Just '@' without username and password",
1509     "http://@example.com/foo", "", default_format_type, UnescapeRule::NORMAL,
1510     L"http://example.com/foo", 7},
1511
1512    // GURL doesn't think local-part of an email address is username for URL.
1513    {"mailto:, omit_username_password=true",
1514     "mailto:foo@example.com", "", default_format_type, UnescapeRule::NORMAL,
1515     L"mailto:foo@example.com", 7},
1516
1517    // -------- unescape flag tests --------
1518    {"Do not unescape",
1519     "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
1520     "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
1521     "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type,
1522     UnescapeRule::NONE,
1523     // GURL parses %-encoded hostnames into Punycode.
1524     L"http://xn--qcka1pmc.jp/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
1525     L"?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", 7},
1526
1527    {"Unescape normally",
1528     "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
1529     "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
1530     "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type,
1531     UnescapeRule::NORMAL,
1532     L"http://xn--qcka1pmc.jp/\x30B0\x30FC\x30B0\x30EB"
1533     L"?q=\x30B0\x30FC\x30B0\x30EB", 7},
1534
1535    {"Unescape normally including unescape spaces",
1536     "http://www.google.com/search?q=Hello%20World", "en", default_format_type,
1537     UnescapeRule::SPACES, L"http://www.google.com/search?q=Hello World", 7},
1538
1539    /*
1540    {"unescape=true with some special characters",
1541    "http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", "",
1542    net::kFormatUrlOmitNothing, UnescapeRule::NORMAL,
1543    L"http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", 25},
1544    */
1545    // Disabled: the resultant URL becomes "...user%253A:%2540passwd...".
1546
1547    // -------- omit http: --------
1548    {"omit http with user name",
1549     "http://user@example.com/foo", "", net::kFormatUrlOmitAll,
1550     UnescapeRule::NORMAL, L"example.com/foo", 0},
1551
1552    {"omit http",
1553     "http://www.google.com/", "en", net::kFormatUrlOmitHTTP,
1554     UnescapeRule::NORMAL, L"www.google.com/",
1555     0},
1556
1557    {"omit http with https",
1558     "https://www.google.com/", "en", net::kFormatUrlOmitHTTP,
1559     UnescapeRule::NORMAL, L"https://www.google.com/",
1560     8},
1561
1562    {"omit http starts with ftp.",
1563     "http://ftp.google.com/", "en", net::kFormatUrlOmitHTTP,
1564     UnescapeRule::NORMAL, L"http://ftp.google.com/",
1565     7},
1566
1567    // -------- omit trailing slash on bare hostname --------
1568    {"omit slash when it's the entire path",
1569     "http://www.google.com/", "en",
1570     net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
1571     L"http://www.google.com", 7},
1572    {"omit slash when there's a ref",
1573     "http://www.google.com/#ref", "en",
1574     net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
1575     L"http://www.google.com/#ref", 7},
1576    {"omit slash when there's a query",
1577     "http://www.google.com/?", "en",
1578     net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
1579     L"http://www.google.com/?", 7},
1580    {"omit slash when it's not the entire path",
1581     "http://www.google.com/foo", "en",
1582     net::kFormatUrlOmitTrailingSlashOnBareHostname, UnescapeRule::NORMAL,
1583     L"http://www.google.com/foo", 7},
1584    {"omit slash for nonstandard URLs",
1585     "data:/", "en", net::kFormatUrlOmitTrailingSlashOnBareHostname,
1586     UnescapeRule::NORMAL, L"data:/", 5},
1587    {"omit slash for file URLs",
1588     "file:///", "en", net::kFormatUrlOmitTrailingSlashOnBareHostname,
1589     UnescapeRule::NORMAL, L"file:///", 7},
1590
1591    // -------- view-source: --------
1592    {"view-source",
1593     "view-source:http://xn--qcka1pmc.jp/", "ja", default_format_type,
1594     UnescapeRule::NORMAL, L"view-source:http://\x30B0\x30FC\x30B0\x30EB.jp/",
1595     19},
1596
1597    {"view-source of view-source",
1598     "view-source:view-source:http://xn--qcka1pmc.jp/", "ja",
1599     default_format_type, UnescapeRule::NORMAL,
1600     L"view-source:view-source:http://xn--qcka1pmc.jp/", 12},
1601
1602    // view-source should omit http and trailing slash where non-view-source
1603    // would.
1604    {"view-source omit http",
1605     "view-source:http://a.b/c", "en", net::kFormatUrlOmitAll,
1606     UnescapeRule::NORMAL, L"view-source:a.b/c",
1607     12},
1608    {"view-source omit http starts with ftp.",
1609     "view-source:http://ftp.b/c", "en", net::kFormatUrlOmitAll,
1610     UnescapeRule::NORMAL, L"view-source:http://ftp.b/c",
1611     19},
1612    {"view-source omit slash when it's the entire path",
1613     "view-source:http://a.b/", "en", net::kFormatUrlOmitAll,
1614     UnescapeRule::NORMAL, L"view-source:a.b",
1615     12},
1616  };
1617
1618  for (size_t i = 0; i < arraysize(tests); ++i) {
1619    size_t prefix_len;
1620    string16 formatted = net::FormatUrl(
1621        GURL(tests[i].input), tests[i].languages, tests[i].format_types,
1622        tests[i].escape_rules, NULL, &prefix_len, NULL);
1623    EXPECT_EQ(WideToUTF16(tests[i].output), formatted) << tests[i].description;
1624    EXPECT_EQ(tests[i].prefix_len, prefix_len) << tests[i].description;
1625  }
1626}
1627
1628TEST(NetUtilTest, FormatUrlParsed) {
1629  // No unescape case.
1630  url_parse::Parsed parsed;
1631  string16 formatted = net::FormatUrl(
1632      GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
1633           "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
1634      "ja", net::kFormatUrlOmitNothing, UnescapeRule::NONE, &parsed, NULL,
1635      NULL);
1636  EXPECT_EQ(WideToUTF16(
1637      L"http://%E3%82%B0:%E3%83%BC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
1638      L"/%E3%82%B0/?q=%E3%82%B0#\x30B0"), formatted);
1639  EXPECT_EQ(WideToUTF16(L"%E3%82%B0"),
1640      formatted.substr(parsed.username.begin, parsed.username.len));
1641  EXPECT_EQ(WideToUTF16(L"%E3%83%BC"),
1642      formatted.substr(parsed.password.begin, parsed.password.len));
1643  EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
1644      formatted.substr(parsed.host.begin, parsed.host.len));
1645  EXPECT_EQ(WideToUTF16(L"8080"),
1646      formatted.substr(parsed.port.begin, parsed.port.len));
1647  EXPECT_EQ(WideToUTF16(L"/%E3%82%B0/"),
1648      formatted.substr(parsed.path.begin, parsed.path.len));
1649  EXPECT_EQ(WideToUTF16(L"q=%E3%82%B0"),
1650      formatted.substr(parsed.query.begin, parsed.query.len));
1651  EXPECT_EQ(WideToUTF16(L"\x30B0"),
1652      formatted.substr(parsed.ref.begin, parsed.ref.len));
1653
1654  // Unescape case.
1655  formatted = net::FormatUrl(
1656      GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
1657           "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
1658      "ja", net::kFormatUrlOmitNothing, UnescapeRule::NORMAL, &parsed, NULL,
1659      NULL);
1660  EXPECT_EQ(WideToUTF16(L"http://\x30B0:\x30FC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
1661      L"/\x30B0/?q=\x30B0#\x30B0"), formatted);
1662  EXPECT_EQ(WideToUTF16(L"\x30B0"),
1663      formatted.substr(parsed.username.begin, parsed.username.len));
1664  EXPECT_EQ(WideToUTF16(L"\x30FC"),
1665      formatted.substr(parsed.password.begin, parsed.password.len));
1666  EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
1667      formatted.substr(parsed.host.begin, parsed.host.len));
1668  EXPECT_EQ(WideToUTF16(L"8080"),
1669      formatted.substr(parsed.port.begin, parsed.port.len));
1670  EXPECT_EQ(WideToUTF16(L"/\x30B0/"),
1671      formatted.substr(parsed.path.begin, parsed.path.len));
1672  EXPECT_EQ(WideToUTF16(L"q=\x30B0"),
1673      formatted.substr(parsed.query.begin, parsed.query.len));
1674  EXPECT_EQ(WideToUTF16(L"\x30B0"),
1675      formatted.substr(parsed.ref.begin, parsed.ref.len));
1676
1677  // Omit_username_password + unescape case.
1678  formatted = net::FormatUrl(
1679      GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
1680           "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
1681      "ja", net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, &parsed,
1682      NULL, NULL);
1683  EXPECT_EQ(WideToUTF16(L"http://\x30B0\x30FC\x30B0\x30EB.jp:8080"
1684      L"/\x30B0/?q=\x30B0#\x30B0"), formatted);
1685  EXPECT_FALSE(parsed.username.is_valid());
1686  EXPECT_FALSE(parsed.password.is_valid());
1687  EXPECT_EQ(WideToUTF16(L"\x30B0\x30FC\x30B0\x30EB.jp"),
1688      formatted.substr(parsed.host.begin, parsed.host.len));
1689  EXPECT_EQ(WideToUTF16(L"8080"),
1690      formatted.substr(parsed.port.begin, parsed.port.len));
1691  EXPECT_EQ(WideToUTF16(L"/\x30B0/"),
1692      formatted.substr(parsed.path.begin, parsed.path.len));
1693  EXPECT_EQ(WideToUTF16(L"q=\x30B0"),
1694      formatted.substr(parsed.query.begin, parsed.query.len));
1695  EXPECT_EQ(WideToUTF16(L"\x30B0"),
1696      formatted.substr(parsed.ref.begin, parsed.ref.len));
1697
1698  // View-source case.
1699  formatted = net::FormatUrl(
1700      GURL("view-source:http://user:passwd@host:81/path?query#ref"),
1701      "", net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, &parsed,
1702      NULL, NULL);
1703  EXPECT_EQ(WideToUTF16(L"view-source:http://host:81/path?query#ref"),
1704      formatted);
1705  EXPECT_EQ(WideToUTF16(L"view-source:http"),
1706      formatted.substr(parsed.scheme.begin, parsed.scheme.len));
1707  EXPECT_FALSE(parsed.username.is_valid());
1708  EXPECT_FALSE(parsed.password.is_valid());
1709  EXPECT_EQ(WideToUTF16(L"host"),
1710      formatted.substr(parsed.host.begin, parsed.host.len));
1711  EXPECT_EQ(WideToUTF16(L"81"),
1712      formatted.substr(parsed.port.begin, parsed.port.len));
1713  EXPECT_EQ(WideToUTF16(L"/path"),
1714      formatted.substr(parsed.path.begin, parsed.path.len));
1715  EXPECT_EQ(WideToUTF16(L"query"),
1716      formatted.substr(parsed.query.begin, parsed.query.len));
1717  EXPECT_EQ(WideToUTF16(L"ref"),
1718      formatted.substr(parsed.ref.begin, parsed.ref.len));
1719
1720  // omit http case.
1721  formatted = net::FormatUrl(
1722      GURL("http://host:8000/a?b=c#d"),
1723      "", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
1724  EXPECT_EQ(WideToUTF16(L"host:8000/a?b=c#d"), formatted);
1725  EXPECT_FALSE(parsed.scheme.is_valid());
1726  EXPECT_FALSE(parsed.username.is_valid());
1727  EXPECT_FALSE(parsed.password.is_valid());
1728  EXPECT_EQ(WideToUTF16(L"host"),
1729      formatted.substr(parsed.host.begin, parsed.host.len));
1730  EXPECT_EQ(WideToUTF16(L"8000"),
1731      formatted.substr(parsed.port.begin, parsed.port.len));
1732  EXPECT_EQ(WideToUTF16(L"/a"),
1733      formatted.substr(parsed.path.begin, parsed.path.len));
1734  EXPECT_EQ(WideToUTF16(L"b=c"),
1735      formatted.substr(parsed.query.begin, parsed.query.len));
1736  EXPECT_EQ(WideToUTF16(L"d"),
1737      formatted.substr(parsed.ref.begin, parsed.ref.len));
1738
1739  // omit http starts with ftp case.
1740  formatted = net::FormatUrl(
1741      GURL("http://ftp.host:8000/a?b=c#d"),
1742      "", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
1743  EXPECT_EQ(WideToUTF16(L"http://ftp.host:8000/a?b=c#d"), formatted);
1744  EXPECT_TRUE(parsed.scheme.is_valid());
1745  EXPECT_FALSE(parsed.username.is_valid());
1746  EXPECT_FALSE(parsed.password.is_valid());
1747  EXPECT_EQ(WideToUTF16(L"http"),
1748      formatted.substr(parsed.scheme.begin, parsed.scheme.len));
1749  EXPECT_EQ(WideToUTF16(L"ftp.host"),
1750      formatted.substr(parsed.host.begin, parsed.host.len));
1751  EXPECT_EQ(WideToUTF16(L"8000"),
1752      formatted.substr(parsed.port.begin, parsed.port.len));
1753  EXPECT_EQ(WideToUTF16(L"/a"),
1754      formatted.substr(parsed.path.begin, parsed.path.len));
1755  EXPECT_EQ(WideToUTF16(L"b=c"),
1756      formatted.substr(parsed.query.begin, parsed.query.len));
1757  EXPECT_EQ(WideToUTF16(L"d"),
1758      formatted.substr(parsed.ref.begin, parsed.ref.len));
1759
1760  // omit http starts with 'f' case.
1761  formatted = net::FormatUrl(
1762      GURL("http://f/"),
1763      "", net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, &parsed, NULL, NULL);
1764  EXPECT_EQ(WideToUTF16(L"f/"), formatted);
1765  EXPECT_FALSE(parsed.scheme.is_valid());
1766  EXPECT_FALSE(parsed.username.is_valid());
1767  EXPECT_FALSE(parsed.password.is_valid());
1768  EXPECT_FALSE(parsed.port.is_valid());
1769  EXPECT_TRUE(parsed.path.is_valid());
1770  EXPECT_FALSE(parsed.query.is_valid());
1771  EXPECT_FALSE(parsed.ref.is_valid());
1772  EXPECT_EQ(WideToUTF16(L"f"),
1773      formatted.substr(parsed.host.begin, parsed.host.len));
1774  EXPECT_EQ(WideToUTF16(L"/"),
1775      formatted.substr(parsed.path.begin, parsed.path.len));
1776}
1777
1778TEST(NetUtilTest, FormatUrlAdjustOffset) {
1779  const AdjustOffsetCase basic_cases[] = {
1780    {0, 0},
1781    {3, 3},
1782    {5, 5},
1783    {6, 6},
1784    {13, 13},
1785    {21, 21},
1786    {22, 22},
1787    {23, 23},
1788    {25, 25},
1789    {26, string16::npos},
1790    {500000, string16::npos},
1791    {string16::npos, string16::npos},
1792  };
1793  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(basic_cases); ++i) {
1794    size_t offset = basic_cases[i].input_offset;
1795    net::FormatUrl(GURL("http://www.google.com/foo/"), "en",
1796                   net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
1797                   NULL, NULL, &offset);
1798    EXPECT_EQ(basic_cases[i].output_offset, offset);
1799  }
1800
1801  const struct {
1802    const char* input_url;
1803    size_t input_offset;
1804    size_t output_offset;
1805  } omit_auth_cases[] = {
1806    {"http://foo:bar@www.google.com/", 6, 6},
1807    {"http://foo:bar@www.google.com/", 7, 7},
1808    {"http://foo:bar@www.google.com/", 8, string16::npos},
1809    {"http://foo:bar@www.google.com/", 10, string16::npos},
1810    {"http://foo:bar@www.google.com/", 11, string16::npos},
1811    {"http://foo:bar@www.google.com/", 14, string16::npos},
1812    {"http://foo:bar@www.google.com/", 15, 7},
1813    {"http://foo:bar@www.google.com/", 25, 17},
1814    {"http://foo@www.google.com/", 9, string16::npos},
1815    {"http://foo@www.google.com/", 11, 7},
1816  };
1817  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_auth_cases); ++i) {
1818    size_t offset = omit_auth_cases[i].input_offset;
1819    net::FormatUrl(GURL(omit_auth_cases[i].input_url), "en",
1820                   net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
1821                   NULL, NULL, &offset);
1822    EXPECT_EQ(omit_auth_cases[i].output_offset, offset);
1823  }
1824
1825  const AdjustOffsetCase view_source_cases[] = {
1826    {0, 0},
1827    {3, 3},
1828    {11, 11},
1829    {12, 12},
1830    {13, 13},
1831    {19, 19},
1832    {20, string16::npos},
1833    {23, 19},
1834    {26, 22},
1835    {string16::npos, string16::npos},
1836  };
1837  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(view_source_cases); ++i) {
1838    size_t offset = view_source_cases[i].input_offset;
1839    net::FormatUrl(GURL("view-source:http://foo@www.google.com/"), "en",
1840                   net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
1841                   NULL, NULL, &offset);
1842    EXPECT_EQ(view_source_cases[i].output_offset, offset);
1843  }
1844
1845  const AdjustOffsetCase idn_hostname_cases[] = {
1846    {8, string16::npos},
1847    {16, string16::npos},
1848    {24, string16::npos},
1849    {25, 12},
1850    {30, 17},
1851  };
1852  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(idn_hostname_cases); ++i) {
1853    size_t offset = idn_hostname_cases[i].input_offset;
1854    // "http://\x671d\x65e5\x3042\x3055\x3072.jp/foo/"
1855    net::FormatUrl(GURL("http://xn--l8jvb1ey91xtjb.jp/foo/"), "ja",
1856                   net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL,
1857                   NULL, NULL, &offset);
1858    EXPECT_EQ(idn_hostname_cases[i].output_offset, offset);
1859  }
1860
1861  const AdjustOffsetCase unescape_cases[] = {
1862    {25, 25},
1863    {26, string16::npos},
1864    {27, string16::npos},
1865    {28, 26},
1866    {35, string16::npos},
1867    {41, 31},
1868    {59, 33},
1869    {60, string16::npos},
1870    {67, string16::npos},
1871    {68, string16::npos},
1872  };
1873  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(unescape_cases); ++i) {
1874    size_t offset = unescape_cases[i].input_offset;
1875    // "http://www.google.com/foo bar/\x30B0\x30FC\x30B0\x30EB"
1876    net::FormatUrl(GURL(
1877        "http://www.google.com/foo%20bar/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"),
1878        "en", net::kFormatUrlOmitUsernamePassword, UnescapeRule::SPACES, NULL,
1879        NULL, &offset);
1880    EXPECT_EQ(unescape_cases[i].output_offset, offset);
1881  }
1882
1883  const AdjustOffsetCase ref_cases[] = {
1884    {30, 30},
1885    {31, 31},
1886    {32, string16::npos},
1887    {34, 32},
1888    {37, 33},
1889    {38, string16::npos},
1890  };
1891  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(ref_cases); ++i) {
1892    size_t offset = ref_cases[i].input_offset;
1893    // "http://www.google.com/foo.html#\x30B0\x30B0z"
1894    net::FormatUrl(GURL(
1895        "http://www.google.com/foo.html#\xE3\x82\xB0\xE3\x82\xB0z"), "en",
1896        net::kFormatUrlOmitUsernamePassword, UnescapeRule::NORMAL, NULL, NULL,
1897        &offset);
1898    EXPECT_EQ(ref_cases[i].output_offset, offset);
1899  }
1900
1901  const AdjustOffsetCase omit_http_cases[] = {
1902    {0, string16::npos},
1903    {3, string16::npos},
1904    {7, 0},
1905    {8, 1},
1906  };
1907  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_http_cases); ++i) {
1908    size_t offset = omit_http_cases[i].input_offset;
1909    net::FormatUrl(GURL("http://www.google.com"), "en",
1910        net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, NULL, NULL, &offset);
1911    EXPECT_EQ(omit_http_cases[i].output_offset, offset);
1912  }
1913
1914  const AdjustOffsetCase omit_http_start_with_ftp[] = {
1915    {0, 0},
1916    {3, 3},
1917    {8, 8},
1918  };
1919  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_http_start_with_ftp); ++i) {
1920    size_t offset = omit_http_start_with_ftp[i].input_offset;
1921    net::FormatUrl(GURL("http://ftp.google.com"), "en",
1922        net::kFormatUrlOmitHTTP, UnescapeRule::NORMAL, NULL, NULL, &offset);
1923    EXPECT_EQ(omit_http_start_with_ftp[i].output_offset, offset);
1924  }
1925
1926  const AdjustOffsetCase omit_all_cases[] = {
1927    {12, 0},
1928    {13, 1},
1929    {0, string16::npos},
1930    {3, string16::npos},
1931  };
1932  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(omit_all_cases); ++i) {
1933    size_t offset = omit_all_cases[i].input_offset;
1934    net::FormatUrl(GURL("http://user@foo.com/"), "en", net::kFormatUrlOmitAll,
1935                   UnescapeRule::NORMAL, NULL, NULL, &offset);
1936    EXPECT_EQ(omit_all_cases[i].output_offset, offset);
1937  }
1938}
1939
1940TEST(NetUtilTest, SimplifyUrlForRequest) {
1941  struct {
1942    const char* input_url;
1943    const char* expected_simplified_url;
1944  } tests[] = {
1945    {
1946      // Reference section should be stripped.
1947      "http://www.google.com:78/foobar?query=1#hash",
1948      "http://www.google.com:78/foobar?query=1",
1949    },
1950    {
1951      // Reference section can itself contain #.
1952      "http://192.168.0.1?query=1#hash#10#11#13#14",
1953      "http://192.168.0.1?query=1",
1954    },
1955    { // Strip username/password.
1956      "http://user:pass@google.com",
1957      "http://google.com/",
1958    },
1959    { // Strip both the reference and the username/password.
1960      "http://user:pass@google.com:80/sup?yo#X#X",
1961      "http://google.com/sup?yo",
1962    },
1963    { // Try an HTTPS URL -- strip both the reference and the username/password.
1964      "https://user:pass@google.com:80/sup?yo#X#X",
1965      "https://google.com:80/sup?yo",
1966    },
1967    { // Try an FTP URL -- strip both the reference and the username/password.
1968      "ftp://user:pass@google.com:80/sup?yo#X#X",
1969      "ftp://google.com:80/sup?yo",
1970    },
1971    { // Try an nonstandard URL
1972      "foobar://user:pass@google.com:80/sup?yo#X#X",
1973      "foobar://user:pass@google.com:80/sup?yo#X#X",
1974    },
1975  };
1976  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
1977    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
1978                                    tests[i].input_url));
1979    GURL input_url(GURL(tests[i].input_url));
1980    GURL expected_url(GURL(tests[i].expected_simplified_url));
1981    EXPECT_EQ(expected_url, net::SimplifyUrlForRequest(input_url));
1982  }
1983}
1984
1985TEST(NetUtilTest, SetExplicitlyAllowedPortsTest) {
1986  std::string invalid[] = { "1,2,a", "'1','2'", "1, 2, 3", "1 0,11,12" };
1987  std::string valid[] = { "", "1", "1,2", "1,2,3", "10,11,12,13" };
1988
1989  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(invalid); ++i) {
1990    net::SetExplicitlyAllowedPorts(invalid[i]);
1991    EXPECT_EQ(0, static_cast<int>(net::explicitly_allowed_ports.size()));
1992  }
1993
1994  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(valid); ++i) {
1995    net::SetExplicitlyAllowedPorts(valid[i]);
1996    EXPECT_EQ(i, net::explicitly_allowed_ports.size());
1997  }
1998}
1999
2000TEST(NetUtilTest, GetHostOrSpecFromURL) {
2001  EXPECT_EQ("example.com",
2002            net::GetHostOrSpecFromURL(GURL("http://example.com/test")));
2003  EXPECT_EQ("example.com",
2004            net::GetHostOrSpecFromURL(GURL("http://example.com./test")));
2005  EXPECT_EQ("file:///tmp/test.html",
2006            net::GetHostOrSpecFromURL(GURL("file:///tmp/test.html")));
2007}
2008
2009// Test that invalid IP literals fail to parse.
2010TEST(NetUtilTest, ParseIPLiteralToNumber_FailParse) {
2011  net::IPAddressNumber number;
2012
2013  EXPECT_FALSE(net::ParseIPLiteralToNumber("bad value", &number));
2014  EXPECT_FALSE(net::ParseIPLiteralToNumber("bad:value", &number));
2015  EXPECT_FALSE(net::ParseIPLiteralToNumber("", &number));
2016  EXPECT_FALSE(net::ParseIPLiteralToNumber("192.168.0.1:30", &number));
2017  EXPECT_FALSE(net::ParseIPLiteralToNumber("  192.168.0.1  ", &number));
2018  EXPECT_FALSE(net::ParseIPLiteralToNumber("[::1]", &number));
2019}
2020
2021// Test parsing an IPv4 literal.
2022TEST(NetUtilTest, ParseIPLiteralToNumber_IPv4) {
2023  net::IPAddressNumber number;
2024  EXPECT_TRUE(net::ParseIPLiteralToNumber("192.168.0.1", &number));
2025  EXPECT_EQ("192,168,0,1", DumpIPNumber(number));
2026}
2027
2028// Test parsing an IPv6 literal.
2029TEST(NetUtilTest, ParseIPLiteralToNumber_IPv6) {
2030  net::IPAddressNumber number;
2031  EXPECT_TRUE(net::ParseIPLiteralToNumber("1:abcd::3:4:ff", &number));
2032  EXPECT_EQ("0,1,171,205,0,0,0,0,0,0,0,3,0,4,0,255", DumpIPNumber(number));
2033}
2034
2035// Test mapping an IPv4 address to an IPv6 address.
2036TEST(NetUtilTest, ConvertIPv4NumberToIPv6Number) {
2037  net::IPAddressNumber ipv4_number;
2038  EXPECT_TRUE(net::ParseIPLiteralToNumber("192.168.0.1", &ipv4_number));
2039
2040  net::IPAddressNumber ipv6_number =
2041      net::ConvertIPv4NumberToIPv6Number(ipv4_number);
2042
2043  // ::ffff:192.168.1.1
2044  EXPECT_EQ("0,0,0,0,0,0,0,0,0,0,255,255,192,168,0,1",
2045            DumpIPNumber(ipv6_number));
2046}
2047
2048// Test parsing invalid CIDR notation literals.
2049TEST(NetUtilTest, ParseCIDRBlock_Invalid) {
2050  const char* bad_literals[] = {
2051      "foobar",
2052      "",
2053      "192.168.0.1",
2054      "::1",
2055      "/",
2056      "/1",
2057      "1",
2058      "192.168.1.1/-1",
2059      "192.168.1.1/33",
2060      "::1/-3",
2061      "a::3/129",
2062      "::1/x",
2063      "192.168.0.1//11"
2064  };
2065
2066  for (size_t i = 0; i < arraysize(bad_literals); ++i) {
2067    net::IPAddressNumber ip_number;
2068    size_t prefix_length_in_bits;
2069
2070    EXPECT_FALSE(net::ParseCIDRBlock(bad_literals[i],
2071                                     &ip_number,
2072                                     &prefix_length_in_bits));
2073  }
2074}
2075
2076// Test parsing a valid CIDR notation literal.
2077TEST(NetUtilTest, ParseCIDRBlock_Valid) {
2078  net::IPAddressNumber ip_number;
2079  size_t prefix_length_in_bits;
2080
2081  EXPECT_TRUE(net::ParseCIDRBlock("192.168.0.1/11",
2082                                  &ip_number,
2083                                  &prefix_length_in_bits));
2084
2085  EXPECT_EQ("192,168,0,1", DumpIPNumber(ip_number));
2086  EXPECT_EQ(11u, prefix_length_in_bits);
2087}
2088
2089TEST(NetUtilTest, IPNumberMatchesPrefix) {
2090  struct {
2091    const char* cidr_literal;
2092    const char* ip_literal;
2093    bool expected_to_match;
2094  } tests[] = {
2095    // IPv4 prefix with IPv4 inputs.
2096    {
2097      "10.10.1.32/27",
2098      "10.10.1.44",
2099      true
2100    },
2101    {
2102      "10.10.1.32/27",
2103      "10.10.1.90",
2104      false
2105    },
2106    {
2107      "10.10.1.32/27",
2108      "10.10.1.90",
2109      false
2110    },
2111
2112    // IPv6 prefix with IPv6 inputs.
2113    {
2114      "2001:db8::/32",
2115      "2001:DB8:3:4::5",
2116      true
2117    },
2118    {
2119      "2001:db8::/32",
2120      "2001:c8::",
2121      false
2122    },
2123
2124    // IPv6 prefix with IPv4 inputs.
2125    {
2126      "2001:db8::/33",
2127      "192.168.0.1",
2128      false
2129    },
2130    {
2131      "::ffff:192.168.0.1/112",
2132      "192.168.33.77",
2133      true
2134    },
2135
2136    // IPv4 prefix with IPv6 inputs.
2137    {
2138      "10.11.33.44/16",
2139      "::ffff:0a0b:89",
2140      true
2141    },
2142    {
2143      "10.11.33.44/16",
2144      "::ffff:10.12.33.44",
2145      false
2146    },
2147  };
2148  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
2149    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s, %s", i,
2150                                    tests[i].cidr_literal,
2151                                    tests[i].ip_literal));
2152
2153    net::IPAddressNumber ip_number;
2154    EXPECT_TRUE(net::ParseIPLiteralToNumber(tests[i].ip_literal, &ip_number));
2155
2156    net::IPAddressNumber ip_prefix;
2157    size_t prefix_length_in_bits;
2158
2159    EXPECT_TRUE(net::ParseCIDRBlock(tests[i].cidr_literal,
2160                                    &ip_prefix,
2161                                    &prefix_length_in_bits));
2162
2163    EXPECT_EQ(tests[i].expected_to_match,
2164              net::IPNumberMatchesPrefix(ip_number,
2165                                         ip_prefix,
2166                                         prefix_length_in_bits));
2167  }
2168}
2169