859e5fcf79a5001b98441b044f11c73c20b6ae06
[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
30 using namespace WebCore;
31
32 namespace TestWebKitAPI {
33
34 class URLParserTest : public testing::Test {
35 public:
36     void SetUp() final {
37         WTF::initializeMainThread();
38     }
39 };
40
41 struct ExpectedParts {
42     String protocol;
43     String user;
44     String password;
45     String host;
46     unsigned short port;
47     String path;
48     String query;
49     String fragment;
50     String string;
51 };
52
53 static bool eq(const String& s1, const String& s2)
54 {
55     EXPECT_STREQ(s1.utf8().data(), s2.utf8().data());
56     return s1.utf8() == s2.utf8();
57 }
58
59 static void checkURL(const String& urlString, const ExpectedParts& parts)
60 {
61     URLParser parser;
62     auto url = parser.parse(urlString);
63     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
64     EXPECT_TRUE(eq(parts.user, url.user()));
65     EXPECT_TRUE(eq(parts.password, url.pass()));
66     EXPECT_TRUE(eq(parts.host, url.host()));
67     EXPECT_EQ(parts.port, url.port());
68     EXPECT_TRUE(eq(parts.path, url.path()));
69     EXPECT_TRUE(eq(parts.query, url.query()));
70     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
71     EXPECT_TRUE(eq(parts.string, url.string()));
72     
73     auto oldURL = URL(URL(), urlString);
74     EXPECT_TRUE(eq(parts.protocol, oldURL.protocol()));
75     EXPECT_TRUE(eq(parts.user, oldURL.user()));
76     EXPECT_TRUE(eq(parts.password, oldURL.pass()));
77     EXPECT_TRUE(eq(parts.host, oldURL.host()));
78     EXPECT_EQ(parts.port, oldURL.port());
79     EXPECT_TRUE(eq(parts.path, oldURL.path()));
80     EXPECT_TRUE(eq(parts.query, oldURL.query()));
81     EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier()));
82     EXPECT_TRUE(eq(parts.string, oldURL.string()));
83     
84     EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));
85     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
86     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
87 }
88
89 template<size_t length>
90 static String wideString(const wchar_t (&url)[length])
91 {
92     StringBuilder builder;
93     builder.reserveCapacity(length - 1);
94     for (size_t i = 0; i < length - 1; ++i)
95         builder.append(url[i]);
96     return builder.toString();
97 }
98
99 TEST_F(URLParserTest, Basic)
100 {
101     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"});
102     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"});
103     checkURL("http://user:pass@webkit.org:123/path", {"http", "user", "pass", "webkit.org", 123, "/path", "", "", "http://user:pass@webkit.org:123/path"});
104     checkURL("http://user:pass@webkit.org:123/", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
105     checkURL("http://user:pass@webkit.org:123", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
106     checkURL("http://user:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
107     checkURL("http://webkit.org", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
108     checkURL("http://127.0.0.1", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
109     checkURL("http://webkit.org/", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
110     checkURL("http://webkit.org/path1/path2/index.html", {"http", "", "", "webkit.org", 0, "/path1/path2/index.html", "", "", "http://webkit.org/path1/path2/index.html"});
111     checkURL("about:blank", {"about", "", "", "", 0, "blank", "", "", "about:blank"});
112     checkURL("about:blank?query", {"about", "", "", "", 0, "blank", "query", "", "about:blank?query"});
113     checkURL("about:blank#fragment", {"about", "", "", "", 0, "blank", "", "fragment", "about:blank#fragment"});
114     checkURL("http://[0:f::f:f:0:0]", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
115     checkURL("http://[0:f:0:0:f::]", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
116     checkURL("http://[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
117     checkURL("http://example.com/path1/path2/.", {"http", "", "", "example.com", 0, "/path1/path2/", "", "", "http://example.com/path1/path2/"});
118     checkURL("http://example.com/path1/path2/..", {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"});
119     checkURL("http://example.com/path1/path2/./path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
120     checkURL("http://example.com/path1/path2/.\\path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
121     checkURL("http://example.com/path1/path2/../path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
122     checkURL("http://example.com/path1/path2/..\\path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
123     checkURL("http://example.com/.", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
124     checkURL("http://example.com/..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
125     checkURL("http://example.com/./path1", {"http", "", "", "example.com", 0, "/path1", "", "", "http://example.com/path1"});
126     checkURL("http://example.com/../path1", {"http", "", "", "example.com", 0, "/path1", "", "", "http://example.com/path1"});
127     checkURL("http://example.com/../path1/../../path2/path3/../path4", {"http", "", "", "example.com", 0, "/path2/path4", "", "", "http://example.com/path2/path4"});
128     checkURL("http://example.com/path1/.%2", {"http", "", "", "example.com", 0, "/path1/.%2", "", "", "http://example.com/path1/.%2"});
129     checkURL("http://example.com/path1/%2", {"http", "", "", "example.com", 0, "/path1/%2", "", "", "http://example.com/path1/%2"});
130     checkURL("http://example.com/path1/%", {"http", "", "", "example.com", 0, "/path1/%", "", "", "http://example.com/path1/%"});
131     checkURL("http://example.com/path1/.%", {"http", "", "", "example.com", 0, "/path1/.%", "", "", "http://example.com/path1/.%"});
132     checkURL("http://example.com//.", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
133     checkURL("http://example.com//./", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
134     checkURL("http://example.com//.//", {"http", "", "", "example.com", 0, "///", "", "", "http://example.com///"});
135     checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
136     checkURL("http://example.com//../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
137     checkURL("http://example.com//..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
138     checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
139     checkURL("http://example.com/.//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
140     checkURL("http://example.com/..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
141     checkURL("http://example.com/./", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
142     checkURL("http://example.com/../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
143     checkURL("http://example.com/path1/.../path3", {"http", "", "", "example.com", 0, "/path1/.../path3", "", "", "http://example.com/path1/.../path3"});
144     checkURL("http://example.com/path1/...", {"http", "", "", "example.com", 0, "/path1/...", "", "", "http://example.com/path1/..."});
145     checkURL("http://example.com/path1/.../", {"http", "", "", "example.com", 0, "/path1/.../", "", "", "http://example.com/path1/.../"});
146     checkURL("http://example.com/.path1/", {"http", "", "", "example.com", 0, "/.path1/", "", "", "http://example.com/.path1/"});
147     checkURL("http://example.com/..path1/", {"http", "", "", "example.com", 0, "/..path1/", "", "", "http://example.com/..path1/"});
148     checkURL("http://example.com/path1/.path2", {"http", "", "", "example.com", 0, "/path1/.path2", "", "", "http://example.com/path1/.path2"});
149     checkURL("http://example.com/path1/..path2", {"http", "", "", "example.com", 0, "/path1/..path2", "", "", "http://example.com/path1/..path2"});
150     checkURL("http://example.com/path1/path2/.?query", {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"});
151     checkURL("http://example.com/path1/path2/..?query", {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"});
152     checkURL("http://example.com/path1/path2/.#fragment", {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"});
153     checkURL("http://example.com/path1/path2/..#fragment", {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"});
154
155     checkURL("file:", {"file", "", "", "", 0, "/", "", "", "file:///"});
156     checkURL("file:/", {"file", "", "", "", 0, "/", "", "", "file:///"});
157     checkURL("file://", {"file", "", "", "", 0, "/", "", "", "file:///"});
158     checkURL("file:///", {"file", "", "", "", 0, "/", "", "", "file:///"});
159     checkURL("file:////", {"file", "", "", "", 0, "//", "", "", "file:////"}); // This matches Firefox and URL::parse which I believe are correct, but not Chrome.
160     checkURL("file:/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
161     checkURL("file://host/path", {"file", "", "", "host", 0, "/path", "", "", "file://host/path"});
162     checkURL("file://host", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
163     checkURL("file://host/", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
164     checkURL("file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
165     checkURL("file:////path", {"file", "", "", "", 0, "//path", "", "", "file:////path"});
166     checkURL("file://localhost/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
167     checkURL("file://localhost/", {"file", "", "", "", 0, "/", "", "", "file:///"});
168     checkURL("file://localhost", {"file", "", "", "", 0, "/", "", "", "file:///"});
169     checkURL("file://lOcAlHoSt", {"file", "", "", "", 0, "/", "", "", "file:///"});
170     checkURL("file://lOcAlHoSt/", {"file", "", "", "", 0, "/", "", "", "file:///"});
171     checkURL("file:/pAtH/", {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"});
172     checkURL("file:/pAtH", {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"});
173     checkURL("file:?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
174     checkURL("file:#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
175     checkURL("file:?query#fragment", {"file", "", "", "", 0, "/", "query", "fragment", "file:///?query#fragment"});
176     checkURL("file:#fragment?notquery", {"file", "", "", "", 0, "/", "", "fragment?notquery", "file:///#fragment?notquery"});
177     checkURL("file:/?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
178     checkURL("file:/#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
179     checkURL("file://?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
180     checkURL("file://#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
181     checkURL("file:///?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
182     checkURL("file:///#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
183     checkURL("file:////?query", {"file", "", "", "", 0, "//", "query", "", "file:////?query"});
184     checkURL("file:////#fragment", {"file", "", "", "", 0, "//", "", "fragment", "file:////#fragment"});
185     checkURL("http://host/A b", {"http", "", "", "host", 0, "/A%20b", "", "", "http://host/A%20b"});
186     checkURL("http://host/a%20B", {"http", "", "", "host", 0, "/a%20B", "", "", "http://host/a%20B"});
187     checkURL("http://host?q=@ <>!#fragment", {"http", "", "", "host", 0, "/", "q=@%20%3C%3E!", "fragment", "http://host/?q=@%20%3C%3E!#fragment"});
188     checkURL("http://user:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
189     checkURL("http://127.0.0.1:10100/path", {"http", "", "", "127.0.0.1", 10100, "/path", "", "", "http://127.0.0.1:10100/path"});
190     checkURL("http://127.0.0.1:/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
191     checkURL("http://127.0.0.1:123", {"http", "", "", "127.0.0.1", 123, "/", "", "", "http://127.0.0.1:123/"});
192     checkURL("http://127.0.0.1:", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
193     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"});
194     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/"});
195     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"});
196     checkURL("http://[0:f::f:f:0:0]:", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
197     checkURL("http://host:10100/path", {"http", "", "", "host", 10100, "/path", "", "", "http://host:10100/path"});
198     checkURL("http://host:/path", {"http", "", "", "host", 0, "/path", "", "", "http://host/path"});
199     checkURL("http://host:123", {"http", "", "", "host", 123, "/", "", "", "http://host:123/"});
200     checkURL("http://host:", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
201     checkURL("http://hos\tt\n:\t1\n2\t3\t/\npath", {"http", "", "", "host", 123, "/path", "", "", "http://host:123/path"});
202     checkURL("http://user@example.org/path3", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
203     checkURL("sc:/pa/pa", {"sc", "", "", "", 0, "/pa/pa", "", "", "sc:/pa/pa"});
204     checkURL("sc:/pa", {"sc", "", "", "", 0, "/pa", "", "", "sc:/pa"});
205     checkURL("sc:/pa/", {"sc", "", "", "", 0, "/pa/", "", "", "sc:/pa/"});
206     checkURL("notspecial:/notuser:notpassword@nothost", {"notspecial", "", "", "", 0, "/notuser:notpassword@nothost", "", "", "notspecial:/notuser:notpassword@nothost"});
207     checkURL("sc://pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
208     checkURL("http://host   \a   ", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
209     checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
210     checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
211     checkURL("http:/a", {"http", "", "", "a", 0, "/", "", "", "http://a/"});
212     checkURL("http://256/", {"http", "", "", "256", 0, "/", "", "", "http://256/"});
213     checkURL("http://256./", {"http", "", "", "256.", 0, "/", "", "", "http://256./"});
214     checkURL("http://123.256/", {"http", "", "", "123.256", 0, "/", "", "", "http://123.256/"});
215     checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
216     checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
217     // FIXME: Fix and add a test with an invalid surrogate pair at the end with a space as the second code unit.
218
219     // This disagrees with the web platform test for http://:@www.example.com but agrees with Chrome and URL::parse,
220     // and Firefox fails the web platform test differently. Maybe the web platform test ought to be changed.
221     checkURL("http://:@host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
222 }
223
224 static void checkRelativeURL(const String& urlString, const String& baseURLString, const ExpectedParts& parts)
225 {
226     URLParser baseParser;
227     auto base = baseParser.parse(baseURLString);
228
229     URLParser parser;
230     auto url = parser.parse(urlString, base);
231     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
232     EXPECT_TRUE(eq(parts.user, url.user()));
233     EXPECT_TRUE(eq(parts.password, url.pass()));
234     EXPECT_TRUE(eq(parts.host, url.host()));
235     EXPECT_EQ(parts.port, url.port());
236     EXPECT_TRUE(eq(parts.path, url.path()));
237     EXPECT_TRUE(eq(parts.query, url.query()));
238     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
239     EXPECT_TRUE(eq(parts.string, url.string()));
240
241     auto oldURL = URL(URL(URL(), baseURLString), urlString);
242     EXPECT_TRUE(eq(parts.protocol, oldURL.protocol()));
243     EXPECT_TRUE(eq(parts.user, oldURL.user()));
244     EXPECT_TRUE(eq(parts.password, oldURL.pass()));
245     EXPECT_TRUE(eq(parts.host, oldURL.host()));
246     EXPECT_EQ(parts.port, oldURL.port());
247     EXPECT_TRUE(eq(parts.path, oldURL.path()));
248     EXPECT_TRUE(eq(parts.query, oldURL.query()));
249     EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier()));
250     EXPECT_TRUE(eq(parts.string, oldURL.string()));
251
252     EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));
253     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
254     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
255 }
256
257 TEST_F(URLParserTest, ParseRelative)
258 {
259     checkRelativeURL("/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "webkit.org", 0, "/index.html", "", "", "http://webkit.org/index.html"});
260     checkRelativeURL("http://whatwg.org/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "whatwg.org", 0, "/index.html", "", "", "http://whatwg.org/index.html"});
261     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"});
262     checkRelativeURL("//whatwg.org/index.html", "https://www.webkit.org/path", {"https", "", "", "whatwg.org", 0, "/index.html", "", "", "https://whatwg.org/index.html"});
263     checkRelativeURL("http://example\t.\norg", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
264     checkRelativeURL("test", "file:///path1/path2", {"file", "", "", "", 0, "/path1/test", "", "", "file:///path1/test"});
265     checkRelativeURL(wideString(L"http://www.foo。bar.com"), "http://other.com/", {"http", "", "", "www.foo.bar.com", 0, "/", "", "", "http://www.foo.bar.com/"});
266     checkRelativeURL(wideString(L"sc://ñ.test/"), "about:blank", {"sc", "", "", "xn--ida.test", 0, "/", "", "", "sc://xn--ida.test/"});
267     checkRelativeURL("#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "", "fragment", "http://host/path#fragment"});
268     checkRelativeURL("?query", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "", "http://host/path?query"});
269     checkRelativeURL("?query#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "fragment", "http://host/path?query#fragment"});
270     checkRelativeURL(wideString(L"?β"), "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "%CE%B2", "", "http://example.org/foo/bar?%CE%B2"});
271     checkRelativeURL("?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?"});
272     checkRelativeURL("#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar#"});
273     checkRelativeURL("?#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?#"});
274     checkRelativeURL("#?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "?", "http://example.org/foo/bar#?"});
275     checkRelativeURL("/", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
276     checkRelativeURL("http://@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
277     checkRelativeURL("http://:@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
278     checkRelativeURL("http://foo.com/\\@", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "//@", "", "", "http://foo.com//@"});
279     checkRelativeURL("\\@", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/@", "", "", "http://example.org/@"});
280     checkRelativeURL("/path3", "http://user@example.org/path1/path2", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
281     checkRelativeURL("", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
282     checkRelativeURL("  \a  \t\n", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
283     checkRelativeURL(":foo.com\\", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "http://example.org/foo/:foo.com/"});
284     checkRelativeURL("http:/example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
285     checkRelativeURL("http:example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
286     checkRelativeURL("http:\\\\foo.com\\", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
287     checkRelativeURL("http:\\\\foo.com/", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
288     checkRelativeURL("http:\\\\foo.com", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
289     checkRelativeURL("http://ExAmPlE.CoM", "http://other.com", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
290     checkRelativeURL("http:", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
291     checkRelativeURL("#x", "data:,", {"data", "", "", "", 0, ",", "", "x", "data:,#x"});
292     checkRelativeURL("#x", "about:blank", {"about", "", "", "", 0, "blank", "", "x", "about:blank#x"});
293     checkRelativeURL("  foo.com  ", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/foo.com", "", "", "http://example.org/foo/foo.com"});
294     checkRelativeURL(" \a baz", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/baz", "", "", "http://example.org/foo/baz"});
295     checkRelativeURL("~", "http://example.org", {"http", "", "", "example.org", 0, "/~", "", "", "http://example.org/~"});
296     checkRelativeURL("notspecial:", "about:blank", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
297     checkRelativeURL("notspecial:", "http://host", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
298     checkRelativeURL("http:", "http://host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
299     
300     // The checking of slashes in SpecialAuthoritySlashes needed to get this to pass contradicts what is in the spec,
301     // but it is included in the web platform tests.
302     checkRelativeURL("http:\\\\host\\foo", "about:blank", {"http", "", "", "host", 0, "/foo", "", "", "http://host/foo"});
303 }
304
305 static void checkURLDifferences(const String& urlString, const ExpectedParts& partsNew, const ExpectedParts& partsOld)
306 {
307     URLParser parser;
308     auto url = parser.parse(urlString);
309     EXPECT_TRUE(eq(partsNew.protocol, url.protocol()));
310     EXPECT_TRUE(eq(partsNew.user, url.user()));
311     EXPECT_TRUE(eq(partsNew.password, url.pass()));
312     EXPECT_TRUE(eq(partsNew.host, url.host()));
313     EXPECT_EQ(partsNew.port, url.port());
314     EXPECT_TRUE(eq(partsNew.path, url.path()));
315     EXPECT_TRUE(eq(partsNew.query, url.query()));
316     EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
317     EXPECT_TRUE(eq(partsNew.string, url.string()));
318     
319     auto oldURL = URL(URL(), urlString);
320     EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol()));
321     EXPECT_TRUE(eq(partsOld.user, oldURL.user()));
322     EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));
323     EXPECT_TRUE(eq(partsOld.host, oldURL.host()));
324     EXPECT_EQ(partsOld.port, oldURL.port());
325     EXPECT_TRUE(eq(partsOld.path, oldURL.path()));
326     EXPECT_TRUE(eq(partsOld.query, oldURL.query()));
327     EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));
328     EXPECT_TRUE(eq(partsOld.string, oldURL.string()));
329     
330     EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));
331     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
332     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
333 }
334
335 static void checkRelativeURLDifferences(const String& urlString, const String& baseURLString, const ExpectedParts& partsNew, const ExpectedParts& partsOld)
336 {
337     URLParser baseParser;
338     auto base = baseParser.parse(baseURLString);
339     
340     URLParser parser;
341     auto url = parser.parse(urlString, base);
342     EXPECT_TRUE(eq(partsNew.protocol, url.protocol()));
343     EXPECT_TRUE(eq(partsNew.user, url.user()));
344     EXPECT_TRUE(eq(partsNew.password, url.pass()));
345     EXPECT_TRUE(eq(partsNew.host, url.host()));
346     EXPECT_EQ(partsNew.port, url.port());
347     EXPECT_TRUE(eq(partsNew.path, url.path()));
348     EXPECT_TRUE(eq(partsNew.query, url.query()));
349     EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
350     EXPECT_TRUE(eq(partsNew.string, url.string()));
351     
352     auto oldURL = URL(URL(URL(), baseURLString), urlString);
353     EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol()));
354     EXPECT_TRUE(eq(partsOld.user, oldURL.user()));
355     EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));
356     EXPECT_TRUE(eq(partsOld.host, oldURL.host()));
357     EXPECT_EQ(partsOld.port, oldURL.port());
358     EXPECT_TRUE(eq(partsOld.path, oldURL.path()));
359     EXPECT_TRUE(eq(partsOld.query, oldURL.query()));
360     EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));
361     EXPECT_TRUE(eq(partsOld.string, oldURL.string()));
362     
363     EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));
364     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
365     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
366 }
367
368 // These are differences between the new URLParser and the old URL::parse which make URLParser more standards compliant.
369 TEST_F(URLParserTest, ParserDifferences)
370 {
371     checkURLDifferences("http://127.0.1",
372         {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
373         {"http", "", "", "127.0.1", 0, "/", "", "", "http://127.0.1/"});
374     checkURLDifferences("http://011.11.0X11.0x011",
375         {"http", "", "", "9.11.17.17", 0, "/", "", "", "http://9.11.17.17/"},
376         {"http", "", "", "011.11.0x11.0x011", 0, "/", "", "", "http://011.11.0x11.0x011/"});
377     checkURLDifferences("http://[1234:0078:90AB:CdEf:0123:0007:89AB:0000]",
378         {"http", "", "", "[1234:78:90ab:cdef:123:7:89ab:0]", 0, "/", "", "", "http://[1234:78:90ab:cdef:123:7:89ab:0]/"},
379         {"http", "", "", "[1234:0078:90ab:cdef:0123:0007:89ab:0000]", 0, "/", "", "", "http://[1234:0078:90ab:cdef:0123:0007:89ab:0000]/"});
380     checkURLDifferences("http://[0:f:0:0:f:f:0:0]",
381         {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"},
382         {"http", "", "", "[0:f:0:0:f:f:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:f:0:0]/"});
383     checkURLDifferences("http://[0:f:0:0:f:0:0:0]",
384         {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"},
385         {"http", "", "", "[0:f:0:0:f:0:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:0:0:0]/"});
386     checkURLDifferences("http://[0:0:f:0:0:f:0:0]",
387         {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"},
388         {"http", "", "", "[0:0:f:0:0:f:0:0]", 0, "/", "", "", "http://[0:0:f:0:0:f:0:0]/"});
389     checkURLDifferences("http://example.com/path1/.%2e",
390         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
391         {"http", "", "", "example.com", 0, "/path1/.%2e", "", "", "http://example.com/path1/.%2e"});
392     checkURLDifferences("http://example.com/path1/.%2E",
393         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
394         {"http", "", "", "example.com", 0, "/path1/.%2E", "", "", "http://example.com/path1/.%2E"});
395     checkURLDifferences("http://example.com/path1/.%2E/",
396         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
397         {"http", "", "", "example.com", 0, "/path1/.%2E/", "", "", "http://example.com/path1/.%2E/"});
398     checkURLDifferences("http://example.com/path1/%2e.",
399         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
400         {"http", "", "", "example.com", 0, "/path1/%2e.", "", "", "http://example.com/path1/%2e."});
401     checkURLDifferences("http://example.com/path1/%2E%2e",
402         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
403         {"http", "", "", "example.com", 0, "/path1/%2E%2e", "", "", "http://example.com/path1/%2E%2e"});
404     checkURLDifferences("http://example.com/path1/%2e",
405         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
406         {"http", "", "", "example.com", 0, "/path1/%2e", "", "", "http://example.com/path1/%2e"});
407     checkURLDifferences("http://example.com/path1/%2E",
408         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
409         {"http", "", "", "example.com", 0, "/path1/%2E", "", "", "http://example.com/path1/%2E"});
410     checkURLDifferences("http://example.com/path1/%2E/",
411         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
412         {"http", "", "", "example.com", 0, "/path1/%2E/", "", "", "http://example.com/path1/%2E/"});
413     checkURLDifferences("http://example.com/path1/path2/%2e?query",
414         {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"},
415         {"http", "", "", "example.com", 0, "/path1/path2/%2e", "query", "", "http://example.com/path1/path2/%2e?query"});
416     checkURLDifferences("http://example.com/path1/path2/%2e%2e?query",
417         {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"},
418         {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "query", "", "http://example.com/path1/path2/%2e%2e?query"});
419     checkURLDifferences("http://example.com/path1/path2/%2e#fragment",
420         {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"},
421         {"http", "", "", "example.com", 0, "/path1/path2/%2e", "", "fragment", "http://example.com/path1/path2/%2e#fragment"});
422     checkURLDifferences("http://example.com/path1/path2/%2e%2e#fragment",
423         {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"},
424         {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "", "fragment", "http://example.com/path1/path2/%2e%2e#fragment"});
425     checkURLDifferences("file://[0:a:0:0:b:c:0:0]/path",
426         {"file", "", "", "[0:a::b:c:0:0]", 0, "/path", "", "", "file://[0:a::b:c:0:0]/path"},
427         {"file", "", "", "[0:a:0:0:b:c:0:0]", 0, "/path", "", "", "file://[0:a:0:0:b:c:0:0]/path"});
428     checkRelativeURLDifferences(wideString(L"#β"), "http://example.org/foo/bar",
429         {"http", "", "", "example.org", 0, "/foo/bar", "", wideString(L"β"), wideString(L"http://example.org/foo/bar#β")},
430         {"http", "", "", "example.org", 0, "/foo/bar", "", "%CE%B2", "http://example.org/foo/bar#%CE%B2"});
431     checkURLDifferences("http://",
432         {"", "", "", "", 0, "", "", "", "http://"},
433         {"http", "", "", "", 0, "/", "", "", "http:/"});
434     checkRelativeURLDifferences("//", "https://www.webkit.org/path",
435         {"", "", "", "", 0, "", "", "", "//"},
436         {"https", "", "", "", 0, "/", "", "", "https:/"});
437     checkURLDifferences("http://127.0.0.1:65536/path",
438         {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536/path"},
439         {"http", "", "", "127.0.0.1", 65535, "/path", "", "", "http://127.0.0.1:65536/path"});
440     checkURLDifferences("http://host:65536",
441         {"", "", "", "", 0, "", "", "", "http://host:65536"},
442         {"http", "", "", "host", 65535, "/", "", "", "http://host:65536/"});
443     checkURLDifferences("http://127.0.0.1:65536",
444         {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536"},
445         {"http", "", "", "127.0.0.1", 65535, "/", "", "", "http://127.0.0.1:65536/"});
446     checkURLDifferences("http://[0:f::f:f:0:0]:65536",
447         {"", "", "", "", 0, "", "", "", "http://[0:f::f:f:0:0]:65536"},
448         {"http", "", "", "[0:f::f:f:0:0]", 65535, "/", "", "", "http://[0:f::f:f:0:0]:65536/"});
449     checkRelativeURLDifferences(":foo.com\\", "notspecial://example.org/foo/bar",
450         {"notspecial", "", "", "example.org", 0, "/foo/:foo.com\\", "", "", "notspecial://example.org/foo/:foo.com\\"},
451         {"notspecial", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "notspecial://example.org/foo/:foo.com/"});
452     checkURLDifferences("sc://pa",
453         {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"},
454         {"sc", "", "", "pa", 0, "", "", "", "sc://pa"});
455     checkRelativeURLDifferences("notspecial:\\\\foo.com\\", "http://example.org/foo/bar",
456         {"notspecial", "", "", "", 0, "\\\\foo.com\\", "", "", "notspecial:\\\\foo.com\\"},
457         {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
458     checkRelativeURLDifferences("notspecial:\\\\foo.com/", "http://example.org/foo/bar",
459         {"notspecial", "", "", "", 0, "\\\\foo.com/", "", "", "notspecial:\\\\foo.com/"},
460         {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
461     checkRelativeURLDifferences("notspecial:\\\\foo.com", "http://example.org/foo/bar",
462         {"notspecial", "", "", "", 0, "\\\\foo.com", "", "", "notspecial:\\\\foo.com"},
463         {"notspecial", "", "", "foo.com", 0, "", "", "", "notspecial://foo.com"});
464     checkURLDifferences("file://notuser:notpassword@test",
465         {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test"},
466         {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
467     checkURLDifferences("file://notuser:notpassword@test/",
468         {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test/"},
469         {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
470     checkRelativeURLDifferences("http:/", "about:blank",
471         {"", "", "", "", 0, "", "", "", "http:/"},
472         {"http", "", "", "", 0, "/", "", "", "http:/"});
473     checkRelativeURLDifferences("http:", "about:blank",
474         {"http", "", "", "", 0, "", "", "", "http:"},
475         {"http", "", "", "", 0, "/", "", "", "http:/"});
476     checkRelativeURLDifferences("http:/", "http://host",
477         {"", "", "", "", 0, "", "", "", "http:/"},
478         {"http", "", "", "", 0, "/", "", "", "http:/"});
479     checkURLDifferences("http:/",
480         {"", "", "", "", 0, "", "", "", "http:/"},
481         {"http", "", "", "", 0, "/", "", "", "http:/"});
482     checkURLDifferences("http:",
483         {"http", "", "", "", 0, "", "", "", "http:"},
484         {"http", "", "", "", 0, "/", "", "", "http:/"});
485     checkRelativeURLDifferences("http:/example.com/", "http://example.org/foo/bar",
486         {"http", "", "", "example.org", 0, "/example.com/", "", "", "http://example.org/example.com/"},
487         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
488     
489     // This behavior matches Chrome and Firefox, but not WebKit using URL::parse.
490     // The behavior of URL::parse is clearly wrong because reparsing file://path would make path the host.
491     // The spec is unclear.
492     checkURLDifferences("file:path",
493         {"file", "", "", "", 0, "/path", "", "", "file:///path"},
494         {"file", "", "", "", 0, "path", "", "", "file://path"});
495     checkURLDifferences("file:pAtH",
496         {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"},
497         {"file", "", "", "", 0, "pAtH", "", "", "file://pAtH"});
498     checkURLDifferences("file:pAtH/",
499         {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"},
500         {"file", "", "", "", 0, "pAtH/", "", "", "file://pAtH/"});
501     
502     // FIXME: Fix and test incomplete percent encoded characters in the middle and end of the input string.
503     // FIXME: Fix and test percent encoded upper case characters in the host.
504     checkURLDifferences("http://host%73",
505         {"http", "", "", "hosts", 0, "/", "", "", "http://hosts/"},
506         {"http", "", "", "host%73", 0, "/", "", "", "http://host%73/"});
507     
508     // URLParser matches Chrome and the spec, but not URL::parse or Firefox.
509     checkURLDifferences(wideString(L"http://0Xc0.0250.01"),
510         {"http", "", "", "192.168.0.1", 0, "/", "", "", "http://192.168.0.1/"},
511         {"http", "", "", "0xc0.0250.01", 0, "/", "", "", "http://0xc0.0250.01/"});
512     checkURLDifferences("http://host/path%2e.%2E",
513         {"http", "", "", "host", 0, "/path...", "", "", "http://host/path..."},
514         {"http", "", "", "host", 0, "/path%2e.%2E", "", "", "http://host/path%2e.%2E"});
515
516     checkRelativeURLDifferences(wideString(L"http://foo:💩@example.com/bar"), "http://other.com/",
517         {"http", "foo", wideString(L"💩"), "example.com", 0, "/bar", "", "", "http://foo:%F0%9F%92%A9@example.com/bar"},
518         {"", "", "", "", 0, "", "", "", wideString(L"http://foo:💩@example.com/bar")});
519     checkRelativeURLDifferences("http://&a:foo(b]c@d:2/", "http://example.org/foo/bar",
520         {"http", "&a", "foo(b]c", "d", 2, "/", "", "", "http://&a:foo(b%5Dc@d:2/"},
521         {"", "", "", "", 0, "", "", "", "http://&a:foo(b]c@d:2/"});
522     checkRelativeURLDifferences("http://`{}:`{}@h/`{}?`{}", "http://doesnotmatter/",
523         {"http", "`{}", "`{}", "h", 0, "/%60%7B%7D", "`{}", "", "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}"},
524         {"", "", "", "", 0, "", "", "", "http://`{}:`{}@h/`{}?`{}"});
525     checkURLDifferences("http://[0:f::f::f]",
526         {"", "", "", "", 0, "" , "", "", "http://[0:f::f::f]"},
527         {"http", "", "", "[0:f::f::f]", 0, "/" , "", "", "http://[0:f::f::f]/"});
528     checkURLDifferences("http://123",
529         {"http", "", "", "0.0.0.123", 0, "/", "", "", "http://0.0.0.123/"},
530         {"http", "", "", "123", 0, "/", "", "", "http://123/"});
531     checkURLDifferences("http://123.234/",
532         {"http", "", "", "123.0.0.234", 0, "/", "", "", "http://123.0.0.234/"},
533         {"http", "", "", "123.234", 0, "/", "", "", "http://123.234/"});
534     checkURLDifferences("http://123.234.012",
535         {"http", "", "", "123.234.0.10", 0, "/", "", "", "http://123.234.0.10/"},
536         {"http", "", "", "123.234.012", 0, "/", "", "", "http://123.234.012/"});
537     checkURLDifferences("http://123.234.12",
538         {"http", "", "", "123.234.0.12", 0, "/", "", "", "http://123.234.0.12/"},
539         {"http", "", "", "123.234.12", 0, "/", "", "", "http://123.234.12/"});
540     checkRelativeURLDifferences("file:c:\\foo\\bar.html", "file:///tmp/mock/path",
541         {"file", "", "", "", 0, "/c:/foo/bar.html", "", "", "file:///c:/foo/bar.html"},
542         {"file", "", "", "", 0, "/tmp/mock/c:/foo/bar.html", "", "", "file:///tmp/mock/c:/foo/bar.html"});
543     checkRelativeURLDifferences("  File:c|////foo\\bar.html", "file:///tmp/mock/path",
544         {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
545         {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
546     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",
547         {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
548         {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
549     checkRelativeURLDifferences("C|/foo/bar", "file:///tmp/mock/path",
550         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
551         {"file", "", "", "", 0, "/tmp/mock/C|/foo/bar", "", "", "file:///tmp/mock/C|/foo/bar"});
552     checkRelativeURLDifferences("/C|/foo/bar", "file:///tmp/mock/path",
553         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
554         {"file", "", "", "", 0, "/C|/foo/bar", "", "", "file:///C|/foo/bar"});
555     checkRelativeURLDifferences("https://@test@test@example:800/", "http://doesnotmatter/",
556         {"https", "@test@test", "", "example", 800, "/", "", "", "https://%40test%40test@example:800/"},
557         {"", "", "", "", 0, "", "", "", "https://@test@test@example:800/"});
558     checkRelativeURLDifferences("foo://", "http://example.org/foo/bar",
559         {"foo", "", "", "", 0, "/", "", "", "foo:///"},
560         {"foo", "", "", "", 0, "//", "", "", "foo://"});
561
562     // This matches the spec and web platform tests, but not Chrome, Firefox, or URL::parse.
563     checkRelativeURLDifferences("notspecial:/", "about:blank",
564         {"notspecial", "", "", "", 0, "", "", "", "notspecial:/"},
565         {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
566     checkRelativeURLDifferences("notspecial:/", "http://host",
567         {"notspecial", "", "", "", 0, "", "", "", "notspecial:/"},
568         {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
569     checkURLDifferences("notspecial:/",
570         {"notspecial", "", "", "", 0, "", "", "", "notspecial:/"},
571         {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
572 }
573
574 TEST_F(URLParserTest, DefaultPort)
575 {
576     checkURL("FtP://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
577     checkURL("ftp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
578     checkURL("ftp://host:22/", {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"});
579     checkURLDifferences("ftp://host:21",
580         {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"},
581         {"ftp", "", "", "host", 0, "", "", "", "ftp://host"});
582     checkURLDifferences("ftp://host:22",
583         {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"},
584         {"ftp", "", "", "host", 22, "", "", "", "ftp://host:22"});
585     
586     checkURL("gOpHeR://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
587     checkURL("gopher://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
588     checkURL("gopher://host:71/", {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"});
589     // Spec, Chrome, Firefox, and URLParser have "/", URL::parse does not.
590     // Spec, Chrome, URLParser, URL::parse recognize gopher default port, Firefox does not.
591     checkURLDifferences("gopher://host:70",
592         {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"},
593         {"gopher", "", "", "host", 0, "", "", "", "gopher://host"});
594     checkURLDifferences("gopher://host:71",
595         {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"},
596         {"gopher", "", "", "host", 71, "", "", "", "gopher://host:71"});
597     
598     checkURL("hTtP://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
599     checkURL("http://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
600     checkURL("http://host:80/", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
601     checkURL("http://host:81", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
602     checkURL("http://host:81/", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
603     
604     checkURL("hTtPs://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
605     checkURL("https://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
606     checkURL("https://host:443/", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
607     checkURL("https://host:444", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
608     checkURL("https://host:444/", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
609     
610     checkURL("wS://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
611     checkURL("ws://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
612     checkURL("ws://host:81/", {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"});
613     // URLParser matches Chrome and Firefox, but not URL::parse
614     checkURLDifferences("ws://host:80",
615         {"ws", "", "", "host", 0, "/", "", "", "ws://host/"},
616         {"ws", "", "", "host", 0, "", "", "", "ws://host"});
617     checkURLDifferences("ws://host:81",
618         {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"},
619         {"ws", "", "", "host", 81, "", "", "", "ws://host:81"});
620     
621     checkURL("WsS://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
622     checkURL("wss://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
623     checkURL("wss://host:444/", {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"});
624     // URLParser matches Chrome and Firefox, but not URL::parse
625     checkURLDifferences("wss://host:443",
626         {"wss", "", "", "host", 0, "/", "", "", "wss://host/"},
627         {"wss", "", "", "host", 0, "", "", "", "wss://host"});
628     checkURLDifferences("wss://host:444",
629         {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"},
630         {"wss", "", "", "host", 444, "", "", "", "wss://host:444"});
631
632     // 990 is the default ftps port in URL::parse, but it's not in the URL spec. Maybe it should be.
633     checkURL("fTpS://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
634     checkURL("ftps://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
635     checkURL("ftps://host:991/", {"ftps", "", "", "host", 991, "/", "", "", "ftps://host:991/"});
636     checkURLDifferences("ftps://host:990",
637         {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"},
638         {"ftps", "", "", "host", 990, "", "", "", "ftps://host:990"});
639     checkURLDifferences("ftps://host:991",
640         {"ftps", "", "", "host", 991, "/", "", "", "ftps://host:991/"},
641         {"ftps", "", "", "host", 991, "", "", "", "ftps://host:991"});
642
643     checkURL("uNkNoWn://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
644     checkURL("unknown://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
645     checkURL("unknown://host:81/", {"unknown", "", "", "host", 81, "/", "", "", "unknown://host:81/"});
646     checkURLDifferences("unknown://host:80",
647         {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"},
648         {"unknown", "", "", "host", 80, "", "", "", "unknown://host:80"});
649     checkURLDifferences("unknown://host:81",
650         {"unknown", "", "", "host", 81, "/", "", "", "unknown://host:81/"},
651         {"unknown", "", "", "host", 81, "", "", "", "unknown://host:81"});
652 }
653     
654 static void shouldFail(const String& urlString)
655 {
656     URLParser parser;
657     auto invalidURL = parser.parse(urlString);
658     checkURL(urlString, {"", "", "", "", 0, "", "", "", urlString});
659 }
660
661 static void shouldFail(const String& urlString, const String& baseString)
662 {
663     URLParser parser;
664     auto invalidURL = parser.parse(urlString);
665     checkRelativeURL(urlString, baseString, {"", "", "", "", 0, "", "", "", urlString});
666 }
667     
668 TEST_F(URLParserTest, ParserFailures)
669 {
670     shouldFail("    ");
671     shouldFail("  \a  ");
672     shouldFail("");
673     shouldFail("http://127.0.0.1:abc");
674     shouldFail("http://host:abc");
675     shouldFail("http://a:@", "about:blank");
676     shouldFail("http://:b@", "about:blank");
677     shouldFail("http://:@", "about:blank");
678     shouldFail("http://a:@");
679     shouldFail("http://:b@");
680     shouldFail("http://@");
681     shouldFail("http://[0:f::f:f:0:0]:abc");
682     shouldFail("../i", "sc:sd");
683     shouldFail("../i", "sc:sd/sd");
684     shouldFail("/i", "sc:sd");
685     shouldFail("/i", "sc:sd/sd");
686     shouldFail("?i", "sc:sd");
687     shouldFail("?i", "sc:sd/sd");
688     shouldFail("http://example example.com", "http://other.com/");
689     shouldFail("http://[www.example.com]/", "about:blank");
690     shouldFail("http://192.168.0.1 hello", "http://other.com/");
691     shouldFail("http://[example.com]", "http://other.com/");
692     shouldFail("i", "sc:sd");
693     shouldFail("i", "sc:sd/sd");
694     shouldFail("i");
695     shouldFail("asdf");
696     shouldFail("~");
697     shouldFail("~", "about:blank");
698     shouldFail("~~~");
699 }
700
701 // These are in the spec but not in the web platform tests.
702 TEST_F(URLParserTest, AdditionalTests)
703 {
704     checkURL("about:\a\aabc", {"about", "", "", "", 0, "%07%07abc", "", "", "about:%07%07abc"});
705     checkURL("notspecial:\t\t\n\t", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
706     checkURLDifferences("notspecial\t\t\n\t:\t\t\n\t/\t\t\n\t/\t\t\n\thost",
707         {"notspecial", "", "", "host", 0, "/", "", "", "notspecial://host/"},
708         {"notspecial", "", "", "host", 0, "", "", "", "notspecial://host"});
709     checkRelativeURL("http:", "http://example.org/foo/bar?query#fragment", {"http", "", "", "example.org", 0, "/foo/bar", "query", "", "http://example.org/foo/bar?query"});
710     checkRelativeURLDifferences("ws:", "http://example.org/foo/bar",
711         {"ws", "", "", "", 0, "", "", "", "ws:"},
712         {"ws", "", "", "", 0, "s:", "", "", "ws:s:"});
713     checkRelativeURL("notspecial:", "http://example.org/foo/bar", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
714 }
715
716 } // namespace TestWebKitAPI