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