Upload upstream chromium 67.0.3396
[platform/framework/web/chromium-efl.git] / url / url_util_unittest.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6
7 #include "base/macros.h"
8 #include "testing/gtest/include/gtest/gtest.h"
9 #include "url/third_party/mozilla/url_parse.h"
10 #include "url/url_canon.h"
11 #include "url/url_canon_stdstring.h"
12 #include "url/url_test_utils.h"
13 #include "url/url_util.h"
14
15 namespace url {
16
17 class URLUtilTest : public testing::Test {
18  public:
19   URLUtilTest() = default;
20   ~URLUtilTest() override {
21     // Reset any added schemes.
22     Shutdown();
23   }
24
25  private:
26   DISALLOW_COPY_AND_ASSIGN(URLUtilTest);
27 };
28
29 TEST_F(URLUtilTest, FindAndCompareScheme) {
30   Component found_scheme;
31
32   // Simple case where the scheme is found and matches.
33   const char kStr1[] = "http://www.com/";
34   EXPECT_TRUE(FindAndCompareScheme(
35       kStr1, static_cast<int>(strlen(kStr1)), "http", NULL));
36   EXPECT_TRUE(FindAndCompareScheme(
37       kStr1, static_cast<int>(strlen(kStr1)), "http", &found_scheme));
38   EXPECT_TRUE(found_scheme == Component(0, 4));
39
40   // A case where the scheme is found and doesn't match.
41   EXPECT_FALSE(FindAndCompareScheme(
42       kStr1, static_cast<int>(strlen(kStr1)), "https", &found_scheme));
43   EXPECT_TRUE(found_scheme == Component(0, 4));
44
45   // A case where there is no scheme.
46   const char kStr2[] = "httpfoobar";
47   EXPECT_FALSE(FindAndCompareScheme(
48       kStr2, static_cast<int>(strlen(kStr2)), "http", &found_scheme));
49   EXPECT_TRUE(found_scheme == Component());
50
51   // When there is an empty scheme, it should match the empty scheme.
52   const char kStr3[] = ":foo.com/";
53   EXPECT_TRUE(FindAndCompareScheme(
54       kStr3, static_cast<int>(strlen(kStr3)), "", &found_scheme));
55   EXPECT_TRUE(found_scheme == Component(0, 0));
56
57   // But when there is no scheme, it should fail.
58   EXPECT_FALSE(FindAndCompareScheme("", 0, "", &found_scheme));
59   EXPECT_TRUE(found_scheme == Component());
60
61   // When there is a whitespace char in scheme, it should canonicalize the URL
62   // before comparison.
63   const char whtspc_str[] = " \r\n\tjav\ra\nscri\tpt:alert(1)";
64   EXPECT_TRUE(FindAndCompareScheme(whtspc_str,
65                                    static_cast<int>(strlen(whtspc_str)),
66                                    "javascript", &found_scheme));
67   EXPECT_TRUE(found_scheme == Component(1, 10));
68
69   // Control characters should be stripped out on the ends, and kept in the
70   // middle.
71   const char ctrl_str[] = "\02jav\02scr\03ipt:alert(1)";
72   EXPECT_FALSE(FindAndCompareScheme(ctrl_str,
73                                     static_cast<int>(strlen(ctrl_str)),
74                                     "javascript", &found_scheme));
75   EXPECT_TRUE(found_scheme == Component(1, 11));
76 }
77
78 TEST_F(URLUtilTest, IsStandard) {
79   const char kHTTPScheme[] = "http";
80   EXPECT_TRUE(IsStandard(kHTTPScheme, Component(0, strlen(kHTTPScheme))));
81
82   const char kFooScheme[] = "foo";
83   EXPECT_FALSE(IsStandard(kFooScheme, Component(0, strlen(kFooScheme))));
84 }
85
86 TEST_F(URLUtilTest, IsReferrerScheme) {
87   const char kHTTPScheme[] = "http";
88   EXPECT_TRUE(IsReferrerScheme(kHTTPScheme, Component(0, strlen(kHTTPScheme))));
89
90   const char kFooScheme[] = "foo";
91   EXPECT_FALSE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
92 }
93
94 TEST_F(URLUtilTest, AddReferrerScheme) {
95   const char kFooScheme[] = "foo";
96   EXPECT_FALSE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
97   AddReferrerScheme(kFooScheme, url::SCHEME_WITH_HOST);
98   EXPECT_TRUE(IsReferrerScheme(kFooScheme, Component(0, strlen(kFooScheme))));
99 }
100
101 TEST_F(URLUtilTest, GetStandardSchemeType) {
102   url::SchemeType scheme_type;
103
104   const char kHTTPScheme[] = "http";
105   scheme_type = url::SCHEME_WITHOUT_AUTHORITY;
106   EXPECT_TRUE(GetStandardSchemeType(kHTTPScheme,
107                                     Component(0, strlen(kHTTPScheme)),
108                                     &scheme_type));
109   EXPECT_EQ(url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION, scheme_type);
110
111   const char kFilesystemScheme[] = "filesystem";
112   scheme_type = url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION;
113   EXPECT_TRUE(GetStandardSchemeType(kFilesystemScheme,
114                                     Component(0, strlen(kFilesystemScheme)),
115                                     &scheme_type));
116   EXPECT_EQ(url::SCHEME_WITHOUT_AUTHORITY, scheme_type);
117
118   const char kFooScheme[] = "foo";
119   scheme_type = url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION;
120   EXPECT_FALSE(GetStandardSchemeType(kFooScheme,
121                                      Component(0, strlen(kFooScheme)),
122                                      &scheme_type));
123 }
124
125 TEST_F(URLUtilTest, ReplaceComponents) {
126   Parsed parsed;
127   RawCanonOutputT<char> output;
128   Parsed new_parsed;
129
130   // Check that the following calls do not cause crash
131   Replacements<char> replacements;
132   replacements.SetRef("test", Component(0, 4));
133   ReplaceComponents(NULL, 0, parsed, replacements, NULL, &output, &new_parsed);
134   ReplaceComponents("", 0, parsed, replacements, NULL, &output, &new_parsed);
135   replacements.ClearRef();
136   replacements.SetHost("test", Component(0, 4));
137   ReplaceComponents(NULL, 0, parsed, replacements, NULL, &output, &new_parsed);
138   ReplaceComponents("", 0, parsed, replacements, NULL, &output, &new_parsed);
139
140   replacements.ClearHost();
141   ReplaceComponents(NULL, 0, parsed, replacements, NULL, &output, &new_parsed);
142   ReplaceComponents("", 0, parsed, replacements, NULL, &output, &new_parsed);
143   ReplaceComponents(NULL, 0, parsed, replacements, NULL, &output, &new_parsed);
144   ReplaceComponents("", 0, parsed, replacements, NULL, &output, &new_parsed);
145 }
146
147 static std::string CheckReplaceScheme(const char* base_url,
148                                       const char* scheme) {
149   // Make sure the input is canonicalized.
150   RawCanonOutput<32> original;
151   Parsed original_parsed;
152   Canonicalize(base_url, strlen(base_url), true, NULL, &original,
153                &original_parsed);
154
155   Replacements<char> replacements;
156   replacements.SetScheme(scheme, Component(0, strlen(scheme)));
157
158   std::string output_string;
159   StdStringCanonOutput output(&output_string);
160   Parsed output_parsed;
161   ReplaceComponents(original.data(), original.length(), original_parsed,
162                     replacements, NULL, &output, &output_parsed);
163
164   output.Complete();
165   return output_string;
166 }
167
168 TEST_F(URLUtilTest, ReplaceScheme) {
169   EXPECT_EQ("https://google.com/",
170             CheckReplaceScheme("http://google.com/", "https"));
171   EXPECT_EQ("file://google.com/",
172             CheckReplaceScheme("http://google.com/", "file"));
173   EXPECT_EQ("http://home/Build",
174             CheckReplaceScheme("file:///Home/Build", "http"));
175   EXPECT_EQ("javascript:foo",
176             CheckReplaceScheme("about:foo", "javascript"));
177   EXPECT_EQ("://google.com/",
178             CheckReplaceScheme("http://google.com/", ""));
179   EXPECT_EQ("http://google.com/",
180             CheckReplaceScheme("about:google.com", "http"));
181   EXPECT_EQ("http:", CheckReplaceScheme("", "http"));
182
183 #ifdef WIN32
184   // Magic Windows drive letter behavior when converting to a file URL.
185   EXPECT_EQ("file:///E:/foo/",
186             CheckReplaceScheme("http://localhost/e:foo/", "file"));
187 #endif
188
189   // This will probably change to "about://google.com/" when we fix
190   // http://crbug.com/160 which should also be an acceptable result.
191   EXPECT_EQ("about://google.com/",
192             CheckReplaceScheme("http://google.com/", "about"));
193
194   EXPECT_EQ("http://example.com/%20hello%20#%20world",
195             CheckReplaceScheme("myscheme:example.com/ hello # world ", "http"));
196 }
197
198 TEST_F(URLUtilTest, DecodeURLEscapeSequences) {
199   struct DecodeCase {
200     const char* input;
201     const char* output;
202     DecodeURLResult result;
203   } decode_cases[] = {
204       {"hello, world", "hello, world", DecodeURLResult::kAsciiOnly},
205       {"%01%02%03%04%05%06%07%08%09%0a%0B%0C%0D%0e%0f/",
206        "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0B\x0C\x0D\x0e\x0f/",
207        DecodeURLResult::kAsciiOnly},
208       {"%10%11%12%13%14%15%16%17%18%19%1a%1B%1C%1D%1e%1f/",
209        "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1B\x1C\x1D\x1e\x1f/",
210        DecodeURLResult::kAsciiOnly},
211       {"%20%21%22%23%24%25%26%27%28%29%2a%2B%2C%2D%2e%2f/",
212        " !\"#$%&'()*+,-.//", DecodeURLResult::kAsciiOnly},
213       {"%30%31%32%33%34%35%36%37%38%39%3a%3B%3C%3D%3e%3f/", "0123456789:;<=>?/",
214        DecodeURLResult::kAsciiOnly},
215       {"%40%41%42%43%44%45%46%47%48%49%4a%4B%4C%4D%4e%4f/", "@ABCDEFGHIJKLMNO/",
216        DecodeURLResult::kAsciiOnly},
217       {"%50%51%52%53%54%55%56%57%58%59%5a%5B%5C%5D%5e%5f/",
218        "PQRSTUVWXYZ[\\]^_/", DecodeURLResult::kAsciiOnly},
219       {"%60%61%62%63%64%65%66%67%68%69%6a%6B%6C%6D%6e%6f/", "`abcdefghijklmno/",
220        DecodeURLResult::kAsciiOnly},
221       {"%70%71%72%73%74%75%76%77%78%79%7a%7B%7C%7D%7e%7f/",
222        "pqrstuvwxyz{|}~\x7f/", DecodeURLResult::kAsciiOnly},
223       // Test un-UTF-8-ization.
224       {"%e4%bd%a0%e5%a5%bd", "\xe4\xbd\xa0\xe5\xa5\xbd",
225        DecodeURLResult::kUTF8},
226   };
227
228   for (size_t i = 0; i < arraysize(decode_cases); i++) {
229     const char* input = decode_cases[i].input;
230     RawCanonOutputT<base::char16> output;
231     EXPECT_EQ(decode_cases[i].result,
232               DecodeURLEscapeSequences(input, strlen(input), &output));
233     EXPECT_EQ(decode_cases[i].output,
234               base::UTF16ToUTF8(base::string16(output.data(),
235                                                output.length())));
236   }
237
238   // Our decode should decode %00
239   const char zero_input[] = "%00";
240   RawCanonOutputT<base::char16> zero_output;
241   DecodeURLEscapeSequences(zero_input, strlen(zero_input), &zero_output);
242   EXPECT_NE("%00", base::UTF16ToUTF8(
243       base::string16(zero_output.data(), zero_output.length())));
244
245   // Test the error behavior for invalid UTF-8.
246   {
247     const char invalid_input[] = "%e4%a0%e5%a5%bd";
248     const base::char16 invalid_expected[4] = {0x00e4, 0x00a0, 0x597d, 0};
249     RawCanonOutputT<base::char16> invalid_output;
250     EXPECT_EQ(DecodeURLResult::kMixed,
251               DecodeURLEscapeSequences(invalid_input, strlen(invalid_input),
252                                        &invalid_output));
253     EXPECT_EQ(base::string16(invalid_expected),
254               base::string16(invalid_output.data(), invalid_output.length()));
255   }
256   {
257     const char invalid_input[] = "%e4%a0%e5%bd";
258     const base::char16 invalid_expected[5] = {0x00e4, 0x00a0, 0x00e5, 0x00bd,
259                                               0};
260     RawCanonOutputT<base::char16> invalid_output;
261     EXPECT_EQ(DecodeURLResult::kIsomorphic,
262               DecodeURLEscapeSequences(invalid_input, strlen(invalid_input),
263                                        &invalid_output));
264     EXPECT_EQ(base::string16(invalid_expected),
265               base::string16(invalid_output.data(), invalid_output.length()));
266   }
267 }
268
269 TEST_F(URLUtilTest, TestEncodeURIComponent) {
270   struct EncodeCase {
271     const char* input;
272     const char* output;
273   } encode_cases[] = {
274     {"hello, world", "hello%2C%20world"},
275     {"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
276      "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F"},
277     {"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
278      "%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F"},
279     {" !\"#$%&'()*+,-./",
280      "%20!%22%23%24%25%26%27()*%2B%2C-.%2F"},
281     {"0123456789:;<=>?",
282      "0123456789%3A%3B%3C%3D%3E%3F"},
283     {"@ABCDEFGHIJKLMNO",
284      "%40ABCDEFGHIJKLMNO"},
285     {"PQRSTUVWXYZ[\\]^_",
286      "PQRSTUVWXYZ%5B%5C%5D%5E_"},
287     {"`abcdefghijklmno",
288      "%60abcdefghijklmno"},
289     {"pqrstuvwxyz{|}~\x7f",
290      "pqrstuvwxyz%7B%7C%7D~%7F"},
291   };
292
293   for (size_t i = 0; i < arraysize(encode_cases); i++) {
294     const char* input = encode_cases[i].input;
295     RawCanonOutputT<char> buffer;
296     EncodeURIComponent(input, strlen(input), &buffer);
297     std::string output(buffer.data(), buffer.length());
298     EXPECT_EQ(encode_cases[i].output, output);
299   }
300 }
301
302 TEST_F(URLUtilTest, TestResolveRelativeWithNonStandardBase) {
303   // This tests non-standard (in the sense that IsStandard() == false)
304   // hierarchical schemes.
305   struct ResolveRelativeCase {
306     const char* base;
307     const char* rel;
308     bool is_valid;
309     const char* out;
310   } resolve_non_standard_cases[] = {
311       // Resolving a relative path against a non-hierarchical URL should fail.
312       {"scheme:opaque_data", "/path", false, ""},
313       // Resolving a relative path against a non-standard authority-based base
314       // URL doesn't alter the authority section.
315       {"scheme://Authority/", "../path", true, "scheme://Authority/path"},
316       // A non-standard hierarchical base is resolved with path URL
317       // canonicalization rules.
318       {"data:/Blah:Blah/", "file.html", true, "data:/Blah:Blah/file.html"},
319       {"data:/Path/../part/part2", "file.html", true,
320        "data:/Path/../part/file.html"},
321       {"data://text/html,payload", "//user:pass@host:33////payload22", true,
322        "data://user:pass@host:33////payload22"},
323       // Path URL canonicalization rules also apply to non-standard authority-
324       // based URLs.
325       {"custom://Authority/", "file.html", true,
326        "custom://Authority/file.html"},
327       {"custom://Authority/", "other://Auth/", true, "other://Auth/"},
328       {"custom://Authority/", "../../file.html", true,
329        "custom://Authority/file.html"},
330       {"custom://Authority/path/", "file.html", true,
331        "custom://Authority/path/file.html"},
332       {"custom://Authority:NoCanon/path/", "file.html", true,
333        "custom://Authority:NoCanon/path/file.html"},
334       // It's still possible to get an invalid path URL.
335       {"custom://Invalid:!#Auth/", "file.html", false, ""},
336       // A path with an authority section gets canonicalized under standard URL
337       // rules, even though the base was non-standard.
338       {"content://content.Provider/", "//other.Provider", true,
339        "content://other.provider/"},
340
341       // Resolving an absolute URL doesn't cause canonicalization of the
342       // result.
343       {"about:blank", "custom://Authority", true, "custom://Authority"},
344       // Fragment URLs can be resolved against a non-standard base.
345       {"scheme://Authority/path", "#fragment", true,
346        "scheme://Authority/path#fragment"},
347       {"scheme://Authority/", "#fragment", true,
348        "scheme://Authority/#fragment"},
349       // Resolving should fail if the base URL is authority-based but is
350       // missing a path component (the '/' at the end).
351       {"scheme://Authority", "path", false, ""},
352       // Test resolving a fragment (only) against any kind of base-URL.
353       {"about:blank", "#id42", true, "about:blank#id42"},
354       {"about:blank", " #id42", true, "about:blank#id42"},
355       {"about:blank#oldfrag", "#newfrag", true, "about:blank#newfrag"},
356       // A surprising side effect of allowing fragments to resolve against
357       // any URL scheme is we might break javascript: URLs by doing so...
358       {"javascript:alert('foo#bar')", "#badfrag", true,
359        "javascript:alert('foo#badfrag"},
360       // In this case, the backslashes will not be canonicalized because it's a
361       // non-standard URL, but they will be treated as a path separators,
362       // giving the base URL here a path of "\".
363       //
364       // The result here is somewhat arbitrary. One could argue it should be
365       // either "aaa://a\" or "aaa://a/" since the path is being replaced with
366       // the "current directory". But in the context of resolving on data URLs,
367       // adding the requested dot doesn't seem wrong either.
368       {"aaa://a\\", "aaa:.", true, "aaa://a\\."}};
369
370   for (size_t i = 0; i < arraysize(resolve_non_standard_cases); i++) {
371     const ResolveRelativeCase& test_data = resolve_non_standard_cases[i];
372     Parsed base_parsed;
373     ParsePathURL(test_data.base, strlen(test_data.base), false, &base_parsed);
374
375     std::string resolved;
376     StdStringCanonOutput output(&resolved);
377     Parsed resolved_parsed;
378     bool valid = ResolveRelative(test_data.base, strlen(test_data.base),
379                                  base_parsed, test_data.rel,
380                                  strlen(test_data.rel), NULL, &output,
381                                  &resolved_parsed);
382     output.Complete();
383
384     EXPECT_EQ(test_data.is_valid, valid) << i;
385     if (test_data.is_valid && valid)
386       EXPECT_EQ(test_data.out, resolved) << i;
387   }
388 }
389
390 TEST_F(URLUtilTest, TestNoRefComponent) {
391   // The hash-mark must be ignored when mailto: scheme is parsed,
392   // even if the URL has a base and relative part.
393   const char* base = "mailto://to/";
394   const char* rel = "any#body";
395
396   Parsed base_parsed;
397   ParsePathURL(base, strlen(base), false, &base_parsed);
398
399   std::string resolved;
400   StdStringCanonOutput output(&resolved);
401   Parsed resolved_parsed;
402
403   bool valid = ResolveRelative(base, strlen(base),
404                                base_parsed, rel,
405                                strlen(rel), NULL, &output,
406                                &resolved_parsed);
407   EXPECT_TRUE(valid);
408   EXPECT_FALSE(resolved_parsed.ref.is_valid());
409 }
410
411 TEST_F(URLUtilTest, PotentiallyDanglingMarkup) {
412   struct ResolveRelativeCase {
413     const char* base;
414     const char* rel;
415     bool potentially_dangling_markup;
416     const char* out;
417   } cases[] = {
418       {"https://example.com/", "/path<", false, "https://example.com/path%3C"},
419       {"https://example.com/", "\n/path<", true, "https://example.com/path%3C"},
420       {"https://example.com/", "\r/path<", true, "https://example.com/path%3C"},
421       {"https://example.com/", "\t/path<", true, "https://example.com/path%3C"},
422       {"https://example.com/", "/pa\nth<", true, "https://example.com/path%3C"},
423       {"https://example.com/", "/pa\rth<", true, "https://example.com/path%3C"},
424       {"https://example.com/", "/pa\tth<", true, "https://example.com/path%3C"},
425       {"https://example.com/", "/path\n<", true, "https://example.com/path%3C"},
426       {"https://example.com/", "/path\r<", true, "https://example.com/path%3C"},
427       {"https://example.com/", "/path\r<", true, "https://example.com/path%3C"},
428       {"https://example.com/", "\n/<path", true, "https://example.com/%3Cpath"},
429       {"https://example.com/", "\r/<path", true, "https://example.com/%3Cpath"},
430       {"https://example.com/", "\t/<path", true, "https://example.com/%3Cpath"},
431       {"https://example.com/", "/<pa\nth", true, "https://example.com/%3Cpath"},
432       {"https://example.com/", "/<pa\rth", true, "https://example.com/%3Cpath"},
433       {"https://example.com/", "/<pa\tth", true, "https://example.com/%3Cpath"},
434       {"https://example.com/", "/<path\n", true, "https://example.com/%3Cpath"},
435       {"https://example.com/", "/<path\r", true, "https://example.com/%3Cpath"},
436       {"https://example.com/", "/<path\r", true, "https://example.com/%3Cpath"},
437   };
438
439   for (const auto& test : cases) {
440     SCOPED_TRACE(::testing::Message() << test.base << ", " << test.rel);
441     Parsed base_parsed;
442     ParseStandardURL(test.base, strlen(test.base), &base_parsed);
443
444     std::string resolved;
445     StdStringCanonOutput output(&resolved);
446     Parsed resolved_parsed;
447     bool valid =
448         ResolveRelative(test.base, strlen(test.base), base_parsed, test.rel,
449                         strlen(test.rel), NULL, &output, &resolved_parsed);
450     ASSERT_TRUE(valid);
451     output.Complete();
452
453     EXPECT_EQ(test.potentially_dangling_markup,
454               resolved_parsed.potentially_dangling_markup);
455     EXPECT_EQ(test.out, resolved);
456   }
457 }
458
459 TEST_F(URLUtilTest, TestDomainIs) {
460   const struct {
461     const char* canonicalized_host;
462     const char* lower_ascii_domain;
463     bool expected_domain_is;
464   } kTestCases[] = {
465       {"google.com", "google.com", true},
466       {"www.google.com", "google.com", true},      // Subdomain is ignored.
467       {"www.google.com.cn", "google.com", false},  // Different TLD.
468       {"www.google.comm", "google.com", false},
469       {"www.iamnotgoogle.com", "google.com", false},  // Different hostname.
470       {"www.google.com", "Google.com", false},  // The input is not lower-cased.
471
472       // If the host ends with a dot, it matches domains with or without a dot.
473       {"www.google.com.", "google.com", true},
474       {"www.google.com.", "google.com.", true},
475       {"www.google.com.", ".com", true},
476       {"www.google.com.", ".com.", true},
477
478       // But, if the host doesn't end with a dot and the input domain does, then
479       // it's considered to not match.
480       {"www.google.com", "google.com.", false},
481
482       // If the host ends with two dots, it doesn't match.
483       {"www.google.com..", "google.com", false},
484
485       // Empty parameters.
486       {"www.google.com", "", false},
487       {"", "www.google.com", false},
488       {"", "", false},
489   };
490
491   for (const auto& test_case : kTestCases) {
492     SCOPED_TRACE(testing::Message() << "(host, domain): ("
493                                     << test_case.canonicalized_host << ", "
494                                     << test_case.lower_ascii_domain << ")");
495
496     EXPECT_EQ(
497         test_case.expected_domain_is,
498         DomainIs(test_case.canonicalized_host, test_case.lower_ascii_domain));
499   }
500 }
501
502 }  // namespace url