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 including unescape spaces",
2552 "http://www.google.com/search?q=Hello%20World", "en", default_format_type
,
2553 UnescapeRule::SPACES
, L
"http://www.google.com/search?q=Hello World", 7},
2556 {"unescape=true with some special characters",
2557 "http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", "",
2558 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
2559 L"http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", 25},
2561 // Disabled: the resultant URL becomes "...user%253A:%2540passwd...".
2563 // -------- omit http: --------
2564 {"omit http with user name",
2565 "http://user@example.com/foo", "", kFormatUrlOmitAll
,
2566 UnescapeRule::NORMAL
, L
"example.com/foo", 0},
2569 "http://www.google.com/", "en", kFormatUrlOmitHTTP
,
2570 UnescapeRule::NORMAL
, L
"www.google.com/",
2573 {"omit http with https",
2574 "https://www.google.com/", "en", kFormatUrlOmitHTTP
,
2575 UnescapeRule::NORMAL
, L
"https://www.google.com/",
2578 {"omit http starts with ftp.",
2579 "http://ftp.google.com/", "en", kFormatUrlOmitHTTP
,
2580 UnescapeRule::NORMAL
, L
"http://ftp.google.com/",
2583 // -------- omit trailing slash on bare hostname --------
2584 {"omit slash when it's the entire path",
2585 "http://www.google.com/", "en",
2586 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2587 L
"http://www.google.com", 7},
2588 {"omit slash when there's a ref",
2589 "http://www.google.com/#ref", "en",
2590 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2591 L
"http://www.google.com/#ref", 7},
2592 {"omit slash when there's a query",
2593 "http://www.google.com/?", "en",
2594 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2595 L
"http://www.google.com/?", 7},
2596 {"omit slash when it's not the entire path",
2597 "http://www.google.com/foo", "en",
2598 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
2599 L
"http://www.google.com/foo", 7},
2600 {"omit slash for nonstandard URLs",
2601 "data:/", "en", kFormatUrlOmitTrailingSlashOnBareHostname
,
2602 UnescapeRule::NORMAL
, L
"data:/", 5},
2603 {"omit slash for file URLs",
2604 "file:///", "en", kFormatUrlOmitTrailingSlashOnBareHostname
,
2605 UnescapeRule::NORMAL
, L
"file:///", 7},
2607 // -------- view-source: --------
2609 "view-source:http://xn--qcka1pmc.jp/", "ja", default_format_type
,
2610 UnescapeRule::NORMAL
, L
"view-source:http://\x30B0\x30FC\x30B0\x30EB.jp/",
2613 {"view-source of view-source",
2614 "view-source:view-source:http://xn--qcka1pmc.jp/", "ja",
2615 default_format_type
, UnescapeRule::NORMAL
,
2616 L
"view-source:view-source:http://xn--qcka1pmc.jp/", 12},
2618 // view-source should omit http and trailing slash where non-view-source
2620 {"view-source omit http",
2621 "view-source:http://a.b/c", "en", kFormatUrlOmitAll
,
2622 UnescapeRule::NORMAL
, L
"view-source:a.b/c",
2624 {"view-source omit http starts with ftp.",
2625 "view-source:http://ftp.b/c", "en", kFormatUrlOmitAll
,
2626 UnescapeRule::NORMAL
, L
"view-source:http://ftp.b/c",
2628 {"view-source omit slash when it's the entire path",
2629 "view-source:http://a.b/", "en", kFormatUrlOmitAll
,
2630 UnescapeRule::NORMAL
, L
"view-source:a.b",
2634 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
2636 base::string16 formatted
= FormatUrl(
2637 GURL(tests
[i
].input
), tests
[i
].languages
, tests
[i
].format_types
,
2638 tests
[i
].escape_rules
, NULL
, &prefix_len
, NULL
);
2639 EXPECT_EQ(WideToUTF16(tests
[i
].output
), formatted
) << tests
[i
].description
;
2640 EXPECT_EQ(tests
[i
].prefix_len
, prefix_len
) << tests
[i
].description
;
2644 TEST(NetUtilTest
, FormatUrlParsed
) {
2645 // No unescape case.
2646 url_parse::Parsed parsed
;
2647 base::string16 formatted
= FormatUrl(
2648 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2649 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2650 "ja", kFormatUrlOmitNothing
, UnescapeRule::NONE
, &parsed
, NULL
,
2652 EXPECT_EQ(WideToUTF16(
2653 L
"http://%E3%82%B0:%E3%83%BC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
2654 L
"/%E3%82%B0/?q=%E3%82%B0#\x30B0"), formatted
);
2655 EXPECT_EQ(WideToUTF16(L
"%E3%82%B0"),
2656 formatted
.substr(parsed
.username
.begin
, parsed
.username
.len
));
2657 EXPECT_EQ(WideToUTF16(L
"%E3%83%BC"),
2658 formatted
.substr(parsed
.password
.begin
, parsed
.password
.len
));
2659 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
2660 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2661 EXPECT_EQ(WideToUTF16(L
"8080"),
2662 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2663 EXPECT_EQ(WideToUTF16(L
"/%E3%82%B0/"),
2664 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2665 EXPECT_EQ(WideToUTF16(L
"q=%E3%82%B0"),
2666 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2667 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2668 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2671 formatted
= FormatUrl(
2672 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2673 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2674 "ja", kFormatUrlOmitNothing
, UnescapeRule::NORMAL
, &parsed
, NULL
,
2676 EXPECT_EQ(WideToUTF16(L
"http://\x30B0:\x30FC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
2677 L
"/\x30B0/?q=\x30B0#\x30B0"), formatted
);
2678 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2679 formatted
.substr(parsed
.username
.begin
, parsed
.username
.len
));
2680 EXPECT_EQ(WideToUTF16(L
"\x30FC"),
2681 formatted
.substr(parsed
.password
.begin
, parsed
.password
.len
));
2682 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
2683 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2684 EXPECT_EQ(WideToUTF16(L
"8080"),
2685 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2686 EXPECT_EQ(WideToUTF16(L
"/\x30B0/"),
2687 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2688 EXPECT_EQ(WideToUTF16(L
"q=\x30B0"),
2689 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2690 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2691 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2693 // Omit_username_password + unescape case.
2694 formatted
= FormatUrl(
2695 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
2696 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
2697 "ja", kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
, &parsed
,
2699 EXPECT_EQ(WideToUTF16(L
"http://\x30B0\x30FC\x30B0\x30EB.jp:8080"
2700 L
"/\x30B0/?q=\x30B0#\x30B0"), formatted
);
2701 EXPECT_FALSE(parsed
.username
.is_valid());
2702 EXPECT_FALSE(parsed
.password
.is_valid());
2703 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
2704 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2705 EXPECT_EQ(WideToUTF16(L
"8080"),
2706 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2707 EXPECT_EQ(WideToUTF16(L
"/\x30B0/"),
2708 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2709 EXPECT_EQ(WideToUTF16(L
"q=\x30B0"),
2710 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2711 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
2712 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2714 // View-source case.
2716 FormatUrl(GURL("view-source:http://user:passwd@host:81/path?query#ref"),
2718 kFormatUrlOmitUsernamePassword
,
2719 UnescapeRule::NORMAL
,
2723 EXPECT_EQ(WideToUTF16(L
"view-source:http://host:81/path?query#ref"),
2725 EXPECT_EQ(WideToUTF16(L
"view-source:http"),
2726 formatted
.substr(parsed
.scheme
.begin
, parsed
.scheme
.len
));
2727 EXPECT_FALSE(parsed
.username
.is_valid());
2728 EXPECT_FALSE(parsed
.password
.is_valid());
2729 EXPECT_EQ(WideToUTF16(L
"host"),
2730 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2731 EXPECT_EQ(WideToUTF16(L
"81"),
2732 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2733 EXPECT_EQ(WideToUTF16(L
"/path"),
2734 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2735 EXPECT_EQ(WideToUTF16(L
"query"),
2736 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2737 EXPECT_EQ(WideToUTF16(L
"ref"),
2738 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2741 formatted
= FormatUrl(GURL("http://host:8000/a?b=c#d"),
2744 UnescapeRule::NORMAL
,
2748 EXPECT_EQ(WideToUTF16(L
"host:8000/a?b=c#d"), formatted
);
2749 EXPECT_FALSE(parsed
.scheme
.is_valid());
2750 EXPECT_FALSE(parsed
.username
.is_valid());
2751 EXPECT_FALSE(parsed
.password
.is_valid());
2752 EXPECT_EQ(WideToUTF16(L
"host"),
2753 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2754 EXPECT_EQ(WideToUTF16(L
"8000"),
2755 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2756 EXPECT_EQ(WideToUTF16(L
"/a"),
2757 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2758 EXPECT_EQ(WideToUTF16(L
"b=c"),
2759 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2760 EXPECT_EQ(WideToUTF16(L
"d"),
2761 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2763 // omit http starts with ftp case.
2764 formatted
= FormatUrl(GURL("http://ftp.host:8000/a?b=c#d"),
2767 UnescapeRule::NORMAL
,
2771 EXPECT_EQ(WideToUTF16(L
"http://ftp.host:8000/a?b=c#d"), formatted
);
2772 EXPECT_TRUE(parsed
.scheme
.is_valid());
2773 EXPECT_FALSE(parsed
.username
.is_valid());
2774 EXPECT_FALSE(parsed
.password
.is_valid());
2775 EXPECT_EQ(WideToUTF16(L
"http"),
2776 formatted
.substr(parsed
.scheme
.begin
, parsed
.scheme
.len
));
2777 EXPECT_EQ(WideToUTF16(L
"ftp.host"),
2778 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2779 EXPECT_EQ(WideToUTF16(L
"8000"),
2780 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
2781 EXPECT_EQ(WideToUTF16(L
"/a"),
2782 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2783 EXPECT_EQ(WideToUTF16(L
"b=c"),
2784 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
2785 EXPECT_EQ(WideToUTF16(L
"d"),
2786 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
2788 // omit http starts with 'f' case.
2789 formatted
= FormatUrl(GURL("http://f/"),
2792 UnescapeRule::NORMAL
,
2796 EXPECT_EQ(WideToUTF16(L
"f/"), formatted
);
2797 EXPECT_FALSE(parsed
.scheme
.is_valid());
2798 EXPECT_FALSE(parsed
.username
.is_valid());
2799 EXPECT_FALSE(parsed
.password
.is_valid());
2800 EXPECT_FALSE(parsed
.port
.is_valid());
2801 EXPECT_TRUE(parsed
.path
.is_valid());
2802 EXPECT_FALSE(parsed
.query
.is_valid());
2803 EXPECT_FALSE(parsed
.ref
.is_valid());
2804 EXPECT_EQ(WideToUTF16(L
"f"),
2805 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
2806 EXPECT_EQ(WideToUTF16(L
"/"),
2807 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
2810 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2811 // results in the original GURL, for each ASCII character in the path.
2812 TEST(NetUtilTest
, FormatUrlRoundTripPathASCII
) {
2813 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
2814 GURL
url(std::string("http://www.google.com/") +
2815 static_cast<char>(test_char
));
2817 base::string16 formatted
= FormatUrl(url
,
2819 kFormatUrlOmitUsernamePassword
,
2820 UnescapeRule::NORMAL
,
2824 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2828 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2829 // results in the original GURL, for each escaped ASCII character in the path.
2830 TEST(NetUtilTest
, FormatUrlRoundTripPathEscaped
) {
2831 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
2832 std::string
original_url("http://www.google.com/");
2833 original_url
.push_back('%');
2834 original_url
.append(base::HexEncode(&test_char
, 1));
2836 GURL
url(original_url
);
2838 base::string16 formatted
= FormatUrl(url
,
2840 kFormatUrlOmitUsernamePassword
,
2841 UnescapeRule::NORMAL
,
2845 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2849 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2850 // results in the original GURL, for each ASCII character in the query.
2851 TEST(NetUtilTest
, FormatUrlRoundTripQueryASCII
) {
2852 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
2853 GURL
url(std::string("http://www.google.com/?") +
2854 static_cast<char>(test_char
));
2856 base::string16 formatted
= FormatUrl(url
,
2858 kFormatUrlOmitUsernamePassword
,
2859 UnescapeRule::NORMAL
,
2863 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2867 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
2868 // only results in a different GURL for certain characters.
2869 TEST(NetUtilTest
, FormatUrlRoundTripQueryEscaped
) {
2870 // A full list of characters which FormatURL should unescape and GURL should
2871 // not escape again, when they appear in a query string.
2872 const char* kUnescapedCharacters
=
2873 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~";
2874 for (unsigned char test_char
= 0; test_char
< 128; ++test_char
) {
2875 std::string
original_url("http://www.google.com/?");
2876 original_url
.push_back('%');
2877 original_url
.append(base::HexEncode(&test_char
, 1));
2879 GURL
url(original_url
);
2881 base::string16 formatted
= FormatUrl(url
,
2883 kFormatUrlOmitUsernamePassword
,
2884 UnescapeRule::NORMAL
,
2890 strchr(kUnescapedCharacters
, static_cast<char>(test_char
))) {
2891 EXPECT_NE(url
.spec(), GURL(formatted
).spec());
2893 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
2898 TEST(NetUtilTest
, FormatUrlWithOffsets
) {
2899 CheckAdjustedOffsets(std::string(), "en", kFormatUrlOmitNothing
,
2900 UnescapeRule::NORMAL
, NULL
);
2902 const size_t basic_offsets
[] = {
2903 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2906 CheckAdjustedOffsets("http://www.google.com/foo/", "en",
2907 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2910 const size_t omit_auth_offsets_1
[] = {
2911 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 7,
2912 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
2914 CheckAdjustedOffsets("http://foo:bar@www.google.com/", "en",
2915 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
2916 omit_auth_offsets_1
);
2918 const size_t omit_auth_offsets_2
[] = {
2919 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, 7, 8, 9, 10, 11, 12, 13, 14,
2920 15, 16, 17, 18, 19, 20, 21
2922 CheckAdjustedOffsets("http://foo@www.google.com/", "en",
2923 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
2924 omit_auth_offsets_2
);
2926 const size_t dont_omit_auth_offsets
[] = {
2927 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2928 kNpos
, kNpos
, 11, 12, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2929 kNpos
, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
2932 // Unescape to "http://foo\x30B0:\x30B0bar@www.google.com".
2933 CheckAdjustedOffsets("http://foo%E3%82%B0:%E3%82%B0bar@www.google.com/", "en",
2934 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2935 dont_omit_auth_offsets
);
2937 const size_t view_source_offsets
[] = {
2938 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, kNpos
,
2939 kNpos
, kNpos
, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
2941 CheckAdjustedOffsets("view-source:http://foo@www.google.com/", "en",
2942 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
2943 view_source_offsets
);
2945 const size_t idn_hostname_offsets_1
[] = {
2946 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2947 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 12,
2948 13, 14, 15, 16, 17, 18, 19
2950 // Convert punycode to "http://\x671d\x65e5\x3042\x3055\x3072.jp/foo/".
2951 CheckAdjustedOffsets("http://xn--l8jvb1ey91xtjb.jp/foo/", "ja",
2952 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2953 idn_hostname_offsets_1
);
2955 const size_t idn_hostname_offsets_2
[] = {
2956 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2957 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 14, 15, kNpos
, kNpos
, kNpos
,
2958 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2959 kNpos
, 19, 20, 21, 22, 23, 24
2961 // Convert punycode to
2962 // "http://test.\x89c6\x9891.\x5317\x4eac\x5927\x5b78.test/".
2963 CheckAdjustedOffsets("http://test.xn--cy2a840a.xn--1lq90ic7f1rc.test/",
2964 "zh-CN", kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
2965 idn_hostname_offsets_2
);
2967 const size_t unescape_offsets
[] = {
2968 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2969 21, 22, 23, 24, 25, kNpos
, kNpos
, 26, 27, 28, 29, 30, kNpos
, kNpos
, kNpos
,
2970 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 31, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2971 kNpos
, kNpos
, kNpos
, 32, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
2972 kNpos
, 33, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
2974 // Unescape to "http://www.google.com/foo bar/\x30B0\x30FC\x30B0\x30EB".
2975 CheckAdjustedOffsets(
2976 "http://www.google.com/foo%20bar/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB",
2977 "en", kFormatUrlOmitNothing
, UnescapeRule::SPACES
, unescape_offsets
);
2979 const size_t ref_offsets
[] = {
2980 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
2981 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, kNpos
, kNpos
, 32, kNpos
, kNpos
,
2984 // Unescape to "http://www.google.com/foo.html#\x30B0\x30B0z".
2985 CheckAdjustedOffsets(
2986 "http://www.google.com/foo.html#\xE3\x82\xB0\xE3\x82\xB0z", "en",
2987 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
, ref_offsets
);
2989 const size_t omit_http_offsets
[] = {
2990 0, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
2993 CheckAdjustedOffsets("http://www.google.com/", "en", kFormatUrlOmitHTTP
,
2994 UnescapeRule::NORMAL
, omit_http_offsets
);
2996 const size_t omit_http_start_with_ftp_offsets
[] = {
2997 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
2999 CheckAdjustedOffsets("http://ftp.google.com/", "en", kFormatUrlOmitHTTP
,
3000 UnescapeRule::NORMAL
, omit_http_start_with_ftp_offsets
);
3002 const size_t omit_all_offsets
[] = {
3003 0, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 0, kNpos
, kNpos
, kNpos
, kNpos
,
3004 0, 1, 2, 3, 4, 5, 6, 7
3006 CheckAdjustedOffsets("http://user@foo.com/", "en", kFormatUrlOmitAll
,
3007 UnescapeRule::NORMAL
, omit_all_offsets
);
3010 TEST(NetUtilTest
, SimplifyUrlForRequest
) {
3012 const char* input_url
;
3013 const char* expected_simplified_url
;
3016 // Reference section should be stripped.
3017 "http://www.google.com:78/foobar?query=1#hash",
3018 "http://www.google.com:78/foobar?query=1",
3021 // Reference section can itself contain #.
3022 "http://192.168.0.1?query=1#hash#10#11#13#14",
3023 "http://192.168.0.1?query=1",
3025 { // Strip username/password.
3026 "http://user:pass@google.com",
3027 "http://google.com/",
3029 { // Strip both the reference and the username/password.
3030 "http://user:pass@google.com:80/sup?yo#X#X",
3031 "http://google.com/sup?yo",
3033 { // Try an HTTPS URL -- strip both the reference and the username/password.
3034 "https://user:pass@google.com:80/sup?yo#X#X",
3035 "https://google.com:80/sup?yo",
3037 { // Try an FTP URL -- strip both the reference and the username/password.
3038 "ftp://user:pass@google.com:80/sup?yo#X#X",
3039 "ftp://google.com:80/sup?yo",
3041 { // Try a nonstandard URL
3042 "foobar://user:pass@google.com:80/sup?yo#X#X",
3043 "foobar://user:pass@google.com:80/sup?yo",
3046 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
3047 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"]: %s", i
,
3048 tests
[i
].input_url
));
3049 GURL
input_url(GURL(tests
[i
].input_url
));
3050 GURL
expected_url(GURL(tests
[i
].expected_simplified_url
));
3051 EXPECT_EQ(expected_url
, SimplifyUrlForRequest(input_url
));
3055 TEST(NetUtilTest
, SetExplicitlyAllowedPortsTest
) {
3056 std::string invalid
[] = { "1,2,a", "'1','2'", "1, 2, 3", "1 0,11,12" };
3057 std::string valid
[] = { "", "1", "1,2", "1,2,3", "10,11,12,13" };
3059 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(invalid
); ++i
) {
3060 SetExplicitlyAllowedPorts(invalid
[i
]);
3061 EXPECT_EQ(0, static_cast<int>(GetCountOfExplicitlyAllowedPorts()));
3064 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(valid
); ++i
) {
3065 SetExplicitlyAllowedPorts(valid
[i
]);
3066 EXPECT_EQ(i
, GetCountOfExplicitlyAllowedPorts());
3070 TEST(NetUtilTest
, GetHostOrSpecFromURL
) {
3071 EXPECT_EQ("example.com",
3072 GetHostOrSpecFromURL(GURL("http://example.com/test")));
3073 EXPECT_EQ("example.com",
3074 GetHostOrSpecFromURL(GURL("http://example.com./test")));
3075 EXPECT_EQ("file:///tmp/test.html",
3076 GetHostOrSpecFromURL(GURL("file:///tmp/test.html")));
3079 TEST(NetUtilTest
, GetAddressFamily
) {
3080 IPAddressNumber number
;
3081 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number
));
3082 EXPECT_EQ(ADDRESS_FAMILY_IPV4
, GetAddressFamily(number
));
3083 EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number
));
3084 EXPECT_EQ(ADDRESS_FAMILY_IPV6
, GetAddressFamily(number
));
3087 // Test that invalid IP literals fail to parse.
3088 TEST(NetUtilTest
, ParseIPLiteralToNumber_FailParse
) {
3089 IPAddressNumber number
;
3091 EXPECT_FALSE(ParseIPLiteralToNumber("bad value", &number
));
3092 EXPECT_FALSE(ParseIPLiteralToNumber("bad:value", &number
));
3093 EXPECT_FALSE(ParseIPLiteralToNumber(std::string(), &number
));
3094 EXPECT_FALSE(ParseIPLiteralToNumber("192.168.0.1:30", &number
));
3095 EXPECT_FALSE(ParseIPLiteralToNumber(" 192.168.0.1 ", &number
));
3096 EXPECT_FALSE(ParseIPLiteralToNumber("[::1]", &number
));
3099 // Test parsing an IPv4 literal.
3100 TEST(NetUtilTest
, ParseIPLiteralToNumber_IPv4
) {
3101 IPAddressNumber number
;
3102 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &number
));
3103 EXPECT_EQ("192,168,0,1", DumpIPNumber(number
));
3104 EXPECT_EQ("192.168.0.1", IPAddressToString(number
));
3107 // Test parsing an IPv6 literal.
3108 TEST(NetUtilTest
, ParseIPLiteralToNumber_IPv6
) {
3109 IPAddressNumber number
;
3110 EXPECT_TRUE(ParseIPLiteralToNumber("1:abcd::3:4:ff", &number
));
3111 EXPECT_EQ("0,1,171,205,0,0,0,0,0,0,0,3,0,4,0,255", DumpIPNumber(number
));
3112 EXPECT_EQ("1:abcd::3:4:ff", IPAddressToString(number
));
3115 // Test mapping an IPv4 address to an IPv6 address.
3116 TEST(NetUtilTest
, ConvertIPv4NumberToIPv6Number
) {
3117 IPAddressNumber ipv4_number
;
3118 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &ipv4_number
));
3120 IPAddressNumber ipv6_number
=
3121 ConvertIPv4NumberToIPv6Number(ipv4_number
);
3123 // ::ffff:192.168.0.1
3124 EXPECT_EQ("0,0,0,0,0,0,0,0,0,0,255,255,192,168,0,1",
3125 DumpIPNumber(ipv6_number
));
3126 EXPECT_EQ("::ffff:c0a8:1", IPAddressToString(ipv6_number
));
3129 TEST(NetUtilTest
, IsIPv4Mapped
) {
3130 IPAddressNumber ipv4_number
;
3131 EXPECT_TRUE(ParseIPLiteralToNumber("192.168.0.1", &ipv4_number
));
3132 EXPECT_FALSE(IsIPv4Mapped(ipv4_number
));
3134 IPAddressNumber ipv6_number
;
3135 EXPECT_TRUE(ParseIPLiteralToNumber("::1", &ipv4_number
));
3136 EXPECT_FALSE(IsIPv4Mapped(ipv6_number
));
3138 IPAddressNumber ipv4mapped_number
;
3139 EXPECT_TRUE(ParseIPLiteralToNumber("::ffff:0101:1", &ipv4mapped_number
));
3140 EXPECT_TRUE(IsIPv4Mapped(ipv4mapped_number
));
3143 TEST(NetUtilTest
, ConvertIPv4MappedToIPv4
) {
3144 IPAddressNumber ipv4mapped_number
;
3145 EXPECT_TRUE(ParseIPLiteralToNumber("::ffff:0101:1", &ipv4mapped_number
));
3146 IPAddressNumber expected
;
3147 EXPECT_TRUE(ParseIPLiteralToNumber("1.1.0.1", &expected
));
3148 IPAddressNumber result
= ConvertIPv4MappedToIPv4(ipv4mapped_number
);
3149 EXPECT_EQ(expected
, result
);
3152 // Test parsing invalid CIDR notation literals.
3153 TEST(NetUtilTest
, ParseCIDRBlock_Invalid
) {
3154 const char* bad_literals
[] = {
3170 for (size_t i
= 0; i
< arraysize(bad_literals
); ++i
) {
3171 IPAddressNumber ip_number
;
3172 size_t prefix_length_in_bits
;
3174 EXPECT_FALSE(ParseCIDRBlock(bad_literals
[i
],
3176 &prefix_length_in_bits
));
3180 // Test parsing a valid CIDR notation literal.
3181 TEST(NetUtilTest
, ParseCIDRBlock_Valid
) {
3182 IPAddressNumber ip_number
;
3183 size_t prefix_length_in_bits
;
3185 EXPECT_TRUE(ParseCIDRBlock("192.168.0.1/11",
3187 &prefix_length_in_bits
));
3189 EXPECT_EQ("192,168,0,1", DumpIPNumber(ip_number
));
3190 EXPECT_EQ(11u, prefix_length_in_bits
);
3193 TEST(NetUtilTest
, IPNumberMatchesPrefix
) {
3195 const char* cidr_literal
;
3196 const char* ip_literal
;
3197 bool expected_to_match
;
3199 // IPv4 prefix with IPv4 inputs.
3216 // IPv6 prefix with IPv6 inputs.
3228 // IPv6 prefix with IPv4 inputs.
3235 "::ffff:192.168.0.1/112",
3240 // IPv4 prefix with IPv6 inputs.
3248 "::ffff:10.12.33.44",
3252 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
3253 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"]: %s, %s", i
,
3254 tests
[i
].cidr_literal
,
3255 tests
[i
].ip_literal
));
3257 IPAddressNumber ip_number
;
3258 EXPECT_TRUE(ParseIPLiteralToNumber(tests
[i
].ip_literal
, &ip_number
));
3260 IPAddressNumber ip_prefix
;
3261 size_t prefix_length_in_bits
;
3263 EXPECT_TRUE(ParseCIDRBlock(tests
[i
].cidr_literal
,
3265 &prefix_length_in_bits
));
3267 EXPECT_EQ(tests
[i
].expected_to_match
,
3268 IPNumberMatchesPrefix(ip_number
,
3270 prefix_length_in_bits
));
3274 TEST(NetUtilTest
, IsLocalhost
) {
3275 EXPECT_TRUE(net::IsLocalhost("localhost"));
3276 EXPECT_TRUE(net::IsLocalhost("localhost.localdomain"));
3277 EXPECT_TRUE(net::IsLocalhost("localhost6"));
3278 EXPECT_TRUE(net::IsLocalhost("localhost6.localdomain6"));
3279 EXPECT_TRUE(net::IsLocalhost("127.0.0.1"));
3280 EXPECT_TRUE(net::IsLocalhost("127.0.1.0"));
3281 EXPECT_TRUE(net::IsLocalhost("127.1.0.0"));
3282 EXPECT_TRUE(net::IsLocalhost("127.0.0.255"));
3283 EXPECT_TRUE(net::IsLocalhost("127.0.255.0"));
3284 EXPECT_TRUE(net::IsLocalhost("127.255.0.0"));
3285 EXPECT_TRUE(net::IsLocalhost("::1"));
3286 EXPECT_TRUE(net::IsLocalhost("0:0:0:0:0:0:0:1"));
3288 EXPECT_FALSE(net::IsLocalhost("localhostx"));
3289 EXPECT_FALSE(net::IsLocalhost("foo.localdomain"));
3290 EXPECT_FALSE(net::IsLocalhost("localhost6x"));
3291 EXPECT_FALSE(net::IsLocalhost("localhost.localdomain6"));
3292 EXPECT_FALSE(net::IsLocalhost("localhost6.localdomain"));
3293 EXPECT_FALSE(net::IsLocalhost("127.0.0.1.1"));
3294 EXPECT_FALSE(net::IsLocalhost(".127.0.0.255"));
3295 EXPECT_FALSE(net::IsLocalhost("::2"));
3296 EXPECT_FALSE(net::IsLocalhost("::1:1"));
3297 EXPECT_FALSE(net::IsLocalhost("0:0:0:0:1:0:0:1"));
3298 EXPECT_FALSE(net::IsLocalhost("::1:1"));
3299 EXPECT_FALSE(net::IsLocalhost("0:0:0:0:0:0:0:0:1"));
3302 // Verify GetNetworkList().
3303 TEST(NetUtilTest
, GetNetworkList
) {
3304 NetworkInterfaceList list
;
3305 ASSERT_TRUE(GetNetworkList(&list
, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES
));
3306 for (NetworkInterfaceList::iterator it
= list
.begin();
3307 it
!= list
.end(); ++it
) {
3308 // Verify that the name is not empty.
3309 EXPECT_FALSE(it
->name
.empty());
3311 // Verify that the address is correct.
3312 EXPECT_TRUE(it
->address
.size() == kIPv4AddressSize
||
3313 it
->address
.size() == kIPv6AddressSize
)
3314 << "Invalid address of size " << it
->address
.size();
3315 bool all_zeroes
= true;
3316 for (size_t i
= 0; i
< it
->address
.size(); ++i
) {
3317 if (it
->address
[i
] != 0) {
3322 EXPECT_FALSE(all_zeroes
);
3323 EXPECT_GT(it
->network_prefix
, 1u);
3324 EXPECT_LE(it
->network_prefix
, it
->address
.size() * 8);
3327 // On Windows |name| is NET_LUID.
3328 base::ScopedNativeLibrary
phlpapi_lib(
3329 base::FilePath(FILE_PATH_LITERAL("iphlpapi.dll")));
3330 ASSERT_TRUE(phlpapi_lib
.is_valid());
3331 typedef NETIO_STATUS (WINAPI
* ConvertInterfaceIndexToLuid
)(NET_IFINDEX
,
3333 ConvertInterfaceIndexToLuid interface_to_luid
=
3334 reinterpret_cast<ConvertInterfaceIndexToLuid
>(
3335 phlpapi_lib
.GetFunctionPointer("ConvertInterfaceIndexToLuid"));
3337 typedef NETIO_STATUS (WINAPI
* ConvertInterfaceLuidToGuid
)(NET_LUID
*,
3339 ConvertInterfaceLuidToGuid luid_to_guid
=
3340 reinterpret_cast<ConvertInterfaceLuidToGuid
>(
3341 phlpapi_lib
.GetFunctionPointer("ConvertInterfaceLuidToGuid"));
3343 if (interface_to_luid
&& luid_to_guid
) {
3345 EXPECT_EQ(interface_to_luid(it
->interface_index
, &luid
), NO_ERROR
);
3347 EXPECT_EQ(luid_to_guid(&luid
, &guid
), NO_ERROR
);
3349 StringFromCLSID(guid
, &name
);
3350 EXPECT_STREQ(base::UTF8ToWide(it
->name
).c_str(), name
);
3351 CoTaskMemFree(name
);
3354 EXPECT_LT(base::win::GetVersion(), base::win::VERSION_VISTA
);
3355 EXPECT_LT(it
->interface_index
, 1u << 24u); // Must fit 0.x.x.x.
3356 EXPECT_NE(it
->interface_index
, 0u); // 0 means to use default.
3358 #elif !defined(OS_ANDROID)
3359 char name
[IF_NAMESIZE
];
3360 EXPECT_TRUE(if_indextoname(it
->interface_index
, name
));
3361 EXPECT_STREQ(it
->name
.c_str(), name
);
3366 static const base::FilePath::CharType
* kSafePortableBasenames
[] = {
3367 FILE_PATH_LITERAL("a"),
3368 FILE_PATH_LITERAL("a.txt"),
3369 FILE_PATH_LITERAL("a b.txt"),
3370 FILE_PATH_LITERAL("a-b.txt"),
3371 FILE_PATH_LITERAL("My Computer"),
3372 FILE_PATH_LITERAL(" Computer"),
3375 static const base::FilePath::CharType
* kUnsafePortableBasenames
[] = {
3376 FILE_PATH_LITERAL(""),
3377 FILE_PATH_LITERAL("."),
3378 FILE_PATH_LITERAL(".."),
3379 FILE_PATH_LITERAL("..."),
3380 FILE_PATH_LITERAL("con"),
3381 FILE_PATH_LITERAL("con.zip"),
3382 FILE_PATH_LITERAL("NUL"),
3383 FILE_PATH_LITERAL("NUL.zip"),
3384 FILE_PATH_LITERAL(".a"),
3385 FILE_PATH_LITERAL("a."),
3386 FILE_PATH_LITERAL("a\"a"),
3387 FILE_PATH_LITERAL("a<a"),
3388 FILE_PATH_LITERAL("a>a"),
3389 FILE_PATH_LITERAL("a?a"),
3390 FILE_PATH_LITERAL("a/"),
3391 FILE_PATH_LITERAL("a\\"),
3392 FILE_PATH_LITERAL("a "),
3393 FILE_PATH_LITERAL("a . ."),
3394 FILE_PATH_LITERAL("My Computer.{a}"),
3395 FILE_PATH_LITERAL("My Computer.{20D04FE0-3AEA-1069-A2D8-08002B30309D}"),
3396 #if !defined(OS_WIN)
3397 FILE_PATH_LITERAL("a\\a"),
3401 static const base::FilePath::CharType
* kSafePortableRelativePaths
[] = {
3402 FILE_PATH_LITERAL("a/a"),
3404 FILE_PATH_LITERAL("a\\a"),
3408 TEST(NetUtilTest
, IsSafePortablePathComponent
) {
3409 for (size_t i
= 0 ; i
< arraysize(kSafePortableBasenames
); ++i
) {
3410 EXPECT_TRUE(IsSafePortablePathComponent(base::FilePath(
3411 kSafePortableBasenames
[i
]))) << kSafePortableBasenames
[i
];
3413 for (size_t i
= 0 ; i
< arraysize(kUnsafePortableBasenames
); ++i
) {
3414 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
3415 kUnsafePortableBasenames
[i
]))) << kUnsafePortableBasenames
[i
];
3417 for (size_t i
= 0 ; i
< arraysize(kSafePortableRelativePaths
); ++i
) {
3418 EXPECT_FALSE(IsSafePortablePathComponent(base::FilePath(
3419 kSafePortableRelativePaths
[i
]))) << kSafePortableRelativePaths
[i
];
3423 TEST(NetUtilTest
, IsSafePortableRelativePath
) {
3424 base::FilePath
safe_dirname(FILE_PATH_LITERAL("a"));
3425 for (size_t i
= 0 ; i
< arraysize(kSafePortableBasenames
); ++i
) {
3426 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
3427 kSafePortableBasenames
[i
]))) << kSafePortableBasenames
[i
];
3428 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname
.Append(base::FilePath(
3429 kSafePortableBasenames
[i
])))) << kSafePortableBasenames
[i
];
3431 for (size_t i
= 0 ; i
< arraysize(kSafePortableRelativePaths
); ++i
) {
3432 EXPECT_TRUE(IsSafePortableRelativePath(base::FilePath(
3433 kSafePortableRelativePaths
[i
]))) << kSafePortableRelativePaths
[i
];
3434 EXPECT_TRUE(IsSafePortableRelativePath(safe_dirname
.Append(base::FilePath(
3435 kSafePortableRelativePaths
[i
])))) << kSafePortableRelativePaths
[i
];
3437 for (size_t i
= 0 ; i
< arraysize(kUnsafePortableBasenames
); ++i
) {
3438 EXPECT_FALSE(IsSafePortableRelativePath(base::FilePath(
3439 kUnsafePortableBasenames
[i
]))) << kUnsafePortableBasenames
[i
];
3440 if (!base::FilePath::StringType(kUnsafePortableBasenames
[i
]).empty()) {
3441 EXPECT_FALSE(IsSafePortableRelativePath(safe_dirname
.Append(
3442 base::FilePath(kUnsafePortableBasenames
[i
]))))
3443 << kUnsafePortableBasenames
[i
];
3448 struct NonUniqueNameTestData
{
3450 const char* hostname
;
3453 // Google Test pretty-printer.
3454 void PrintTo(const NonUniqueNameTestData
& data
, std::ostream
* os
) {
3455 ASSERT_TRUE(data
.hostname
);
3456 *os
<< " hostname: " << testing::PrintToString(data
.hostname
)
3457 << "; is_unique: " << testing::PrintToString(data
.is_unique
);
3460 const NonUniqueNameTestData kNonUniqueNameTestData
[] = {
3461 // Domains under ICANN-assigned domains.
3462 { true, "google.com" },
3463 { true, "google.co.uk" },
3464 // Domains under private registries.
3465 { true, "appspot.com" },
3466 { true, "test.appspot.com" },
3467 // Unreserved IPv4 addresses (in various forms).
3468 { true, "8.8.8.8" },
3469 { true, "99.64.0.0" },
3470 { true, "212.15.0.0" },
3472 { true, "212.15.0" },
3473 { true, "3557752832" },
3474 // Reserved IPv4 addresses (in various forms).
3475 { false, "192.168.0.0" },
3476 { false, "192.168.0.6" },
3477 { false, "10.0.0.5" },
3479 { false, "10.0.0" },
3480 { false, "3232235526" },
3481 // Unreserved IPv6 addresses.
3482 { true, "FFC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
3483 { true, "2000:ba98:7654:2301:EFCD:BA98:7654:3210" },
3484 // Reserved IPv6 addresses.
3485 { false, "::192.9.5.5" },
3486 { false, "FEED::BEEF" },
3487 { false, "FEC0:ba98:7654:3210:FEDC:BA98:7654:3210" },
3488 // 'internal'/non-IANA assigned domains.
3489 { false, "intranet" },
3490 { false, "intranet." },
3491 { false, "intranet.example" },
3492 { false, "host.intranet.example" },
3493 // gTLDs under discussion, but not yet assigned.
3494 { false, "intranet.corp" },
3495 { false, "example.tech" },
3496 { false, "intranet.internal" },
3497 // Invalid host names are treated as unique - but expected to be
3498 // filtered out before then.
3499 { true, "junk)(£)$*!@~#" },
3500 { true, "w$w.example.com" },
3501 { true, "nocolonsallowed:example" },
3502 { true, "[::4.5.6.9]" },
3505 class NetUtilNonUniqueNameTest
3506 : public testing::TestWithParam
<NonUniqueNameTestData
> {
3508 virtual ~NetUtilNonUniqueNameTest() {}
3511 bool IsUnique(const std::string
& hostname
) {
3512 return !IsHostnameNonUnique(hostname
);
3516 // Test that internal/non-unique names are properly identified as such, but
3517 // that IP addresses and hosts beneath registry-controlled domains are flagged
3519 TEST_P(NetUtilNonUniqueNameTest
, IsHostnameNonUnique
) {
3520 const NonUniqueNameTestData
& test_data
= GetParam();
3522 EXPECT_EQ(test_data
.is_unique
, IsUnique(test_data
.hostname
));
3525 INSTANTIATE_TEST_CASE_P(, NetUtilNonUniqueNameTest
,
3526 testing::ValuesIn(kNonUniqueNameTestData
));