eea9b9199c8bc17e6d85c8e593d14fd0f71d2763
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / WebCore / URLParser.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include <WebCore/URLParser.h>
28 #include <wtf/MainThread.h>
29 #include <wtf/text/StringBuilder.h>
30
31 using namespace WebCore;
32
33 namespace TestWebKitAPI {
34
35 class URLParserTest : public testing::Test {
36 public:
37     void SetUp() final {
38         WTF::initializeMainThread();
39     }
40 };
41
42 struct ExpectedParts {
43     String protocol;
44     String user;
45     String password;
46     String host;
47     unsigned short port;
48     String path;
49     String query;
50     String fragment;
51     String string;
52
53     bool isInvalid() const
54     {
55         return protocol.isEmpty()
56             && user.isEmpty()
57             && password.isEmpty()
58             && host.isEmpty()
59             && !port
60             && path.isEmpty()
61             && query.isEmpty()
62             && fragment.isEmpty();
63     }
64 };
65
66 static bool eq(const String& s1, const String& s2)
67 {
68     EXPECT_STREQ(s1.utf8().data(), s2.utf8().data());
69     return s1.utf8() == s2.utf8();
70 }
71
72 static String insertTabAtLocation(const String& string, size_t location)
73 {
74     ASSERT(location <= string.length());
75     return makeString(string.substring(0, location), "\t", string.substring(location));
76 }
77
78 static ExpectedParts invalidParts(const String& urlStringWithTab)
79 {
80     return {"", "", "", "", 0, "" , "", "", urlStringWithTab};
81 }
82
83 enum class TestTabs { No, Yes };
84
85 // Inserting tabs between surrogate pairs changes the encoded value instead of being skipped by the URLParser.
86 const TestTabs testTabsValueForSurrogatePairs = TestTabs::No;
87
88 static void checkURL(const String& urlString, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
89 {
90     bool wasEnabled = URLParser::enabled();
91     URLParser::setEnabled(true);
92     auto url = URL(URL(), urlString);
93     URLParser::setEnabled(false);
94     auto oldURL = URL(URL(), urlString);
95     URLParser::setEnabled(wasEnabled);
96     
97     EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
98     EXPECT_TRUE(eq(parts.user, url.user()));
99     EXPECT_TRUE(eq(parts.password, url.pass()));
100     EXPECT_TRUE(eq(parts.host, url.host()));
101     EXPECT_EQ(parts.port, url.port().valueOr(0));
102     EXPECT_TRUE(eq(parts.path, url.path()));
103     EXPECT_TRUE(eq(parts.query, url.query()));
104     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
105     EXPECT_TRUE(eq(parts.string, url.string()));
106     
107     EXPECT_TRUE(eq(parts.protocol, oldURL.protocol().toString()));
108     EXPECT_TRUE(eq(parts.user, oldURL.user()));
109     EXPECT_TRUE(eq(parts.password, oldURL.pass()));
110     EXPECT_TRUE(eq(parts.host, oldURL.host()));
111     EXPECT_EQ(parts.port, oldURL.port().valueOr(0));
112     EXPECT_TRUE(eq(parts.path, oldURL.path()));
113     EXPECT_TRUE(eq(parts.query, oldURL.query()));
114     EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier()));
115     EXPECT_TRUE(eq(parts.string, oldURL.string()));
116     
117     EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));
118     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
119     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
120
121     if (testTabs == TestTabs::No)
122         return;
123
124     for (size_t i = 0; i < urlString.length(); ++i) {
125         String urlStringWithTab = insertTabAtLocation(urlString, i);
126         checkURL(urlStringWithTab,
127             parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
128             TestTabs::No);
129     }
130 }
131
132 static void checkRelativeURL(const String& urlString, const String& baseURLString, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
133 {
134     bool wasEnabled = URLParser::enabled();
135     URLParser::setEnabled(true);
136     auto url = URL(URL(URL(), baseURLString), urlString);
137     URLParser::setEnabled(false);
138     auto oldURL = URL(URL(URL(), baseURLString), urlString);
139     URLParser::setEnabled(wasEnabled);
140     
141     EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
142     EXPECT_TRUE(eq(parts.user, url.user()));
143     EXPECT_TRUE(eq(parts.password, url.pass()));
144     EXPECT_TRUE(eq(parts.host, url.host()));
145     EXPECT_EQ(parts.port, url.port().valueOr(0));
146     EXPECT_TRUE(eq(parts.path, url.path()));
147     EXPECT_TRUE(eq(parts.query, url.query()));
148     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
149     EXPECT_TRUE(eq(parts.string, url.string()));
150     
151     EXPECT_TRUE(eq(parts.protocol, oldURL.protocol().toString()));
152     EXPECT_TRUE(eq(parts.user, oldURL.user()));
153     EXPECT_TRUE(eq(parts.password, oldURL.pass()));
154     EXPECT_TRUE(eq(parts.host, oldURL.host()));
155     EXPECT_EQ(parts.port, oldURL.port().valueOr(0));
156     EXPECT_TRUE(eq(parts.path, oldURL.path()));
157     EXPECT_TRUE(eq(parts.query, oldURL.query()));
158     EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier()));
159     EXPECT_TRUE(eq(parts.string, oldURL.string()));
160     
161     EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));
162     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
163     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
164     
165     if (testTabs == TestTabs::No)
166         return;
167     
168     for (size_t i = 0; i < urlString.length(); ++i) {
169         String urlStringWithTab = insertTabAtLocation(urlString, i);
170         checkRelativeURL(urlStringWithTab,
171             baseURLString,
172             parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
173             TestTabs::No);
174     }
175 }
176
177 static void checkURLDifferences(const String& urlString, const ExpectedParts& partsNew, const ExpectedParts& partsOld, TestTabs testTabs = TestTabs::Yes)
178 {
179     bool wasEnabled = URLParser::enabled();
180     URLParser::setEnabled(true);
181     auto url = URL(URL(), urlString);
182     URLParser::setEnabled(false);
183     auto oldURL = URL(URL(), urlString);
184     URLParser::setEnabled(wasEnabled);
185     
186     EXPECT_TRUE(eq(partsNew.protocol, url.protocol().toString()));
187     EXPECT_TRUE(eq(partsNew.user, url.user()));
188     EXPECT_TRUE(eq(partsNew.password, url.pass()));
189     EXPECT_TRUE(eq(partsNew.host, url.host()));
190     EXPECT_EQ(partsNew.port, url.port().valueOr(0));
191     EXPECT_TRUE(eq(partsNew.path, url.path()));
192     EXPECT_TRUE(eq(partsNew.query, url.query()));
193     EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
194     EXPECT_TRUE(eq(partsNew.string, url.string()));
195     
196     EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol().toString()));
197     EXPECT_TRUE(eq(partsOld.user, oldURL.user()));
198     EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));
199     EXPECT_TRUE(eq(partsOld.host, oldURL.host()));
200     EXPECT_EQ(partsOld.port, oldURL.port().valueOr(0));
201     EXPECT_TRUE(eq(partsOld.path, oldURL.path()));
202     EXPECT_TRUE(eq(partsOld.query, oldURL.query()));
203     EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));
204     EXPECT_TRUE(eq(partsOld.string, oldURL.string()));
205     
206     EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));
207     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
208     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
209     
210     if (testTabs == TestTabs::No)
211         return;
212     
213     for (size_t i = 0; i < urlString.length(); ++i) {
214         String urlStringWithTab = insertTabAtLocation(urlString, i);
215         checkURLDifferences(urlStringWithTab,
216             partsNew.isInvalid() ? invalidParts(urlStringWithTab) : partsNew,
217             partsOld.isInvalid() ? invalidParts(urlStringWithTab) : partsOld,
218             TestTabs::No);
219     }
220 }
221
222 static void checkRelativeURLDifferences(const String& urlString, const String& baseURLString, const ExpectedParts& partsNew, const ExpectedParts& partsOld, TestTabs testTabs = TestTabs::Yes)
223 {
224     bool wasEnabled = URLParser::enabled();
225     URLParser::setEnabled(true);
226     auto url = URL(URL(URL(), baseURLString), urlString);
227     URLParser::setEnabled(false);
228     auto oldURL = URL(URL(URL(), baseURLString), urlString);
229     URLParser::setEnabled(wasEnabled);
230     
231     EXPECT_TRUE(eq(partsNew.protocol, url.protocol().toString()));
232     EXPECT_TRUE(eq(partsNew.user, url.user()));
233     EXPECT_TRUE(eq(partsNew.password, url.pass()));
234     EXPECT_TRUE(eq(partsNew.host, url.host()));
235     EXPECT_EQ(partsNew.port, url.port().valueOr(0));
236     EXPECT_TRUE(eq(partsNew.path, url.path()));
237     EXPECT_TRUE(eq(partsNew.query, url.query()));
238     EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
239     EXPECT_TRUE(eq(partsNew.string, url.string()));
240     
241     EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol().toString()));
242     EXPECT_TRUE(eq(partsOld.user, oldURL.user()));
243     EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));
244     EXPECT_TRUE(eq(partsOld.host, oldURL.host()));
245     EXPECT_EQ(partsOld.port, oldURL.port().valueOr(0));
246     EXPECT_TRUE(eq(partsOld.path, oldURL.path()));
247     EXPECT_TRUE(eq(partsOld.query, oldURL.query()));
248     EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));
249     EXPECT_TRUE(eq(partsOld.string, oldURL.string()));
250     
251     EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));
252     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
253     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
254     
255     if (testTabs == TestTabs::No)
256         return;
257     
258     for (size_t i = 0; i < urlString.length(); ++i) {
259         String urlStringWithTab = insertTabAtLocation(urlString, i);
260         checkRelativeURLDifferences(urlStringWithTab, baseURLString,
261             partsNew.isInvalid() ? invalidParts(urlStringWithTab) : partsNew,
262             partsOld.isInvalid() ? invalidParts(urlStringWithTab) : partsOld,
263             TestTabs::No);
264     }
265 }
266
267 static void shouldFail(const String& urlString)
268 {
269     checkURL(urlString, {"", "", "", "", 0, "", "", "", urlString});
270 }
271
272 static void shouldFail(const String& urlString, const String& baseString)
273 {
274     checkRelativeURL(urlString, baseString, {"", "", "", "", 0, "", "", "", urlString});
275 }
276
277 static void checkURL(const String& urlString, const TextEncoding& encoding, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
278 {
279     URLParser parser(urlString, { }, encoding);
280     auto url = parser.result();
281     EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
282     EXPECT_TRUE(eq(parts.user, url.user()));
283     EXPECT_TRUE(eq(parts.password, url.pass()));
284     EXPECT_TRUE(eq(parts.host, url.host()));
285     EXPECT_EQ(parts.port, url.port().valueOr(0));
286     EXPECT_TRUE(eq(parts.path, url.path()));
287     EXPECT_TRUE(eq(parts.query, url.query()));
288     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
289     EXPECT_TRUE(eq(parts.string, url.string()));
290     
291     if (testTabs == TestTabs::No)
292         return;
293     
294     for (size_t i = 0; i < urlString.length(); ++i) {
295         String urlStringWithTab = insertTabAtLocation(urlString, i);
296         checkURL(urlStringWithTab, encoding,
297             parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
298             TestTabs::No);
299     }
300 }
301
302 static void checkURL(const String& urlString, const String& baseURLString, const TextEncoding& encoding, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes)
303 {
304     URLParser baseParser(baseURLString, { }, encoding);
305     URLParser parser(urlString, baseParser.result(), encoding);
306     auto url = parser.result();
307     EXPECT_TRUE(eq(parts.protocol, url.protocol().toString()));
308     EXPECT_TRUE(eq(parts.user, url.user()));
309     EXPECT_TRUE(eq(parts.password, url.pass()));
310     EXPECT_TRUE(eq(parts.host, url.host()));
311     EXPECT_EQ(parts.port, url.port().valueOr(0));
312     EXPECT_TRUE(eq(parts.path, url.path()));
313     EXPECT_TRUE(eq(parts.query, url.query()));
314     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
315     EXPECT_TRUE(eq(parts.string, url.string()));
316     
317     if (testTabs == TestTabs::No)
318         return;
319     
320     for (size_t i = 0; i < urlString.length(); ++i) {
321         String urlStringWithTab = insertTabAtLocation(urlString, i);
322         checkURL(urlStringWithTab, baseURLString, encoding,
323             parts.isInvalid() ? invalidParts(urlStringWithTab) : parts,
324             TestTabs::No);
325     }
326 }
327
328 template<size_t length>
329 static String utf16String(const char16_t (&url)[length])
330 {
331     StringBuilder builder;
332     builder.reserveCapacity(length - 1);
333     for (size_t i = 0; i < length - 1; ++i)
334         builder.append(static_cast<UChar>(url[i]));
335     return builder.toString();
336 }
337
338 TEST_F(URLParserTest, Basic)
339 {
340     checkURL("http://user:pass@webkit.org:123/path?query#fragment", {"http", "user", "pass", "webkit.org", 123, "/path", "query", "fragment", "http://user:pass@webkit.org:123/path?query#fragment"});
341     checkURL("http://user:pass@webkit.org:123/path?query", {"http", "user", "pass", "webkit.org", 123, "/path", "query", "", "http://user:pass@webkit.org:123/path?query"});
342     checkURL("http://user:pass@webkit.org:123/path", {"http", "user", "pass", "webkit.org", 123, "/path", "", "", "http://user:pass@webkit.org:123/path"});
343     checkURL("http://user:pass@webkit.org:123/", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
344     checkURL("http://user:pass@webkit.org:123", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
345     checkURL("http://user:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
346     checkURL("http://user:\t\t\tpass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
347     checkURL("http://us\ter:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
348     checkURL("http://user:pa\tss@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
349     checkURL("http://user:pass\t@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
350     checkURL("http://\tuser:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
351     checkURL("http://user\t:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
352     checkURL("http://webkit.org", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
353     checkURL("http://127.0.0.1", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
354     checkURL("http://webkit.org/", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
355     checkURL("http://webkit.org/path1/path2/index.html", {"http", "", "", "webkit.org", 0, "/path1/path2/index.html", "", "", "http://webkit.org/path1/path2/index.html"});
356     checkURL("about:blank", {"about", "", "", "", 0, "blank", "", "", "about:blank"});
357     checkURL("about:blank?query", {"about", "", "", "", 0, "blank", "query", "", "about:blank?query"});
358     checkURL("about:blank#fragment", {"about", "", "", "", 0, "blank", "", "fragment", "about:blank#fragment"});
359     checkURL("http://[0:f::f:f:0:0]", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
360     checkURL("http://[0:f:0:0:f::]", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
361     checkURL("http://[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
362     checkURL("http://[0:f:0:0:f::]:", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
363     checkURL("http://[0:f:0:0:f::]:\t", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
364     checkURL("http://[0:f:0:0:f::]\t:", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
365     checkURL("http://\t[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
366     checkURL("http://[\t::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
367     checkURL("http://[:\t:f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
368     checkURL("http://[::\tf:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
369     checkURL("http://[::f\t:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
370     checkURL("http://[::f:\t0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
371     checkURL("http://example.com/path1/path2/.", {"http", "", "", "example.com", 0, "/path1/path2/", "", "", "http://example.com/path1/path2/"});
372     checkURL("http://example.com/path1/path2/..", {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"});
373     checkURL("http://example.com/path1/path2/./path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
374     checkURL("http://example.com/path1/path2/.\\path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
375     checkURL("http://example.com/path1/path2/../path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
376     checkURL("http://example.com/path1/path2/..\\path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
377     checkURL("http://example.com/.", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
378     checkURL("http://example.com/..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
379     checkURL("http://example.com/./path1", {"http", "", "", "example.com", 0, "/path1", "", "", "http://example.com/path1"});
380     checkURL("http://example.com/../path1", {"http", "", "", "example.com", 0, "/path1", "", "", "http://example.com/path1"});
381     checkURL("http://example.com/../path1/../../path2/path3/../path4", {"http", "", "", "example.com", 0, "/path2/path4", "", "", "http://example.com/path2/path4"});
382     checkURL("http://example.com/path1/.%2", {"http", "", "", "example.com", 0, "/path1/.%2", "", "", "http://example.com/path1/.%2"});
383     checkURL("http://example.com/path1/%2", {"http", "", "", "example.com", 0, "/path1/%2", "", "", "http://example.com/path1/%2"});
384     checkURL("http://example.com/path1/%", {"http", "", "", "example.com", 0, "/path1/%", "", "", "http://example.com/path1/%"});
385     checkURL("http://example.com/path1/.%", {"http", "", "", "example.com", 0, "/path1/.%", "", "", "http://example.com/path1/.%"});
386     checkURL("http://example.com//.", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
387     checkURL("http://example.com//./", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
388     checkURL("http://example.com//.//", {"http", "", "", "example.com", 0, "///", "", "", "http://example.com///"});
389     checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
390     checkURL("http://example.com//../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
391     checkURL("http://example.com//..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
392     checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
393     checkURL("http://example.com/.//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
394     checkURL("http://example.com/..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
395     checkURL("http://example.com/./", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
396     checkURL("http://example.com/../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
397     checkURL("http://example.com/path1/.../path3", {"http", "", "", "example.com", 0, "/path1/.../path3", "", "", "http://example.com/path1/.../path3"});
398     checkURL("http://example.com/path1/...", {"http", "", "", "example.com", 0, "/path1/...", "", "", "http://example.com/path1/..."});
399     checkURL("http://example.com/path1/.../", {"http", "", "", "example.com", 0, "/path1/.../", "", "", "http://example.com/path1/.../"});
400     checkURL("http://example.com/.path1/", {"http", "", "", "example.com", 0, "/.path1/", "", "", "http://example.com/.path1/"});
401     checkURL("http://example.com/..path1/", {"http", "", "", "example.com", 0, "/..path1/", "", "", "http://example.com/..path1/"});
402     checkURL("http://example.com/path1/.path2", {"http", "", "", "example.com", 0, "/path1/.path2", "", "", "http://example.com/path1/.path2"});
403     checkURL("http://example.com/path1/..path2", {"http", "", "", "example.com", 0, "/path1/..path2", "", "", "http://example.com/path1/..path2"});
404     checkURL("http://example.com/path1/path2/.?query", {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"});
405     checkURL("http://example.com/path1/path2/..?query", {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"});
406     checkURL("http://example.com/path1/path2/.#fragment", {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"});
407     checkURL("http://example.com/path1/path2/..#fragment", {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"});
408
409     checkURL("file:", {"file", "", "", "", 0, "/", "", "", "file:///"});
410     checkURL("file:/", {"file", "", "", "", 0, "/", "", "", "file:///"});
411     checkURL("file://", {"file", "", "", "", 0, "/", "", "", "file:///"});
412     checkURL("file:///", {"file", "", "", "", 0, "/", "", "", "file:///"});
413     checkURL("file:////", {"file", "", "", "", 0, "//", "", "", "file:////"}); // This matches Firefox and URL::parse which I believe are correct, but not Chrome.
414     checkURL("file:/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
415     checkURL("file://host/path", {"file", "", "", "host", 0, "/path", "", "", "file://host/path"});
416     checkURL("file://host", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
417     checkURL("file://host/", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
418     checkURL("file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
419     checkURL("file:////path", {"file", "", "", "", 0, "//path", "", "", "file:////path"});
420     checkURL("file://localhost/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
421     checkURL("file://localhost/", {"file", "", "", "", 0, "/", "", "", "file:///"});
422     checkURL("file://localhost", {"file", "", "", "", 0, "/", "", "", "file:///"});
423     checkURL("file://lOcAlHoSt", {"file", "", "", "", 0, "/", "", "", "file:///"});
424     checkURL("file://lOcAlHoSt/", {"file", "", "", "", 0, "/", "", "", "file:///"});
425     checkURL("file:/pAtH/", {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"});
426     checkURL("file:/pAtH", {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"});
427     checkURL("file:?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
428     checkURL("file:#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
429     checkURL("file:?query#fragment", {"file", "", "", "", 0, "/", "query", "fragment", "file:///?query#fragment"});
430     checkURL("file:#fragment?notquery", {"file", "", "", "", 0, "/", "", "fragment?notquery", "file:///#fragment?notquery"});
431     checkURL("file:/?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
432     checkURL("file:/#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
433     checkURL("file://?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
434     checkURL("file://#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
435     checkURL("file:///?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
436     checkURL("file:///#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
437     checkURL("file:////?query", {"file", "", "", "", 0, "//", "query", "", "file:////?query"});
438     checkURL("file:////#fragment", {"file", "", "", "", 0, "//", "", "fragment", "file:////#fragment"});
439     checkURL("http://host/A b", {"http", "", "", "host", 0, "/A%20b", "", "", "http://host/A%20b"});
440     checkURL("http://host/a%20B", {"http", "", "", "host", 0, "/a%20B", "", "", "http://host/a%20B"});
441     checkURL("http://host?q=@ <>!#fragment", {"http", "", "", "host", 0, "/", "q=@%20%3C%3E!", "fragment", "http://host/?q=@%20%3C%3E!#fragment"});
442     checkURL("http://user:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
443     checkURL("http://user:@\thost", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
444     checkURL("http://user:\t@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
445     checkURL("http://user\t:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
446     checkURL("http://use\tr:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
447     checkURL("http://127.0.0.1:10100/path", {"http", "", "", "127.0.0.1", 10100, "/path", "", "", "http://127.0.0.1:10100/path"});
448     checkURL("http://127.0.0.1:/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
449     checkURL("http://127.0.0.1\t:/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
450     checkURL("http://127.0.0.1:\t/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
451     checkURL("http://127.0.0.1:/\tpath", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
452     checkURL("http://127.0.0.1:123", {"http", "", "", "127.0.0.1", 123, "/", "", "", "http://127.0.0.1:123/"});
453     checkURL("http://127.0.0.1:", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
454     checkURL("http://[0:f::f:f:0:0]:123/path", {"http", "", "", "[0:f::f:f:0:0]", 123, "/path", "", "", "http://[0:f::f:f:0:0]:123/path"});
455     checkURL("http://[0:f::f:f:0:0]:123", {"http", "", "", "[0:f::f:f:0:0]", 123, "/", "", "", "http://[0:f::f:f:0:0]:123/"});
456     checkURL("http://[0:f:0:0:f:\t:]:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
457     checkURL("http://[0:f:0:0:f::\t]:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
458     checkURL("http://[0:f:0:0:f::]\t:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
459     checkURL("http://[0:f:0:0:f::]:\t123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
460     checkURL("http://[0:f:0:0:f::]:1\t23", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
461     checkURL("http://[0:f::f:f:0:0]:/path", {"http", "", "", "[0:f::f:f:0:0]", 0, "/path", "", "", "http://[0:f::f:f:0:0]/path"});
462     checkURL("http://[0:f::f:f:0:0]:", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
463     checkURL("http://host:10100/path", {"http", "", "", "host", 10100, "/path", "", "", "http://host:10100/path"});
464     checkURL("http://host:/path", {"http", "", "", "host", 0, "/path", "", "", "http://host/path"});
465     checkURL("http://host:123", {"http", "", "", "host", 123, "/", "", "", "http://host:123/"});
466     checkURL("http://host:", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
467     checkURL("http://hos\tt\n:\t1\n2\t3\t/\npath", {"http", "", "", "host", 123, "/path", "", "", "http://host:123/path"});
468     checkURL("http://user@example.org/path3", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
469     checkURL("sc:/pa/pa", {"sc", "", "", "", 0, "/pa/pa", "", "", "sc:/pa/pa"});
470     checkURL("sc:/pa", {"sc", "", "", "", 0, "/pa", "", "", "sc:/pa"});
471     checkURL("sc:/pa/", {"sc", "", "", "", 0, "/pa/", "", "", "sc:/pa/"});
472     checkURL("notspecial:/notuser:notpassword@nothost", {"notspecial", "", "", "", 0, "/notuser:notpassword@nothost", "", "", "notspecial:/notuser:notpassword@nothost"});
473     checkURL("sc://pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
474     checkURL("sc://\tpa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
475     checkURL("sc:/\t/pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
476     checkURL("sc:\t//pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
477     checkURL("http://host   \a   ", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
478     checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
479     checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
480     checkURL("http:/a", {"http", "", "", "a", 0, "/", "", "", "http://a/"});
481     checkURL("http://256../", {"http", "", "", "256..", 0, "/", "", "", "http://256../"});
482     checkURL("http://256..", {"http", "", "", "256..", 0, "/", "", "", "http://256../"});
483     checkURL("http://127..1/", {"http", "", "", "127..1", 0, "/", "", "", "http://127..1/"});
484     checkURL("http://127.a.0.1/", {"http", "", "", "127.a.0.1", 0, "/", "", "", "http://127.a.0.1/"});
485     checkURL("http://127.0.0.1/", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
486     checkURL("http://12\t7.0.0.1/", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
487     checkURL("http://127.\t0.0.1/", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
488     checkURL("http://./", {"http", "", "", ".", 0, "/", "", "", "http://./"});
489     checkURL("http://.", {"http", "", "", ".", 0, "/", "", "", "http://./"});
490     checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
491     checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
492     checkURL("notspecial:/", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
493     checkURL("data:image/png;base64,encoded-data-follows-here", {"data", "", "", "", 0, "image/png;base64,encoded-data-follows-here", "", "", "data:image/png;base64,encoded-data-follows-here"});
494     checkURL("data:image/png;base64,encoded/data-with-slash", {"data", "", "", "", 0, "image/png;base64,encoded/data-with-slash", "", "", "data:image/png;base64,encoded/data-with-slash"});
495     checkURL("about:~", {"about", "", "", "", 0, "~", "", "", "about:~"});
496     checkURL("https://@test@test@example:800\\path@end", {"", "", "", "", 0, "", "", "", "https://@test@test@example:800\\path@end"});
497     checkURL("http://www.example.com/#a\nb\rc\td", {"http", "", "", "www.example.com", 0, "/", "", "abcd", "http://www.example.com/#abcd"});
498     checkURL("http://[A:b:c:DE:fF:0:1:aC]/", {"http", "", "", "[a:b:c:de:ff:0:1:ac]", 0, "/", "", "", "http://[a:b:c:de:ff:0:1:ac]/"});
499     checkURL("http:////////user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
500     checkURL("http:////////user:@webkit.org:99#foo", {"http", "user", "", "webkit.org", 99, "/", "", "foo", "http://user@webkit.org:99/#foo"});
501     checkURL("http:////\t////user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
502     checkURL("http://\t//\\///user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
503     checkURL("http:/\\user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
504     checkURL("http://127.0.0.1", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
505     checkURL("http://127.0.0.1.", {"http", "", "", "127.0.0.1.", 0, "/", "", "", "http://127.0.0.1./"});
506     checkURL("http://127.0.0.1./", {"http", "", "", "127.0.0.1.", 0, "/", "", "", "http://127.0.0.1./"});
507     checkURL("http://0x100.0/", {"http", "", "", "0x100.0", 0, "/", "", "", "http://0x100.0/"});
508     checkURL("http://0.0.0x100.0/", {"http", "", "", "0.0.0x100.0", 0, "/", "", "", "http://0.0.0x100.0/"});
509     checkURL("http://0.0.0.0x100/", {"http", "", "", "0.0.0.0x100", 0, "/", "", "", "http://0.0.0.0x100/"});
510     checkURL("http://host:123?", {"http", "", "", "host", 123, "/", "", "", "http://host:123/?"});
511     checkURL("http://host:123?query", {"http", "", "", "host", 123, "/", "query", "", "http://host:123/?query"});
512     checkURL("http://host:123#", {"http", "", "", "host", 123, "/", "", "", "http://host:123/#"});
513     checkURL("http://host:123#fragment", {"http", "", "", "host", 123, "/", "", "fragment", "http://host:123/#fragment"});
514     checkURL("foo:////", {"foo", "", "", "", 0, "////", "", "", "foo:////"});
515     checkURL("foo:///?", {"foo", "", "", "", 0, "///", "", "", "foo:///?"});
516     checkURL("foo:///#", {"foo", "", "", "", 0, "///", "", "", "foo:///#"});
517     checkURL("foo:///", {"foo", "", "", "", 0, "///", "", "", "foo:///"});
518     checkURL("foo://?", {"foo", "", "", "", 0, "//", "", "", "foo://?"});
519     checkURL("foo://#", {"foo", "", "", "", 0, "//", "", "", "foo://#"});
520     checkURL("foo://", {"foo", "", "", "", 0, "//", "", "", "foo://"});
521     checkURL("foo:/?", {"foo", "", "", "", 0, "/", "", "", "foo:/?"});
522     checkURL("foo:/#", {"foo", "", "", "", 0, "/", "", "", "foo:/#"});
523     checkURL("foo:/", {"foo", "", "", "", 0, "/", "", "", "foo:/"});
524     checkURL("foo:?", {"foo", "", "", "", 0, "", "", "", "foo:?"});
525     checkURL("foo:#", {"foo", "", "", "", 0, "", "", "", "foo:#"});
526     checkURL("A://", {"a", "", "", "", 0, "//", "", "", "a://"});
527     checkURL("aA://", {"aa", "", "", "", 0, "//", "", "", "aa://"});
528     checkURL(utf16String(u"foo://host/#ПП\u0007 a</"), {"foo", "", "", "host", 0, "/", "", "%D0%9F%D0%9F%07 a</", "foo://host/#%D0%9F%D0%9F%07 a</"});
529     checkURL(utf16String(u"foo://host/#\u0007 a</"), {"foo", "", "", "host", 0, "/", "", "%07 a</", "foo://host/#%07 a</"});
530     checkURL(utf16String(u"http://host?ß😍#ß😍"), {"http", "", "", "host", 0, "/", "%C3%9F%F0%9F%98%8D", "%C3%9F%F0%9F%98%8D", "http://host/?%C3%9F%F0%9F%98%8D#%C3%9F%F0%9F%98%8D"}, testTabsValueForSurrogatePairs);
531     checkURL(utf16String(u"http://host/path#💩\t💩"), {"http", "", "", "host", 0, "/path", "", "%F0%9F%92%A9%F0%9F%92%A9", "http://host/path#%F0%9F%92%A9%F0%9F%92%A9"}, testTabsValueForSurrogatePairs);
532     checkURL(utf16String(u"http://host/#ПП\u0007 a</"), {"http", "", "", "host", 0, "/", "", "%D0%9F%D0%9F%07 a</", "http://host/#%D0%9F%D0%9F%07 a</"});
533     checkURL(utf16String(u"http://host/#\u0007 a</"), {"http", "", "", "host", 0, "/", "", "%07 a</", "http://host/#%07 a</"});
534
535     // This disagrees with the web platform test for http://:@www.example.com but agrees with Chrome and URL::parse,
536     // and Firefox fails the web platform test differently. Maybe the web platform test ought to be changed.
537     checkURL("http://:@host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
538 }
539
540 TEST_F(URLParserTest, ParseRelative)
541 {
542     checkRelativeURL("/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "webkit.org", 0, "/index.html", "", "", "http://webkit.org/index.html"});
543     checkRelativeURL("http://whatwg.org/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "whatwg.org", 0, "/index.html", "", "", "http://whatwg.org/index.html"});
544     checkRelativeURL("index.html", "http://webkit.org/path1/path2/page.html?query#fragment", {"http", "", "", "webkit.org", 0, "/path1/path2/index.html", "", "", "http://webkit.org/path1/path2/index.html"});
545     checkRelativeURL("//whatwg.org/index.html", "https://www.webkit.org/path", {"https", "", "", "whatwg.org", 0, "/index.html", "", "", "https://whatwg.org/index.html"});
546     checkRelativeURL("http://example\t.\norg", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
547     checkRelativeURL("test", "file:///path1/path2", {"file", "", "", "", 0, "/path1/test", "", "", "file:///path1/test"});
548     checkRelativeURL(utf16String(u"http://www.foo。bar.com"), "http://other.com/", {"http", "", "", "www.foo.bar.com", 0, "/", "", "", "http://www.foo.bar.com/"});
549     checkRelativeURLDifferences(utf16String(u"sc://ñ.test/"), "about:blank",
550         {"sc", "", "", "%C3%B1.test", 0, "/", "", "", "sc://%C3%B1.test/"},
551         {"sc", "", "", "xn--ida.test", 0, "/", "", "", "sc://xn--ida.test/"});
552     checkRelativeURL("#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "", "fragment", "http://host/path#fragment"});
553     checkRelativeURL("#fragment", "file:///path", {"file", "", "", "", 0, "/path", "", "fragment", "file:///path#fragment"});
554     checkRelativeURL("#fragment", "file:///path#old", {"file", "", "", "", 0, "/path", "", "fragment", "file:///path#fragment"});
555     checkRelativeURL("#", "file:///path#old", {"file", "", "", "", 0, "/path", "", "", "file:///path#"});
556     checkRelativeURL("  ", "file:///path#old", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
557     checkRelativeURL("#", "file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path#"});
558     checkRelativeURL("#", "file:///path?query", {"file", "", "", "", 0, "/path", "query", "", "file:///path?query#"});
559     checkRelativeURL("#", "file:///path?query#old", {"file", "", "", "", 0, "/path", "query", "", "file:///path?query#"});
560     checkRelativeURL("?query", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "", "http://host/path?query"});
561     checkRelativeURL("?query#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "fragment", "http://host/path?query#fragment"});
562     checkRelativeURL("?new", "file:///path?old#fragment", {"file", "", "", "", 0, "/path", "new", "", "file:///path?new"});
563     checkRelativeURL("?", "file:///path?old#fragment", {"file", "", "", "", 0, "/path", "", "", "file:///path?"});
564     checkRelativeURL("?", "file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path?"});
565     checkRelativeURL("?query", "file:///path", {"file", "", "", "", 0, "/path", "query", "", "file:///path?query"});
566     checkRelativeURL(utf16String(u"?β"), "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "%CE%B2", "", "http://example.org/foo/bar?%CE%B2"});
567     checkRelativeURL("?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?"});
568     checkRelativeURL("#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar#"});
569     checkRelativeURL("?#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?#"});
570     checkRelativeURL("#?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "?", "http://example.org/foo/bar#?"});
571     checkRelativeURL("/", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
572     checkRelativeURL("http://@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
573     checkRelativeURL("http://:@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
574     checkRelativeURL("http://foo.com/\\@", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "//@", "", "", "http://foo.com//@"});
575     checkRelativeURL("\\@", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/@", "", "", "http://example.org/@"});
576     checkRelativeURL("/path3", "http://user@example.org/path1/path2", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
577     checkRelativeURL("", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
578     checkRelativeURL("\t", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
579     checkRelativeURL(" ", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
580     checkRelativeURL("  \a  \t\n", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
581     checkRelativeURL(":foo.com\\", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "http://example.org/foo/:foo.com/"});
582     checkRelativeURL("http:/example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
583     checkRelativeURL("http:example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
584     checkRelativeURL("http:\\\\foo.com\\", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
585     checkRelativeURL("http:\\\\foo.com/", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
586     checkRelativeURL("http:\\\\foo.com", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
587     checkRelativeURL("http://ExAmPlE.CoM", "http://other.com", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
588     checkRelativeURL("http:", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
589     checkRelativeURL("#x", "data:,", {"data", "", "", "", 0, ",", "", "x", "data:,#x"});
590     checkRelativeURL("#x", "about:blank", {"about", "", "", "", 0, "blank", "", "x", "about:blank#x"});
591     checkRelativeURL("  foo.com  ", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/foo.com", "", "", "http://example.org/foo/foo.com"});
592     checkRelativeURL(" \a baz", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/baz", "", "", "http://example.org/foo/baz"});
593     checkRelativeURL("~", "http://example.org", {"http", "", "", "example.org", 0, "/~", "", "", "http://example.org/~"});
594     checkRelativeURL("notspecial:", "about:blank", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
595     checkRelativeURL("notspecial:", "http://host", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
596     checkRelativeURL("http:", "http://host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
597     checkRelativeURL("i", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
598     checkRelativeURL("i    ", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
599     checkRelativeURL("i\t\n  ", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
600     checkRelativeURL("i", "sc://ho/pa", {"sc", "", "", "ho", 0, "/i", "", "", "sc://ho/i"});
601     checkRelativeURL("!", "sc://ho/pa", {"sc", "", "", "ho", 0, "/!", "", "", "sc://ho/!"});
602     checkRelativeURL("!", "sc:/ho/pa", {"sc", "", "", "", 0, "/ho/!", "", "", "sc:/ho/!"});
603     checkRelativeURL("notspecial:/", "about:blank", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
604     checkRelativeURL("notspecial:/", "http://host", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
605     checkRelativeURL("foo:/", "http://example.org/foo/bar", {"foo", "", "", "", 0, "/", "", "", "foo:/"});
606     checkRelativeURL("://:0/", "http://webkit.org/", {"http", "", "", "webkit.org", 0, "/://:0/", "", "", "http://webkit.org/://:0/"});
607     checkRelativeURL(String(), "http://webkit.org/", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
608     checkRelativeURL("https://@test@test@example:800\\path@end", "http://doesnotmatter/", {"", "", "", "", 0, "", "", "", "https://@test@test@example:800\\path@end"});
609     checkRelativeURL("http://f:0/c", "http://example.org/foo/bar", {"http", "", "", "f", 0, "/c", "", "", "http://f:0/c"});
610     checkRelativeURL(String(), "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
611     checkRelativeURL("", "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
612     checkRelativeURL("  ", "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
613     checkRelativeURL("  ", "http://host/path?query#fra#gment", {"http", "", "", "host", 0, "/path", "query", "", "http://host/path?query"});
614     checkRelativeURL(" \a ", "http://host/#fragment", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
615     checkRelativeURL("foo://", "http://example.org/foo/bar", {"foo", "", "", "", 0, "//", "", "", "foo://"});
616     checkRelativeURL(utf16String(u"#β"), "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "%CE%B2", "http://example.org/foo/bar#%CE%B2"});
617
618     // The checking of slashes in SpecialAuthoritySlashes needed to get this to pass contradicts what is in the spec,
619     // but it is included in the web platform tests.
620     checkRelativeURL("http:\\\\host\\foo", "about:blank", {"http", "", "", "host", 0, "/foo", "", "", "http://host/foo"});
621 }
622
623 // These are differences between the new URLParser and the old URL::parse which make URLParser more standards compliant.
624 TEST_F(URLParserTest, ParserDifferences)
625 {
626     checkURLDifferences("http://127.0.1",
627         {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
628         {"http", "", "", "127.0.1", 0, "/", "", "", "http://127.0.1/"});
629     checkURLDifferences("http://011.11.0X11.0x011",
630         {"http", "", "", "9.11.17.17", 0, "/", "", "", "http://9.11.17.17/"},
631         {"http", "", "", "011.11.0x11.0x011", 0, "/", "", "", "http://011.11.0x11.0x011/"});
632     checkURLDifferences("http://[1234:0078:90AB:CdEf:0123:0007:89AB:0000]",
633         {"http", "", "", "[1234:78:90ab:cdef:123:7:89ab:0]", 0, "/", "", "", "http://[1234:78:90ab:cdef:123:7:89ab:0]/"},
634         {"http", "", "", "[1234:0078:90ab:cdef:0123:0007:89ab:0000]", 0, "/", "", "", "http://[1234:0078:90ab:cdef:0123:0007:89ab:0000]/"});
635     checkURLDifferences("http://[0:f:0:0:f:f:0:0]",
636         {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"},
637         {"http", "", "", "[0:f:0:0:f:f:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:f:0:0]/"});
638     checkURLDifferences("http://[0:f:0:0:f:0:0:0]",
639         {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"},
640         {"http", "", "", "[0:f:0:0:f:0:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:0:0:0]/"});
641     checkURLDifferences("http://[0:0:f:0:0:f:0:0]",
642         {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"},
643         {"http", "", "", "[0:0:f:0:0:f:0:0]", 0, "/", "", "", "http://[0:0:f:0:0:f:0:0]/"});
644     checkURLDifferences("http://[a:0:0:0:b:c::d]",
645         {"http", "", "", "[a::b:c:0:d]", 0, "/", "", "", "http://[a::b:c:0:d]/"},
646         {"http", "", "", "[a:0:0:0:b:c::d]", 0, "/", "", "", "http://[a:0:0:0:b:c::d]/"});
647     checkURLDifferences("http://[::7f00:0001]/",
648         {"http", "", "", "[::7f00:1]", 0, "/", "", "", "http://[::7f00:1]/"},
649         {"http", "", "", "[::7f00:0001]", 0, "/", "", "", "http://[::7f00:0001]/"});
650     checkURLDifferences("http://[::7f00:00]/",
651         {"http", "", "", "[::7f00:0]", 0, "/", "", "", "http://[::7f00:0]/"},
652         {"http", "", "", "[::7f00:00]", 0, "/", "", "", "http://[::7f00:00]/"});
653     checkURLDifferences("http://[::0:7f00:0001]/",
654         {"http", "", "", "[::7f00:1]", 0, "/", "", "", "http://[::7f00:1]/"},
655         {"http", "", "", "[::0:7f00:0001]", 0, "/", "", "", "http://[::0:7f00:0001]/"});
656     checkURLDifferences("http://127.00.0.1/",
657         {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
658         {"http", "", "", "127.00.0.1", 0, "/", "", "", "http://127.00.0.1/"});
659     checkURLDifferences("http://127.0.0.01/",
660         {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
661         {"http", "", "", "127.0.0.01", 0, "/", "", "", "http://127.0.0.01/"});
662     checkURLDifferences("http://example.com/path1/.%2e",
663         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
664         {"http", "", "", "example.com", 0, "/path1/.%2e", "", "", "http://example.com/path1/.%2e"});
665     checkURLDifferences("http://example.com/path1/.%2E",
666         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
667         {"http", "", "", "example.com", 0, "/path1/.%2E", "", "", "http://example.com/path1/.%2E"});
668     checkURLDifferences("http://example.com/path1/.%2E/",
669         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
670         {"http", "", "", "example.com", 0, "/path1/.%2E/", "", "", "http://example.com/path1/.%2E/"});
671     checkURLDifferences("http://example.com/path1/%2e.",
672         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
673         {"http", "", "", "example.com", 0, "/path1/%2e.", "", "", "http://example.com/path1/%2e."});
674     checkURLDifferences("http://example.com/path1/%2E%2e",
675         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
676         {"http", "", "", "example.com", 0, "/path1/%2E%2e", "", "", "http://example.com/path1/%2E%2e"});
677     checkURLDifferences("http://example.com/path1/%2e",
678         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
679         {"http", "", "", "example.com", 0, "/path1/%2e", "", "", "http://example.com/path1/%2e"});
680     checkURLDifferences("http://example.com/path1/%2E",
681         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
682         {"http", "", "", "example.com", 0, "/path1/%2E", "", "", "http://example.com/path1/%2E"});
683     checkURLDifferences("http://example.com/path1/%2E/",
684         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
685         {"http", "", "", "example.com", 0, "/path1/%2E/", "", "", "http://example.com/path1/%2E/"});
686     checkURLDifferences("http://example.com/path1/path2/%2e?query",
687         {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"},
688         {"http", "", "", "example.com", 0, "/path1/path2/%2e", "query", "", "http://example.com/path1/path2/%2e?query"});
689     checkURLDifferences("http://example.com/path1/path2/%2e%2e?query",
690         {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"},
691         {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "query", "", "http://example.com/path1/path2/%2e%2e?query"});
692     checkURLDifferences("http://example.com/path1/path2/%2e#fragment",
693         {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"},
694         {"http", "", "", "example.com", 0, "/path1/path2/%2e", "", "fragment", "http://example.com/path1/path2/%2e#fragment"});
695     checkURLDifferences("http://example.com/path1/path2/%2e%2e#fragment",
696         {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"},
697         {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "", "fragment", "http://example.com/path1/path2/%2e%2e#fragment"});
698     checkURL("http://example.com/path1/path2/A%2e%2e#fragment", {"http", "", "", "example.com", 0, "/path1/path2/A%2e%2e", "", "fragment", "http://example.com/path1/path2/A%2e%2e#fragment"});
699     checkURLDifferences("file://[0:a:0:0:b:c:0:0]/path",
700         {"file", "", "", "[0:a::b:c:0:0]", 0, "/path", "", "", "file://[0:a::b:c:0:0]/path"},
701         {"file", "", "", "[0:a:0:0:b:c:0:0]", 0, "/path", "", "", "file://[0:a:0:0:b:c:0:0]/path"});
702     checkURLDifferences("http://",
703         {"", "", "", "", 0, "", "", "", "http://"},
704         {"http", "", "", "", 0, "/", "", "", "http:/"});
705     checkRelativeURLDifferences("//", "https://www.webkit.org/path",
706         {"", "", "", "", 0, "", "", "", "//"},
707         {"https", "", "", "", 0, "/", "", "", "https:/"});
708     checkURLDifferences("http://127.0.0.1:65536/path",
709         {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536/path"},
710         {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1:65536/path"});
711     checkURLDifferences("http://host:65536",
712         {"", "", "", "", 0, "", "", "", "http://host:65536"},
713         {"http", "", "", "host", 0, "/", "", "", "http://host:65536/"});
714     checkURLDifferences("http://127.0.0.1:65536",
715         {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536"},
716         {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1:65536/"});
717     checkURLDifferences("http://[0:f::f:f:0:0]:65536",
718         {"", "", "", "", 0, "", "", "", "http://[0:f::f:f:0:0]:65536"},
719         {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]:65536/"});
720     checkRelativeURLDifferences(":foo.com\\", "notspecial://example.org/foo/bar",
721         {"notspecial", "", "", "example.org", 0, "/foo/:foo.com\\", "", "", "notspecial://example.org/foo/:foo.com\\"},
722         {"notspecial", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "notspecial://example.org/foo/:foo.com/"});
723     checkURL("sc://pa", {"sc", "", "", "pa", 0, "", "", "", "sc://pa"});
724     checkRelativeURLDifferences("notspecial:\\\\foo.com\\", "http://example.org/foo/bar",
725         {"notspecial", "", "", "", 0, "\\\\foo.com\\", "", "", "notspecial:\\\\foo.com\\"},
726         {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
727     checkRelativeURLDifferences("notspecial:\\\\foo.com/", "http://example.org/foo/bar",
728         {"notspecial", "", "", "", 0, "\\\\foo.com/", "", "", "notspecial:\\\\foo.com/"},
729         {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
730     checkRelativeURLDifferences("notspecial:\\\\foo.com", "http://example.org/foo/bar",
731         {"notspecial", "", "", "", 0, "\\\\foo.com", "", "", "notspecial:\\\\foo.com"},
732         {"notspecial", "", "", "foo.com", 0, "", "", "", "notspecial://foo.com"});
733     checkURLDifferences("file://notuser:notpassword@test",
734         {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test"},
735         {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
736     checkURLDifferences("file://notuser:notpassword@test/",
737         {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test/"},
738         {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
739     checkRelativeURLDifferences("http:/", "about:blank",
740         {"", "", "", "", 0, "", "", "", "http:/"},
741         {"http", "", "", "", 0, "/", "", "", "http:/"});
742     checkRelativeURLDifferences("http:", "about:blank",
743         {"http", "", "", "", 0, "", "", "", "http:"},
744         {"http", "", "", "", 0, "/", "", "", "http:/"});
745     checkRelativeURLDifferences("http:/", "http://host",
746         {"", "", "", "", 0, "", "", "", "http:/"},
747         {"http", "", "", "", 0, "/", "", "", "http:/"});
748     checkURLDifferences("http:/",
749         {"", "", "", "", 0, "", "", "", "http:/"},
750         {"http", "", "", "", 0, "/", "", "", "http:/"});
751     checkURLDifferences("http:",
752         {"http", "", "", "", 0, "", "", "", "http:"},
753         {"http", "", "", "", 0, "/", "", "", "http:/"});
754     checkRelativeURLDifferences("http:/example.com/", "http://example.org/foo/bar",
755         {"http", "", "", "example.org", 0, "/example.com/", "", "", "http://example.org/example.com/"},
756         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
757
758     // This behavior matches Chrome and Firefox, but not WebKit using URL::parse.
759     // The behavior of URL::parse is clearly wrong because reparsing file://path would make path the host.
760     // The spec is unclear.
761     checkURLDifferences("file:path",
762         {"file", "", "", "", 0, "/path", "", "", "file:///path"},
763         {"file", "", "", "", 0, "path", "", "", "file://path"});
764     checkURLDifferences("file:pAtH",
765         {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"},
766         {"file", "", "", "", 0, "pAtH", "", "", "file://pAtH"});
767     checkURLDifferences("file:pAtH/",
768         {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"},
769         {"file", "", "", "", 0, "pAtH/", "", "", "file://pAtH/"});
770     
771     checkURLDifferences("http://host%73",
772         {"http", "", "", "hosts", 0, "/", "", "", "http://hosts/"},
773         {"http", "", "", "host%73", 0, "/", "", "", "http://host%73/"});
774     checkURLDifferences("http://host%53",
775         {"http", "", "", "hosts", 0, "/", "", "", "http://hosts/"},
776         {"http", "", "", "host%53", 0, "/", "", "", "http://host%53/"});
777     checkURLDifferences("http://%",
778         {"", "", "", "", 0, "", "", "", "http://%"},
779         {"http", "", "", "%", 0, "/", "", "", "http://%/"});
780     checkURLDifferences("http://%7",
781         {"", "", "", "", 0, "", "", "", "http://%7"},
782         {"http", "", "", "%7", 0, "/", "", "", "http://%7/"});
783     checkURLDifferences("http://%7s",
784         {"", "", "", "", 0, "", "", "", "http://%7s"},
785         {"http", "", "", "%7s", 0, "/", "", "", "http://%7s/"});
786     checkURLDifferences("http://%73",
787         {"http", "", "", "s", 0, "/", "", "", "http://s/"},
788         {"http", "", "", "%73", 0, "/", "", "", "http://%73/"});
789     checkURLDifferences("http://abcdefg%",
790         {"", "", "", "", 0, "", "", "", "http://abcdefg%"},
791         {"http", "", "", "abcdefg%", 0, "/", "", "", "http://abcdefg%/"});
792     checkURLDifferences("http://abcd%7Xefg",
793         {"", "", "", "", 0, "", "", "", "http://abcd%7Xefg"},
794         {"http", "", "", "abcd%7xefg", 0, "/", "", "", "http://abcd%7xefg/"});
795
796     
797     // URLParser matches Chrome and the spec, but not URL::parse or Firefox.
798     checkURLDifferences(utf16String(u"http://0Xc0.0250.01"),
799         {"http", "", "", "192.168.0.1", 0, "/", "", "", "http://192.168.0.1/"},
800         {"http", "", "", "0xc0.0250.01", 0, "/", "", "", "http://0xc0.0250.01/"});
801
802     checkURL("http://host/path%2e.%2E", {"http", "", "", "host", 0, "/path%2e.%2E", "", "", "http://host/path%2e.%2E"});
803
804     checkRelativeURLDifferences(utf16String(u"http://foo:💩@example.com/bar"), "http://other.com/",
805         {"http", "foo", utf16String(u"💩"), "example.com", 0, "/bar", "", "", "http://foo:%F0%9F%92%A9@example.com/bar"},
806         {"", "", "", "", 0, "", "", "", utf16String(u"http://foo:💩@example.com/bar")}, testTabsValueForSurrogatePairs);
807     checkRelativeURLDifferences("http://&a:foo(b]c@d:2/", "http://example.org/foo/bar",
808         {"http", "&a", "foo(b]c", "d", 2, "/", "", "", "http://&a:foo(b%5Dc@d:2/"},
809         {"", "", "", "", 0, "", "", "", "http://&a:foo(b]c@d:2/"});
810     checkRelativeURLDifferences("http://`{}:`{}@h/`{}?`{}", "http://doesnotmatter/",
811         {"http", "`{}", "`{}", "h", 0, "/%60%7B%7D", "`{}", "", "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}"},
812         {"", "", "", "", 0, "", "", "", "http://`{}:`{}@h/`{}?`{}"});
813     checkURLDifferences("http://[0:f::f::f]",
814         {"", "", "", "", 0, "" , "", "", "http://[0:f::f::f]"},
815         {"http", "", "", "[0:f::f::f]", 0, "/" , "", "", "http://[0:f::f::f]/"});
816     checkURLDifferences("http://123",
817         {"http", "", "", "0.0.0.123", 0, "/", "", "", "http://0.0.0.123/"},
818         {"http", "", "", "123", 0, "/", "", "", "http://123/"});
819     checkURLDifferences("http://123.234/",
820         {"http", "", "", "123.0.0.234", 0, "/", "", "", "http://123.0.0.234/"},
821         {"http", "", "", "123.234", 0, "/", "", "", "http://123.234/"});
822     checkURLDifferences("http://123.234.012",
823         {"http", "", "", "123.234.0.10", 0, "/", "", "", "http://123.234.0.10/"},
824         {"http", "", "", "123.234.012", 0, "/", "", "", "http://123.234.012/"});
825     checkURLDifferences("http://123.234.12",
826         {"http", "", "", "123.234.0.12", 0, "/", "", "", "http://123.234.0.12/"},
827         {"http", "", "", "123.234.12", 0, "/", "", "", "http://123.234.12/"});
828     checkRelativeURLDifferences("file:c:\\foo\\bar.html", "file:///tmp/mock/path",
829         {"file", "", "", "", 0, "/c:/foo/bar.html", "", "", "file:///c:/foo/bar.html"},
830         {"file", "", "", "", 0, "/tmp/mock/c:/foo/bar.html", "", "", "file:///tmp/mock/c:/foo/bar.html"});
831     checkRelativeURLDifferences("  File:c|////foo\\bar.html", "file:///tmp/mock/path",
832         {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
833         {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
834     checkRelativeURLDifferences("  Fil\t\n\te\n\t\n:\t\n\tc\t\n\t|\n\t\n/\t\n\t/\n\t\n//foo\\bar.html", "file:///tmp/mock/path",
835         {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
836         {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
837     checkRelativeURLDifferences("C|/foo/bar", "file:///tmp/mock/path",
838         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
839         {"file", "", "", "", 0, "/tmp/mock/C|/foo/bar", "", "", "file:///tmp/mock/C|/foo/bar"});
840     checkRelativeURLDifferences("/C|/foo/bar", "file:///tmp/mock/path",
841         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
842         {"file", "", "", "", 0, "/C|/foo/bar", "", "", "file:///C|/foo/bar"});
843     checkRelativeURLDifferences("https://@test@test@example:800/", "http://doesnotmatter/",
844         {"https", "@test@test", "", "example", 800, "/", "", "", "https://%40test%40test@example:800/"},
845         {"", "", "", "", 0, "", "", "", "https://@test@test@example:800/"});
846     checkRelativeURLDifferences("https://@test@test@example:800/path@end", "http://doesnotmatter/",
847         {"https", "@test@test", "", "example", 800, "/path@end", "", "", "https://%40test%40test@example:800/path@end"},
848         {"", "", "", "", 0, "", "", "", "https://@test@test@example:800/path@end"});
849     checkURLDifferences("notspecial://@test@test@example:800/path@end",
850         {"notspecial", "@test@test", "", "example", 800, "/path@end", "", "", "notspecial://%40test%40test@example:800/path@end"},
851         {"", "", "", "", 0, "", "", "", "notspecial://@test@test@example:800/path@end"});
852     checkURLDifferences("notspecial://@test@test@example:800\\path@end",
853         {"notspecial", "@test@test@example", "800\\path", "end", 0, "", "", "", "notspecial://%40test%40test%40example:800%5Cpath@end"},
854         {"", "", "", "", 0, "", "", "", "notspecial://@test@test@example:800\\path@end"});
855     checkURLDifferences("http://%48OsT",
856         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
857         {"http", "", "", "%48ost", 0, "/", "", "", "http://%48ost/"});
858     checkURLDifferences("http://h%4FsT",
859         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
860         {"http", "", "", "h%4fst", 0, "/", "", "", "http://h%4fst/"});
861     checkURLDifferences("http://h%4fsT",
862         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
863         {"http", "", "", "h%4fst", 0, "/", "", "", "http://h%4fst/"});
864     checkURLDifferences("http://h%6fsT",
865         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
866         {"http", "", "", "h%6fst", 0, "/", "", "", "http://h%6fst/"});
867     checkURLDifferences("http://host/`",
868         {"http", "", "", "host", 0, "/%60", "", "", "http://host/%60"},
869         {"http", "", "", "host", 0, "/`", "", "", "http://host/`"});
870     checkURLDifferences("http://://",
871         {"", "", "", "", 0, "", "", "", "http://://"},
872         {"http", "", "", "", 0, "//", "", "", "http://://"});
873     checkURLDifferences("http://:123?",
874         {"", "", "", "", 0, "", "", "", "http://:123?"},
875         {"http", "", "", "", 123, "/", "", "", "http://:123/?"});
876     checkURLDifferences("http:/:",
877         {"", "", "", "", 0, "", "", "", "http:/:"},
878         {"http", "", "", "", 0, "/", "", "", "http://:/"});
879     checkURLDifferences("asdf://:",
880         {"", "", "", "", 0, "", "", "", "asdf://:"},
881         {"asdf", "", "", "", 0, "", "", "", "asdf://:"});
882     checkURLDifferences("http://:",
883         {"", "", "", "", 0, "", "", "", "http://:"},
884         {"http", "", "", "", 0, "/", "", "", "http://:/"});
885     checkURLDifferences("http:##foo",
886         {"http", "", "", "", 0, "//", "", "#foo", "http://##foo"},
887         {"http", "", "", "", 0, "/", "", "#foo", "http:/##foo"});
888     checkURLDifferences("http:??bar",
889         {"http", "", "", "", 0, "//", "?bar", "", "http://??bar"},
890         {"http", "", "", "", 0, "/", "?bar", "", "http:/??bar"});
891     checkRelativeURLDifferences("//C|/foo/bar", "file:///tmp/mock/path",
892         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
893         {"", "", "", "", 0, "", "", "", "//C|/foo/bar"});
894     checkRelativeURLDifferences("//C:/foo/bar", "file:///tmp/mock/path",
895         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
896         {"file", "", "", "c", 0, "/foo/bar", "", "", "file://c/foo/bar"});
897     checkRelativeURLDifferences("//C|?foo/bar", "file:///tmp/mock/path",
898         {"file", "", "", "", 0, "/C:/", "foo/bar", "", "file:///C:/?foo/bar"},
899         {"", "", "", "", 0, "", "", "", "//C|?foo/bar"});
900     checkRelativeURLDifferences("//C|#foo/bar", "file:///tmp/mock/path",
901         {"file", "", "", "", 0, "/C:/", "", "foo/bar", "file:///C:/#foo/bar"},
902         {"", "", "", "", 0, "", "", "", "//C|#foo/bar"});
903     checkURLDifferences("http://0xFFFFFfFF/",
904         {"http", "", "", "255.255.255.255", 0, "/", "", "", "http://255.255.255.255/"},
905         {"http", "", "", "0xffffffff", 0, "/", "", "", "http://0xffffffff/"});
906     checkURLDifferences("http://0000000000000000037777777777/",
907         {"http", "", "", "255.255.255.255", 0, "/", "", "", "http://255.255.255.255/"},
908         {"http", "", "", "0000000000000000037777777777", 0, "/", "", "", "http://0000000000000000037777777777/"});
909     checkURLDifferences("http://4294967295/",
910         {"http", "", "", "255.255.255.255", 0, "/", "", "", "http://255.255.255.255/"},
911         {"http", "", "", "4294967295", 0, "/", "", "", "http://4294967295/"});
912     checkURLDifferences("http://256/",
913         {"http", "", "", "0.0.1.0", 0, "/", "", "", "http://0.0.1.0/"},
914         {"http", "", "", "256", 0, "/", "", "", "http://256/"});
915     checkURLDifferences("http://256./",
916         {"http", "", "", "0.0.1.0", 0, "/", "", "", "http://0.0.1.0/"},
917         {"http", "", "", "256.", 0, "/", "", "", "http://256./"});
918     checkURLDifferences("http://123.256/",
919         {"http", "", "", "123.0.1.0", 0, "/", "", "", "http://123.0.1.0/"},
920         {"http", "", "", "123.256", 0, "/", "", "", "http://123.256/"});
921     checkURLDifferences("http://127.%.0.1/",
922         {"", "", "", "", 0, "", "", "", "http://127.%.0.1/"},
923         {"http", "", "", "127.%.0.1", 0, "/", "", "", "http://127.%.0.1/"});
924     checkURLDifferences("http://[1:2:3:4:5:6:7:8:]/",
925         {"", "", "", "", 0, "", "", "", "http://[1:2:3:4:5:6:7:8:]/"},
926         {"http", "", "", "[1:2:3:4:5:6:7:8:]", 0, "/", "", "", "http://[1:2:3:4:5:6:7:8:]/"});
927     checkURLDifferences("http://[:2:3:4:5:6:7:8:]/",
928         {"", "", "", "", 0, "", "", "", "http://[:2:3:4:5:6:7:8:]/"},
929         {"http", "", "", "[:2:3:4:5:6:7:8:]", 0, "/", "", "", "http://[:2:3:4:5:6:7:8:]/"});
930     checkURLDifferences("http://[1:2:3:4:5:6:7::]/",
931         {"http", "", "", "[1:2:3:4:5:6:7:0]", 0, "/", "", "", "http://[1:2:3:4:5:6:7:0]/"},
932         {"http", "", "", "[1:2:3:4:5:6:7::]", 0, "/", "", "", "http://[1:2:3:4:5:6:7::]/"});
933     checkURLDifferences("http://[1:2:3:4:5:6:7:::]/",
934         {"", "", "", "", 0, "", "", "", "http://[1:2:3:4:5:6:7:::]/"},
935         {"http", "", "", "[1:2:3:4:5:6:7:::]", 0, "/", "", "", "http://[1:2:3:4:5:6:7:::]/"});
936     checkURLDifferences("http://127.0.0.1~/",
937         {"http", "", "", "127.0.0.1~", 0, "/", "", "", "http://127.0.0.1~/"},
938         {"", "", "", "", 0, "", "", "", "http://127.0.0.1~/"});
939     checkURLDifferences("http://127.0.1~/",
940         {"http", "", "", "127.0.1~", 0, "/", "", "", "http://127.0.1~/"},
941         {"", "", "", "", 0, "", "", "", "http://127.0.1~/"});
942     checkURLDifferences("http://127.0.1./",
943         {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
944         {"http", "", "", "127.0.1.", 0, "/", "", "", "http://127.0.1./"});
945     checkURLDifferences("http://127.0.1.~/",
946         {"http", "", "", "127.0.1.~", 0, "/", "", "", "http://127.0.1.~/"},
947         {"", "", "", "", 0, "", "", "", "http://127.0.1.~/"});
948     checkURLDifferences("http://127.0.1.~",
949         {"http", "", "", "127.0.1.~", 0, "/", "", "", "http://127.0.1.~/"},
950         {"", "", "", "", 0, "", "", "", "http://127.0.1.~"});
951     checkRelativeURLDifferences("http://f:000/c", "http://example.org/foo/bar",
952         {"http", "", "", "f", 0, "/c", "", "", "http://f:0/c"},
953         {"http", "", "", "f", 0, "/c", "", "", "http://f:000/c"});
954     checkRelativeURLDifferences("http://f:010/c", "http://example.org/foo/bar",
955         {"http", "", "", "f", 10, "/c", "", "", "http://f:10/c"},
956         {"http", "", "", "f", 10, "/c", "", "", "http://f:010/c"});
957     checkURL("notspecial://HoSt", {"notspecial", "", "", "HoSt", 0, "", "", "", "notspecial://HoSt"});
958     checkURL("notspecial://H%6FSt", {"notspecial", "", "", "H%6FSt", 0, "", "", "", "notspecial://H%6FSt"});
959     checkURL("notspecial://H%4fSt", {"notspecial", "", "", "H%4fSt", 0, "", "", "", "notspecial://H%4fSt"});
960     checkURLDifferences(utf16String(u"notspecial://H😍ßt"),
961         {"notspecial", "", "", "H%F0%9F%98%8D%C3%9Ft", 0, "", "", "", "notspecial://H%F0%9F%98%8D%C3%9Ft"},
962         {"notspecial", "", "", "xn--hsst-qc83c", 0, "", "", "", "notspecial://xn--hsst-qc83c"}, testTabsValueForSurrogatePairs);
963     checkURLDifferences("http://[ffff:aaaa:cccc:eeee:bbbb:dddd:255.255.255.255]/",
964         {"http", "", "", "[ffff:aaaa:cccc:eeee:bbbb:dddd:ffff:ffff]", 0, "/", "", "", "http://[ffff:aaaa:cccc:eeee:bbbb:dddd:ffff:ffff]/"},
965         {"http", "", "", "[ffff:aaaa:cccc:eeee:bbbb:dddd:255.255.255.255]", 0, "/", "", "", "http://[ffff:aaaa:cccc:eeee:bbbb:dddd:255.255.255.255]/"}, TestTabs::No);
966     checkURLDifferences("http://[::123.234.12.210]/",
967         {"http", "", "", "[::7bea:cd2]", 0, "/", "", "", "http://[::7bea:cd2]/"},
968         {"http", "", "", "[::123.234.12.210]", 0, "/", "", "", "http://[::123.234.12.210]/"});
969     checkURLDifferences("http://[::a:255.255.255.255]/",
970         {"http", "", "", "[::a:ffff:ffff]", 0, "/", "", "", "http://[::a:ffff:ffff]/"},
971         {"http", "", "", "[::a:255.255.255.255]", 0, "/", "", "", "http://[::a:255.255.255.255]/"});
972     checkURLDifferences("http://[::0.00.255.255]/",
973         {"", "", "", "", 0, "", "", "", "http://[::0.00.255.255]/"},
974         {"http", "", "", "[::0.00.255.255]", 0, "/", "", "", "http://[::0.00.255.255]/"});
975     checkURLDifferences("http://[::0.0.255.255]/",
976         {"http", "", "", "[::ffff]", 0, "/", "", "", "http://[::ffff]/"},
977         {"http", "", "", "[::0.0.255.255]", 0, "/", "", "", "http://[::0.0.255.255]/"});
978     checkURLDifferences("http://[::0:1.0.255.255]/",
979         {"http", "", "", "[::100:ffff]", 0, "/", "", "", "http://[::100:ffff]/"},
980         {"http", "", "", "[::0:1.0.255.255]", 0, "/", "", "", "http://[::0:1.0.255.255]/"});
981     checkURLDifferences("http://[::A:1.0.255.255]/",
982         {"http", "", "", "[::a:100:ffff]", 0, "/", "", "", "http://[::a:100:ffff]/"},
983         {"http", "", "", "[::a:1.0.255.255]", 0, "/", "", "", "http://[::a:1.0.255.255]/"});
984     checkURLDifferences("http://[:127.0.0.1]",
985         {"", "", "", "", 0, "", "", "", "http://[:127.0.0.1]"},
986         {"http", "", "", "[:127.0.0.1]", 0, "/", "", "", "http://[:127.0.0.1]/"});
987     checkURLDifferences("http://[127.0.0.1]",
988         {"", "", "", "", 0, "", "", "", "http://[127.0.0.1]"},
989         {"http", "", "", "[127.0.0.1]", 0, "/", "", "", "http://[127.0.0.1]/"});
990     checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.1]",
991         {"http", "", "", "[a:b:c:d:e:f:7f00:1]", 0, "/", "", "", "http://[a:b:c:d:e:f:7f00:1]/"},
992         {"http", "", "", "[a:b:c:d:e:f:127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.1]/"});
993     checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.101]",
994         {"http", "", "", "[a:b:c:d:e:f:7f00:65]", 0, "/", "", "", "http://[a:b:c:d:e:f:7f00:65]/"},
995         {"http", "", "", "[a:b:c:d:e:f:127.0.0.101]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.101]/"});
996     checkURLDifferences("http://[::a:b:c:d:e:f:127.0.0.1]",
997         {"", "", "", "", 0, "", "", "", "http://[::a:b:c:d:e:f:127.0.0.1]"},
998         {"http", "", "", "[::a:b:c:d:e:f:127.0.0.1]", 0, "/", "", "", "http://[::a:b:c:d:e:f:127.0.0.1]/"});
999     checkURLDifferences("http://[a:b::c:d:e:f:127.0.0.1]",
1000         {"", "", "", "", 0, "", "", "", "http://[a:b::c:d:e:f:127.0.0.1]"},
1001         {"http", "", "", "[a:b::c:d:e:f:127.0.0.1]", 0, "/", "", "", "http://[a:b::c:d:e:f:127.0.0.1]/"});
1002     checkURLDifferences("http://[a:b:c:d:e:127.0.0.1]",
1003         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:127.0.0.1]"},
1004         {"http", "", "", "[a:b:c:d:e:127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:127.0.0.1]/"});
1005     checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.0.1]",
1006         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.0.0.1]"},
1007         {"http", "", "", "[a:b:c:d:e:f:127.0.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.0.1]/"});
1008     checkURLDifferences("http://[a:b:c:d:e:f:127.0.1]",
1009         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.1]"},
1010         {"http", "", "", "[a:b:c:d:e:f:127.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.1]/"});
1011     checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.011]", // Chrome treats this as octal, Firefox and the spec fail
1012         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.0.011]"},
1013         {"http", "", "", "[a:b:c:d:e:f:127.0.0.011]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.011]/"});
1014     checkURLDifferences("http://[a:b:c:d:e:f:127.0.00.1]",
1015         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.00.1]"},
1016         {"http", "", "", "[a:b:c:d:e:f:127.0.00.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.00.1]/"});
1017     checkURLDifferences("http://[a:b:c:d:e:f:127.0.0.1.]",
1018         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0.0.1.]"},
1019         {"http", "", "", "[a:b:c:d:e:f:127.0.0.1.]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0.0.1.]/"});
1020     checkURLDifferences("http://[a:b:c:d:e:f:127.0..0.1]",
1021         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f:127.0..0.1]"},
1022         {"http", "", "", "[a:b:c:d:e:f:127.0..0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f:127.0..0.1]/"});
1023     checkURLDifferences("http://[a:b:c:d:e:f::127.0.0.1]",
1024         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f::127.0.0.1]"},
1025         {"http", "", "", "[a:b:c:d:e:f::127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e:f::127.0.0.1]/"});
1026     checkURLDifferences("http://[a:b:c:d:e::127.0.0.1]",
1027         {"http", "", "", "[a:b:c:d:e:0:7f00:1]", 0, "/", "", "", "http://[a:b:c:d:e:0:7f00:1]/"},
1028         {"http", "", "", "[a:b:c:d:e::127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d:e::127.0.0.1]/"});
1029     checkURLDifferences("http://[a:b:c:d::e:127.0.0.1]",
1030         {"http", "", "", "[a:b:c:d:0:e:7f00:1]", 0, "/", "", "", "http://[a:b:c:d:0:e:7f00:1]/"},
1031         {"http", "", "", "[a:b:c:d::e:127.0.0.1]", 0, "/", "", "", "http://[a:b:c:d::e:127.0.0.1]/"});
1032     checkURLDifferences("http://[a:b:c:d:e:f::127.0.0.]",
1033         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f::127.0.0.]"},
1034         {"http", "", "", "[a:b:c:d:e:f::127.0.0.]", 0, "/", "", "", "http://[a:b:c:d:e:f::127.0.0.]/"});
1035     checkURLDifferences("http://[a:b:c:d:e:f::127.0.0.256]",
1036         {"", "", "", "", 0, "", "", "", "http://[a:b:c:d:e:f::127.0.0.256]"},
1037         {"http", "", "", "[a:b:c:d:e:f::127.0.0.256]", 0, "/", "", "", "http://[a:b:c:d:e:f::127.0.0.256]/"});
1038     checkURLDifferences("http://123456", {"http", "", "", "0.1.226.64", 0, "/", "", "", "http://0.1.226.64/"}, {"http", "", "", "123456", 0, "/", "", "", "http://123456/"});
1039     checkURL("asdf://123456", {"asdf", "", "", "123456", 0, "", "", "", "asdf://123456"});
1040     checkURLDifferences("http://[0:0:0:0:a:b:c:d]",
1041         {"http", "", "", "[::a:b:c:d]", 0, "/", "", "", "http://[::a:b:c:d]/"},
1042         {"http", "", "", "[0:0:0:0:a:b:c:d]", 0, "/", "", "", "http://[0:0:0:0:a:b:c:d]/"});
1043     checkURLDifferences("asdf://[0:0:0:0:a:b:c:d]",
1044         {"asdf", "", "", "[::a:b:c:d]", 0, "", "", "", "asdf://[::a:b:c:d]"},
1045         {"asdf", "", "", "[0:0:0:0:a:b:c:d]", 0, "", "", "", "asdf://[0:0:0:0:a:b:c:d]"}, TestTabs::No);
1046     shouldFail("a://%:a");
1047     checkURL("a://%:/", {"a", "", "", "%", 0, "/", "", "", "a://%/"});
1048     checkURL("a://%:", {"a", "", "", "%", 0, "", "", "", "a://%"});
1049     checkURL("a://%:1/", {"a", "", "", "%", 1, "/", "", "", "a://%:1/"});
1050     checkURLDifferences("http://%:",
1051         {"", "", "", "", 0, "", "", "", "http://%:"},
1052         {"http", "", "", "%", 0, "/", "", "", "http://%/"});
1053     checkURL("a://123456", {"a", "", "", "123456", 0, "", "", "", "a://123456"});
1054     checkURL("a://123456:7", {"a", "", "", "123456", 7, "", "", "", "a://123456:7"});
1055     checkURL("a://123456:7/", {"a", "", "", "123456", 7, "/", "", "", "a://123456:7/"});
1056     checkURL("a://A", {"a", "", "", "A", 0, "", "", "", "a://A"});
1057     checkURL("a://A:2", {"a", "", "", "A", 2, "", "", "", "a://A:2"});
1058     checkURL("a://A:2/", {"a", "", "", "A", 2, "/", "", "", "a://A:2/"});
1059     checkURLDifferences("asd://ß",
1060         {"asd", "", "", "%C3%83%C2%9F", 0, "", "", "", "asd://%C3%83%C2%9F"},
1061         {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
1062     checkURLDifferences("asd://ß:4",
1063         {"asd", "", "", "%C3%83%C2%9F", 4, "", "", "", "asd://%C3%83%C2%9F:4"},
1064         {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
1065     checkURLDifferences("asd://ß:4/",
1066         {"asd", "", "", "%C3%83%C2%9F", 4, "/", "", "", "asd://%C3%83%C2%9F:4/"},
1067         {"", "", "", "", 0, "", "", "", "about:blank"}, TestTabs::No);
1068     checkURLDifferences("a://[A::b]:4",
1069         {"a", "", "", "[a::b]", 4, "", "", "", "a://[a::b]:4"},
1070         {"a", "", "", "[A::b]", 4, "", "", "", "a://[A::b]:4"});
1071     shouldFail("http://[~]");
1072     shouldFail("a://[~]");
1073     checkRelativeURLDifferences("a://b", "//[aBc]",
1074         {"a", "", "", "b", 0, "", "", "", "a://b"},
1075         {"", "", "", "", 0, "", "", "", "a://b"});
1076 }
1077
1078 TEST_F(URLParserTest, DefaultPort)
1079 {
1080     checkURL("FtP://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1081     checkURL("ftp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1082     checkURL("f\ttp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1083     checkURL("f\ttp://host\t:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1084     checkURL("f\ttp://host:\t21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1085     checkURL("f\ttp://host:2\t1/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1086     checkURL("f\ttp://host:21\t/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1087     checkURL("ftp://host\t:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1088     checkURL("ftp://host:\t21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1089     checkURL("ftp://host:2\t1/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1090     checkURL("ftp://host:21\t/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
1091     checkURL("ftp://host:22/", {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"});
1092     checkURLDifferences("ftp://host:21",
1093         {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"},
1094         {"ftp", "", "", "host", 0, "", "", "", "ftp://host"});
1095     checkURLDifferences("ftp://host:22",
1096         {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"},
1097         {"ftp", "", "", "host", 22, "", "", "", "ftp://host:22"});
1098     
1099     checkURL("gOpHeR://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
1100     checkURL("gopher://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
1101     checkURL("gopher://host:71/", {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"});
1102     // Spec, Chrome, Firefox, and URLParser have "/", URL::parse does not.
1103     // Spec, Chrome, URLParser, URL::parse recognize gopher default port, Firefox does not.
1104     checkURLDifferences("gopher://host:70",
1105         {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"},
1106         {"gopher", "", "", "host", 0, "", "", "", "gopher://host"});
1107     checkURLDifferences("gopher://host:71",
1108         {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"},
1109         {"gopher", "", "", "host", 71, "", "", "", "gopher://host:71"});
1110     
1111     checkURL("hTtP://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
1112     checkURL("http://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
1113     checkURL("http://host:80/", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
1114     checkURL("http://host:81", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
1115     checkURL("http://host:81/", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
1116     
1117     checkURL("hTtPs://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
1118     checkURL("https://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
1119     checkURL("https://host:443/", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
1120     checkURL("https://host:444", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
1121     checkURL("https://host:444/", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
1122     
1123     checkURL("wS://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
1124     checkURL("ws://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
1125     checkURL("ws://host:81/", {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"});
1126     // URLParser matches Chrome and Firefox, but not URL::parse
1127     checkURLDifferences("ws://host:80",
1128         {"ws", "", "", "host", 0, "/", "", "", "ws://host/"},
1129         {"ws", "", "", "host", 0, "", "", "", "ws://host"});
1130     checkURLDifferences("ws://host:81",
1131         {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"},
1132         {"ws", "", "", "host", 81, "", "", "", "ws://host:81"});
1133     
1134     checkURL("WsS://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
1135     checkURL("wss://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
1136     checkURL("wss://host:444/", {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"});
1137     // URLParser matches Chrome and Firefox, but not URL::parse
1138     checkURLDifferences("wss://host:443",
1139         {"wss", "", "", "host", 0, "/", "", "", "wss://host/"},
1140         {"wss", "", "", "host", 0, "", "", "", "wss://host"});
1141     checkURLDifferences("wss://host:444",
1142         {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"},
1143         {"wss", "", "", "host", 444, "", "", "", "wss://host:444"});
1144
1145     checkURL("fTpS://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
1146     checkURL("ftps://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
1147     checkURL("ftps://host:991/", {"ftps", "", "", "host", 991, "/", "", "", "ftps://host:991/"});
1148     checkURL("ftps://host:990", {"ftps", "", "", "host", 990, "", "", "", "ftps://host:990"});
1149     checkURL("ftps://host:991", {"ftps", "", "", "host", 991, "", "", "", "ftps://host:991"});
1150
1151     checkURL("uNkNoWn://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
1152     checkURL("unknown://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
1153     checkURL("unknown://host:81/", {"unknown", "", "", "host", 81, "/", "", "", "unknown://host:81/"});
1154     checkURL("unknown://host:80", {"unknown", "", "", "host", 80, "", "", "", "unknown://host:80"});
1155     checkURL("unknown://host:81", {"unknown", "", "", "host", 81, "", "", "", "unknown://host:81"});
1156
1157     checkURL("file://host:0", {"file", "", "", "host", 0, "/", "", "", "file://host:0/"});
1158     checkURL("file://host:80", {"file", "", "", "host", 80, "/", "", "", "file://host:80/"});
1159     checkURL("file://host:80/path", {"file", "", "", "host", 80, "/path", "", "", "file://host:80/path"});
1160     checkURLDifferences("file://:80/path",
1161         {"", "", "", "", 0, "", "", "", "file://:80/path"},
1162         {"file", "", "", "", 80, "/path", "", "", "file://:80/path"});
1163     checkURLDifferences("file://:0/path",
1164         {"", "", "", "", 0, "", "", "", "file://:0/path"},
1165         {"file", "", "", "", 0, "/path", "", "", "file://:0/path"});
1166 }
1167
1168 TEST_F(URLParserTest, ParserFailures)
1169 {
1170     shouldFail("    ");
1171     shouldFail("  \a  ");
1172     shouldFail("");
1173     shouldFail(String());
1174     shouldFail("", "about:blank");
1175     shouldFail(String(), "about:blank");
1176     shouldFail("http://127.0.0.1:abc");
1177     shouldFail("http://host:abc");
1178     shouldFail("http://:abc");
1179     shouldFail("http://a:@", "about:blank");
1180     shouldFail("http://:b@", "about:blank");
1181     shouldFail("http://:@", "about:blank");
1182     shouldFail("http://a:@");
1183     shouldFail("http://:b@");
1184     shouldFail("http://@");
1185     shouldFail("http://[0:f::f:f:0:0]:abc");
1186     shouldFail("../i", "sc:sd");
1187     shouldFail("../i", "sc:sd/sd");
1188     shouldFail("/i", "sc:sd");
1189     shouldFail("/i", "sc:sd/sd");
1190     shouldFail("?i", "sc:sd");
1191     shouldFail("?i", "sc:sd/sd");
1192     shouldFail("http://example example.com", "http://other.com/");
1193     shouldFail("http://[www.example.com]/", "about:blank");
1194     shouldFail("http://192.168.0.1 hello", "http://other.com/");
1195     shouldFail("http://[example.com]", "http://other.com/");
1196     shouldFail("i", "sc:sd");
1197     shouldFail("i", "sc:sd/sd");
1198     shouldFail("i");
1199     shouldFail("asdf");
1200     shouldFail("~");
1201     shouldFail("%");
1202     shouldFail("//%");
1203     shouldFail("~", "about:blank");
1204     shouldFail("~~~");
1205     shouldFail("://:0/");
1206     shouldFail("://:0/", "");
1207     shouldFail("://:0/", "about:blank");
1208     shouldFail("about~");
1209     shouldFail("//C:asdf/foo/bar", "file:///tmp/mock/path");
1210     shouldFail("http://[1234::ab#]");
1211     shouldFail("http://[1234::ab/]");
1212     shouldFail("http://[1234::ab?]");
1213     shouldFail("http://[1234::ab@]");
1214     shouldFail("http://[1234::ab~]");
1215     shouldFail("http://[2001::1");
1216     shouldFail("http://[1:2:3:4:5:6:7:8~]/");
1217     shouldFail("http://[a:b:c:d:e:f:g:127.0.0.1]");
1218     shouldFail("http://[a:b:c:d:e:f:g:h:127.0.0.1]");
1219     shouldFail("http://[a:b:c:d:e:f:127.0.0.0x11]"); // Chrome treats this as hex, Firefox and the spec fail
1220     shouldFail("http://[a:b:c:d:e:f:127.0.-0.1]");
1221     checkURLDifferences("asdf://space In\aHost",
1222         {"asdf", "", "", "space In%07Host", 0, "", "", "", "asdf://space In%07Host"},
1223         {"", "", "", "", 0, "", "", "", "asdf://space In\aHost"});
1224     shouldFail("asdf://[0:0:0:0:a:b:c:d");
1225 }
1226
1227 // These are in the spec but not in the web platform tests.
1228 TEST_F(URLParserTest, AdditionalTests)
1229 {
1230     checkURL("about:\a\aabc", {"about", "", "", "", 0, "%07%07abc", "", "", "about:%07%07abc"});
1231     checkURL("notspecial:\t\t\n\t", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
1232     checkURL("notspecial\t\t\n\t:\t\t\n\t/\t\t\n\t/\t\t\n\thost", {"notspecial", "", "", "host", 0, "", "", "", "notspecial://host"});
1233     checkRelativeURL("http:", "http://example.org/foo/bar?query#fragment", {"http", "", "", "example.org", 0, "/foo/bar", "query", "", "http://example.org/foo/bar?query"});
1234     checkRelativeURLDifferences("ws:", "http://example.org/foo/bar",
1235         {"ws", "", "", "", 0, "", "", "", "ws:"},
1236         {"ws", "", "", "", 0, "s:", "", "", "ws:s:"});
1237     checkRelativeURL("notspecial:", "http://example.org/foo/bar", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
1238
1239     const wchar_t surrogateBegin = 0xD800;
1240     const wchar_t validSurrogateEnd = 0xDD55;
1241     const wchar_t invalidSurrogateEnd = 'A';
1242     checkURL(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, validSurrogateEnd, '\0'}),
1243         {"http", "", "", "w", 0, "/%F0%90%85%95", "", "", "http://w/%F0%90%85%95"}, testTabsValueForSurrogatePairs);
1244
1245     // URLParser matches Chrome and Firefox but not URL::parse.
1246     checkURLDifferences(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, invalidSurrogateEnd}),
1247         {"http", "", "", "w", 0, "/%EF%BF%BDA", "", "", "http://w/%EF%BF%BDA"},
1248         {"http", "", "", "w", 0, "/%ED%A0%80A", "", "", "http://w/%ED%A0%80A"});
1249     checkURLDifferences(utf16String<13>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, invalidSurrogateEnd, '\0'}),
1250         {"http", "", "", "w", 0, "/", "%EF%BF%BDA", "", "http://w/?%EF%BF%BDA"},
1251         {"http", "", "", "w", 0, "/", "%ED%A0%80A", "", "http://w/?%ED%A0%80A"});
1252     checkURLDifferences(utf16String<11>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, '\0'}),
1253         {"http", "", "", "w", 0, "/%EF%BF%BD", "", "", "http://w/%EF%BF%BD"},
1254         {"http", "", "", "w", 0, "/%ED%A0%80", "", "", "http://w/%ED%A0%80"});
1255     checkURLDifferences(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, '\0'}),
1256         {"http", "", "", "w", 0, "/", "%EF%BF%BD", "", "http://w/?%EF%BF%BD"},
1257         {"http", "", "", "w", 0, "/", "%ED%A0%80", "", "http://w/?%ED%A0%80"});
1258     checkURLDifferences(utf16String<13>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, ' ', '\0'}),
1259         {"http", "", "", "w", 0, "/", "%EF%BF%BD", "", "http://w/?%EF%BF%BD"},
1260         {"http", "", "", "w", 0, "/", "%ED%A0%80", "", "http://w/?%ED%A0%80"});
1261     
1262     // FIXME: Write more invalid surrogate pair tests based on feedback from https://bugs.webkit.org/show_bug.cgi?id=162105
1263 }
1264
1265 TEST_F(URLParserTest, QueryEncoding)
1266 {
1267     checkURL(utf16String(u"http://host?ß😍#ß😍"), UTF8Encoding(), {"http", "", "", "host", 0, "/", "%C3%9F%F0%9F%98%8D", "%C3%9F%F0%9F%98%8D", utf16String(u"http://host/?%C3%9F%F0%9F%98%8D#%C3%9F%F0%9F%98%8D")}, testTabsValueForSurrogatePairs);
1268
1269     TextEncoding latin1(String("latin1"));
1270     checkURL("http://host/?query with%20spaces", latin1, {"http", "", "", "host", 0, "/", "query%20with%20spaces", "", "http://host/?query%20with%20spaces"});
1271     checkURL("http://host/?query", latin1, {"http", "", "", "host", 0, "/", "query", "", "http://host/?query"});
1272     checkURL("http://host/?\tquery", latin1, {"http", "", "", "host", 0, "/", "query", "", "http://host/?query"});
1273     checkURL("http://host/?q\tuery", latin1, {"http", "", "", "host", 0, "/", "query", "", "http://host/?query"});
1274     checkURL("http://host/?query with SpAcEs#fragment", latin1, {"http", "", "", "host", 0, "/", "query%20with%20SpAcEs", "fragment", "http://host/?query%20with%20SpAcEs#fragment"});
1275     checkURL("http://host/?que\rry\t\r\n#fragment", latin1, {"http", "", "", "host", 0, "/", "query", "fragment", "http://host/?query#fragment"});
1276
1277     TextEncoding unrecognized(String("unrecognized invalid encoding name"));
1278     checkURL("http://host/?query", unrecognized, {"http", "", "", "host", 0, "/", "", "", "http://host/?"});
1279     checkURL("http://host/?", unrecognized, {"http", "", "", "host", 0, "/", "", "", "http://host/?"});
1280
1281     TextEncoding iso88591(String("ISO-8859-1"));
1282     String withUmlauts = utf16String<4>({0xDC, 0x430, 0x451, '\0'});
1283     checkURL(makeString("ws://host/path?", withUmlauts), iso88591, {"ws", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "", "ws://host/path?%C3%9C%D0%B0%D1%91"});
1284     checkURL(makeString("wss://host/path?", withUmlauts), iso88591, {"wss", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "", "wss://host/path?%C3%9C%D0%B0%D1%91"});
1285     checkURL(makeString("asdf://host/path?", withUmlauts), iso88591, {"asdf", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "", "asdf://host/path?%C3%9C%D0%B0%D1%91"});
1286     checkURL(makeString("https://host/path?", withUmlauts), iso88591, {"https", "", "", "host", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "", "https://host/path?%DC%26%231072%3B%26%231105%3B"});
1287     checkURL(makeString("gopher://host/path?", withUmlauts), iso88591, {"gopher", "", "", "host", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "", "gopher://host/path?%DC%26%231072%3B%26%231105%3B"});
1288     checkURL(makeString("/path?", withUmlauts, "#fragment"), "ws://example.com/", iso88591, {"ws", "", "", "example.com", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "ws://example.com/path?%C3%9C%D0%B0%D1%91#fragment"});
1289     checkURL(makeString("/path?", withUmlauts, "#fragment"), "wss://example.com/", iso88591, {"wss", "", "", "example.com", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "wss://example.com/path?%C3%9C%D0%B0%D1%91#fragment"});
1290     checkURL(makeString("/path?", withUmlauts, "#fragment"), "asdf://example.com/", iso88591, {"asdf", "", "", "example.com", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "asdf://example.com/path?%C3%9C%D0%B0%D1%91#fragment"});
1291     checkURL(makeString("/path?", withUmlauts, "#fragment"), "https://example.com/", iso88591, {"https", "", "", "example.com", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "fragment", "https://example.com/path?%DC%26%231072%3B%26%231105%3B#fragment"});
1292     checkURL(makeString("/path?", withUmlauts, "#fragment"), "gopher://example.com/", iso88591, {"gopher", "", "", "example.com", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "fragment", "gopher://example.com/path?%DC%26%231072%3B%26%231105%3B#fragment"});
1293     checkURL(makeString("gopher://host/path?", withUmlauts, "#fragment"), "asdf://example.com/?doesntmatter", iso88591, {"gopher", "", "", "host", 0, "/path", "%DC%26%231072%3B%26%231105%3B", "fragment", "gopher://host/path?%DC%26%231072%3B%26%231105%3B#fragment"});
1294     checkURL(makeString("asdf://host/path?", withUmlauts, "#fragment"), "http://example.com/?doesntmatter", iso88591, {"asdf", "", "", "host", 0, "/path", "%C3%9C%D0%B0%D1%91", "fragment", "asdf://host/path?%C3%9C%D0%B0%D1%91#fragment"});
1295
1296     // FIXME: Add more tests with other encodings and things like non-ascii characters, emoji and unmatched surrogate pairs.
1297 }
1298
1299 } // namespace TestWebKitAPI