1 // Copyright 2014 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/format_macros.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "testing/gtest/include/gtest/gtest.h"
18 using base::ASCIIToUTF16
;
19 using base::WideToUTF16
;
25 static const size_t kNpos
= base::string16::npos
;
27 const char* kLanguages
[] = {
28 "", "en", "zh-CN", "ja", "ko",
29 "he", "ar", "ru", "el", "fr",
30 "de", "pt", "sv", "th", "hi",
31 "de,en", "el,en", "zh-TW,en", "ko,ja", "he,ru,en",
37 const wchar_t* unicode_output
;
38 const bool unicode_allowed
[arraysize(kLanguages
)];
41 // TODO(jungshik) This is just a random sample of languages and is far
42 // from exhaustive. We may have to generate all the combinations
43 // of languages (powerset of a set of all the languages).
44 const IDNTestCase idn_cases
[] = {
46 {"www.google.com", L
"www.google.com",
47 {true, true, true, true, true,
48 true, true, true, true, true,
49 true, true, true, true, true,
50 true, true, true, true, true,
52 {"www.google.com.", L
"www.google.com.",
53 {true, true, true, true, true,
54 true, true, true, true, true,
55 true, true, true, true, true,
56 true, true, true, true, true,
59 {true, true, true, true, true,
60 true, true, true, true, true,
61 true, true, true, true, true,
62 true, true, true, true, true,
65 {true, true, true, true, true,
66 true, true, true, true, true,
67 true, true, true, true, true,
68 true, true, true, true, true,
71 // Hanzi (Traditional Chinese)
72 {"xn--1lq90ic7f1rc.cn", L
"\x5317\x4eac\x5927\x5b78.cn",
73 {true, false, true, true, false,
74 false, false, false, false, false,
75 false, false, false, false, false,
76 false, false, true, true, false,
78 // Hanzi ('video' in Simplified Chinese : will pass only in zh-CN,zh)
79 {"xn--cy2a840a.com", L
"\x89c6\x9891.com",
80 {true, false, true, false, false,
81 false, false, false, false, false,
82 false, false, false, false, false,
83 false, false, false, false, false,
86 {"www.xn--123-p18d.com", L
"www.\x4e00" L
"123.com",
87 {true, false, true, true, false,
88 false, false, false, false, false,
89 false, false, false, false, false,
90 false, false, true, true, false,
92 // Hanzi + Latin : U+56FD is simplified and is regarded
93 // as not supported in zh-TW.
94 {"www.xn--hello-9n1hm04c.com", L
"www.hello\x4e2d\x56fd.com",
95 {false, false, true, true, false,
96 false, false, false, false, false,
97 false, false, false, false, false,
98 false, false, false, true, false,
100 // Kanji + Kana (Japanese)
101 {"xn--l8jvb1ey91xtjb.jp", L
"\x671d\x65e5\x3042\x3055\x3072.jp",
102 {true, false, false, true, false,
103 false, false, false, false, false,
104 false, false, false, false, false,
105 false, false, false, true, false,
107 // Katakana including U+30FC
108 {"xn--tckm4i2e.jp", L
"\x30b3\x30de\x30fc\x30b9.jp",
109 {true, false, false, true, false,
110 false, false, false, false, false,
111 false, false, false, false, false,
112 false, false, false, true, false,
114 {"xn--3ck7a7g.jp", L
"\u30ce\u30f3\u30bd.jp",
115 {true, false, false, true, false,
116 false, false, false, false, false,
117 false, false, false, false, false,
118 false, false, false, true, false,
120 // Katakana + Latin (Japanese)
121 // TODO(jungshik): Change 'false' in the first element to 'true'
122 // after upgrading to ICU 4.2.1 to use new uspoof_* APIs instead
123 // of our IsIDNComponentInSingleScript().
124 {"xn--e-efusa1mzf.jp", L
"e\x30b3\x30de\x30fc\x30b9.jp",
125 {false, false, false, true, false,
126 false, false, false, false, false,
127 false, false, false, false, false,
128 false, false, false, true, false,
130 {"xn--3bkxe.jp", L
"\x30c8\x309a.jp",
131 {false, false, false, true, false,
132 false, false, false, false, false,
133 false, false, false, false, false,
134 false, false, false, true, false,
137 {"www.xn--or3b17p6jjc.kr", L
"www.\xc804\xc790\xc815\xbd80.kr",
138 {true, false, false, false, true,
139 false, false, false, false, false,
140 false, false, false, false, false,
141 false, false, false, true, false,
143 // b<u-umlaut>cher (German)
144 {"xn--bcher-kva.de", L
"b\x00fc" L
"cher.de",
145 {true, false, false, false, false,
146 false, false, false, false, true,
147 true, false, false, false, false,
148 true, false, false, false, false,
151 {"www.xn--frgbolaget-q5a.se", L
"www.f\x00e4rgbolaget.se",
152 {true, false, false, false, false,
153 false, false, false, false, false,
154 true, false, true, false, false,
155 true, false, false, false, false,
157 // c-cedilla (French)
158 {"www.xn--alliancefranaise-npb.fr", L
"www.alliancefran\x00e7" L
"aise.fr",
159 {true, false, false, false, false,
160 false, false, false, false, true,
161 false, true, false, false, false,
162 false, false, false, false, false,
164 // caf'e with acute accent' (French)
165 {"xn--caf-dma.fr", L
"caf\x00e9.fr",
166 {true, false, false, false, false,
167 false, false, false, false, true,
168 false, true, true, false, false,
169 false, false, false, false, false,
171 // c-cedillla and a with tilde (Portuguese)
172 {"xn--poema-9qae5a.com.br", L
"p\x00e3oema\x00e7\x00e3.com.br",
173 {true, false, false, false, false,
174 false, false, false, false, false,
175 false, true, false, false, false,
176 false, false, false, false, false,
179 {"xn--achy-f6a.com", L
"\x0161" L
"achy.com",
180 {true, false, false, false, false,
181 false, false, false, false, false,
182 false, false, false, false, false,
183 false, false, false, false, false,
185 // TODO(jungshik) : Add examples with Cyrillic letters
186 // only used in some languages written in Cyrillic.
188 {"xn--kxae4bafwg.gr", L
"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1.gr",
189 {true, false, false, false, false,
190 false, false, false, true, false,
191 false, false, false, false, false,
192 false, true, false, false, false,
194 // Eutopia + 123 (Greek)
195 {"xn---123-pldm0haj2bk.gr",
196 L
"\x03bf\x03c5\x03c4\x03bf\x03c0\x03af\x03b1-123.gr",
197 {true, false, false, false, false,
198 false, false, false, true, false,
199 false, false, false, false, false,
200 false, true, false, false, false,
202 // Cyrillic (Russian)
203 {"xn--n1aeec9b.ru", L
"\x0442\x043e\x0440\x0442\x044b.ru",
204 {true, false, false, false, false,
205 false, false, true, false, false,
206 false, false, false, false, false,
207 false, false, false, false, true,
209 // Cyrillic + 123 (Russian)
210 {"xn---123-45dmmc5f.ru", L
"\x0442\x043e\x0440\x0442\x044b-123.ru",
211 {true, false, false, false, false,
212 false, false, true, false, false,
213 false, false, false, false, false,
214 false, false, false, false, true,
217 {"xn--mgba1fmg.ar", L
"\x0627\x0641\x0644\x0627\x0645.ar",
218 {true, false, false, false, false,
219 false, true, false, false, false,
220 false, false, false, false, false,
221 false, false, false, false, false,
224 {"xn--4dbib.he", L
"\x05d5\x05d0\x05d4.he",
225 {true, false, false, false, false,
226 true, false, false, false, false,
227 false, false, false, false, false,
228 false, false, false, false, true,
231 {"xn--12c2cc4ag3b4ccu.th",
232 L
"\x0e2a\x0e32\x0e22\x0e01\x0e32\x0e23\x0e1a\x0e34\x0e19.th",
233 {true, false, false, false, false,
234 false, false, false, false, false,
235 false, false, false, true, false,
236 false, false, false, false, false,
239 {"www.xn--l1b6a9e1b7c.in", L
"www.\x0905\x0915\x094b\x0932\x093e.in",
240 {true, false, false, false, false,
241 false, false, false, false, false,
242 false, false, false, false, true,
243 false, false, false, false, false,
246 {"xn--hello?world.com", NULL
,
247 {false, false, false, false, false,
248 false, false, false, false, false,
249 false, false, false, false, false,
250 false, false, false, false, false,
253 // "payp<alpha>l.com"
254 {"www.xn--paypl-g9d.com", L
"payp\x03b1l.com",
255 {false, false, false, false, false,
256 false, false, false, false, false,
257 false, false, false, false, false,
258 false, false, false, false, false,
260 // google.gr with Greek omicron and epsilon
261 {"xn--ggl-6xc1ca.gr", L
"g\x03bf\x03bfgl\x03b5.gr",
262 {false, false, false, false, false,
263 false, false, false, false, false,
264 false, false, false, false, false,
265 false, false, false, false, false,
267 // google.ru with Cyrillic o
268 {"xn--ggl-tdd6ba.ru", L
"g\x043e\x043egl\x0435.ru",
269 {false, false, false, false, false,
270 false, false, false, false, false,
271 false, false, false, false, false,
272 false, false, false, false, false,
274 // h<e with acute>llo<China in Han>.cn
275 {"xn--hllo-bpa7979ih5m.cn", L
"h\x00e9llo\x4e2d\x56fd.cn",
276 {false, false, false, false, false,
277 false, false, false, false, false,
278 false, false, false, false, false,
279 false, false, false, false, false,
281 // <Greek rho><Cyrillic a><Cyrillic u>.ru
282 {"xn--2xa6t2b.ru", L
"\x03c1\x0430\x0443.ru",
283 {false, false, false, false, false,
284 false, false, false, false, false,
285 false, false, false, false, false,
286 false, false, false, false, false,
288 // One that's really long that will force a buffer realloc
289 {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
291 L
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
293 {true, true, true, true, true,
294 true, true, true, true, true,
295 true, true, true, true, true,
296 true, true, true, true, true,
298 // Test cases for characters we blacklisted although allowed in IDN.
299 // Embedded spaces will be turned to %20 in the display.
300 // TODO(jungshik): We need to have more cases. This is a typical
301 // data-driven trap. The following test cases need to be separated
302 // and tested only for a couple of languages.
303 {"xn--osd3820f24c.kr", L
"\xac00\xb098\x115f.kr",
304 {false, false, false, false, false,
305 false, false, false, false, false,
306 false, false, false, false, false,
307 false, false, false, false, false,
309 {"www.xn--google-ho0coa.com", L
"www.\x2039google\x203a.com",
310 {false, false, false, false, false,
311 false, false, false, false, false,
312 false, false, false, false, false,
313 false, false, false, false, false,
315 {"google.xn--comabc-k8d", L
"google.com\x0338" L
"abc",
316 {false, false, false, false, false,
317 false, false, false, false, false,
318 false, false, false, false, false,
319 false, false, false, false, false,
321 {"google.xn--com-oh4ba.evil.jp", L
"google.com\x309a\x309a.evil.jp",
322 {false, false, false, false, false,
323 false, false, false, false, false,
324 false, false, false, false, false,
325 false, false, false, false, false,
327 {"google.xn--comevil-v04f.jp", L
"google.com\x30ce" L
"evil.jp",
328 {false, false, false, false, false,
329 false, false, false, false, false,
330 false, false, false, false, false,
331 false, false, false, false, false,
334 // These two cases are special. We need a separate test.
335 // U+3000 and U+3002 are normalized to ASCII space and dot.
336 {"xn-- -kq6ay5z.cn", L
"\x4e2d\x56fd\x3000.cn",
337 {false, false, true, false, false,
338 false, false, false, false, false,
339 false, false, false, false, false,
340 false, false, true, false, false,
342 {"xn--fiqs8s.cn", L
"\x4e2d\x56fd\x3002" L
"cn",
343 {false, false, true, false, false,
344 false, false, false, false, false,
345 false, false, false, false, false,
346 false, false, true, false, false,
351 struct AdjustOffsetCase
{
353 size_t output_offset
;
357 const char* description
;
359 const char* languages
;
360 FormatUrlTypes format_types
;
361 UnescapeRule::Type escape_rules
;
362 const wchar_t* output
; // Use |wchar_t| to handle Unicode constants easily.
366 // A helper for IDN*{Fast,Slow}.
367 // Append "::<language list>" to |expected| and |actual| to make it
368 // easy to tell which sub-case fails without debugging.
369 void AppendLanguagesToOutputs(const char* languages
,
370 base::string16
* expected
,
371 base::string16
* actual
) {
372 base::string16 to_append
= ASCIIToUTF16("::") + ASCIIToUTF16(languages
);
373 expected
->append(to_append
);
374 actual
->append(to_append
);
377 // A pair of helpers for the FormatUrlWithOffsets() test.
378 void VerboseExpect(size_t expected
,
380 const std::string
& original_url
,
382 const base::string16
& formatted_url
) {
383 EXPECT_EQ(expected
, actual
) << "Original URL: " << original_url
384 << " (at char " << position
<< ")\nFormatted URL: " << formatted_url
;
387 void CheckAdjustedOffsets(const std::string
& url_string
,
388 const std::string
& languages
,
389 FormatUrlTypes format_types
,
390 UnescapeRule::Type unescape_rules
,
391 const size_t* output_offsets
) {
392 GURL
url(url_string
);
393 size_t url_length
= url_string
.length();
394 std::vector
<size_t> offsets
;
395 for (size_t i
= 0; i
<= url_length
+ 1; ++i
)
396 offsets
.push_back(i
);
397 offsets
.push_back(500000); // Something larger than any input length.
398 offsets
.push_back(std::string::npos
);
399 base::string16 formatted_url
= FormatUrlWithOffsets(url
, languages
,
400 format_types
, unescape_rules
, NULL
, NULL
, &offsets
);
401 for (size_t i
= 0; i
< url_length
; ++i
)
402 VerboseExpect(output_offsets
[i
], offsets
[i
], url_string
, i
, formatted_url
);
403 VerboseExpect(formatted_url
.length(), offsets
[url_length
], url_string
,
404 url_length
, formatted_url
);
405 VerboseExpect(base::string16::npos
, offsets
[url_length
+ 1], url_string
,
406 500000, formatted_url
);
407 VerboseExpect(base::string16::npos
, offsets
[url_length
+ 2], url_string
,
408 std::string::npos
, formatted_url
);
411 } // anonymous namespace
413 TEST(NetUtilTest
, IDNToUnicodeFast
) {
414 for (size_t i
= 0; i
< arraysize(idn_cases
); i
++) {
415 for (size_t j
= 0; j
< arraysize(kLanguages
); j
++) {
416 // ja || zh-TW,en || ko,ja -> IDNToUnicodeSlow
417 if (j
== 3 || j
== 17 || j
== 18)
419 base::string16
output(IDNToUnicode(idn_cases
[i
].input
, kLanguages
[j
]));
420 base::string16
expected(idn_cases
[i
].unicode_allowed
[j
] ?
421 WideToUTF16(idn_cases
[i
].unicode_output
) :
422 ASCIIToUTF16(idn_cases
[i
].input
));
423 AppendLanguagesToOutputs(kLanguages
[j
], &expected
, &output
);
424 EXPECT_EQ(expected
, output
);
429 TEST(NetUtilTest
, IDNToUnicodeSlow
) {
430 for (size_t i
= 0; i
< arraysize(idn_cases
); i
++) {
431 for (size_t j
= 0; j
< arraysize(kLanguages
); j
++) {
432 // !(ja || zh-TW,en || ko,ja) -> IDNToUnicodeFast
433 if (!(j
== 3 || j
== 17 || j
== 18))
435 base::string16
output(IDNToUnicode(idn_cases
[i
].input
, kLanguages
[j
]));
436 base::string16
expected(idn_cases
[i
].unicode_allowed
[j
] ?
437 WideToUTF16(idn_cases
[i
].unicode_output
) :
438 ASCIIToUTF16(idn_cases
[i
].input
));
439 AppendLanguagesToOutputs(kLanguages
[j
], &expected
, &output
);
440 EXPECT_EQ(expected
, output
);
445 TEST(NetUtilTest
, StripWWW
) {
446 EXPECT_EQ(base::string16(), StripWWW(base::string16()));
447 EXPECT_EQ(base::string16(), StripWWW(ASCIIToUTF16("www.")));
448 EXPECT_EQ(ASCIIToUTF16("blah"), StripWWW(ASCIIToUTF16("www.blah")));
449 EXPECT_EQ(ASCIIToUTF16("blah"), StripWWW(ASCIIToUTF16("blah")));
452 // This is currently a windows specific function.
456 struct GetDirectoryListingEntryCase
{
458 const char* raw_bytes
;
462 const char* expected
;
467 TEST(NetUtilTest
, GetDirectoryListingEntry
) {
468 const GetDirectoryListingEntryCase test_cases
[] = {
474 "<script>addRow(\"Foo\",\"Foo\",0,\"9.8 kB\",\"\");</script>\n"},
480 "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
487 "<script>addRow(\"quo\\\"tes\",\"quo%22tes\",0,\"9.8 kB\",\"\");</script>"
489 // U+D55C0 U+AE00. raw_bytes is empty (either a local file with
490 // UTF-8/UTF-16 encoding or a remote file on an ftp server using UTF-8
491 {L
"\xD55C\xAE00.txt",
496 "<script>addRow(\"\xED\x95\x9C\xEA\xB8\x80.txt\","
497 "\"%ED%95%9C%EA%B8%80.txt\",0,\"9.8 kB\",\"\");</script>\n"},
498 // U+D55C0 U+AE00. raw_bytes is the corresponding EUC-KR sequence:
499 // a local or remote file in EUC-KR.
500 {L
"\xD55C\xAE00.txt",
501 "\xC7\xD1\xB1\xDB.txt",
505 "<script>addRow(\"\xED\x95\x9C\xEA\xB8\x80.txt\",\"%C7%D1%B1%DB.txt\""
506 ",0,\"9.8 kB\",\"\");</script>\n"},
509 for (size_t i
= 0; i
< arraysize(test_cases
); ++i
) {
510 const std::string results
= GetDirectoryListingEntry(
511 WideToUTF16(test_cases
[i
].name
),
512 test_cases
[i
].raw_bytes
,
513 test_cases
[i
].is_dir
,
514 test_cases
[i
].filesize
,
516 EXPECT_EQ(test_cases
[i
].expected
, results
);
522 TEST(NetUtilTest
, FormatUrl
) {
523 FormatUrlTypes default_format_type
= kFormatUrlOmitUsernamePassword
;
524 const UrlTestData tests
[] = {
525 {"Empty URL", "", "", default_format_type
, UnescapeRule::NORMAL
, L
"", 0},
528 "http://www.google.com/", "", default_format_type
, UnescapeRule::NORMAL
,
529 L
"http://www.google.com/", 7},
531 {"With a port number and a reference",
532 "http://www.google.com:8080/#\xE3\x82\xB0", "", default_format_type
,
533 UnescapeRule::NORMAL
,
534 L
"http://www.google.com:8080/#\x30B0", 7},
536 // -------- IDN tests --------
537 {"Japanese IDN with ja",
538 "http://xn--l8jvb1ey91xtjb.jp", "ja", default_format_type
,
539 UnescapeRule::NORMAL
, L
"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
541 {"Japanese IDN with en",
542 "http://xn--l8jvb1ey91xtjb.jp", "en", default_format_type
,
543 UnescapeRule::NORMAL
, L
"http://xn--l8jvb1ey91xtjb.jp/", 7},
545 {"Japanese IDN without any languages",
546 "http://xn--l8jvb1ey91xtjb.jp", "", default_format_type
,
547 UnescapeRule::NORMAL
,
548 // Single script is safe for empty languages.
549 L
"http://\x671d\x65e5\x3042\x3055\x3072.jp/", 7},
551 {"mailto: with Japanese IDN",
552 "mailto:foo@xn--l8jvb1ey91xtjb.jp", "ja", default_format_type
,
553 UnescapeRule::NORMAL
,
554 // GURL doesn't assume an email address's domain part as a host name.
555 L
"mailto:foo@xn--l8jvb1ey91xtjb.jp", 7},
557 {"file: with Japanese IDN",
558 "file://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type
,
559 UnescapeRule::NORMAL
,
560 L
"file://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 7},
562 {"ftp: with Japanese IDN",
563 "ftp://xn--l8jvb1ey91xtjb.jp/config.sys", "ja", default_format_type
,
564 UnescapeRule::NORMAL
,
565 L
"ftp://\x671d\x65e5\x3042\x3055\x3072.jp/config.sys", 6},
567 // -------- omit_username_password flag tests --------
568 {"With username and password, omit_username_password=false",
569 "http://user:passwd@example.com/foo", "",
570 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
571 L
"http://user:passwd@example.com/foo", 19},
573 {"With username and password, omit_username_password=true",
574 "http://user:passwd@example.com/foo", "", default_format_type
,
575 UnescapeRule::NORMAL
, L
"http://example.com/foo", 7},
577 {"With username and no password",
578 "http://user@example.com/foo", "", default_format_type
,
579 UnescapeRule::NORMAL
, L
"http://example.com/foo", 7},
581 {"Just '@' without username and password",
582 "http://@example.com/foo", "", default_format_type
, UnescapeRule::NORMAL
,
583 L
"http://example.com/foo", 7},
585 // GURL doesn't think local-part of an email address is username for URL.
586 {"mailto:, omit_username_password=true",
587 "mailto:foo@example.com", "", default_format_type
, UnescapeRule::NORMAL
,
588 L
"mailto:foo@example.com", 7},
590 // -------- unescape flag tests --------
592 "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
593 "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
594 "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type
,
596 // GURL parses %-encoded hostnames into Punycode.
597 L
"http://xn--qcka1pmc.jp/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
598 L
"?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", 7},
600 {"Unescape normally",
601 "http://%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB.jp/"
602 "%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB"
603 "?q=%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB", "en", default_format_type
,
604 UnescapeRule::NORMAL
,
605 L
"http://xn--qcka1pmc.jp/\x30B0\x30FC\x30B0\x30EB"
606 L
"?q=\x30B0\x30FC\x30B0\x30EB", 7},
608 {"Unescape normally with BiDi control character",
609 "http://example.com/%E2%80%AEabc?q=%E2%80%8Fxy", "en", default_format_type
,
610 UnescapeRule::NORMAL
, L
"http://example.com/%E2%80%AEabc?q=%E2%80%8Fxy", 7},
612 {"Unescape normally including unescape spaces",
613 "http://www.google.com/search?q=Hello%20World", "en", default_format_type
,
614 UnescapeRule::SPACES
, L
"http://www.google.com/search?q=Hello World", 7},
617 {"unescape=true with some special characters",
618 "http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", "",
619 kFormatUrlOmitNothing, UnescapeRule::NORMAL,
620 L"http://user%3A:%40passwd@example.com/foo%3Fbar?q=b%26z", 25},
622 // Disabled: the resultant URL becomes "...user%253A:%2540passwd...".
624 // -------- omit http: --------
625 {"omit http with user name",
626 "http://user@example.com/foo", "", kFormatUrlOmitAll
,
627 UnescapeRule::NORMAL
, L
"example.com/foo", 0},
630 "http://www.google.com/", "en", kFormatUrlOmitHTTP
,
631 UnescapeRule::NORMAL
, L
"www.google.com/",
634 {"omit http with https",
635 "https://www.google.com/", "en", kFormatUrlOmitHTTP
,
636 UnescapeRule::NORMAL
, L
"https://www.google.com/",
639 {"omit http starts with ftp.",
640 "http://ftp.google.com/", "en", kFormatUrlOmitHTTP
,
641 UnescapeRule::NORMAL
, L
"http://ftp.google.com/",
644 // -------- omit trailing slash on bare hostname --------
645 {"omit slash when it's the entire path",
646 "http://www.google.com/", "en",
647 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
648 L
"http://www.google.com", 7},
649 {"omit slash when there's a ref",
650 "http://www.google.com/#ref", "en",
651 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
652 L
"http://www.google.com/#ref", 7},
653 {"omit slash when there's a query",
654 "http://www.google.com/?", "en",
655 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
656 L
"http://www.google.com/?", 7},
657 {"omit slash when it's not the entire path",
658 "http://www.google.com/foo", "en",
659 kFormatUrlOmitTrailingSlashOnBareHostname
, UnescapeRule::NORMAL
,
660 L
"http://www.google.com/foo", 7},
661 {"omit slash for nonstandard URLs",
662 "data:/", "en", kFormatUrlOmitTrailingSlashOnBareHostname
,
663 UnescapeRule::NORMAL
, L
"data:/", 5},
664 {"omit slash for file URLs",
665 "file:///", "en", kFormatUrlOmitTrailingSlashOnBareHostname
,
666 UnescapeRule::NORMAL
, L
"file:///", 7},
668 // -------- view-source: --------
670 "view-source:http://xn--qcka1pmc.jp/", "ja", default_format_type
,
671 UnescapeRule::NORMAL
, L
"view-source:http://\x30B0\x30FC\x30B0\x30EB.jp/",
674 {"view-source of view-source",
675 "view-source:view-source:http://xn--qcka1pmc.jp/", "ja",
676 default_format_type
, UnescapeRule::NORMAL
,
677 L
"view-source:view-source:http://xn--qcka1pmc.jp/", 12},
679 // view-source should omit http and trailing slash where non-view-source
681 {"view-source omit http",
682 "view-source:http://a.b/c", "en", kFormatUrlOmitAll
,
683 UnescapeRule::NORMAL
, L
"view-source:a.b/c",
685 {"view-source omit http starts with ftp.",
686 "view-source:http://ftp.b/c", "en", kFormatUrlOmitAll
,
687 UnescapeRule::NORMAL
, L
"view-source:http://ftp.b/c",
689 {"view-source omit slash when it's the entire path",
690 "view-source:http://a.b/", "en", kFormatUrlOmitAll
,
691 UnescapeRule::NORMAL
, L
"view-source:a.b",
695 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
697 base::string16 formatted
= FormatUrl(
698 GURL(tests
[i
].input
), tests
[i
].languages
, tests
[i
].format_types
,
699 tests
[i
].escape_rules
, NULL
, &prefix_len
, NULL
);
700 EXPECT_EQ(WideToUTF16(tests
[i
].output
), formatted
) << tests
[i
].description
;
701 EXPECT_EQ(tests
[i
].prefix_len
, prefix_len
) << tests
[i
].description
;
705 TEST(NetUtilTest
, FormatUrlParsed
) {
708 base::string16 formatted
= FormatUrl(
709 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
710 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
711 "ja", kFormatUrlOmitNothing
, UnescapeRule::NONE
, &parsed
, NULL
,
713 EXPECT_EQ(WideToUTF16(
714 L
"http://%E3%82%B0:%E3%83%BC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
715 L
"/%E3%82%B0/?q=%E3%82%B0#\x30B0"), formatted
);
716 EXPECT_EQ(WideToUTF16(L
"%E3%82%B0"),
717 formatted
.substr(parsed
.username
.begin
, parsed
.username
.len
));
718 EXPECT_EQ(WideToUTF16(L
"%E3%83%BC"),
719 formatted
.substr(parsed
.password
.begin
, parsed
.password
.len
));
720 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
721 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
722 EXPECT_EQ(WideToUTF16(L
"8080"),
723 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
724 EXPECT_EQ(WideToUTF16(L
"/%E3%82%B0/"),
725 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
726 EXPECT_EQ(WideToUTF16(L
"q=%E3%82%B0"),
727 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
728 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
729 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
732 formatted
= FormatUrl(
733 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
734 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
735 "ja", kFormatUrlOmitNothing
, UnescapeRule::NORMAL
, &parsed
, NULL
,
737 EXPECT_EQ(WideToUTF16(L
"http://\x30B0:\x30FC@\x30B0\x30FC\x30B0\x30EB.jp:8080"
738 L
"/\x30B0/?q=\x30B0#\x30B0"), formatted
);
739 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
740 formatted
.substr(parsed
.username
.begin
, parsed
.username
.len
));
741 EXPECT_EQ(WideToUTF16(L
"\x30FC"),
742 formatted
.substr(parsed
.password
.begin
, parsed
.password
.len
));
743 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
744 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
745 EXPECT_EQ(WideToUTF16(L
"8080"),
746 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
747 EXPECT_EQ(WideToUTF16(L
"/\x30B0/"),
748 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
749 EXPECT_EQ(WideToUTF16(L
"q=\x30B0"),
750 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
751 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
752 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
754 // Omit_username_password + unescape case.
755 formatted
= FormatUrl(
756 GURL("http://\xE3\x82\xB0:\xE3\x83\xBC@xn--qcka1pmc.jp:8080/"
757 "%E3%82%B0/?q=%E3%82%B0#\xE3\x82\xB0"),
758 "ja", kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
, &parsed
,
760 EXPECT_EQ(WideToUTF16(L
"http://\x30B0\x30FC\x30B0\x30EB.jp:8080"
761 L
"/\x30B0/?q=\x30B0#\x30B0"), formatted
);
762 EXPECT_FALSE(parsed
.username
.is_valid());
763 EXPECT_FALSE(parsed
.password
.is_valid());
764 EXPECT_EQ(WideToUTF16(L
"\x30B0\x30FC\x30B0\x30EB.jp"),
765 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
766 EXPECT_EQ(WideToUTF16(L
"8080"),
767 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
768 EXPECT_EQ(WideToUTF16(L
"/\x30B0/"),
769 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
770 EXPECT_EQ(WideToUTF16(L
"q=\x30B0"),
771 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
772 EXPECT_EQ(WideToUTF16(L
"\x30B0"),
773 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
777 FormatUrl(GURL("view-source:http://user:passwd@host:81/path?query#ref"),
779 kFormatUrlOmitUsernamePassword
,
780 UnescapeRule::NORMAL
,
784 EXPECT_EQ(WideToUTF16(L
"view-source:http://host:81/path?query#ref"),
786 EXPECT_EQ(WideToUTF16(L
"view-source:http"),
787 formatted
.substr(parsed
.scheme
.begin
, parsed
.scheme
.len
));
788 EXPECT_FALSE(parsed
.username
.is_valid());
789 EXPECT_FALSE(parsed
.password
.is_valid());
790 EXPECT_EQ(WideToUTF16(L
"host"),
791 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
792 EXPECT_EQ(WideToUTF16(L
"81"),
793 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
794 EXPECT_EQ(WideToUTF16(L
"/path"),
795 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
796 EXPECT_EQ(WideToUTF16(L
"query"),
797 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
798 EXPECT_EQ(WideToUTF16(L
"ref"),
799 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
802 formatted
= FormatUrl(GURL("http://host:8000/a?b=c#d"),
805 UnescapeRule::NORMAL
,
809 EXPECT_EQ(WideToUTF16(L
"host:8000/a?b=c#d"), formatted
);
810 EXPECT_FALSE(parsed
.scheme
.is_valid());
811 EXPECT_FALSE(parsed
.username
.is_valid());
812 EXPECT_FALSE(parsed
.password
.is_valid());
813 EXPECT_EQ(WideToUTF16(L
"host"),
814 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
815 EXPECT_EQ(WideToUTF16(L
"8000"),
816 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
817 EXPECT_EQ(WideToUTF16(L
"/a"),
818 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
819 EXPECT_EQ(WideToUTF16(L
"b=c"),
820 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
821 EXPECT_EQ(WideToUTF16(L
"d"),
822 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
824 // omit http starts with ftp case.
825 formatted
= FormatUrl(GURL("http://ftp.host:8000/a?b=c#d"),
828 UnescapeRule::NORMAL
,
832 EXPECT_EQ(WideToUTF16(L
"http://ftp.host:8000/a?b=c#d"), formatted
);
833 EXPECT_TRUE(parsed
.scheme
.is_valid());
834 EXPECT_FALSE(parsed
.username
.is_valid());
835 EXPECT_FALSE(parsed
.password
.is_valid());
836 EXPECT_EQ(WideToUTF16(L
"http"),
837 formatted
.substr(parsed
.scheme
.begin
, parsed
.scheme
.len
));
838 EXPECT_EQ(WideToUTF16(L
"ftp.host"),
839 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
840 EXPECT_EQ(WideToUTF16(L
"8000"),
841 formatted
.substr(parsed
.port
.begin
, parsed
.port
.len
));
842 EXPECT_EQ(WideToUTF16(L
"/a"),
843 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
844 EXPECT_EQ(WideToUTF16(L
"b=c"),
845 formatted
.substr(parsed
.query
.begin
, parsed
.query
.len
));
846 EXPECT_EQ(WideToUTF16(L
"d"),
847 formatted
.substr(parsed
.ref
.begin
, parsed
.ref
.len
));
849 // omit http starts with 'f' case.
850 formatted
= FormatUrl(GURL("http://f/"),
853 UnescapeRule::NORMAL
,
857 EXPECT_EQ(WideToUTF16(L
"f/"), formatted
);
858 EXPECT_FALSE(parsed
.scheme
.is_valid());
859 EXPECT_FALSE(parsed
.username
.is_valid());
860 EXPECT_FALSE(parsed
.password
.is_valid());
861 EXPECT_FALSE(parsed
.port
.is_valid());
862 EXPECT_TRUE(parsed
.path
.is_valid());
863 EXPECT_FALSE(parsed
.query
.is_valid());
864 EXPECT_FALSE(parsed
.ref
.is_valid());
865 EXPECT_EQ(WideToUTF16(L
"f"),
866 formatted
.substr(parsed
.host
.begin
, parsed
.host
.len
));
867 EXPECT_EQ(WideToUTF16(L
"/"),
868 formatted
.substr(parsed
.path
.begin
, parsed
.path
.len
));
871 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
872 // results in the original GURL, for each ASCII character in the path.
873 TEST(NetUtilTest
, FormatUrlRoundTripPathASCII
) {
874 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
875 GURL
url(std::string("http://www.google.com/") +
876 static_cast<char>(test_char
));
878 base::string16 formatted
= FormatUrl(url
,
880 kFormatUrlOmitUsernamePassword
,
881 UnescapeRule::NORMAL
,
885 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
889 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
890 // results in the original GURL, for each escaped ASCII character in the path.
891 TEST(NetUtilTest
, FormatUrlRoundTripPathEscaped
) {
892 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
893 std::string
original_url("http://www.google.com/");
894 original_url
.push_back('%');
895 original_url
.append(base::HexEncode(&test_char
, 1));
897 GURL
url(original_url
);
899 base::string16 formatted
= FormatUrl(url
,
901 kFormatUrlOmitUsernamePassword
,
902 UnescapeRule::NORMAL
,
906 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
910 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
911 // results in the original GURL, for each ASCII character in the query.
912 TEST(NetUtilTest
, FormatUrlRoundTripQueryASCII
) {
913 for (unsigned char test_char
= 32; test_char
< 128; ++test_char
) {
914 GURL
url(std::string("http://www.google.com/?") +
915 static_cast<char>(test_char
));
917 base::string16 formatted
= FormatUrl(url
,
919 kFormatUrlOmitUsernamePassword
,
920 UnescapeRule::NORMAL
,
924 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
928 // Make sure that calling FormatUrl on a GURL and then converting back to a GURL
929 // only results in a different GURL for certain characters.
930 TEST(NetUtilTest
, FormatUrlRoundTripQueryEscaped
) {
931 // A full list of characters which FormatURL should unescape and GURL should
932 // not escape again, when they appear in a query string.
933 const char* kUnescapedCharacters
=
934 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~";
935 for (unsigned char test_char
= 0; test_char
< 128; ++test_char
) {
936 std::string
original_url("http://www.google.com/?");
937 original_url
.push_back('%');
938 original_url
.append(base::HexEncode(&test_char
, 1));
940 GURL
url(original_url
);
942 base::string16 formatted
= FormatUrl(url
,
944 kFormatUrlOmitUsernamePassword
,
945 UnescapeRule::NORMAL
,
951 strchr(kUnescapedCharacters
, static_cast<char>(test_char
))) {
952 EXPECT_NE(url
.spec(), GURL(formatted
).spec());
954 EXPECT_EQ(url
.spec(), GURL(formatted
).spec());
959 TEST(NetUtilTest
, FormatUrlWithOffsets
) {
960 CheckAdjustedOffsets(std::string(), "en", kFormatUrlOmitNothing
,
961 UnescapeRule::NORMAL
, NULL
);
963 const size_t basic_offsets
[] = {
964 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
967 CheckAdjustedOffsets("http://www.google.com/foo/", "en",
968 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
971 const size_t omit_auth_offsets_1
[] = {
972 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 7,
973 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
975 CheckAdjustedOffsets("http://foo:bar@www.google.com/", "en",
976 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
977 omit_auth_offsets_1
);
979 const size_t omit_auth_offsets_2
[] = {
980 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, 7, 8, 9, 10, 11, 12, 13, 14,
981 15, 16, 17, 18, 19, 20, 21
983 CheckAdjustedOffsets("http://foo@www.google.com/", "en",
984 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
985 omit_auth_offsets_2
);
987 const size_t dont_omit_auth_offsets
[] = {
988 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
989 kNpos
, kNpos
, 11, 12, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
990 kNpos
, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
993 // Unescape to "http://foo\x30B0:\x30B0bar@www.google.com".
994 CheckAdjustedOffsets("http://foo%E3%82%B0:%E3%82%B0bar@www.google.com/", "en",
995 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
996 dont_omit_auth_offsets
);
998 const size_t view_source_offsets
[] = {
999 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, kNpos
,
1000 kNpos
, kNpos
, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33
1002 CheckAdjustedOffsets("view-source:http://foo@www.google.com/", "en",
1003 kFormatUrlOmitUsernamePassword
, UnescapeRule::NORMAL
,
1004 view_source_offsets
);
1006 const size_t idn_hostname_offsets_1
[] = {
1007 0, 1, 2, 3, 4, 5, 6, 7, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
1008 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 12,
1009 13, 14, 15, 16, 17, 18, 19
1011 // Convert punycode to "http://\x671d\x65e5\x3042\x3055\x3072.jp/foo/".
1012 CheckAdjustedOffsets("http://xn--l8jvb1ey91xtjb.jp/foo/", "ja",
1013 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
1014 idn_hostname_offsets_1
);
1016 const size_t idn_hostname_offsets_2
[] = {
1017 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
1018 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 14, 15, kNpos
, kNpos
, kNpos
,
1019 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
1020 kNpos
, 19, 20, 21, 22, 23, 24
1022 // Convert punycode to
1023 // "http://test.\x89c6\x9891.\x5317\x4eac\x5927\x5b78.test/".
1024 CheckAdjustedOffsets("http://test.xn--cy2a840a.xn--1lq90ic7f1rc.test/",
1025 "zh-CN", kFormatUrlOmitNothing
, UnescapeRule::NORMAL
,
1026 idn_hostname_offsets_2
);
1028 const size_t unescape_offsets
[] = {
1029 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
1030 21, 22, 23, 24, 25, kNpos
, kNpos
, 26, 27, 28, 29, 30, kNpos
, kNpos
, kNpos
,
1031 kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 31, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
1032 kNpos
, kNpos
, kNpos
, 32, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
,
1033 kNpos
, 33, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
1035 // Unescape to "http://www.google.com/foo bar/\x30B0\x30FC\x30B0\x30EB".
1036 CheckAdjustedOffsets(
1037 "http://www.google.com/foo%20bar/%E3%82%B0%E3%83%BC%E3%82%B0%E3%83%AB",
1038 "en", kFormatUrlOmitNothing
, UnescapeRule::SPACES
, unescape_offsets
);
1040 const size_t ref_offsets
[] = {
1041 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
1042 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, kNpos
, kNpos
, 32, kNpos
, kNpos
,
1045 // Unescape to "http://www.google.com/foo.html#\x30B0\x30B0z".
1046 CheckAdjustedOffsets(
1047 "http://www.google.com/foo.html#\xE3\x82\xB0\xE3\x82\xB0z", "en",
1048 kFormatUrlOmitNothing
, UnescapeRule::NORMAL
, ref_offsets
);
1050 const size_t omit_http_offsets
[] = {
1051 0, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
1054 CheckAdjustedOffsets("http://www.google.com/", "en", kFormatUrlOmitHTTP
,
1055 UnescapeRule::NORMAL
, omit_http_offsets
);
1057 const size_t omit_http_start_with_ftp_offsets
[] = {
1058 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21
1060 CheckAdjustedOffsets("http://ftp.google.com/", "en", kFormatUrlOmitHTTP
,
1061 UnescapeRule::NORMAL
, omit_http_start_with_ftp_offsets
);
1063 const size_t omit_all_offsets
[] = {
1064 0, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, kNpos
, 0, kNpos
, kNpos
, kNpos
, kNpos
,
1065 0, 1, 2, 3, 4, 5, 6, 7
1067 CheckAdjustedOffsets("http://user@foo.com/", "en", kFormatUrlOmitAll
,
1068 UnescapeRule::NORMAL
, omit_all_offsets
);