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