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.
5 #include "net/base/net_util.h"
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"
28 #include "base/win/windows_version.h"
29 #elif !defined(OS_ANDROID)
33 using base::ASCIIToUTF16
;
34 using base::WideToUTF16
;
40 static const size_t kNpos
= base::string16::npos
;
48 const char* header_name
;
52 struct HeaderParamCase
{
53 const char* header_name
;
54 const char* param_name
;
58 struct FileNameCDCase
{
59 const char* header_field
;
60 const char* referrer_charset
;
61 const wchar_t* expected
;
64 const char* kLanguages
[] = {
65 "", "en", "zh-CN", "ja", "ko",
66 "he", "ar", "ru", "el", "fr",
67 "de", "pt", "sv", "th", "hi",
68 "de,en", "el,en", "zh-TW,en", "ko,ja", "he,ru,en",
74 const wchar_t* unicode_output
;
75 const bool unicode_allowed
[arraysize(kLanguages
)];
78 // TODO(jungshik) This is just a random sample of languages and is far
79 // from exhaustive. We may have to generate all the combinations
80 // of languages (powerset of a set of all the languages).
81 const IDNTestCase idn_cases
[] = {
83 {"www.google.com", L
"www.google.com",
84 {true, true, true, true, true,
85 true, true, true, true, true,
86 true, true, true, true, true,
87 true, true, true, true, true,
89 {"www.google.com.", L
"www.google.com.",
90 {true, true, true, true, true,
91 true, true, true, true, true,
92 true, true, true, true, true,
93 true, true, true, true, true,
96 {true, true, true, true, true,
97 true, true, true, true, true,
98 true, true, true, true, true,
99 true, true, true, true, true,
102 {true, true, true, true, true,
103 true, true, true, true, true,
104 true, true, true, true, true,
105 true, true, true, true, true,
108 // Hanzi (Traditional Chinese)
109 {"xn--1lq90ic7f1rc.cn", L
"\x5317\x4eac\x5927\x5b78.cn",
110 {true, false, true, true, false,
111 false, false, false, false, false,
112 false, false, false, false, false,
113 false, false, true, true, false,
115 // Hanzi ('video' in Simplified Chinese : will pass only in zh-CN,zh)
116 {"xn--cy2a840a.com", L
"\x89c6\x9891.com",
117 {true, false, true, false, false,
118 false, false, false, false, false,
119 false, false, false, false, false,
120 false, false, false, false, false,
123 {"www.xn--123-p18d.com", L
"www.\x4e00" L
"123.com",
124 {true, false, true, true, false,
125 false, false, false, false, false,
126 false, false, false, false, false,
127 false, false, true, true, false,
129 // Hanzi + Latin : U+56FD is simplified and is regarded
130 // as not supported in zh-TW.
131 {"www.xn--hello-9n1hm04c.com", L
"www.hello\x4e2d\x56fd.com",
132 {false, false, true, true, false,
133 false, false, false, false, false,
134 false, false, false, false, false,
135 false, false, false, true, false,
137 // Kanji + Kana (Japanese)
138 {"xn--l8jvb1ey91xtjb.jp", L
"\x671d\x65e5\x3042\x3055\x3072.jp",
139 {true, false, false, true, false,
140 false, false, false, false, false,
141 false, false, false, false, false,
142 false, false, false, true, false,
144 // Katakana including U+30FC
145 {"xn--tckm4i2e.jp", L
"\x30b3\x30de\x30fc\x30b9.jp",
146 {true, false, false, true, false,
147 false, false, false, false, false,
148 false, false, false, false, false,
149 false, false, false, true, false,
151 {"xn--3ck7a7g.jp", L
"\u30ce\u30f3\u30bd.jp",
152 {true, false, false, true, false,
153 false, false, false, false, false,
154 false, false, false, false, false,
155 false, false, false, true, false,
157 // Katakana + Latin (Japanese)
158 // TODO(jungshik): Change 'false' in the first element to 'true'
159 // after upgrading to ICU 4.2.1 to use new uspoof_* APIs instead
160 // of our IsIDNComponentInSingleScript().
161 {"xn--e-efusa1mzf.jp", L
"e\x30b3\x30de\x30fc\x30b9.jp",
162 {false, false, false, true, false,
163 false, false, false, false, false,
164 false, false, false, false, false,
165 false, false, false, true, false,
167 {"xn--3bkxe.jp", L
"\x30c8\x309a.jp",
168 {false, false, false, true, false,
169 false, false, false, false, false,
170 false, false, false, false, false,
171 false, false, false, true, false,
174 {"www.xn--or3b17p6jjc.kr", L
"www.\xc804\xc790\xc815\xbd80.kr",
175 {true, false, false, false, true,
176 false, false, false, false, false,
177 false, false, false, false, false,
178 false, false, false, true, false,
180 // b<u-umlaut>cher (German)
181 {"xn--bcher-kva.de", L
"b\x00fc" L
"cher.de",
182 {true, false, false, false, false,
183 false, false, false, false, true,
184 true, false, false, false, false,
185 true, false, false, false, false,
188 {"www.xn--frgbolaget-q5a.se", L
"www.f\x00e4rgbolaget.se",
189 {true, false, false, false, false,
190 false, false, false, false, false,
191 true, false, true, false, false,
192 true, false, false, false, false,
194 // c-cedilla (French)
195 {"www.xn--alliancefranaise-npb.fr", L
"www.alliancefran\x00e7" L
"aise.fr",
196 {true, false, false, false, false,
197 false, false, false, false, true,
198 false, true, false, false, false,
199 false, false, false, false, false,
201 // caf'e with acute accent' (French)
202 {"xn--caf-dma.fr", L
"caf\x00e9.fr",
203 {true, false, false, false, false,
204 false, false, false, false, true,
205 false, true, true, false, false,
206 false, false, false, false, false,
208 // c-cedillla and a with tilde (Portuguese)
209 {"xn--poema-9qae5a.com.br", L
"p\x00e3oema\x00e7\x00e3.com.br",
210 {true, false, false, false, false,
211 false, false, false, false, false,
212 false, true, false, false, false,
213 false, false, false, false, false,
216 {"xn--achy-f6a.com", L
"\x0161" L
"achy.com",
217 {true, false, false, false, false,
218 false, false, false, false, false,
219 false, false, false, false, false,
220 false, false, false, false, false,
222 // TODO(jungshik) : Add examples with Cyrillic letters
223 // only used in some languages written in Cyrillic.
225 {"xn--kxae4bafwg.gr", L
"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1.gr",
226 {true, false, false, false, false,
227 false, false, false, true, false,
228 false, false, false, false, false,
229 false, true, false, false, false,
231 // Eutopia + 123 (Greek)
232 {"xn---123-pldm0haj2bk.gr",
233 L
"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1-123.gr",
234 {true, false, false, false, false,
235 false, false, false, true, false,
236 false, false, false, false, false,
237 false, true, false, false, false,
239 // Cyrillic (Russian)
240 {"xn--n1aeec9b.ru", L
"\x0442\x043e\x0440\x0442\x044b.ru",
241 {true, false, false, false, false,
242 false, false, true, false, false,
243 false, false, false, false, false,
244 false, false, false, false, true,
246 // Cyrillic + 123 (Russian)
247 {"xn---123-45dmmc5f.ru", L
"\x0442\x043e\x0440\x0442\x044b-123.ru",
248 {true, false, false, false, false,
249 false, false, true, false, false,
250 false, false, false, false, false,
251 false, false, false, false, true,
254 {"xn--mgba1fmg.ar", L
"\x0627\x0641\x0644\x0627\x0645.ar",
255 {true, false, false, false, false,
256 false, true, false, false, false,
257 false, false, false, false, false,
258 false, false, false, false, false,
261 {"xn--4dbib.he", L
"\x05d5\x05d0\x05d4.he",
262 {true, false, false, false, false,
263 true, false, false, false, false,
264 false, false, false, false, false,
265 false, false, false, false, true,
268 {"xn--12c2cc4ag3b4ccu.th",
269 L
"\x0e2a\x0e32\x0e22\x0e01\x0e32\x0e23\x0e1a\x0e34\x0e19.th",
270 {true, false, false, false, false,
271 false, false, false, false, false,
272 false, false, false, true, false,
273 false, false, false, false, false,
276 {"www.xn--l1b6a9e1b7c.in", L
"www.\x0905\x0915\x094b\x0932\x093e.in",
277 {true, false, false, false, false,
278 false, false, false, false, false,
279 false, false, false, false, true,
280 false, false, false, false, false,
283 {"xn--hello?world.com", NULL
,
284 {false, false, false, false, false,
285 false, false, false, false, false,
286 false, false, false, false, false,
287 false, false, false, false, false,
290 // "payp<alpha>l.com"
291 {"www.xn--paypl-g9d.com", L
"payp\x03b1l.com",
292 {false, false, false, false, false,
293 false, false, false, false, false,
294 false, false, false, false, false,
295 false, false, false, false, false,
297 // google.gr with Greek omicron and epsilon
298 {"xn--ggl-6xc1ca.gr", L
"g\x03bf\x03bfgl\x03b5.gr",
299 {false, false, false, false, false,
300 false, false, false, false, false,
301 false, false, false, false, false,
302 false, false, false, false, false,
304 // google.ru with Cyrillic o
305 {"xn--ggl-tdd6ba.ru", L
"g\x043e\x043egl\x0435.ru",
306 {false, false, false, false, false,
307 false, false, false, false, false,
308 false, false, false, false, false,
309 false, false, false, false, false,
311 // h<e with acute>llo<China in Han>.cn
312 {"xn--hllo-bpa7979ih5m.cn", L
"h\x00e9llo\x4e2d\x56fd.cn",
313 {false, false, false, false, false,
314 false, false, false, false, false,
315 false, false, false, false, false,
316 false, false, false, false, false,
318 // <Greek rho><Cyrillic a><Cyrillic u>.ru
319 {"xn--2xa6t2b.ru", L
"\x03c1\x0430\x0443.ru",
320 {false, false, false, false, false,
321 false, false, false, false, false,
322 false, false, false, false, false,
323 false, false, false, false, false,
325 // One that's really long that will force a buffer realloc
326 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
328 L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
330 {true, true, true, true, true,
331 true, true, true, true, true,
332 true, true, true, true, true,
333 true, true, true, true, true,
335 // Test cases for characters we blacklisted although allowed in IDN.
336 // Embedded spaces will be turned to %20 in the display.
337 // TODO(jungshik): We need to have more cases. This is a typical
338 // data-driven trap. The following test cases need to be separated
339 // and tested only for a couple of languages.
340 {"xn--osd3820f24c.kr", L
"\xac00\xb098\x115f.kr",
341 {false, false, false, false, false,
342 false, false, false, false, false,
343 false, false, false, false, false,
344 false, false, false, false, false,
346 {"www.xn--google-ho0coa.com", L
"www.\x2039google\x203a.com",
347 {false, false, false, false, false,
348 false, false, false, false, false,
349 false, false, false, false, false,
350 false, false, false, false, false,
352 {"google.xn--comabc-k8d", L
"google.com\x0338" L
"abc",
353 {false, false, false, false, false,
354 false, false, false, false, false,
355 false, false, false, false, false,
356 false, false, false, false, false,
358 {"google.xn--com-oh4ba.evil.jp", L
"google.com\x309a\x309a.evil.jp",
359 {false, false, false, false, false,
360 false, false, false, false, false,
361 false, false, false, false, false,
362 false, false, false, false, false,
364 {"google.xn--comevil-v04f.jp", L
"google.com\x30ce" L
"evil.jp",
365 {false, false, false, false, false,
366 false, false, false, false, false,
367 false, false, false, false, false,
368 false, false, false, false, false,
371 // These two cases are special. We need a separate test.
372 // U+3000 and U+3002 are normalized to ASCII space and dot.
373 {"xn-- -kq6ay5z.cn", L
"\x4e2d\x56fd\x3000.cn",
374 {false, false, true, false, false,
375 false, false, false, false, false,
376 false, false, false, false, false,
377 false, false, true, false, false,
379 {"xn--fiqs8s.cn", L
"\x4e2d\x56fd\x3002" L
"cn",
380 {false, false, true, false, false,
381 false, false, false, false, false,
382 false, false, false, false, false,
383 false, false, true, false, false,
388 struct AdjustOffsetCase
{
390 size_t output_offset
;
393 struct CompliantHostCase
{
395 const char* desired_tld
;
396 bool expected_output
;
399 struct GenerateFilenameCase
{
402 const char* content_disp_header
;
403 const char* referrer_charset
;
404 const char* suggested_filename
;
405 const char* mime_type
;
406 const wchar_t* default_filename
;
407 const wchar_t* expected_filename
;
411 const char* description
;
413 const char* languages
;
414 FormatUrlTypes format_types
;
415 UnescapeRule::Type escape_rules
;
416 const wchar_t* output
; // Use |wchar_t| to handle Unicode constants easily.
420 // Fills in sockaddr for the given 32-bit address (IPv4.)
421 // |bytes| should be an array of length 4.
422 void MakeIPv4Address(const uint8
* bytes
, int port
, SockaddrStorage
* storage
) {
423 memset(&storage
->addr_storage
, 0, sizeof(storage
->addr_storage
));
424 storage
->addr_len
= sizeof(struct sockaddr_in
);
425 struct sockaddr_in
* addr4
= reinterpret_cast<sockaddr_in
*>(storage
->addr
);
426 addr4
->sin_port
= base::HostToNet16(port
);
427 addr4
->sin_family
= AF_INET
;
428 memcpy(&addr4
->sin_addr
, bytes
, 4);
431 // Fills in sockaddr for the given 128-bit address (IPv6.)
432 // |bytes| should be an array of length 16.
433 void MakeIPv6Address(const uint8
* bytes
, int port
, SockaddrStorage
* storage
) {
434 memset(&storage
->addr_storage
, 0, sizeof(storage
->addr_storage
));
435 storage
->addr_len
= sizeof(struct sockaddr_in6
);
436 struct sockaddr_in6
* addr6
= reinterpret_cast<sockaddr_in6
*>(storage
->addr
);
437 addr6
->sin6_port
= base::HostToNet16(port
);
438 addr6
->sin6_family
= AF_INET6
;
439 memcpy(&addr6
->sin6_addr
, bytes
, 16);
442 // A helper for IDN*{Fast,Slow}.
443 // Append "::<language list>" to |expected| and |actual| to make it
444 // easy to tell which sub-case fails without debugging.
445 void AppendLanguagesToOutputs(const char* languages
,
446 base::string16
* expected
,
447 base::string16
* actual
) {
448 base::string16 to_append
= ASCIIToUTF16("::") + ASCIIToUTF16(languages
);
449 expected
->append(to_append
);
450 actual
->append(to_append
);
453 // A pair of helpers for the FormatUrlWithOffsets() test.
454 void VerboseExpect(size_t expected
,
456 const std::string
& original_url
,
458 const base::string16
& formatted_url
) {
459 EXPECT_EQ(expected
, actual
) << "Original URL: " << original_url
460 << " (at char " << position
<< ")\nFormatted URL: " << formatted_url
;
463 void CheckAdjustedOffsets(const std::string
& url_string
,
464 const std::string
& languages
,
465 FormatUrlTypes format_types
,
466 UnescapeRule::Type unescape_rules
,
467 const size_t* output_offsets
) {
468 GURL
url(url_string
);
469 size_t url_length
= url_string
.length();
470 std::vector
<size_t> offsets
;
471 for (size_t i
= 0; i
<= url_length
+ 1; ++i
)
472 offsets
.push_back(i
);
473 offsets
.push_back(500000); // Something larger than any input length.
474 offsets
.push_back(std::string::npos
);
475 base::string16 formatted_url
= FormatUrlWithOffsets(url
, languages
,
476 format_types
, unescape_rules
, NULL
, NULL
, &offsets
);
477 for (size_t i
= 0; i
< url_length
; ++i
)
478 VerboseExpect(output_offsets
[i
], offsets
[i
], url_string
, i
, formatted_url
);
479 VerboseExpect(formatted_url
.length(), offsets
[url_length
], url_string
,
480 url_length
, formatted_url
);
481 VerboseExpect(base::string16::npos
, offsets
[url_length
+ 1], url_string
,
482 500000, formatted_url
);
483 VerboseExpect(base::string16::npos
, offsets
[url_length
+ 2], url_string
,
484 std::string::npos
, formatted_url
);
487 // Helper to strignize an IP number (used to define expectations).
488 std::string
DumpIPNumber(const IPAddressNumber
& v
) {
490 for (size_t i
= 0; i
< v
.size(); ++i
) {
493 out
.append(base::IntToString(static_cast<int>(v
[i
])));
498 void RunGenerateFileNameTestCase(const GenerateFilenameCase
* test_case
) {
499 std::string
default_filename(base::WideToUTF8(test_case
->default_filename
));
500 base::FilePath file_path
= GenerateFileName(
501 GURL(test_case
->url
), test_case
->content_disp_header
,
502 test_case
->referrer_charset
, test_case
->suggested_filename
,
503 test_case
->mime_type
, default_filename
);
504 EXPECT_EQ(test_case
->expected_filename
,
505 file_util::FilePathAsWString(file_path
))
506 << "test case at line number: " << test_case
->lineno
;
509 } // anonymous namespace
511 TEST(NetUtilTest
, FileURLConversion
) {
512 // a list of test file names and the corresponding URLs
513 const FileCase round_trip_cases
[] = {
515 {L
"C:\\foo\\bar.txt", "file:///C:/foo/bar.txt"},
516 {L
"\\\\some computer\\foo\\bar.txt",
517 "file://some%20computer/foo/bar.txt"}, // UNC
518 {L
"D:\\Name;with%some symbols*#",
519 "file:///D:/Name%3Bwith%25some%20symbols*%23"},
520 // issue 14153: To be tested with the OS default codepage other than 1252.
521 {L
"D:\\latin1\\caf\x00E9\x00DD.txt",
522 "file:///D:/latin1/caf%C3%A9%C3%9D.txt"},
523 {L
"D:\\otherlatin\\caf\x0119.txt",
524 "file:///D:/otherlatin/caf%C4%99.txt"},
525 {L
"D:\\greek\\\x03B1\x03B2\x03B3.txt",
526 "file:///D:/greek/%CE%B1%CE%B2%CE%B3.txt"},
527 {L
"D:\\Chinese\\\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
528 "file:///D:/Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD%91"
530 {L
"D:\\plane1\\\xD835\xDC00\xD835\xDC01.txt", // Math alphabet "AB"
531 "file:///D:/plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
532 #elif defined(OS_POSIX)
533 {L
"/foo/bar.txt", "file:///foo/bar.txt"},
534 {L
"/foo/BAR.txt", "file:///foo/BAR.txt"},
535 {L
"/C:/foo/bar.txt", "file:///C:/foo/bar.txt"},
536 {L
"/foo/bar?.txt", "file:///foo/bar%3F.txt"},
537 {L
"/some computer/foo/bar.txt", "file:///some%20computer/foo/bar.txt"},
538 {L
"/Name;with%some symbols*#", "file:///Name%3Bwith%25some%20symbols*%23"},
539 {L
"/latin1/caf\x00E9\x00DD.txt", "file:///latin1/caf%C3%A9%C3%9D.txt"},
540 {L
"/otherlatin/caf\x0119.txt", "file:///otherlatin/caf%C4%99.txt"},
541 {L
"/greek/\x03B1\x03B2\x03B3.txt", "file:///greek/%CE%B1%CE%B2%CE%B3.txt"},
542 {L
"/Chinese/\x6240\x6709\x4e2d\x6587\x7f51\x9875.doc",
543 "file:///Chinese/%E6%89%80%E6%9C%89%E4%B8%AD%E6%96%87%E7%BD"
545 {L
"/plane1/\x1D400\x1D401.txt", // Math alphabet "AB"
546 "file:///plane1/%F0%9D%90%80%F0%9D%90%81.txt"},
550 // First, we'll test that we can round-trip all of the above cases of URLs
551 base::FilePath output
;
552 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(round_trip_cases
); i
++) {
553 // convert to the file URL
554 GURL
file_url(FilePathToFileURL(
555 file_util::WStringAsFilePath(round_trip_cases
[i
].file
)));
556 EXPECT_EQ(round_trip_cases
[i
].url
, file_url
.spec());
558 // Back to the filename.
559 EXPECT_TRUE(FileURLToFilePath(file_url
, &output
));
560 EXPECT_EQ(round_trip_cases
[i
].file
, file_util::FilePathAsWString(output
));
563 // Test that various file: URLs get decoded into the correct file type
564 FileCase url_cases
[] = {
566 {L
"C:\\foo\\bar.txt", "file:c|/foo\\bar.txt"},
567 {L
"C:\\foo\\bar.txt", "file:/c:/foo/bar.txt"},
568 {L
"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
569 {L
"C:\\foo\\bar.txt", "file:///c:/foo/bar.txt"},
570 {L
"\\\\foo\\bar.txt", "file:////foo\\bar.txt"},
571 {L
"\\\\foo\\bar.txt", "file:/foo/bar.txt"},
572 {L
"\\\\foo\\bar.txt", "file://foo\\bar.txt"},
573 {L
"C:\\foo\\bar.txt", "file:\\\\\\c:/foo/bar.txt"},
574 #elif defined(OS_POSIX)
575 {L
"/c:/foo/bar.txt", "file:/c:/foo/bar.txt"},
576 {L
"/c:/foo/bar.txt", "file:///c:/foo/bar.txt"},
577 {L
"/foo/bar.txt", "file:/foo/bar.txt"},
578 {L
"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
579 {L
"/foo/bar.txt", "file:foo/bar.txt"},
580 {L
"/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
"/foo/bar.txt", "file:////foo//bar.txt"},
584 {L
"/foo/bar.txt", "file:////foo///bar.txt"},
585 {L
"/foo/bar.txt", "file:////foo////bar.txt"},
586 {L
"/c:/foo/bar.txt", "file:\\\\\\c:/foo/bar.txt"},
587 {L
"/c:/foo/bar.txt", "file:c:/foo/bar.txt"},
588 // We get these wrong because GURL turns back slashes into forward
590 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
591 //{L"/c|/foo%5Cbar.txt", "file:c|/foo\\bar.txt"},
592 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
593 //{L"/foo%5Cbar.txt", "file:////foo\\bar.txt"},
594 //{L"/foo%5Cbar.txt", "file://foo\\bar.txt"},
597 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(url_cases
); i
++) {
598 FileURLToFilePath(GURL(url_cases
[i
].url
), &output
);
599 EXPECT_EQ(url_cases
[i
].file
, file_util::FilePathAsWString(output
));
602 // Unfortunately, UTF8ToWide discards invalid UTF8 input.
603 #ifdef BUG_878908_IS_FIXED
604 // Test that no conversion happens if the UTF-8 input is invalid, and that
605 // the input is preserved in UTF-8
606 const char invalid_utf8
[] = "file:///d:/Blah/\xff.doc";
607 const wchar_t invalid_wide
[] = L
"D:\\Blah\\\xff.doc";
608 EXPECT_TRUE(FileURLToFilePath(
609 GURL(std::string(invalid_utf8
)), &output
));
610 EXPECT_EQ(std::wstring(invalid_wide
), output
);
613 // Test that if a file URL is malformed, we get a failure
614 EXPECT_FALSE(FileURLToFilePath(GURL("filefoobar"), &output
));
617 TEST(NetUtilTest
, GetIdentityFromURL
) {
619 const char* input_url
;
620 const char* expected_username
;
621 const char* expected_password
;
624 "http://username:password@google.com",
628 { // Test for http://crbug.com/19200
629 "http://username:p@ssword@google.com",
633 { // Special URL characters should be unescaped.
634 "http://username:p%3fa%26s%2fs%23@google.com",
638 { // Username contains %20.
639 "http://use rname:password@google.com",
644 "http://use%00rname:password@google.com",
648 { // Use a '+' in the username.
649 "http://use+rname:password@google.com",
653 { // Use a '&' in the password.
654 "http://username:p&ssword@google.com",
659 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
660 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"]: %s", i
,
661 tests
[i
].input_url
));
662 GURL
url(tests
[i
].input_url
);
664 base::string16 username
, password
;
665 GetIdentityFromURL(url
, &username
, &password
);
667 EXPECT_EQ(ASCIIToUTF16(tests
[i
].expected_username
), username
);
668 EXPECT_EQ(ASCIIToUTF16(tests
[i
].expected_password
), password
);
672 // Try extracting a username which was encoded with UTF8.
673 TEST(NetUtilTest
, GetIdentityFromURL_UTF8
) {
674 GURL
url(WideToUTF16(L
"http://foo:\x4f60\x597d@blah.com"));
676 EXPECT_EQ("foo", url
.username());
677 EXPECT_EQ("%E4%BD%A0%E5%A5%BD", url
.password());
679 // Extract the unescaped identity.
680 base::string16 username
, password
;
681 GetIdentityFromURL(url
, &username
, &password
);
683 // Verify that it was decoded as UTF8.
684 EXPECT_EQ(ASCIIToUTF16("foo"), username
);
685 EXPECT_EQ(WideToUTF16(L
"\x4f60\x597d"), password
);
688 // Just a bunch of fake headers.
689 const char* google_headers
=
691 "Content-TYPE: text/html; charset=utf-8\n"
692 "Content-disposition: attachment; filename=\"download.pdf\"\n"
693 "Content-Length: 378557\n"
694 "X-Google-Google1: 314159265\n"
695 "X-Google-Google2: aaaa2:7783,bbb21:9441\n"
696 "X-Google-Google4: home\n"
697 "Transfer-Encoding: chunked\n"
698 "Set-Cookie: HEHE_AT=6666x66beef666x6-66xx6666x66; Path=/mail\n"
699 "Set-Cookie: HEHE_HELP=owned:0;Path=/\n"
700 "Set-Cookie: S=gmail=Xxx-beefbeefbeef_beefb:gmail_yj=beefbeef000beefbee"
701 "fbee:gmproxy=bee-fbeefbe; Domain=.google.com; Path=/\n"
702 "X-Google-Google2: /one/two/three/four/five/six/seven-height/nine:9411\n"
704 "Transfer-Encoding: chunked\n"
705 "Date: Mon, 13 Nov 2006 21:38:09 GMT\n"
706 "Expires: Tue, 14 Nov 2006 19:23:58 GMT\n"
707 "X-Malformed: bla; arg=test\"\n"
708 "X-Malformed2: bla; arg=\n"
709 "X-Test: bla; arg1=val1; arg2=val2";
711 TEST(NetUtilTest
, GetSpecificHeader
) {
712 const HeaderCase tests
[] = {
713 {"content-type", "text/html; charset=utf-8"},
714 {"CONTENT-LENGTH", "378557"},
715 {"Date", "Mon, 13 Nov 2006 21:38:09 GMT"},
720 // Test first with google_headers.
721 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
723 GetSpecificHeader(google_headers
, tests
[i
].header_name
);
724 EXPECT_EQ(result
, tests
[i
].expected
);
727 // Test again with empty headers.
728 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
729 std::string result
= GetSpecificHeader(std::string(), tests
[i
].header_name
);
730 EXPECT_EQ(result
, std::string());
734 TEST(NetUtilTest
, IDNToUnicodeFast
) {
735 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(idn_cases
); i
++) {
736 for (size_t j
= 0; j
< arraysize(kLanguages
); j
++) {
737 // ja || zh-TW,en || ko,ja -> IDNToUnicodeSlow
738 if (j
== 3 || j
== 17 || j
== 18)
740 base::string16
output(IDNToUnicode(idn_cases
[i
].input
, kLanguages
[j
]));
741 base::string16
expected(idn_cases
[i
].unicode_allowed
[j
] ?
742 WideToUTF16(idn_cases
[i
].unicode_output
) :
743 ASCIIToUTF16(idn_cases
[i
].input
));
744 AppendLanguagesToOutputs(kLanguages
[j
], &expected
, &output
);
745 EXPECT_EQ(expected
, output
);
750 TEST(NetUtilTest
, IDNToUnicodeSlow
) {
751 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(idn_cases
); i
++) {
752 for (size_t j
= 0; j
< arraysize(kLanguages
); j
++) {
753 // !(ja || zh-TW,en || ko,ja) -> IDNToUnicodeFast
754 if (!(j
== 3 || j
== 17 || j
== 18))
756 base::string16
output(IDNToUnicode(idn_cases
[i
].input
, kLanguages
[j
]));
757 base::string16
expected(idn_cases
[i
].unicode_allowed
[j
] ?
758 WideToUTF16(idn_cases
[i
].unicode_output
) :
759 ASCIIToUTF16(idn_cases
[i
].input
));
760 AppendLanguagesToOutputs(kLanguages
[j
], &expected
, &output
);
761 EXPECT_EQ(expected
, output
);
766 TEST(NetUtilTest
, CompliantHost
) {
767 const CompliantHostCase compliant_host_cases
[] = {
782 {"a.-a9", "", false},
785 {"1-.a-b", "", true},
786 {"1_.a-b", "", false},
787 {"1-2.a_b", "", true},
788 {"a.b.c.d.e", "", true},
789 {"1.2.3.4.5", "", true},
790 {"1.2.3.4.5.", "", true},
793 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(compliant_host_cases
); ++i
) {
794 EXPECT_EQ(compliant_host_cases
[i
].expected_output
,
795 IsCanonicalizedHostCompliant(compliant_host_cases
[i
].host
,
796 compliant_host_cases
[i
].desired_tld
));
800 TEST(NetUtilTest
, StripWWW
) {
801 EXPECT_EQ(base::string16(), StripWWW(base::string16()));
802 EXPECT_EQ(base::string16(), StripWWW(ASCIIToUTF16("www.")));
803 EXPECT_EQ(ASCIIToUTF16("blah"), StripWWW(ASCIIToUTF16("www.blah")));
804 EXPECT_EQ(ASCIIToUTF16("blah"), StripWWW(ASCIIToUTF16("blah")));
808 #define JPEG_EXT L".jpg"
809 #define HTML_EXT L".htm"
810 #elif defined(OS_MACOSX)
811 #define JPEG_EXT L".jpeg"
812 #define HTML_EXT L".html"
814 #define JPEG_EXT L".jpg"
815 #define HTML_EXT L".html"
817 #define TXT_EXT L".txt"
818 #define TAR_EXT L".tar"
820 TEST(NetUtilTest
, GenerateSafeFileName
) {
822 const char* mime_type
;
823 const base::FilePath::CharType
* filename
;
824 const base::FilePath::CharType
* expected_filename
;
829 FILE_PATH_LITERAL("C:\\foo\\bar.htm"),
830 FILE_PATH_LITERAL("C:\\foo\\bar.htm")
834 FILE_PATH_LITERAL("C:\\foo\\bar.html"),
835 FILE_PATH_LITERAL("C:\\foo\\bar.html")
839 FILE_PATH_LITERAL("C:\\foo\\bar"),
840 FILE_PATH_LITERAL("C:\\foo\\bar.htm")
844 FILE_PATH_LITERAL("C:\\bar.html"),
845 FILE_PATH_LITERAL("C:\\bar.html")
849 FILE_PATH_LITERAL("C:\\bar"),
850 FILE_PATH_LITERAL("C:\\bar.png")
854 FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
855 FILE_PATH_LITERAL("C:\\foo\\bar.exe")
859 FILE_PATH_LITERAL("C:\\foo\\bar.exe"),
860 FILE_PATH_LITERAL("C:\\foo\\bar.exe")
864 FILE_PATH_LITERAL("C:\\foo\\google.com"),
865 FILE_PATH_LITERAL("C:\\foo\\google.com")
869 FILE_PATH_LITERAL("C:\\foo\\con.htm"),
870 FILE_PATH_LITERAL("C:\\foo\\_con.htm")
874 FILE_PATH_LITERAL("C:\\foo\\con"),
875 FILE_PATH_LITERAL("C:\\foo\\_con.htm")
879 FILE_PATH_LITERAL("C:\\foo\\harmless.{not-really-this-may-be-a-guid}"),
880 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
884 FILE_PATH_LITERAL("C:\\foo\\harmless.local"),
885 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
889 FILE_PATH_LITERAL("C:\\foo\\harmless.lnk"),
890 FILE_PATH_LITERAL("C:\\foo\\harmless.download")
894 FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-"),
895 FILE_PATH_LITERAL("C:\\foo\\harmless.{mismatched-")
897 // Allow extension synonyms.
900 FILE_PATH_LITERAL("C:\\foo\\bar.jpg"),
901 FILE_PATH_LITERAL("C:\\foo\\bar.jpg")
905 FILE_PATH_LITERAL("C:\\foo\\bar.jpeg"),
906 FILE_PATH_LITERAL("C:\\foo\\bar.jpeg")
908 #else // !defined(OS_WIN)
911 FILE_PATH_LITERAL("/foo/bar.htm"),
912 FILE_PATH_LITERAL("/foo/bar.htm")
916 FILE_PATH_LITERAL("/foo/bar.html"),
917 FILE_PATH_LITERAL("/foo/bar.html")
921 FILE_PATH_LITERAL("/foo/bar"),
922 FILE_PATH_LITERAL("/foo/bar.html")
926 FILE_PATH_LITERAL("/bar.html"),
927 FILE_PATH_LITERAL("/bar.html")
931 FILE_PATH_LITERAL("/bar"),
932 FILE_PATH_LITERAL("/bar.png")
936 FILE_PATH_LITERAL("/foo/bar.exe"),
937 FILE_PATH_LITERAL("/foo/bar.exe")
941 FILE_PATH_LITERAL("/foo/google.com"),
942 FILE_PATH_LITERAL("/foo/google.com")
946 FILE_PATH_LITERAL("/foo/con.htm"),
947 FILE_PATH_LITERAL("/foo/con.htm")
951 FILE_PATH_LITERAL("/foo/con"),
952 FILE_PATH_LITERAL("/foo/con.html")
954 // Allow extension synonyms.
957 FILE_PATH_LITERAL("/bar.jpg"),
958 FILE_PATH_LITERAL("/bar.jpg")
962 FILE_PATH_LITERAL("/bar.jpeg"),
963 FILE_PATH_LITERAL("/bar.jpeg")
965 #endif // !defined(OS_WIN)
968 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(safe_tests
); ++i
) {
969 base::FilePath
file_path(safe_tests
[i
].filename
);
970 GenerateSafeFileName(safe_tests
[i
].mime_type
, false, &file_path
);
971 EXPECT_EQ(safe_tests
[i
].expected_filename
, file_path
.value())
972 << "Iteration " << i
;
976 TEST(NetUtilTest
, GenerateFileName
) {
977 #if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
978 // This test doesn't run when the locale is not UTF-8 because some of the
979 // string conversions fail. This is OK (we have the default value) but they
980 // don't match our expectations.
981 std::string locale
= setlocale(LC_CTYPE
, NULL
);
982 StringToLowerASCII(&locale
);
983 EXPECT_TRUE(locale
.find("utf-8") != std::string::npos
||
984 locale
.find("utf8") != std::string::npos
)
985 << "Your locale (" << locale
<< ") must be set to UTF-8 "
986 << "for this test to pass!";
989 // Tests whether the correct filename is selected from the the given
990 // parameters and that Content-Disposition headers are properly
991 // handled including failovers when the header is malformed.
992 const GenerateFilenameCase selection_tests
[] = {
995 "http://www.google.com/",
996 "attachment; filename=test.html",
1005 "http://www.google.com/",
1006 "attachment; filename=\"test.html\"",
1015 "http://www.google.com/",
1016 "attachment; filename= \"test.html\"",
1025 "http://www.google.com/",
1026 "attachment; filename = \"test.html\"",
1033 { // filename is whitespace. Should failover to URL host
1035 "http://www.google.com/",
1036 "attachment; filename= ",
1045 "http://www.google.com/path/test.html",
1055 "http://www.google.com/path/test.html",
1065 "http://www.google.com/",
1075 "http://www.google.com/test.html",
1083 { // Now that we use src/url's ExtractFileName, this case falls back to
1084 // the hostname. If this behavior is not desirable, we'd better change
1085 // ExtractFileName (in url_parse).
1087 "http://www.google.com/path/",
1097 "http://www.google.com/path",
1117 "file:///path/testfile",
1127 "non-standard-scheme:",
1135 { // C-D should override default
1137 "http://www.google.com/",
1138 "attachment; filename =\"test.html\"",
1145 { // But the URL shouldn't
1147 "http://www.google.com/",
1157 "http://www.google.com/",
1158 "attachment; filename=\"../test.html\"",
1167 "http://www.google.com/",
1168 "attachment; filename=\"..\\test.html\"",
1177 "http://www.google.com/",
1178 "attachment; filename=\"..\\\\test.html\"",
1185 { // Filename disappears after leading and trailing periods are removed.
1187 "http://www.google.com/",
1188 "attachment; filename=\"..\"",
1195 { // C-D specified filename disappears. Failover to final filename.
1197 "http://www.google.com/test.html",
1198 "attachment; filename=\"..\"",
1205 // Below is a small subset of cases taken from HttpContentDisposition tests.
1208 "http://www.google.com/",
1209 "attachment; filename=\"%EC%98%88%EC%88%A0%20"
1210 "%EC%98%88%EC%88%A0.jpg\"",
1215 L
"\uc608\uc220 \uc608\uc220.jpg"
1219 "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
1225 L
"\uc608\uc220 \uc608\uc220.jpg"
1229 "http://www.google.com/",
1234 L
"\uB2E4\uC6B4\uB85C\uB4DC",
1235 L
"\uB2E4\uC6B4\uB85C\uB4DC"
1239 "http://www.google.com/",
1240 "attachment; filename=\"=?EUC-JP?Q?=B7=DD=BD="
1246 L
"\u82b8\u88533.png"
1250 "http://www.example.com/images?id=3",
1251 "attachment; filename=caf\xc3\xa9.png",
1260 "http://www.example.com/images?id=3",
1261 "attachment; filename=caf\xe5.png",
1270 "http://www.example.com/file?id=3",
1271 "attachment; name=\xcf\xc2\xd4\xd8.zip",
1278 { // Invalid C-D header. Extracts filename from url.
1280 "http://www.google.com/test.html",
1281 "attachment; filename==?iiso88591?Q?caf=EG?=",
1288 // about: and data: URLs
1301 "data:,looks/like/a.path",
1311 "data:text/plain;base64,VG8gYmUgb3Igbm90IHRvIGJlLg=",
1321 "data:,looks/like/a.path",
1326 L
"default_filename_is_given",
1327 L
"default_filename_is_given"
1331 "data:,looks/like/a.path",
1336 L
"\u65e5\u672c\u8a9e", // Japanese Kanji.
1337 L
"\u65e5\u672c\u8a9e"
1339 { // The filename encoding is specified by the referrer charset.
1341 "http://example.com/V%FDvojov%E1%20psychologie.doc",
1347 L
"V\u00fdvojov\u00e1 psychologie.doc"
1349 { // Suggested filename takes precedence over URL
1351 "http://www.google.com/test",
1359 { // The content-disposition has higher precedence over the suggested name.
1361 "http://www.google.com/test",
1362 "attachment; filename=test.html",
1370 { // The filename encoding doesn't match the referrer charset, the system
1371 // charset, or UTF-8.
1372 // TODO(jshin): we need to handle this case.
1374 "http://example.com/V%FDvojov%E1%20psychologie.doc",
1380 L
"V\u00fdvojov\u00e1 psychologie.doc",
1383 // Raw 8bit characters in C-D
1386 "http://www.example.com/images?id=3",
1387 "attachment; filename=caf\xc3\xa9.png",
1396 "http://www.example.com/images?id=3",
1397 "attachment; filename=caf\xe5.png",
1404 { // No 'filename' keyword in the disposition, use the URL
1406 "http://www.evil.com/my_download.txt",
1414 { // Spaces in the disposition file name
1416 "http://www.frontpagehacker.com/a_download.exe",
1417 "filename=My Downloaded File.exe",
1420 "application/octet-stream",
1422 L
"My Downloaded File.exe"
1426 "http://www.examples.com/",
1428 "filename=\"%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg\"",
1433 L
"\uc608\uc220 \uc608\uc220.jpg"
1435 { // name= parameter
1437 "http://www.examples.com/q.cgi?id=abc",
1438 "attachment; name=abc de.pdf",
1441 "application/octet-stream",
1447 "http://www.example.com/path",
1448 "filename=\"=?EUC-JP?Q?=B7=DD=BD=D13=2Epng?=\"",
1453 L
"\x82b8\x8853" L
"3.png"
1455 { // The following two have invalid CD headers and filenames come from the
1458 "http://www.example.com/test%20123",
1459 "attachment; filename==?iiso88591?Q?caf=EG?=",
1464 L
"test 123" JPEG_EXT
1468 "http://www.google.com/%EC%98%88%EC%88%A0%20%EC%98%88%EC%88%A0.jpg",
1469 "malformed_disposition",
1474 L
"\uc608\uc220 \uc608\uc220.jpg"
1476 { // Invalid C-D. No filename from URL. Falls back to 'download'.
1478 "http://www.google.com/path1/path2/",
1479 "attachment; filename==?iso88591?Q?caf=E3?",
1484 L
"download" JPEG_EXT
1488 // Tests filename generation. Once the correct filename is
1489 // selected, they should be passed through the validation steps and
1490 // a correct extension should be added if necessary.
1491 const GenerateFilenameCase generation_tests
[] = {
1492 // Dotfiles. Ensures preceeding period(s) stripped.
1495 "http://www.google.com/.test.html",
1505 "http://www.google.com/.test",
1515 "http://www.google.com/..test",
1523 { // Disposition has relative paths, remove directory separators
1525 "http://www.evil.com/my_download.txt",
1526 "filename=../../../../././../a_file_name.txt",
1531 L
"-..-..-..-.-.-..-a_file_name.txt"
1533 { // Disposition has parent directories, remove directory separators
1535 "http://www.evil.com/my_download.txt",
1536 "filename=dir1/dir2/a_file_name.txt",
1541 L
"dir1-dir2-a_file_name.txt"
1543 { // Disposition has relative paths, remove directory separators
1545 "http://www.evil.com/my_download.txt",
1546 "filename=..\\..\\..\\..\\.\\.\\..\\a_file_name.txt",
1551 L
"-..-..-..-.-.-..-a_file_name.txt"
1553 { // Disposition has parent directories, remove directory separators
1555 "http://www.evil.com/my_download.txt",
1556 "filename=dir1\\dir2\\a_file_name.txt",
1561 L
"dir1-dir2-a_file_name.txt"
1563 { // No useful information in disposition or URL, use default
1565 "http://www.truncated.com/path/",
1573 { // Filename looks like HTML?
1575 "http://www.evil.com/get/malware/here",
1576 "filename=\"<blink>Hello kitty</blink>\"",
1581 L
"-blink-Hello kitty--blink-" TXT_EXT
1583 { // A normal avi should get .avi and not .avi.avi
1585 "https://blah.google.com/misc/2.avi",
1593 { // Extension generation
1595 "http://www.example.com/my-cat",
1605 "http://www.example.com/my-cat",
1615 "http://www.example.com/my-cat",
1623 { // Unknown MIME type
1625 "http://www.example.com/my-cat",
1635 "http://www.example.com/my-cat.jpg",
1636 "filename=my-cat.jpg",
1643 // Windows specific tests
1647 "http://www.goodguy.com/evil.exe",
1648 "filename=evil.exe",
1657 "http://www.goodguy.com/ok.exe",
1661 "binary/octet-stream",
1667 "http://www.goodguy.com/evil.dll",
1668 "filename=evil.dll",
1677 "http://www.goodguy.com/evil.exe",
1681 "application/rss+xml",
1685 // Test truncation of trailing dots and spaces
1688 "http://www.goodguy.com/evil.exe ",
1689 "filename=evil.exe ",
1692 "binary/octet-stream",
1698 "http://www.goodguy.com/evil.exe.",
1699 "filename=evil.exe.",
1702 "binary/octet-stream",
1708 "http://www.goodguy.com/evil.exe. . .",
1709 "filename=evil.exe. . .",
1712 "binary/octet-stream",
1718 "http://www.goodguy.com/evil.",
1722 "binary/octet-stream",
1728 "http://www.goodguy.com/. . . . .",
1729 "filename=. . . . .",
1732 "binary/octet-stream",
1738 "http://www.badguy.com/attachment?name=meh.exe%C2%A0",
1739 "attachment; filename=\"meh.exe\xC2\xA0\"",
1742 "binary/octet-stream",
1749 "http://www.goodguy.com/utils.js",
1750 "filename=utils.js",
1753 "application/x-javascript",
1759 "http://www.goodguy.com/contacts.js",
1760 "filename=contacts.js",
1769 "http://www.goodguy.com/utils.js",
1770 "filename=utils.js",
1779 "http://www.goodguy.com/utils.js",
1780 "filename=utils.js",
1783 "text/javascript;version=2",
1789 "http://www.goodguy.com/utils.js",
1790 "filename=utils.js",
1793 "application/ecmascript",
1799 "http://www.goodguy.com/utils.js",
1800 "filename=utils.js",
1803 "application/ecmascript;version=4",
1809 "http://www.goodguy.com/program.exe",
1810 "filename=program.exe",
1813 "application/foo-bar",
1819 "http://www.evil.com/../foo.txt",
1820 "filename=../foo.txt",
1829 "http://www.evil.com/..\\foo.txt",
1830 "filename=..\\foo.txt",
1839 "http://www.evil.com/.hidden",
1849 "http://www.evil.com/trailing.",
1850 "filename=trailing.",
1863 "http://www.evil.com/trailing.",
1864 "filename=trailing.",
1870 L
"trailing-" TXT_EXT
1877 "http://www.evil.com/.",
1887 "http://www.evil.com/..",
1897 "http://www.evil.com/...",
1905 { // Note that this one doesn't have "filename=" on it.
1907 "http://www.evil.com/",
1913 L
"download" JPEG_EXT
1917 "http://www.evil.com/",
1923 L
"download" JPEG_EXT
1927 "http://www.example.com/simple",
1931 "application/octet-stream",
1935 // Reserved words on Windows
1938 "http://www.goodguy.com/COM1",
1942 "application/foo-bar",
1952 "http://www.goodguy.com/COM4.txt",
1953 "filename=COM4.txt",
1966 "http://www.goodguy.com/lpt1.TXT",
1967 "filename=lpt1.TXT",
1980 "http://www.goodguy.com/clock$.txt",
1981 "filename=clock$.txt",
1992 { // Validation should also apply to sugested name
1994 "http://www.goodguy.com/blah$.txt",
1995 "filename=clock$.txt",
2008 "http://www.goodguy.com/mycom1.foo",
2009 "filename=mycom1.foo",
2018 "http://www.badguy.com/Setup.exe.local",
2019 "filename=Setup.exe.local",
2022 "application/foo-bar",
2025 L
"Setup.exe.download"
2032 "http://www.badguy.com/Setup.exe.local",
2033 "filename=Setup.exe.local.local",
2036 "application/foo-bar",
2039 L
"Setup.exe.local.download"
2041 L
"Setup.exe.local.local"
2046 "http://www.badguy.com/Setup.exe.lnk",
2047 "filename=Setup.exe.lnk",
2050 "application/foo-bar",
2053 L
"Setup.exe.download"
2060 "http://www.badguy.com/Desktop.ini",
2061 "filename=Desktop.ini",
2064 "application/foo-bar",
2074 "http://www.badguy.com/Thumbs.db",
2075 "filename=Thumbs.db",
2078 "application/foo-bar",
2088 "http://www.hotmail.com",
2089 "filename=source.jpg",
2092 "application/x-javascript",
2096 { // http://crbug.com/5772.
2098 "http://www.example.com/foo.tar.gz",
2102 "application/x-tar",
2106 { // http://crbug.com/52250.
2108 "http://www.example.com/foo.tgz",
2112 "application/x-tar",
2116 { // http://crbug.com/7337.
2118 "http://maged.lordaeron.org/blank.reg",
2128 "http://www.example.com/bar.tar",
2132 "application/x-tar",
2138 "http://www.example.com/bar.bogus",
2142 "application/x-tar",
2146 { // http://crbug.com/20337
2148 "http://www.example.com/.download.txt",
2149 "filename=.download.txt",
2156 { // http://crbug.com/56855.
2158 "http://www.example.com/bar.sh",
2166 { // http://crbug.com/61571
2168 "http://www.example.com/npdf.php?fn=foobar.pdf",
2176 { // Shouldn't overwrite C-D specified extension.
2178 "http://www.example.com/npdf.php?fn=foobar.pdf",
2179 "filename=foobar.jpg",
2186 { // http://crbug.com/87719
2188 "http://www.example.com/image.aspx?id=blargh",
2196 #if defined(OS_CHROMEOS)
2197 { // http://crosbug.com/26028
2199 "http://www.example.com/fooa%cc%88.txt",
2210 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(selection_tests
); ++i
)
2211 RunGenerateFileNameTestCase(&selection_tests
[i
]);
2213 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(generation_tests
); ++i
)
2214 RunGenerateFileNameTestCase(&generation_tests
[i
]);
2216 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(generation_tests
); ++i
) {
2217 GenerateFilenameCase test_case
= generation_tests
[i
];
2218 test_case
.referrer_charset
= "GBK";
2219 RunGenerateFileNameTestCase(&test_case
);
2223 // This is currently a windows specific function.
2227 struct GetDirectoryListingEntryCase
{
2228 const wchar_t* name
;
2229 const char* raw_bytes
;
2233 const char* expected
;
2237 TEST(NetUtilTest
, GetDirectoryListingEntry
) {
2238 const GetDirectoryListingEntryCase test_cases
[] = {
2244 "<script>addRow(\"Foo\",\"Foo\",0,\"9.8 kB\",\"\");</script>\n"},
2250 "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
2257 "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
2259 // U+D55C0 U+AE00. raw_bytes is empty (either a local file with
2260 // UTF-8/UTF-16 encoding or a remote file on an ftp server using UTF-8
2261 {L
"\xD55C\xAE00.txt",
2266 "<script>addRow(\"\xED\x95\x9C\xEA\xB8\x80.txt\","
2267 "\"%ED%95%9C%EA%B8%80.txt\",0,\"9.8 kB\",\"\");</script>\n"},
2268 // U+D55C0 U+AE00. raw_bytes is the corresponding EUC-KR sequence:
2269 // a local or remote file in EUC-KR.
2270 {L
"\xD55C\xAE00.txt",
2271 "\xC7\xD1\xB1\xDB.txt",
2275 "<script>addRow(\"\xED\x95\x9C\xEA\xB8\x80.txt\",\"%C7%D1%B1%DB.txt\""
2276 ",0,\"9.8 kB\",\"\");</script>\n"},
2279 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(test_cases
); ++i
) {
2280 const std::string results
= GetDirectoryListingEntry(
2281 WideToUTF16(test_cases
[i
].name
),
2282 test_cases
[i
].raw_bytes
,
2283 test_cases
[i
].is_dir
,
2284 test_cases
[i
].filesize
,
2285 test_cases
[i
].time
);
2286 EXPECT_EQ(test_cases
[i
].expected
, results
);
2292 TEST(NetUtilTest
, ParseHostAndPort
) {
2296 const char* expected_host
;
2300 {"foo:10", true, "foo", 10},
2301 {"foo", true, "foo", -1},
2303 "[1080:0:0:0:8:800:200C:4171]:11",
2305 "[1080:0:0:0:8:800:200C:4171]",
2309 {"foo:bar", false, "", -1},
2310 {"foo:", false, "", -1},
2311 {":", false, "", -1},
2312 {":80", false, "", -1},
2313 {"", false, "", -1},
2314 {"porttoolong:300000", false, "", -1},
2315 {"usrname@host", false, "", -1},
2316 {"usrname:password@host", false, "", -1},
2317 {":password@host", false, "", -1},
2318 {":password@host:80", false, "", -1},
2319 {":password@host", false, "", -1},
2320 {"@host", false, "", -1},
2323 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
2326 bool ok
= ParseHostAndPort(tests
[i
].input
, &host
, &port
);
2328 EXPECT_EQ(tests
[i
].success
, ok
);
2330 if (tests
[i
].success
) {
2331 EXPECT_EQ(tests
[i
].expected_host
, host
);
2332 EXPECT_EQ(tests
[i
].expected_port
, port
);
2337 TEST(NetUtilTest
, GetHostAndPort
) {
2340 const char* expected_host_and_port
;
2342 { GURL("http://www.foo.com/x"), "www.foo.com:80"},
2343 { GURL("http://www.foo.com:21/x"), "www.foo.com:21"},
2345 // For IPv6 literals should always include the brackets.
2346 { GURL("http://[1::2]/x"), "[1::2]:80"},
2347 { GURL("http://[::a]:33/x"), "[::a]:33"},
2349 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
2350 std::string host_and_port
= GetHostAndPort(tests
[i
].url
);
2351 EXPECT_EQ(std::string(tests
[i
].expected_host_and_port
), host_and_port
);
2355 TEST(NetUtilTest
, GetHostAndOptionalPort
) {
2358 const char* expected_host_and_port
;
2360 { GURL("http://www.foo.com/x"), "www.foo.com"},
2361 { GURL("http://www.foo.com:21/x"), "www.foo.com:21"},
2363 // For IPv6 literals should always include the brackets.
2364 { GURL("http://[1::2]/x"), "[1::2]"},
2365 { GURL("http://[::a]:33/x"), "[::a]:33"},
2367 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
2368 std::string host_and_port
= GetHostAndOptionalPort(tests
[i
].url
);
2369 EXPECT_EQ(std::string(tests
[i
].expected_host_and_port
), host_and_port
);
2373 TEST(NetUtilTest
, IPAddressToString
) {
2374 uint8 addr1
[4] = {0, 0, 0, 0};
2375 EXPECT_EQ("0.0.0.0", IPAddressToString(addr1
, sizeof(addr1
)));
2377 uint8 addr2
[4] = {192, 168, 0, 1};
2378 EXPECT_EQ("192.168.0.1", IPAddressToString(addr2
, sizeof(addr2
)));
2380 uint8 addr3
[16] = {0xFE, 0xDC, 0xBA, 0x98};
2381 EXPECT_EQ("fedc:ba98::", IPAddressToString(addr3
, sizeof(addr3
)));
2384 TEST(NetUtilTest
, IPAddressToStringWithPort
) {
2385 uint8 addr1
[4] = {0, 0, 0, 0};
2386 EXPECT_EQ("0.0.0.0:3", IPAddressToStringWithPort(addr1
, sizeof(addr1
), 3));
2388 uint8 addr2
[4] = {192, 168, 0, 1};
2389 EXPECT_EQ("192.168.0.1:99",
2390 IPAddressToStringWithPort(addr2
, sizeof(addr2
), 99));
2392 uint8 addr3
[16] = {0xFE, 0xDC, 0xBA, 0x98};
2393 EXPECT_EQ("[fedc:ba98::]:8080",
2394 IPAddressToStringWithPort(addr3
, sizeof(addr3
), 8080));
2397 TEST(NetUtilTest
, NetAddressToString_IPv4
) {
2402 {{0, 0, 0, 0}, "0.0.0.0"},
2403 {{127, 0, 0, 1}, "127.0.0.1"},
2404 {{192, 168, 0, 1}, "192.168.0.1"},
2407 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
2408 SockaddrStorage storage
;
2409 MakeIPv4Address(tests
[i
].addr
, 80, &storage
);
2410 std::string result
= NetAddressToString(storage
.addr
, storage
.addr_len
);
2411 EXPECT_EQ(std::string(tests
[i
].result
), result
);
2415 TEST(NetUtilTest
, NetAddressToString_IPv6
) {
2420 {{0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA,
2421 0x98, 0x76, 0x54, 0x32, 0x10},
2422 "fedc:ba98:7654:3210:fedc:ba98:7654:3210"},
2425 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
2426 SockaddrStorage storage
;
2427 MakeIPv6Address(tests
[i
].addr
, 80, &storage
);
2428 EXPECT_EQ(std::string(tests
[i
].result
),
2429 NetAddressToString(storage
.addr
, storage
.addr_len
));
2433 TEST(NetUtilTest
, NetAddressToStringWithPort_IPv4
) {
2434 uint8 addr
[] = {127, 0, 0, 1};
2435 SockaddrStorage storage
;
2436 MakeIPv4Address(addr
, 166, &storage
);
2437 std::string result
= NetAddressToStringWithPort(storage
.addr
,
2439 EXPECT_EQ("127.0.0.1:166", result
);
2442 TEST(NetUtilTest
, NetAddressToStringWithPort_IPv6
) {
2444 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0xFE, 0xDC, 0xBA,
2445 0x98, 0x76, 0x54, 0x32, 0x10
2447 SockaddrStorage storage
;
2448 MakeIPv6Address(addr
, 361, &storage
);
2449 std::string result
= NetAddressToStringWithPort(storage
.addr
,
2452 // May fail on systems that don't support IPv6.
2453 if (!result
.empty())
2454 EXPECT_EQ("[fedc:ba98:7654:3210:fedc:ba98:7654:3210]:361", result
);
2457 TEST(NetUtilTest
, GetHostName
) {
2458 // We can't check the result of GetHostName() directly, since the result
2459 // will differ across machines. Our goal here is to simply exercise the
2460 // code path, and check that things "look about right".
2461 std::string hostname
= GetHostName();
2462 EXPECT_FALSE(hostname
.empty());
2465 TEST(NetUtilTest
, FormatUrl
) {
2466 FormatUrlTypes default_format_type
= kFormatUrlOmitUsernamePassword
;
2467 const UrlTestData tests
[] = {
2468 {"Empty URL", "", "", default_format_type
, UnescapeRule::NORMAL
, L
"", 0},
2471 "http://www.google.com/", "", default_format_type
, UnescapeRule::NORMAL
,
2472 L
"http://www.google.com/", 7},
2474 {"With a port number and a reference",
2475 "http://www.google.com:8080/#\xE3\x82\xB0", "", default_format_type
,
2476 UnescapeRule::NORMAL
,
2477 L
"http://www.google.com:8080/#\x30B0", 7},
2479 // -------- IDN tests --------
2480 {"Japanese IDN with ja",
2481 "http://xn--l8jvb1ey91xtjb.jp", "ja", default_format_type
,
2482 UnescapeRule::NORMAL
, L
"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
2484 {"Japanese IDN with en",
2485 "http://xn--l8jvb1ey91xtjb.jp", "en", default_format_type
,
2486 UnescapeRule::NORMAL
, L
"http://xn--l8jvb1ey91xtjb.jp/", 7},
2488 {"Japanese IDN without any languages",
2489 "http://xn--l8jvb1ey91xtjb.jp", "", default_format_type
,
2490 UnescapeRule::NORMAL
,
2491 // Single script is safe for empty languages.
2492 L
"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
2494 {"mailto: with Japanese IDN",
2495 "mailto:foo@xn--l8jvb1ey91xtjb.jp", "ja", default_format_type
,
2496 UnescapeRule::NORMAL
,
2497 // GURL doesn't assume an email address's domain part as a host name.
2498 L
"mailto:foo@xn--l8jvb1ey91xtjb.jp", 7},
2500 {"file: with Japanese IDN",
2501 "file://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type
,
2502 UnescapeRule::NORMAL
,
2503 L
"file://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 7},
2505 {"ftp: with Japanese IDN",
2506 "ftp://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type
,
2507 UnescapeRule::NORMAL
,
2508 L
"ftp://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 6},
2510 // -------- omit_username_password flag tests --------
2511 {"With username and password, omit_username_password=false",
2512 "http://user:passwd@example.com/foo", "",
2513 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2514 L
"http://user:passwd@example.com/foo", 19},
2516 {"With username and password, omit_username_password=true",
2517 "http://user:passwd@example.com/foo", "", default_format_type
,
2518 UnescapeRule::NORMAL
, L
"http://example.com/foo", 7},
2520 {"With username and no password",
2521 "http://user@example.com/foo", "", default_format_type
,
2522 UnescapeRule::NORMAL
, L
"http://example.com/foo", 7},
2524 {"Just '@' without username and password",
2525 "http://@example.com/foo", "", default_format_type
, UnescapeRule::NORMAL
,
2526 L
"http://example.com/foo", 7},
2528 // GURL doesn't think local-part of an email address is username for URL.
2529 {"mailto:, omit_username_password=true",
2530 "mailto:foo@example.com", "", default_format_type
, UnescapeRule::NORMAL
,
2531 L
"mailto:foo@example.com", 7},
2533 // -------- unescape flag tests --------
2535 "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
2536 "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
2537 "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type
,
2539 // GURL parses %-encoded hostnames into Punycode.
2540 L
"http://xn--qcka1pmc.jp/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
2541 L
"?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", 7},
2543 {"Unescape normally",
2544 "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
2545 "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
2546 "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type
,
2547 UnescapeRule::NORMAL
,
2548 L
"http://xn--qcka1pmc.jp/\x30B0\x30FC\x30B0\x30EB"
2549 L
"?q=\x30B0\x30FC\x30B0\x30EB", 7},
2551 {"Unescape normally with BiDi control character",
2552 "http://example.com/%E2%80%AEabc?q=%E2%80%8Fxy", "en", default_format_type
,
2553 UnescapeRule::NORMAL
, L
"http://example.com/%E2%80%AEabc?q=%E2%80%8Fxy", 7},
2555 {"Unescape normally including unescape spaces",
2556 "http://www.google.com/search?q=Hello%20World", "en", default_format_type
,
2557 UnescapeRule::SPACES
, L
"http://www.google.com/search?q=Hello World", 7},
2560 {"unescape=true with some special characters",
2561 "http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", "",
2562 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2563 L"http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", 25},
2565 // Disabled: the resultant URL becomes "...user%253A:%2540passwd...".
2567 // -------- omit http: --------
2568 {"omit http with user name",
2569 "http://user@example.com/foo", "", kFormatUrlOmitAll
,
2570 UnescapeRule::NORMAL
, L
"example.com/foo", 0},
2573 "http://www.google.com/", "en", kFormatUrlOmitHTTP
,
2574 UnescapeRule::NORMAL
, L
"www.google.com/",
2577 {"omit http with https",
2578 "https://www.google.com/", "en", kFormatUrlOmitHTTP
,
2579 UnescapeRule::NORMAL
, L
"https://www.google.com/",
2582 {"omit http starts with ftp.",
2583 "http://ftp.google.com/", "en", kFormatUrlOmitHTTP
,
2584 UnescapeRule::NORMAL
, L
"http://ftp.google.com/",
2587 // -------- omit trailing slash on bare hostname --------
2588 {"omit slash when it's the entire path",
2589 "http://www.google.com/", "en",
2590 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2591 L
"http://www.google.com", 7},
2592 {"omit slash when there's a ref",
2593 "http://www.google.com/#ref", "en",
2594 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2595 L
"http://www.google.com/#ref", 7},
2596 {"omit slash when there's a query",
2597 "http://www.google.com/?", "en",
2598 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2599 L
"http://www.google.com/?", 7},
2600 {"omit slash when it's not the entire path",
2601 "http://www.google.com/foo", "en",
2602 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2603 L
"http://www.google.com/foo", 7},
2604 {"omit slash for nonstandard URLs",
2605 "data:/", "en", kFormatUrlOmitTrailingSlashOnBareHostname
,
2606 UnescapeRule::NORMAL
, L
"data:/", 5},
2607 {"omit slash for file URLs",
2608 "file:///", "en", kFormatUrlOmitTrailingSlashOnBareHostname
,
2609 UnescapeRule::NORMAL
, L
"file:///", 7},
2611 // -------- view-source: --------
2613 "view-source:http://xn--qcka1pmc.jp/", "ja", default_format_type
,
2614 UnescapeRule::NORMAL
, L
"view-source:http://\x30B0\x30FC\x30B0\x30EB.jp/",
2617 {"view-source of view-source",
2618 "view-source:view-source:http://xn--qcka1pmc.jp/", "ja",
2619 default_format_type
, UnescapeRule::NORMAL
,
2620 L
"view-source:view-source:http://xn--qcka1pmc.jp/", 12},
2622 // view-source should omit http and trailing slash where non-view-source
2624 {"view-source omit http",
2625 "view-source:http://a.b/c", "en", kFormatUrlOmitAll
,
2626 UnescapeRule::NORMAL
, L
"view-source:a.b/c",
2628 {"view-source omit http starts with ftp.",
2629 "view-source:http://ftp.b/c", "en", kFormatUrlOmitAll
,
2630 UnescapeRule::NORMAL
, L
"view-source:http://ftp.b/c",
2632 {"view-source omit slash when it's the entire path",
2633 "view-source:http://a.b/", "en", kFormatUrlOmitAll
,
2634 UnescapeRule::NORMAL
, L
"view-source:a.b",
2638 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
2640 base::string16 formatted
= FormatUrl(
2641 GURL(tests
[i
].input
), tests
[i
].languages
, tests
[i
].format_types
,
2642 tests
[i
].escape_rules
, NULL
, &prefix_len
, NULL
);
2643 EXPECT_EQ(WideToUTF16(tests
[i
].output
), formatted
) << tests
[i
].description
;
2644 EXPECT_EQ(tests
[i
].prefix_len
, prefix_len
) << tests
[i
].description
;
2648 TEST(NetUtilTest
, FormatUrlParsed
) {
2649 // No unescape case.
2650 url_parse::Parsed parsed
;
2651 base::string16 formatted
= FormatUrl(
2652 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2653 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2654 "ja", kFormatUrlOmitNothing
, UnescapeRule::NONE
, &parsed
, NULL
,
2656 EXPECT_EQ(WideToUTF16(
2657 L
"http://%E3%82%B0:%E3%83%BC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
2658 L
"/%E3%82%B0/?q=%E3%82%B0#\x30B0"), formatted
);
2659 EXPECT_EQ(WideToUTF16(L
"%E3%82%B0"),
2660 formatted
.substr(parsed
.username
.begin
, parsed
.username
.len
));
2661 EXPECT_EQ(WideToUTF16(L
"%E3%83%BC"),
2662 formatted
.substr(parsed
.password
.begin
, parsed
.password
.len
));
2663 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
2664 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2665 EXPECT_EQ(WideToUTF16(L
"8080"),
2666 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2667 EXPECT_EQ(WideToUTF16(L
"/%E3%82%B0/"),
2668 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2669 EXPECT_EQ(WideToUTF16(L
"q=%E3%82%B0"),
2670 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2671 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2672 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2675 formatted
= FormatUrl(
2676 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2677 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2678 "ja", kFormatUrlOmitNothing
, UnescapeRule::NORMAL
, &parsed
, NULL
,
2680 EXPECT_EQ(WideToUTF16(L
"http://\x30B0:\x30FC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
2681 L
"/\x30B0/?q=\x30B0#\x30B0"), formatted
);
2682 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2683 formatted
.substr(parsed
.username
.begin
, parsed
.username
.len
));
2684 EXPECT_EQ(WideToUTF16(L
"\x30FC"),
2685 formatted
.substr(parsed
.password
.begin
, parsed
.password
.len
));
2686 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
2687 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2688 EXPECT_EQ(WideToUTF16(L
"8080"),
2689 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2690 EXPECT_EQ(WideToUTF16(L
"/\x30B0/"),
2691 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2692 EXPECT_EQ(WideToUTF16(L
"q=\x30B0"),
2693 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2694 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2695 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2697 // Omit_username_password + unescape case.
2698 formatted
= FormatUrl(
2699 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2700 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2701 "ja", kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
, &parsed
,
2703 EXPECT_EQ(WideToUTF16(L
"http://\x30B0\x30FC\x30B0\x30EB.jp:8080"
2704 L
"/\x30B0/?q=\x30B0#\x30B0"), formatted
);
2705 EXPECT_FALSE(parsed
.username
.is_valid());
2706 EXPECT_FALSE(parsed
.password
.is_valid());
2707 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
2708 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2709 EXPECT_EQ(WideToUTF16(L
"8080"),
2710 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2711 EXPECT_EQ(WideToUTF16(L
"/\x30B0/"),
2712 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2713 EXPECT_EQ(WideToUTF16(L
"q=\x30B0"),
2714 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2715 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2716 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2718 // View-source case.
2720 FormatUrl(GURL("view-source:http://user:passwd@host:81/path?query#ref"),
2722 kFormatUrlOmitUsernamePassword
,
2723 UnescapeRule::NORMAL
,
2727 EXPECT_EQ(WideToUTF16(L
"view-source:http://host:81/path?query#ref"),
2729 EXPECT_EQ(WideToUTF16(L
"view-source:http"),
2730 formatted
.substr(parsed
.scheme
.begin
, parsed
.scheme
.len
));
2731 EXPECT_FALSE(parsed
.username
.is_valid());
2732 EXPECT_FALSE(parsed
.password
.is_valid());
2733 EXPECT_EQ(WideToUTF16(L
"host"),
2734 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2735 EXPECT_EQ(WideToUTF16(L
"81"),
2736 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2737 EXPECT_EQ(WideToUTF16(L
"/path"),
2738 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2739 EXPECT_EQ(WideToUTF16(L
"query"),
2740 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2741 EXPECT_EQ(WideToUTF16(L
"ref"),
2742 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2745 formatted
= FormatUrl(GURL("http://host:8000/a?b=c#d"),
2748 UnescapeRule::NORMAL
,
2752 EXPECT_EQ(WideToUTF16(L
"host:8000/a?b=c#d"), formatted
);
2753 EXPECT_FALSE(parsed
.scheme
.is_valid());
2754 EXPECT_FALSE(parsed
.username
.is_valid());
2755 EXPECT_FALSE(parsed
.password
.is_valid());
2756 EXPECT_EQ(WideToUTF16(L
"host"),
2757 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2758 EXPECT_EQ(WideToUTF16(L
"8000"),
2759 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2760 EXPECT_EQ(WideToUTF16(L
"/a"),
2761 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2762 EXPECT_EQ(WideToUTF16(L
"b=c"),
2763 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2764 EXPECT_EQ(WideToUTF16(L
"d"),
2765 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2767 // omit http starts with ftp case.
2768 formatted
= FormatUrl(GURL("http://ftp.host:8000/a?b=c#d"),
2771 UnescapeRule::NORMAL
,
2775 EXPECT_EQ(WideToUTF16(L
"http://ftp.host:8000/a?b=c#d"), formatted
);
2776 EXPECT_TRUE(parsed
.scheme
.is_valid());
2777 EXPECT_FALSE(parsed
.username
.is_valid());
2778 EXPECT_FALSE(parsed
.password
.is_valid());
2779 EXPECT_EQ(WideToUTF16(L
"http"),
2780 formatted
.substr(parsed
.scheme
.begin
, parsed
.scheme
.len
));
2781 EXPECT_EQ(WideToUTF16(L
"ftp.host"),
2782 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2783 EXPECT_EQ(WideToUTF16(L
"8000"),
2784 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2785 EXPECT_EQ(WideToUTF16(L
"/a"),
2786 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2787 EXPECT_EQ(WideToUTF16(L
"b=c"),
2788 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2789 EXPECT_EQ(WideToUTF16(L
"d"),
2790 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2792 // omit http starts with 'f' case.
2793 formatted
= FormatUrl(GURL("http://f/"),
2796 UnescapeRule::NORMAL
,
2800 EXPECT_EQ(WideToUTF16(L
"f/"), formatted
);
2801 EXPECT_FALSE(parsed
.scheme
.is_valid());
2802 EXPECT_FALSE(parsed
.username
.is_valid());
2803 EXPECT_FALSE(parsed
.password
.is_valid());
2804 EXPECT_FALSE(parsed
.port
.is_valid());
2805 EXPECT_TRUE(parsed
.path
.is_valid());
2806 EXPECT_FALSE(parsed
.query
.is_valid());
2807 EXPECT_FALSE(parsed
.ref
.is_valid());
2808 EXPECT_EQ(WideToUTF16(L
"f"),
2809 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2810 EXPECT_EQ(WideToUTF16(L
"/"),
2811 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2814 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2815 // results in the original GURL, for each ASCII character in the path.
2816 TEST(NetUtilTest
, FormatUrlRoundTripPathASCII
) {
2817 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
2818 GURL
url(std::string("http://www.google.com/") +
2819 static_cast<char>(test_char
));
2821 base::string16 formatted
= FormatUrl(url
,
2823 kFormatUrlOmitUsernamePassword
,
2824 UnescapeRule::NORMAL
,
2828 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2832 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2833 // results in the original GURL, for each escaped ASCII character in the path.
2834 TEST(NetUtilTest
, FormatUrlRoundTripPathEscaped
) {
2835 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
2836 std::string
original_url("http://www.google.com/");
2837 original_url
.push_back('%');
2838 original_url
.append(base::HexEncode(&test_char
, 1));
2840 GURL
url(original_url
);
2842 base::string16 formatted
= FormatUrl(url
,
2844 kFormatUrlOmitUsernamePassword
,
2845 UnescapeRule::NORMAL
,
2849 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2853 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2854 // results in the original GURL, for each ASCII character in the query.
2855 TEST(NetUtilTest
, FormatUrlRoundTripQueryASCII
) {
2856 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
2857 GURL
url(std::string("http://www.google.com/?") +
2858 static_cast<char>(test_char
));
2860 base::string16 formatted
= FormatUrl(url
,
2862 kFormatUrlOmitUsernamePassword
,
2863 UnescapeRule::NORMAL
,
2867 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2871 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2872 // only results in a different GURL for certain characters.
2873 TEST(NetUtilTest
, FormatUrlRoundTripQueryEscaped
) {
2874 // A full list of characters which FormatURL should unescape and GURL should
2875 // not escape again, when they appear in a query string.
2876 const char* kUnescapedCharacters
=
2877 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~";
2878 for (unsigned char test_char
= 0; test_char
< 128; ++test_char
) {
2879 std::string
original_url("http://www.google.com/?");
2880 original_url
.push_back('%');
2881 original_url
.append(base::HexEncode(&test_char
, 1));
2883 GURL
url(original_url
);
2885 base::string16 formatted
= FormatUrl(url
,
2887 kFormatUrlOmitUsernamePassword
,
2888 UnescapeRule::NORMAL
,
2894 strchr(kUnescapedCharacters
, static_cast<char>(test_char
))) {
2895 EXPECT_NE(url
.spec(), GURL(formatted
).spec());
2897 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2902 TEST(NetUtilTest
, FormatUrlWithOffsets
) {
2903 CheckAdjustedOffsets(std::string(), "en", kFormatUrlOmitNothing
,
2904 UnescapeRule::NORMAL
, NULL
);
2906 const size_t basic_offsets
[] = {
2907 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2910 CheckAdjustedOffsets("http://www.google.com/foo/", "en",
2911 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2914 const size_t omit_auth_offsets_1
[] = {
2915 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 7,
2916 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
2918 CheckAdjustedOffsets("http://foo:bar@www.google.com/", "en",
2919 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
2920 omit_auth_offsets_1
);
2922 const size_t omit_auth_offsets_2
[] = {
2923 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, 7, 8, 9, 10, 11, 12, 13, 14,
2924 15, 16, 17, 18, 19, 20, 21
2926 CheckAdjustedOffsets("http://foo@www.google.com/", "en",
2927 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
2928 omit_auth_offsets_2
);
2930 const size_t dont_omit_auth_offsets
[] = {
2931 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2932 kNpos
, kNpos
, 11, 12, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2933 kNpos
, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
2936 // Unescape to "http://foo\x30B0:\x30B0bar@www.google.com".
2937 CheckAdjustedOffsets("http://foo%E3%82%B0:%E3%82%B0bar@www.google.com/", "en",
2938 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2939 dont_omit_auth_offsets
);
2941 const size_t view_source_offsets
[] = {
2942 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, kNpos
,
2943 kNpos
, kNpos
, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
2945 CheckAdjustedOffsets("view-source:http://foo@www.google.com/", "en",
2946 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
2947 view_source_offsets
);
2949 const size_t idn_hostname_offsets_1
[] = {
2950 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2951 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 12,
2952 13, 14, 15, 16, 17, 18, 19
2954 // Convert punycode to "http://\x671d\x65e5\x3042\x3055\x3072.jp/foo/".
2955 CheckAdjustedOffsets("http://xn--l8jvb1ey91xtjb.jp/foo/", "ja",
2956 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2957 idn_hostname_offsets_1
);
2959 const size_t idn_hostname_offsets_2
[] = {
2960 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2961 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 14, 15, kNpos
, kNpos
, kNpos
,
2962 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2963 kNpos
, 19, 20, 21, 22, 23, 24
2965 // Convert punycode to
2966 // "http://test.\x89c6\x9891.\x5317\x4eac\x5927\x5b78.test/".
2967 CheckAdjustedOffsets("http://test.xn--cy2a840a.xn--1lq90ic7f1rc.test/",
2968 "zh-CN", kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2969 idn_hostname_offsets_2
);
2971 const size_t unescape_offsets
[] = {
2972 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2973 21, 22, 23, 24, 25, kNpos
, kNpos
, 26, 27, 28, 29, 30, kNpos
, kNpos
, kNpos
,
2974 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 31, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2975 kNpos
, kNpos
, kNpos
, 32, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2976 kNpos
, 33, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
2978 // Unescape to "http://www.google.com/foo bar/\x30B0\x30FC\x30B0\x30EB".
2979 CheckAdjustedOffsets(
2980 "http://www.google.com/foo%20bar/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB",
2981 "en", kFormatUrlOmitNothing
, UnescapeRule::SPACES
, unescape_offsets
);
2983 const size_t ref_offsets
[] = {
2984 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2985 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, kNpos
, kNpos
, 32, kNpos
, kNpos
,
2988 // Unescape to "http://www.google.com/foo.html#\x30B0\x30B0z".
2989 CheckAdjustedOffsets(
2990 "http://www.google.com/foo.html#\xE3\x82\xB0\xE3\x82\xB0z", "en",
2991 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
, ref_offsets
);
2993 const size_t omit_http_offsets
[] = {
2994 0, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
2997 CheckAdjustedOffsets("http://www.google.com/", "en", kFormatUrlOmitHTTP
,
2998 UnescapeRule::NORMAL
, omit_http_offsets
);
3000 const size_t omit_http_start_with_ftp_offsets
[] = {
3001 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
3003 CheckAdjustedOffsets("http://ftp.google.com/", "en", kFormatUrlOmitHTTP
,
3004 UnescapeRule::NORMAL
, omit_http_start_with_ftp_offsets
);
3006 const size_t omit_all_offsets
[] = {
3007 0, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 0, kNpos
, kNpos
, kNpos
, kNpos
,
3008 0, 1, 2, 3, 4, 5, 6, 7
3010 CheckAdjustedOffsets("http://user@foo.com/", "en", kFormatUrlOmitAll
,
3011 UnescapeRule::NORMAL
, omit_all_offsets
);
3014 TEST(NetUtilTest
, SimplifyUrlForRequest
) {
3016 const char* input_url
;
3017 const char* expected_simplified_url
;
3020 // Reference section should be stripped.
3021 "http://www.google.com:78/foobar?query=1#hash",
3022 "http://www.google.com:78/foobar?query=1",
3025 // Reference section can itself contain #.
3026 "http://192.168.0.1?query=1#hash#10#11#13#14",
3027 "http://192.168.0.1?query=1",
3029 { // Strip username/password.
3030 "http://user:pass@google.com",
3031 "http://google.com/",
3033 { // Strip both the reference and the username/password.
3034 "http://user:pass@google.com:80/sup?yo#X#X",
3035 "http://google.com/sup?yo",
3037 { // Try an HTTPS URL -- strip both the reference and the username/password.
3038 "https://user:pass@google.com:80/sup?yo#X#X",
3039 "https://google.com:80/sup?yo",
3041 { // Try an FTP URL -- strip both the reference and the username/password.
3042 "ftp://user:pass@google.com:80/sup?yo#X#X",
3043 "ftp://google.com:80/sup?yo",
3045 { // Try a nonstandard URL
3046 "foobar://user:pass@google.com:80/sup?yo#X#X",
3047 "foobar://user:pass@google.com:80/sup?yo",
3050 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
3051 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"]: %s", i
,
3052 tests
[i
].input_url
));
3053 GURL
input_url(GURL(tests
[i
].input_url
));
3054 GURL
expected_url(GURL(tests
[i
].expected_simplified_url
));
3055 EXPECT_EQ(expected_url
, SimplifyUrlForRequest(input_url
));
3059 TEST(NetUtilTest
, SetExplicitlyAllowedPortsTest
) {
3060 std::string invalid
[] = { "1,2,a", "'1','2'", "1, 2, 3", "1 0,11,12" };
3061 std::string valid
[] = { "", "1", "1,2", "1,2,3", "10,11,12,13" };
3063 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(invalid
); ++i
) {
3064 SetExplicitlyAllowedPorts(invalid
[i
]);
3065 EXPECT_EQ(0, static_cast<int>(GetCountOfExplicitlyAllowedPorts()));
3068 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(valid
); ++i
) {
3069 SetExplicitlyAllowedPorts(valid
[i
]);
3070 EXPECT_EQ(i
, GetCountOfExplicitlyAllowedPorts());
3074 TEST(NetUtilTest
, GetHostOrSpecFromURL
) {
3075 EXPECT_EQ("example.com",
3076 GetHostOrSpecFromURL(GURL("http://example.com/test")));
3077 EXPECT_EQ("example.com",
3078 GetHostOrSpecFromURL(GURL("http://example.com./test")));
3079 EXPECT_EQ("file:///tmp/test.html",
3080 GetHostOrSpecFromURL(GURL("file:///tmp/test.html")));
3083 TEST(NetUtilTest
, GetAddressFamily
) {
3084 IPAddressNumber number
;
3085 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number
));
3086 EXPECT_EQ(ADDRESS_FAMILY_IPV4
, GetAddressFamily(number
));
3087 EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number
));
3088 EXPECT_EQ(ADDRESS_FAMILY_IPV6
, GetAddressFamily(number
));
3091 // Test that invalid IP literals fail to parse.
3092 TEST(NetUtilTest
, ParseIPLiteralToNumber_FailParse
) {
3093 IPAddressNumber number
;
3095 EXPECT_FALSE(ParseIPLiteralToNumber("bad value", &number
));
3096 EXPECT_FALSE(ParseIPLiteralToNumber("bad:value", &number
));
3097 EXPECT_FALSE(ParseIPLiteralToNumber(std::string(), &number
));
3098 EXPECT_FALSE(ParseIPLiteralToNumber("192.168.0.1:30", &number
));
3099 EXPECT_FALSE(ParseIPLiteralToNumber(" 192.168.0.1 ", &number
));
3100 EXPECT_FALSE(ParseIPLiteralToNumber("[::1]", &number
));
3103 // Test parsing an IPv4 literal.
3104 TEST(NetUtilTest
, ParseIPLiteralToNumber_IPv4
) {
3105 IPAddressNumber number
;
3106 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number
));
3107 EXPECT_EQ("192,168,0,1", DumpIPNumber(number
));
3108 EXPECT_EQ("192.168.0.1", IPAddressToString(number
));
3111 // Test parsing an IPv6 literal.
3112 TEST(NetUtilTest
, ParseIPLiteralToNumber_IPv6
) {
3113 IPAddressNumber number
;
3114 EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number
));
3115 EXPECT_EQ("0,1,171,205,0,0,0,0,0,0,0,3,0,4,0,255", DumpIPNumber(number
));
3116 EXPECT_EQ("1:abcd::3:4:ff", IPAddressToString(number
));
3119 // Test mapping an IPv4 address to an IPv6 address.
3120 TEST(NetUtilTest
, ConvertIPv4NumberToIPv6Number
) {
3121 IPAddressNumber ipv4_number
;
3122 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &ipv4_number
));
3124 IPAddressNumber ipv6_number
=
3125 ConvertIPv4NumberToIPv6Number(ipv4_number
);
3127 // ::ffff:192.168.0.1
3128 EXPECT_EQ("0,0,0,0,0,0,0,0,0,0,255,255,192,168,0,1",
3129 DumpIPNumber(ipv6_number
));
3130 EXPECT_EQ("::ffff:c0a8:1", IPAddressToString(ipv6_number
));
3133 TEST(NetUtilTest
, IsIPv4Mapped
) {
3134 IPAddressNumber ipv4_number
;
3135 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &ipv4_number
));
3136 EXPECT_FALSE(IsIPv4Mapped(ipv4_number
));
3138 IPAddressNumber ipv6_number
;
3139 EXPECT_TRUE(ParseIPLiteralToNumber("::1", &ipv4_number
));
3140 EXPECT_FALSE(IsIPv4Mapped(ipv6_number
));
3142 IPAddressNumber ipv4mapped_number
;
3143 EXPECT_TRUE(ParseIPLiteralToNumber("::ffff:0101:1", &ipv4mapped_number
));
3144 EXPECT_TRUE(IsIPv4Mapped(ipv4mapped_number
));
3147 TEST(NetUtilTest
, ConvertIPv4MappedToIPv4
) {
3148 IPAddressNumber ipv4mapped_number
;
3149 EXPECT_TRUE(ParseIPLiteralToNumber("::ffff:0101:1", &ipv4mapped_number
));
3150 IPAddressNumber expected
;
3151 EXPECT_TRUE(ParseIPLiteralToNumber("1.1.0.1", &expected
));
3152 IPAddressNumber result
= ConvertIPv4MappedToIPv4(ipv4mapped_number
);
3153 EXPECT_EQ(expected
, result
);
3156 // Test parsing invalid CIDR notation literals.
3157 TEST(NetUtilTest
, ParseCIDRBlock_Invalid
) {
3158 const char* bad_literals
[] = {
3174 for (size_t i
= 0; i
< arraysize(bad_literals
); ++i
) {
3175 IPAddressNumber ip_number
;
3176 size_t prefix_length_in_bits
;
3178 EXPECT_FALSE(ParseCIDRBlock(bad_literals
[i
],
3180 &prefix_length_in_bits
));
3184 // Test parsing a valid CIDR notation literal.
3185 TEST(NetUtilTest
, ParseCIDRBlock_Valid
) {
3186 IPAddressNumber ip_number
;
3187 size_t prefix_length_in_bits
;
3189 EXPECT_TRUE(ParseCIDRBlock("192.168.0.1/11",
3191 &prefix_length_in_bits
));
3193 EXPECT_EQ("192,168,0,1", DumpIPNumber(ip_number
));
3194 EXPECT_EQ(11u, prefix_length_in_bits
);
3197 TEST(NetUtilTest
, IPNumberMatchesPrefix
) {
3199 const char* cidr_literal
;
3200 const char* ip_literal
;
3201 bool expected_to_match
;
3203 // IPv4 prefix with IPv4 inputs.
3220 // IPv6 prefix with IPv6 inputs.
3232 // IPv6 prefix with IPv4 inputs.
3239 "::ffff:192.168.0.1/112",
3244 // IPv4 prefix with IPv6 inputs.
3252 "::ffff:10.12.33.44",
3256 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
3257 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"]: %s, %s", i
,
3258 tests
[i
].cidr_literal
,
3259 tests
[i
].ip_literal
));
3261 IPAddressNumber ip_number
;
3262 EXPECT_TRUE(ParseIPLiteralToNumber(tests
[i
].ip_literal
, &ip_number
));
3264 IPAddressNumber ip_prefix
;
3265 size_t prefix_length_in_bits
;
3267 EXPECT_TRUE(ParseCIDRBlock(tests
[i
].cidr_literal
,
3269 &prefix_length_in_bits
));
3271 EXPECT_EQ(tests
[i
].expected_to_match
,
3272 IPNumberMatchesPrefix(ip_number
,
3274 prefix_length_in_bits
));
3278 TEST(NetUtilTest
, IsLocalhost
) {
3279 EXPECT_TRUE(net::IsLocalhost("localhost"));
3280 EXPECT_TRUE(net::IsLocalhost("localhost.localdomain"));
3281 EXPECT_TRUE(net::IsLocalhost("localhost6"));
3282 EXPECT_TRUE(net::IsLocalhost("localhost6.localdomain6"));
3283 EXPECT_TRUE(net::IsLocalhost("127.0.0.1"));
3284 EXPECT_TRUE(net::IsLocalhost("127.0.1.0"));
3285 EXPECT_TRUE(net::IsLocalhost("127.1.0.0"));
3286 EXPECT_TRUE(net::IsLocalhost("127.0.0.255"));
3287 EXPECT_TRUE(net::IsLocalhost("127.0.255.0"));
3288 EXPECT_TRUE(net::IsLocalhost("127.255.0.0"));
3289 EXPECT_TRUE(net::IsLocalhost("::1"));
3290 EXPECT_TRUE(net::IsLocalhost("0:0:0:0:0:0:0:1"));
3292 EXPECT_FALSE(net::IsLocalhost("localhostx"));
3293 EXPECT_FALSE(net::IsLocalhost("foo.localdomain"));
3294 EXPECT_FALSE(net::IsLocalhost("localhost6x"));
3295 EXPECT_FALSE(net::IsLocalhost("localhost.localdomain6"));
3296 EXPECT_FALSE(net::IsLocalhost("localhost6.localdomain"));
3297 EXPECT_FALSE(net::IsLocalhost("127.0.0.1.1"));
3298 EXPECT_FALSE(net::IsLocalhost(".127.0.0.255"));
3299 EXPECT_FALSE(net::IsLocalhost("::2"));
3300 EXPECT_FALSE(net::IsLocalhost("::1:1"));
3301 EXPECT_FALSE(net::IsLocalhost("0:0:0:0:1:0:0:1"));
3302 EXPECT_FALSE(net::IsLocalhost("::1:1"));
3303 EXPECT_FALSE(net::IsLocalhost("0:0:0:0:0:0:0:0:1"));
3306 // Verify GetNetworkList().
3307 TEST(NetUtilTest
, GetNetworkList
) {
3308 NetworkInterfaceList list
;
3309 ASSERT_TRUE(GetNetworkList(&list
, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES
));
3310 for (NetworkInterfaceList::iterator it
= list
.begin();
3311 it
!= list
.end(); ++it
) {
3312 // Verify that the names are not empty.
3313 EXPECT_FALSE(it
->name
.empty());
3314 EXPECT_FALSE(it
->friendly_name
.empty());
3316 // Verify that the address is correct.
3317 EXPECT_TRUE(it
->address
.size() == kIPv4AddressSize
||
3318 it
->address
.size() == kIPv6AddressSize
)
3319 << "Invalid address of size " << it
->address
.size();
3320 bool all_zeroes
= true;
3321 for (size_t i
= 0; i
< it
->address
.size(); ++i
) {
3322 if (it
->address
[i
] != 0) {
3327 EXPECT_FALSE(all_zeroes
);
3328 EXPECT_GT(it
->network_prefix
, 1u);
3329 EXPECT_LE(it
->network_prefix
, it
->address
.size() * 8);
3332 // On Windows |name| is NET_LUID.
3333 base::ScopedNativeLibrary
phlpapi_lib(
3334 base::FilePath(FILE_PATH_LITERAL("iphlpapi.dll")));
3335 ASSERT_TRUE(phlpapi_lib
.is_valid());
3336 typedef NETIO_STATUS (WINAPI
* ConvertInterfaceIndexToLuid
)(NET_IFINDEX
,
3338 ConvertInterfaceIndexToLuid interface_to_luid
=
3339 reinterpret_cast<ConvertInterfaceIndexToLuid
>(
3340 phlpapi_lib
.GetFunctionPointer("ConvertInterfaceIndexToLuid"));
3342 typedef NETIO_STATUS (WINAPI
* ConvertInterfaceLuidToGuid
)(NET_LUID
*,
3344 ConvertInterfaceLuidToGuid luid_to_guid
=
3345 reinterpret_cast<ConvertInterfaceLuidToGuid
>(
3346 phlpapi_lib
.GetFunctionPointer("ConvertInterfaceLuidToGuid"));
3348 if (interface_to_luid
&& luid_to_guid
) {
3350 EXPECT_EQ(interface_to_luid(it
->interface_index
, &luid
), NO_ERROR
);
3352 EXPECT_EQ(luid_to_guid(&luid
, &guid
), NO_ERROR
);
3354 StringFromCLSID(guid
, &name
);
3355 EXPECT_STREQ(base::UTF8ToWide(it
->name
).c_str(), name
);
3356 CoTaskMemFree(name
);
3359 EXPECT_LT(base::win::GetVersion(), base::win::VERSION_VISTA
);
3360 EXPECT_LT(it
->interface_index
, 1u << 24u); // Must fit 0.x.x.x.
3361 EXPECT_NE(it
->interface_index
, 0u); // 0 means to use default.
3363 #elif !defined(OS_ANDROID)
3364 char name
[IF_NAMESIZE
];
3365 EXPECT_TRUE(if_indextoname(it
->interface_index
, name
));
3366 EXPECT_STREQ(it
->name
.c_str(), name
);
3371 static const base::FilePath::CharType
* kSafePortableBasenames
[] = {
3372 FILE_PATH_LITERAL("a"),
3373 FILE_PATH_LITERAL("a.txt"),
3374 FILE_PATH_LITERAL("a b.txt"),
3375 FILE_PATH_LITERAL("a-b.txt"),
3376 FILE_PATH_LITERAL("My Computer"),
3377 FILE_PATH_LITERAL(" Computer"),
3380 static const base::FilePath::CharType
* kUnsafePortableBasenames
[] = {
3381 FILE_PATH_LITERAL(""),
3382 FILE_PATH_LITERAL("."),
3383 FILE_PATH_LITERAL(".."),
3384 FILE_PATH_LITERAL("..."),
3385 FILE_PATH_LITERAL("con"),
3386 FILE_PATH_LITERAL("con.zip"),
3387 FILE_PATH_LITERAL("NUL"),
3388 FILE_PATH_LITERAL("NUL.zip"),
3389 FILE_PATH_LITERAL(".a"),
3390 FILE_PATH_LITERAL("a."),
3391 FILE_PATH_LITERAL("a\"a"),
3392 FILE_PATH_LITERAL("a<a"),
3393 FILE_PATH_LITERAL("a>a"),
3394 FILE_PATH_LITERAL("a?a"),
3395 FILE_PATH_LITERAL("a/"),
3396 FILE_PATH_LITERAL("a\\"),
3397 FILE_PATH_LITERAL("a "),
3398 FILE_PATH_LITERAL("a . ."),
3399 FILE_PATH_LITERAL("My Computer.{a}"),
3400 FILE_PATH_LITERAL("My Computer.{20D04FE0-3AEA-1069-A2D8-08002B30309D}"),
3401 #if !defined(OS_WIN)
3402 FILE_PATH_LITERAL("a\\a"),
3406 static const base::FilePath::CharType
* kSafePortableRelativePaths
[] = {
3407 FILE_PATH_LITERAL("a/a"),
3409 FILE_PATH_LITERAL("a\\a"),
3413 TEST(NetUtilTest
, IsSafePortablePathComponent
) {
3414 for (size_t i
= 0 ; i
< arraysize(kSafePortableBasenames
); ++i
) {
3415 EXPECT_TRUE(IsSafePortablePathComponent(base::FilePath(
3416 kSafePortableBasenames
[i
]))) << kSafePortableBasenames
[i
];
3418 for (size_t i
= 0 ; i
< arraysize(kUnsafePortableBasenames
); ++i
) {
3419 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
3420 kUnsafePortableBasenames
[i
]))) << kUnsafePortableBasenames
[i
];
3422 for (size_t i
= 0 ; i
< arraysize(kSafePortableRelativePaths
); ++i
) {
3423 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
3424 kSafePortableRelativePaths
[i
]))) << kSafePortableRelativePaths
[i
];
3428 TEST(NetUtilTest
, IsSafePortableRelativePath
) {
3429 base::FilePath
safe_dirname(FILE_PATH_LITERAL("a"));
3430 for (size_t i
= 0 ; i
< arraysize(kSafePortableBasenames
); ++i
) {
3431 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
3432 kSafePortableBasenames
[i
]))) << kSafePortableBasenames
[i
];
3433 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname
.Append(base::FilePath(
3434 kSafePortableBasenames
[i
])))) << kSafePortableBasenames
[i
];
3436 for (size_t i
= 0 ; i
< arraysize(kSafePortableRelativePaths
); ++i
) {
3437 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
3438 kSafePortableRelativePaths
[i
]))) << kSafePortableRelativePaths
[i
];
3439 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname
.Append(base::FilePath(
3440 kSafePortableRelativePaths
[i
])))) << kSafePortableRelativePaths
[i
];
3442 for (size_t i
= 0 ; i
< arraysize(kUnsafePortableBasenames
); ++i
) {
3443 EXPECT_FALSE(IsSafePortableRelativePath(base::FilePath(
3444 kUnsafePortableBasenames
[i
]))) << kUnsafePortableBasenames
[i
];
3445 if (!base::FilePath::StringType(kUnsafePortableBasenames
[i
]).empty()) {
3446 EXPECT_FALSE(IsSafePortableRelativePath(safe_dirname
.Append(
3447 base::FilePath(kUnsafePortableBasenames
[i
]))))
3448 << kUnsafePortableBasenames
[i
];
3453 struct NonUniqueNameTestData
{
3455 const char* hostname
;
3458 // Google Test pretty-printer.
3459 void PrintTo(const NonUniqueNameTestData
& data
, std::ostream
* os
) {
3460 ASSERT_TRUE(data
.hostname
);
3461 *os
<< " hostname: " << testing::PrintToString(data
.hostname
)
3462 << "; is_unique: " << testing::PrintToString(data
.is_unique
);
3465 const NonUniqueNameTestData kNonUniqueNameTestData
[] = {
3466 // Domains under ICANN-assigned domains.
3467 { true, "google.com" },
3468 { true, "google.co.uk" },
3469 // Domains under private registries.
3470 { true, "appspot.com" },
3471 { true, "test.appspot.com" },
3472 // Unreserved IPv4 addresses (in various forms).
3473 { true, "8.8.8.8" },
3474 { true, "99.64.0.0" },
3475 { true, "212.15.0.0" },
3477 { true, "212.15.0" },
3478 { true, "3557752832" },
3479 // Reserved IPv4 addresses (in various forms).
3480 { false, "192.168.0.0" },
3481 { false, "192.168.0.6" },
3482 { false, "10.0.0.5" },
3484 { false, "10.0.0" },
3485 { false, "3232235526" },
3486 // Unreserved IPv6 addresses.
3487 { true, "FFC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
3488 { true, "2000:ba98:7654:2301:EFCD:BA98:7654:3210" },
3489 // Reserved IPv6 addresses.
3490 { false, "::192.9.5.5" },
3491 { false, "FEED::BEEF" },
3492 { false, "FEC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
3493 // 'internal'/non-IANA assigned domains.
3494 { false, "intranet" },
3495 { false, "intranet." },
3496 { false, "intranet.example" },
3497 { false, "host.intranet.example" },
3498 // gTLDs under discussion, but not yet assigned.
3499 { false, "intranet.corp" },
3500 { false, "example.tech" },
3501 { false, "intranet.internal" },
3502 // Invalid host names are treated as unique - but expected to be
3503 // filtered out before then.
3504 { true, "junk)(£)$*!@~#" },
3505 { true, "w$w.example.com" },
3506 { true, "nocolonsallowed:example" },
3507 { true, "[::4.5.6.9]" },
3510 class NetUtilNonUniqueNameTest
3511 : public testing::TestWithParam
<NonUniqueNameTestData
> {
3513 virtual ~NetUtilNonUniqueNameTest() {}
3516 bool IsUnique(const std::string
& hostname
) {
3517 return !IsHostnameNonUnique(hostname
);
3521 // Test that internal/non-unique names are properly identified as such, but
3522 // that IP addresses and hosts beneath registry-controlled domains are flagged
3524 TEST_P(NetUtilNonUniqueNameTest
, IsHostnameNonUnique
) {
3525 const NonUniqueNameTestData
& test_data
= GetParam();
3527 EXPECT_EQ(test_data
.is_unique
, IsUnique(test_data
.hostname
));
3530 INSTANTIATE_TEST_CASE_P(, NetUtilNonUniqueNameTest
,
3531 testing::ValuesIn(kNonUniqueNameTestData
));