URLParser should ignore tabs in authority
[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
54 static bool eq(const String& s1, const String& s2)
55 {
56     EXPECT_STREQ(s1.utf8().data(), s2.utf8().data());
57     return s1.utf8() == s2.utf8();
58 }
59
60 static void checkURL(const String& urlString, const ExpectedParts& parts)
61 {
62     bool wasEnabled = URLParser::enabled();
63     URLParser::setEnabled(true);
64     auto url = URL(URL(), urlString);
65     URLParser::setEnabled(false);
66     auto oldURL = URL(URL(), urlString);
67     URLParser::setEnabled(wasEnabled);
68     
69     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
70     EXPECT_TRUE(eq(parts.user, url.user()));
71     EXPECT_TRUE(eq(parts.password, url.pass()));
72     EXPECT_TRUE(eq(parts.host, url.host()));
73     EXPECT_EQ(parts.port, url.port());
74     EXPECT_TRUE(eq(parts.path, url.path()));
75     EXPECT_TRUE(eq(parts.query, url.query()));
76     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
77     EXPECT_TRUE(eq(parts.string, url.string()));
78     
79     EXPECT_TRUE(eq(parts.protocol, oldURL.protocol()));
80     EXPECT_TRUE(eq(parts.user, oldURL.user()));
81     EXPECT_TRUE(eq(parts.password, oldURL.pass()));
82     EXPECT_TRUE(eq(parts.host, oldURL.host()));
83     EXPECT_EQ(parts.port, oldURL.port());
84     EXPECT_TRUE(eq(parts.path, oldURL.path()));
85     EXPECT_TRUE(eq(parts.query, oldURL.query()));
86     EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier()));
87     EXPECT_TRUE(eq(parts.string, oldURL.string()));
88     
89     EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));
90     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
91     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
92 }
93
94 template<size_t length>
95 static String utf16String(const char16_t (&url)[length])
96 {
97     StringBuilder builder;
98     builder.reserveCapacity(length - 1);
99     for (size_t i = 0; i < length - 1; ++i)
100         builder.append(static_cast<UChar>(url[i]));
101     return builder.toString();
102 }
103
104 TEST_F(URLParserTest, Basic)
105 {
106     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"});
107     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"});
108     checkURL("http://user:pass@webkit.org:123/path", {"http", "user", "pass", "webkit.org", 123, "/path", "", "", "http://user:pass@webkit.org:123/path"});
109     checkURL("http://user:pass@webkit.org:123/", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
110     checkURL("http://user:pass@webkit.org:123", {"http", "user", "pass", "webkit.org", 123, "/", "", "", "http://user:pass@webkit.org:123/"});
111     checkURL("http://user:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
112     checkURL("http://user:\t\t\tpass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
113     checkURL("http://us\ter:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
114     checkURL("http://user:pa\tss@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
115     checkURL("http://user:pass\t@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
116     checkURL("http://\tuser:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
117     checkURL("http://user\t:pass@webkit.org", {"http", "user", "pass", "webkit.org", 0, "/", "", "", "http://user:pass@webkit.org/"});
118     checkURL("http://webkit.org", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
119     checkURL("http://127.0.0.1", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
120     checkURL("http://webkit.org/", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
121     checkURL("http://webkit.org/path1/path2/index.html", {"http", "", "", "webkit.org", 0, "/path1/path2/index.html", "", "", "http://webkit.org/path1/path2/index.html"});
122     checkURL("about:blank", {"about", "", "", "", 0, "blank", "", "", "about:blank"});
123     checkURL("about:blank?query", {"about", "", "", "", 0, "blank", "query", "", "about:blank?query"});
124     checkURL("about:blank#fragment", {"about", "", "", "", 0, "blank", "", "fragment", "about:blank#fragment"});
125     checkURL("http://[0:f::f:f:0:0]", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
126     checkURL("http://[0:f:0:0:f::]", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
127     checkURL("http://[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
128     checkURL("http://[0:f:0:0:f::]:", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
129     checkURL("http://[0:f:0:0:f::]:\t", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
130     checkURL("http://[0:f:0:0:f::]\t:", {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"});
131     checkURL("http://\t[::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
132     checkURL("http://[\t::f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
133     checkURL("http://[:\t:f:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
134     checkURL("http://[::\tf:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
135     checkURL("http://[::f\t:0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
136     checkURL("http://[::f:\t0:0:f:0:0]", {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"});
137     checkURL("http://example.com/path1/path2/.", {"http", "", "", "example.com", 0, "/path1/path2/", "", "", "http://example.com/path1/path2/"});
138     checkURL("http://example.com/path1/path2/..", {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"});
139     checkURL("http://example.com/path1/path2/./path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
140     checkURL("http://example.com/path1/path2/.\\path3", {"http", "", "", "example.com", 0, "/path1/path2/path3", "", "", "http://example.com/path1/path2/path3"});
141     checkURL("http://example.com/path1/path2/../path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
142     checkURL("http://example.com/path1/path2/..\\path3", {"http", "", "", "example.com", 0, "/path1/path3", "", "", "http://example.com/path1/path3"});
143     checkURL("http://example.com/.", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
144     checkURL("http://example.com/..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
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/../../path2/path3/../path4", {"http", "", "", "example.com", 0, "/path2/path4", "", "", "http://example.com/path2/path4"});
148     checkURL("http://example.com/path1/.%2", {"http", "", "", "example.com", 0, "/path1/.%2", "", "", "http://example.com/path1/.%2"});
149     checkURL("http://example.com/path1/%2", {"http", "", "", "example.com", 0, "/path1/%2", "", "", "http://example.com/path1/%2"});
150     checkURL("http://example.com/path1/%", {"http", "", "", "example.com", 0, "/path1/%", "", "", "http://example.com/path1/%"});
151     checkURL("http://example.com/path1/.%", {"http", "", "", "example.com", 0, "/path1/.%", "", "", "http://example.com/path1/.%"});
152     checkURL("http://example.com//.", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
153     checkURL("http://example.com//./", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
154     checkURL("http://example.com//.//", {"http", "", "", "example.com", 0, "///", "", "", "http://example.com///"});
155     checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
156     checkURL("http://example.com//../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
157     checkURL("http://example.com//..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
158     checkURL("http://example.com//..", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
159     checkURL("http://example.com/.//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
160     checkURL("http://example.com/..//", {"http", "", "", "example.com", 0, "//", "", "", "http://example.com//"});
161     checkURL("http://example.com/./", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
162     checkURL("http://example.com/../", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
163     checkURL("http://example.com/path1/.../path3", {"http", "", "", "example.com", 0, "/path1/.../path3", "", "", "http://example.com/path1/.../path3"});
164     checkURL("http://example.com/path1/...", {"http", "", "", "example.com", 0, "/path1/...", "", "", "http://example.com/path1/..."});
165     checkURL("http://example.com/path1/.../", {"http", "", "", "example.com", 0, "/path1/.../", "", "", "http://example.com/path1/.../"});
166     checkURL("http://example.com/.path1/", {"http", "", "", "example.com", 0, "/.path1/", "", "", "http://example.com/.path1/"});
167     checkURL("http://example.com/..path1/", {"http", "", "", "example.com", 0, "/..path1/", "", "", "http://example.com/..path1/"});
168     checkURL("http://example.com/path1/.path2", {"http", "", "", "example.com", 0, "/path1/.path2", "", "", "http://example.com/path1/.path2"});
169     checkURL("http://example.com/path1/..path2", {"http", "", "", "example.com", 0, "/path1/..path2", "", "", "http://example.com/path1/..path2"});
170     checkURL("http://example.com/path1/path2/.?query", {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"});
171     checkURL("http://example.com/path1/path2/..?query", {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"});
172     checkURL("http://example.com/path1/path2/.#fragment", {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"});
173     checkURL("http://example.com/path1/path2/..#fragment", {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"});
174
175     checkURL("file:", {"file", "", "", "", 0, "/", "", "", "file:///"});
176     checkURL("file:/", {"file", "", "", "", 0, "/", "", "", "file:///"});
177     checkURL("file://", {"file", "", "", "", 0, "/", "", "", "file:///"});
178     checkURL("file:///", {"file", "", "", "", 0, "/", "", "", "file:///"});
179     checkURL("file:////", {"file", "", "", "", 0, "//", "", "", "file:////"}); // This matches Firefox and URL::parse which I believe are correct, but not Chrome.
180     checkURL("file:/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
181     checkURL("file://host/path", {"file", "", "", "host", 0, "/path", "", "", "file://host/path"});
182     checkURL("file://host", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
183     checkURL("file://host/", {"file", "", "", "host", 0, "/", "", "", "file://host/"});
184     checkURL("file:///path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
185     checkURL("file:////path", {"file", "", "", "", 0, "//path", "", "", "file:////path"});
186     checkURL("file://localhost/path", {"file", "", "", "", 0, "/path", "", "", "file:///path"});
187     checkURL("file://localhost/", {"file", "", "", "", 0, "/", "", "", "file:///"});
188     checkURL("file://localhost", {"file", "", "", "", 0, "/", "", "", "file:///"});
189     checkURL("file://lOcAlHoSt", {"file", "", "", "", 0, "/", "", "", "file:///"});
190     checkURL("file://lOcAlHoSt/", {"file", "", "", "", 0, "/", "", "", "file:///"});
191     checkURL("file:/pAtH/", {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"});
192     checkURL("file:/pAtH", {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"});
193     checkURL("file:?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
194     checkURL("file:#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
195     checkURL("file:?query#fragment", {"file", "", "", "", 0, "/", "query", "fragment", "file:///?query#fragment"});
196     checkURL("file:#fragment?notquery", {"file", "", "", "", 0, "/", "", "fragment?notquery", "file:///#fragment?notquery"});
197     checkURL("file:/?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
198     checkURL("file:/#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
199     checkURL("file://?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
200     checkURL("file://#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
201     checkURL("file:///?query", {"file", "", "", "", 0, "/", "query", "", "file:///?query"});
202     checkURL("file:///#fragment", {"file", "", "", "", 0, "/", "", "fragment", "file:///#fragment"});
203     checkURL("file:////?query", {"file", "", "", "", 0, "//", "query", "", "file:////?query"});
204     checkURL("file:////#fragment", {"file", "", "", "", 0, "//", "", "fragment", "file:////#fragment"});
205     checkURL("http://host/A b", {"http", "", "", "host", 0, "/A%20b", "", "", "http://host/A%20b"});
206     checkURL("http://host/a%20B", {"http", "", "", "host", 0, "/a%20B", "", "", "http://host/a%20B"});
207     checkURL("http://host?q=@ <>!#fragment", {"http", "", "", "host", 0, "/", "q=@%20%3C%3E!", "fragment", "http://host/?q=@%20%3C%3E!#fragment"});
208     checkURL("http://user:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
209     checkURL("http://user:@\thost", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
210     checkURL("http://user:\t@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
211     checkURL("http://user\t:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
212     checkURL("http://use\tr:@host", {"http", "user", "", "host", 0, "/", "", "", "http://user@host/"});
213     checkURL("http://127.0.0.1:10100/path", {"http", "", "", "127.0.0.1", 10100, "/path", "", "", "http://127.0.0.1:10100/path"});
214     checkURL("http://127.0.0.1:/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
215     checkURL("http://127.0.0.1\t:/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
216     checkURL("http://127.0.0.1:\t/path", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
217     checkURL("http://127.0.0.1:/\tpath", {"http", "", "", "127.0.0.1", 0, "/path", "", "", "http://127.0.0.1/path"});
218     checkURL("http://127.0.0.1:123", {"http", "", "", "127.0.0.1", 123, "/", "", "", "http://127.0.0.1:123/"});
219     checkURL("http://127.0.0.1:", {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"});
220     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"});
221     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/"});
222     checkURL("http://[0:f:0:0:f:\t:]:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
223     checkURL("http://[0:f:0:0:f::\t]:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
224     checkURL("http://[0:f:0:0:f::]\t:123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
225     checkURL("http://[0:f:0:0:f::]:\t123", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
226     checkURL("http://[0:f:0:0:f::]:1\t23", {"http", "", "", "[0:f:0:0:f::]", 123, "/", "", "", "http://[0:f:0:0:f::]:123/"});
227     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"});
228     checkURL("http://[0:f::f:f:0:0]:", {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"});
229     checkURL("http://host:10100/path", {"http", "", "", "host", 10100, "/path", "", "", "http://host:10100/path"});
230     checkURL("http://host:/path", {"http", "", "", "host", 0, "/path", "", "", "http://host/path"});
231     checkURL("http://host:123", {"http", "", "", "host", 123, "/", "", "", "http://host:123/"});
232     checkURL("http://host:", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
233     checkURL("http://hos\tt\n:\t1\n2\t3\t/\npath", {"http", "", "", "host", 123, "/path", "", "", "http://host:123/path"});
234     checkURL("http://user@example.org/path3", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
235     checkURL("sc:/pa/pa", {"sc", "", "", "", 0, "/pa/pa", "", "", "sc:/pa/pa"});
236     checkURL("sc:/pa", {"sc", "", "", "", 0, "/pa", "", "", "sc:/pa"});
237     checkURL("sc:/pa/", {"sc", "", "", "", 0, "/pa/", "", "", "sc:/pa/"});
238     checkURL("notspecial:/notuser:notpassword@nothost", {"notspecial", "", "", "", 0, "/notuser:notpassword@nothost", "", "", "notspecial:/notuser:notpassword@nothost"});
239     checkURL("sc://pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
240     checkURL("sc://\tpa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
241     checkURL("sc:/\t/pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
242     checkURL("sc:\t//pa/", {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"});
243     checkURL("http://host   \a   ", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
244     checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
245     checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
246     checkURL("http:/a", {"http", "", "", "a", 0, "/", "", "", "http://a/"});
247     checkURL("http://256/", {"http", "", "", "256", 0, "/", "", "", "http://256/"});
248     checkURL("http://256./", {"http", "", "", "256.", 0, "/", "", "", "http://256./"});
249     checkURL("http://123.256/", {"http", "", "", "123.256", 0, "/", "", "", "http://123.256/"});
250     checkURL("http://123\t.256/", {"http", "", "", "123.256", 0, "/", "", "", "http://123.256/"});
251     checkURL("http://123.\t256/", {"http", "", "", "123.256", 0, "/", "", "", "http://123.256/"});
252     checkURL("notspecial:/a", {"notspecial", "", "", "", 0, "/a", "", "", "notspecial:/a"});
253     checkURL("notspecial:", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
254     checkURL("notspecial:/", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
255     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"});
256     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"});
257     checkURL("about:~", {"about", "", "", "", 0, "~", "", "", "about:~"});
258     checkURL("https://@test@test@example:800\\path@end", {"", "", "", "", 0, "", "", "", "https://@test@test@example:800\\path@end"});
259     checkURL("http://www.example.com/#a\nb\rc\td", {"http", "", "", "www.example.com", 0, "/", "", "abcd", "http://www.example.com/#abcd"});
260     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]/"});
261     checkURL("http:////////user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
262     checkURL("http:////////user:@webkit.org:99#foo", {"http", "user", "", "webkit.org", 99, "/", "", "foo", "http://user@webkit.org:99/#foo"});
263     checkURL("http:////\t////user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
264     checkURL("http://\t//\\///user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
265     checkURL("http:/\\user:@webkit.org:99?foo", {"http", "user", "", "webkit.org", 99, "/", "foo", "", "http://user@webkit.org:99/?foo"});
266
267     // This disagrees with the web platform test for http://:@www.example.com but agrees with Chrome and URL::parse,
268     // and Firefox fails the web platform test differently. Maybe the web platform test ought to be changed.
269     checkURL("http://:@host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
270 }
271
272 static void checkRelativeURL(const String& urlString, const String& baseURLString, const ExpectedParts& parts)
273 {
274     bool wasEnabled = URLParser::enabled();
275     URLParser::setEnabled(true);
276     auto url = URL(URL(URL(), baseURLString), urlString);
277     URLParser::setEnabled(false);
278     auto oldURL = URL(URL(URL(), baseURLString), urlString);
279     URLParser::setEnabled(wasEnabled);
280
281     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
282     EXPECT_TRUE(eq(parts.user, url.user()));
283     EXPECT_TRUE(eq(parts.password, url.pass()));
284     EXPECT_TRUE(eq(parts.host, url.host()));
285     EXPECT_EQ(parts.port, url.port());
286     EXPECT_TRUE(eq(parts.path, url.path()));
287     EXPECT_TRUE(eq(parts.query, url.query()));
288     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
289     EXPECT_TRUE(eq(parts.string, url.string()));
290
291     EXPECT_TRUE(eq(parts.protocol, oldURL.protocol()));
292     EXPECT_TRUE(eq(parts.user, oldURL.user()));
293     EXPECT_TRUE(eq(parts.password, oldURL.pass()));
294     EXPECT_TRUE(eq(parts.host, oldURL.host()));
295     EXPECT_EQ(parts.port, oldURL.port());
296     EXPECT_TRUE(eq(parts.path, oldURL.path()));
297     EXPECT_TRUE(eq(parts.query, oldURL.query()));
298     EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier()));
299     EXPECT_TRUE(eq(parts.string, oldURL.string()));
300
301     EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));
302     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
303     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
304 }
305
306 TEST_F(URLParserTest, ParseRelative)
307 {
308     checkRelativeURL("/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "webkit.org", 0, "/index.html", "", "", "http://webkit.org/index.html"});
309     checkRelativeURL("http://whatwg.org/index.html", "http://webkit.org/path1/path2/", {"http", "", "", "whatwg.org", 0, "/index.html", "", "", "http://whatwg.org/index.html"});
310     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"});
311     checkRelativeURL("//whatwg.org/index.html", "https://www.webkit.org/path", {"https", "", "", "whatwg.org", 0, "/index.html", "", "", "https://whatwg.org/index.html"});
312     checkRelativeURL("http://example\t.\norg", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
313     checkRelativeURL("test", "file:///path1/path2", {"file", "", "", "", 0, "/path1/test", "", "", "file:///path1/test"});
314     checkRelativeURL(utf16String(u"http://www.foo。bar.com"), "http://other.com/", {"http", "", "", "www.foo.bar.com", 0, "/", "", "", "http://www.foo.bar.com/"});
315     checkRelativeURL(utf16String(u"sc://ñ.test/"), "about:blank", {"sc", "", "", "xn--ida.test", 0, "/", "", "", "sc://xn--ida.test/"});
316     checkRelativeURL("#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "", "fragment", "http://host/path#fragment"});
317     checkRelativeURL("?query", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "", "http://host/path?query"});
318     checkRelativeURL("?query#fragment", "http://host/path", {"http", "", "", "host", 0, "/path", "query", "fragment", "http://host/path?query#fragment"});
319     checkRelativeURL(utf16String(u"?β"), "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "%CE%B2", "", "http://example.org/foo/bar?%CE%B2"});
320     checkRelativeURL("?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?"});
321     checkRelativeURL("#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar#"});
322     checkRelativeURL("?#", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar?#"});
323     checkRelativeURL("#?", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "?", "http://example.org/foo/bar#?"});
324     checkRelativeURL("/", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/", "", "", "http://example.org/"});
325     checkRelativeURL("http://@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
326     checkRelativeURL("http://:@host", "about:blank", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
327     checkRelativeURL("http://foo.com/\\@", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "//@", "", "", "http://foo.com//@"});
328     checkRelativeURL("\\@", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/@", "", "", "http://example.org/@"});
329     checkRelativeURL("/path3", "http://user@example.org/path1/path2", {"http", "user", "", "example.org", 0, "/path3", "", "", "http://user@example.org/path3"});
330     checkRelativeURL("", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
331     checkRelativeURL("\t", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
332     checkRelativeURL(" ", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
333     checkRelativeURL("  \a  \t\n", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
334     checkRelativeURL(":foo.com\\", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "http://example.org/foo/:foo.com/"});
335     checkRelativeURL("http:/example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
336     checkRelativeURL("http:example.com/", "about:blank", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
337     checkRelativeURL("http:\\\\foo.com\\", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
338     checkRelativeURL("http:\\\\foo.com/", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
339     checkRelativeURL("http:\\\\foo.com", "http://example.org/foo/bar", {"http", "", "", "foo.com", 0, "/", "", "", "http://foo.com/"});
340     checkRelativeURL("http://ExAmPlE.CoM", "http://other.com", {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
341     checkRelativeURL("http:", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/bar", "", "", "http://example.org/foo/bar"});
342     checkRelativeURL("#x", "data:,", {"data", "", "", "", 0, ",", "", "x", "data:,#x"});
343     checkRelativeURL("#x", "about:blank", {"about", "", "", "", 0, "blank", "", "x", "about:blank#x"});
344     checkRelativeURL("  foo.com  ", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/foo.com", "", "", "http://example.org/foo/foo.com"});
345     checkRelativeURL(" \a baz", "http://example.org/foo/bar", {"http", "", "", "example.org", 0, "/foo/baz", "", "", "http://example.org/foo/baz"});
346     checkRelativeURL("~", "http://example.org", {"http", "", "", "example.org", 0, "/~", "", "", "http://example.org/~"});
347     checkRelativeURL("notspecial:", "about:blank", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
348     checkRelativeURL("notspecial:", "http://host", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
349     checkRelativeURL("http:", "http://host", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
350     checkRelativeURL("i", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
351     checkRelativeURL("i    ", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
352     checkRelativeURL("i\t\n  ", "sc:/pa/po", {"sc", "", "", "", 0, "/pa/i", "", "", "sc:/pa/i"});
353     checkRelativeURL("i", "sc://ho/pa", {"sc", "", "", "ho", 0, "/i", "", "", "sc://ho/i"});
354     checkRelativeURL("!", "sc://ho/pa", {"sc", "", "", "ho", 0, "/!", "", "", "sc://ho/!"});
355     checkRelativeURL("!", "sc:/ho/pa", {"sc", "", "", "", 0, "/ho/!", "", "", "sc:/ho/!"});
356     checkRelativeURL("notspecial:/", "about:blank", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
357     checkRelativeURL("notspecial:/", "http://host", {"notspecial", "", "", "", 0, "/", "", "", "notspecial:/"});
358     checkRelativeURL("foo:/", "http://example.org/foo/bar", {"foo", "", "", "", 0, "/", "", "", "foo:/"});
359     checkRelativeURL("://:0/", "http://webkit.org/", {"http", "", "", "webkit.org", 0, "/://:0/", "", "", "http://webkit.org/://:0/"});
360     checkRelativeURL(String(), "http://webkit.org/", {"http", "", "", "webkit.org", 0, "/", "", "", "http://webkit.org/"});
361     checkRelativeURL("https://@test@test@example:800\\path@end", "http://doesnotmatter/", {"", "", "", "", 0, "", "", "", "https://@test@test@example:800\\path@end"});
362
363     // The checking of slashes in SpecialAuthoritySlashes needed to get this to pass contradicts what is in the spec,
364     // but it is included in the web platform tests.
365     checkRelativeURL("http:\\\\host\\foo", "about:blank", {"http", "", "", "host", 0, "/foo", "", "", "http://host/foo"});
366 }
367
368 static void checkURLDifferences(const String& urlString, const ExpectedParts& partsNew, const ExpectedParts& partsOld)
369 {
370     bool wasEnabled = URLParser::enabled();
371     URLParser::setEnabled(true);
372     auto url = URL(URL(), urlString);
373     URLParser::setEnabled(false);
374     auto oldURL = URL(URL(), urlString);
375     URLParser::setEnabled(wasEnabled);
376
377     EXPECT_TRUE(eq(partsNew.protocol, url.protocol()));
378     EXPECT_TRUE(eq(partsNew.user, url.user()));
379     EXPECT_TRUE(eq(partsNew.password, url.pass()));
380     EXPECT_TRUE(eq(partsNew.host, url.host()));
381     EXPECT_EQ(partsNew.port, url.port());
382     EXPECT_TRUE(eq(partsNew.path, url.path()));
383     EXPECT_TRUE(eq(partsNew.query, url.query()));
384     EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
385     EXPECT_TRUE(eq(partsNew.string, url.string()));
386     
387     EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol()));
388     EXPECT_TRUE(eq(partsOld.user, oldURL.user()));
389     EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));
390     EXPECT_TRUE(eq(partsOld.host, oldURL.host()));
391     EXPECT_EQ(partsOld.port, oldURL.port());
392     EXPECT_TRUE(eq(partsOld.path, oldURL.path()));
393     EXPECT_TRUE(eq(partsOld.query, oldURL.query()));
394     EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));
395     EXPECT_TRUE(eq(partsOld.string, oldURL.string()));
396     
397     EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));
398     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
399     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
400 }
401
402 static void checkRelativeURLDifferences(const String& urlString, const String& baseURLString, const ExpectedParts& partsNew, const ExpectedParts& partsOld)
403 {
404     bool wasEnabled = URLParser::enabled();
405     URLParser::setEnabled(true);
406     auto url = URL(URL(URL(), baseURLString), urlString);
407     URLParser::setEnabled(false);
408     auto oldURL = URL(URL(URL(), baseURLString), urlString);
409     URLParser::setEnabled(wasEnabled);
410
411     EXPECT_TRUE(eq(partsNew.protocol, url.protocol()));
412     EXPECT_TRUE(eq(partsNew.user, url.user()));
413     EXPECT_TRUE(eq(partsNew.password, url.pass()));
414     EXPECT_TRUE(eq(partsNew.host, url.host()));
415     EXPECT_EQ(partsNew.port, url.port());
416     EXPECT_TRUE(eq(partsNew.path, url.path()));
417     EXPECT_TRUE(eq(partsNew.query, url.query()));
418     EXPECT_TRUE(eq(partsNew.fragment, url.fragmentIdentifier()));
419     EXPECT_TRUE(eq(partsNew.string, url.string()));
420     
421     EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol()));
422     EXPECT_TRUE(eq(partsOld.user, oldURL.user()));
423     EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));
424     EXPECT_TRUE(eq(partsOld.host, oldURL.host()));
425     EXPECT_EQ(partsOld.port, oldURL.port());
426     EXPECT_TRUE(eq(partsOld.path, oldURL.path()));
427     EXPECT_TRUE(eq(partsOld.query, oldURL.query()));
428     EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));
429     EXPECT_TRUE(eq(partsOld.string, oldURL.string()));
430     
431     EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));
432     EXPECT_TRUE(URLParser::internalValuesConsistent(url));
433     EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));
434 }
435
436 // These are differences between the new URLParser and the old URL::parse which make URLParser more standards compliant.
437 TEST_F(URLParserTest, ParserDifferences)
438 {
439     checkURLDifferences("http://127.0.1",
440         {"http", "", "", "127.0.0.1", 0, "/", "", "", "http://127.0.0.1/"},
441         {"http", "", "", "127.0.1", 0, "/", "", "", "http://127.0.1/"});
442     checkURLDifferences("http://011.11.0X11.0x011",
443         {"http", "", "", "9.11.17.17", 0, "/", "", "", "http://9.11.17.17/"},
444         {"http", "", "", "011.11.0x11.0x011", 0, "/", "", "", "http://011.11.0x11.0x011/"});
445     checkURLDifferences("http://[1234:0078:90AB:CdEf:0123:0007:89AB:0000]",
446         {"http", "", "", "[1234:78:90ab:cdef:123:7:89ab:0]", 0, "/", "", "", "http://[1234:78:90ab:cdef:123:7:89ab:0]/"},
447         {"http", "", "", "[1234:0078:90ab:cdef:0123:0007:89ab:0000]", 0, "/", "", "", "http://[1234:0078:90ab:cdef:0123:0007:89ab:0000]/"});
448     checkURLDifferences("http://[0:f:0:0:f:f:0:0]",
449         {"http", "", "", "[0:f::f:f:0:0]", 0, "/", "", "", "http://[0:f::f:f:0:0]/"},
450         {"http", "", "", "[0:f:0:0:f:f:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:f:0:0]/"});
451     checkURLDifferences("http://[0:f:0:0:f:0:0:0]",
452         {"http", "", "", "[0:f:0:0:f::]", 0, "/", "", "", "http://[0:f:0:0:f::]/"},
453         {"http", "", "", "[0:f:0:0:f:0:0:0]", 0, "/", "", "", "http://[0:f:0:0:f:0:0:0]/"});
454     checkURLDifferences("http://[0:0:f:0:0:f:0:0]",
455         {"http", "", "", "[::f:0:0:f:0:0]", 0, "/", "", "", "http://[::f:0:0:f:0:0]/"},
456         {"http", "", "", "[0:0:f:0:0:f:0:0]", 0, "/", "", "", "http://[0:0:f:0:0:f:0:0]/"});
457     checkURLDifferences("http://[a:0:0:0:b:c::d]",
458         {"http", "", "", "[a::b:c:0:d]", 0, "/", "", "", "http://[a::b:c:0:d]/"},
459         {"http", "", "", "[a:0:0:0:b:c::d]", 0, "/", "", "", "http://[a:0:0:0:b:c::d]/"});
460     checkURLDifferences("http://example.com/path1/.%2e",
461         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
462         {"http", "", "", "example.com", 0, "/path1/.%2e", "", "", "http://example.com/path1/.%2e"});
463     checkURLDifferences("http://example.com/path1/.%2E",
464         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
465         {"http", "", "", "example.com", 0, "/path1/.%2E", "", "", "http://example.com/path1/.%2E"});
466     checkURLDifferences("http://example.com/path1/.%2E/",
467         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
468         {"http", "", "", "example.com", 0, "/path1/.%2E/", "", "", "http://example.com/path1/.%2E/"});
469     checkURLDifferences("http://example.com/path1/%2e.",
470         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
471         {"http", "", "", "example.com", 0, "/path1/%2e.", "", "", "http://example.com/path1/%2e."});
472     checkURLDifferences("http://example.com/path1/%2E%2e",
473         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"},
474         {"http", "", "", "example.com", 0, "/path1/%2E%2e", "", "", "http://example.com/path1/%2E%2e"});
475     checkURLDifferences("http://example.com/path1/%2e",
476         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
477         {"http", "", "", "example.com", 0, "/path1/%2e", "", "", "http://example.com/path1/%2e"});
478     checkURLDifferences("http://example.com/path1/%2E",
479         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
480         {"http", "", "", "example.com", 0, "/path1/%2E", "", "", "http://example.com/path1/%2E"});
481     checkURLDifferences("http://example.com/path1/%2E/",
482         {"http", "", "", "example.com", 0, "/path1/", "", "", "http://example.com/path1/"},
483         {"http", "", "", "example.com", 0, "/path1/%2E/", "", "", "http://example.com/path1/%2E/"});
484     checkURLDifferences("http://example.com/path1/path2/%2e?query",
485         {"http", "", "", "example.com", 0, "/path1/path2/", "query", "", "http://example.com/path1/path2/?query"},
486         {"http", "", "", "example.com", 0, "/path1/path2/%2e", "query", "", "http://example.com/path1/path2/%2e?query"});
487     checkURLDifferences("http://example.com/path1/path2/%2e%2e?query",
488         {"http", "", "", "example.com", 0, "/path1/", "query", "", "http://example.com/path1/?query"},
489         {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "query", "", "http://example.com/path1/path2/%2e%2e?query"});
490     checkURLDifferences("http://example.com/path1/path2/%2e#fragment",
491         {"http", "", "", "example.com", 0, "/path1/path2/", "", "fragment", "http://example.com/path1/path2/#fragment"},
492         {"http", "", "", "example.com", 0, "/path1/path2/%2e", "", "fragment", "http://example.com/path1/path2/%2e#fragment"});
493     checkURLDifferences("http://example.com/path1/path2/%2e%2e#fragment",
494         {"http", "", "", "example.com", 0, "/path1/", "", "fragment", "http://example.com/path1/#fragment"},
495         {"http", "", "", "example.com", 0, "/path1/path2/%2e%2e", "", "fragment", "http://example.com/path1/path2/%2e%2e#fragment"});
496     checkURLDifferences("file://[0:a:0:0:b:c:0:0]/path",
497         {"file", "", "", "[0:a::b:c:0:0]", 0, "/path", "", "", "file://[0:a::b:c:0:0]/path"},
498         {"file", "", "", "[0:a:0:0:b:c:0:0]", 0, "/path", "", "", "file://[0:a:0:0:b:c:0:0]/path"});
499     checkRelativeURLDifferences(utf16String(u"#β"), "http://example.org/foo/bar",
500         {"http", "", "", "example.org", 0, "/foo/bar", "", utf16String(u"β"), utf16String(u"http://example.org/foo/bar#β")},
501         {"http", "", "", "example.org", 0, "/foo/bar", "", "%CE%B2", "http://example.org/foo/bar#%CE%B2"});
502     checkURLDifferences("http://",
503         {"", "", "", "", 0, "", "", "", "http://"},
504         {"http", "", "", "", 0, "/", "", "", "http:/"});
505     checkRelativeURLDifferences("//", "https://www.webkit.org/path",
506         {"", "", "", "", 0, "", "", "", "//"},
507         {"https", "", "", "", 0, "/", "", "", "https:/"});
508     checkURLDifferences("http://127.0.0.1:65536/path",
509         {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536/path"},
510         {"http", "", "", "127.0.0.1", 65535, "/path", "", "", "http://127.0.0.1:65536/path"});
511     checkURLDifferences("http://host:65536",
512         {"", "", "", "", 0, "", "", "", "http://host:65536"},
513         {"http", "", "", "host", 65535, "/", "", "", "http://host:65536/"});
514     checkURLDifferences("http://127.0.0.1:65536",
515         {"", "", "", "", 0, "", "", "", "http://127.0.0.1:65536"},
516         {"http", "", "", "127.0.0.1", 65535, "/", "", "", "http://127.0.0.1:65536/"});
517     checkURLDifferences("http://[0:f::f:f:0:0]:65536",
518         {"", "", "", "", 0, "", "", "", "http://[0:f::f:f:0:0]:65536"},
519         {"http", "", "", "[0:f::f:f:0:0]", 65535, "/", "", "", "http://[0:f::f:f:0:0]:65536/"});
520     checkRelativeURLDifferences(":foo.com\\", "notspecial://example.org/foo/bar",
521         {"notspecial", "", "", "example.org", 0, "/foo/:foo.com\\", "", "", "notspecial://example.org/foo/:foo.com\\"},
522         {"notspecial", "", "", "example.org", 0, "/foo/:foo.com/", "", "", "notspecial://example.org/foo/:foo.com/"});
523     checkURLDifferences("sc://pa",
524         {"sc", "", "", "pa", 0, "/", "", "", "sc://pa/"},
525         {"sc", "", "", "pa", 0, "", "", "", "sc://pa"});
526     checkRelativeURLDifferences("notspecial:\\\\foo.com\\", "http://example.org/foo/bar",
527         {"notspecial", "", "", "", 0, "\\\\foo.com\\", "", "", "notspecial:\\\\foo.com\\"},
528         {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
529     checkRelativeURLDifferences("notspecial:\\\\foo.com/", "http://example.org/foo/bar",
530         {"notspecial", "", "", "", 0, "\\\\foo.com/", "", "", "notspecial:\\\\foo.com/"},
531         {"notspecial", "", "", "foo.com", 0, "/", "", "", "notspecial://foo.com/"});
532     checkRelativeURLDifferences("notspecial:\\\\foo.com", "http://example.org/foo/bar",
533         {"notspecial", "", "", "", 0, "\\\\foo.com", "", "", "notspecial:\\\\foo.com"},
534         {"notspecial", "", "", "foo.com", 0, "", "", "", "notspecial://foo.com"});
535     checkURLDifferences("file://notuser:notpassword@test",
536         {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test"},
537         {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
538     checkURLDifferences("file://notuser:notpassword@test/",
539         {"", "", "", "", 0, "", "", "", "file://notuser:notpassword@test/"},
540         {"file", "notuser", "notpassword", "test", 0, "/", "", "", "file://notuser:notpassword@test/"});
541     checkRelativeURLDifferences("http:/", "about:blank",
542         {"", "", "", "", 0, "", "", "", "http:/"},
543         {"http", "", "", "", 0, "/", "", "", "http:/"});
544     checkRelativeURLDifferences("http:", "about:blank",
545         {"http", "", "", "", 0, "", "", "", "http:"},
546         {"http", "", "", "", 0, "/", "", "", "http:/"});
547     checkRelativeURLDifferences("http:/", "http://host",
548         {"", "", "", "", 0, "", "", "", "http:/"},
549         {"http", "", "", "", 0, "/", "", "", "http:/"});
550     checkURLDifferences("http:/",
551         {"", "", "", "", 0, "", "", "", "http:/"},
552         {"http", "", "", "", 0, "/", "", "", "http:/"});
553     checkURLDifferences("http:",
554         {"http", "", "", "", 0, "", "", "", "http:"},
555         {"http", "", "", "", 0, "/", "", "", "http:/"});
556     checkRelativeURLDifferences("http:/example.com/", "http://example.org/foo/bar",
557         {"http", "", "", "example.org", 0, "/example.com/", "", "", "http://example.org/example.com/"},
558         {"http", "", "", "example.com", 0, "/", "", "", "http://example.com/"});
559     
560     // This behavior matches Chrome and Firefox, but not WebKit using URL::parse.
561     // The behavior of URL::parse is clearly wrong because reparsing file://path would make path the host.
562     // The spec is unclear.
563     checkURLDifferences("file:path",
564         {"file", "", "", "", 0, "/path", "", "", "file:///path"},
565         {"file", "", "", "", 0, "path", "", "", "file://path"});
566     checkURLDifferences("file:pAtH",
567         {"file", "", "", "", 0, "/pAtH", "", "", "file:///pAtH"},
568         {"file", "", "", "", 0, "pAtH", "", "", "file://pAtH"});
569     checkURLDifferences("file:pAtH/",
570         {"file", "", "", "", 0, "/pAtH/", "", "", "file:///pAtH/"},
571         {"file", "", "", "", 0, "pAtH/", "", "", "file://pAtH/"});
572     
573     // FIXME: Fix and test incomplete percent encoded characters in the middle and end of the input string.
574     // FIXME: Fix and test percent encoded upper case characters in the host.
575     checkURLDifferences("http://host%73",
576         {"http", "", "", "hosts", 0, "/", "", "", "http://hosts/"},
577         {"http", "", "", "host%73", 0, "/", "", "", "http://host%73/"});
578     
579     // URLParser matches Chrome and the spec, but not URL::parse or Firefox.
580     checkURLDifferences(utf16String(u"http://0Xc0.0250.01"),
581         {"http", "", "", "192.168.0.1", 0, "/", "", "", "http://192.168.0.1/"},
582         {"http", "", "", "0xc0.0250.01", 0, "/", "", "", "http://0xc0.0250.01/"});
583     checkURLDifferences("http://host/path%2e.%2E",
584         {"http", "", "", "host", 0, "/path...", "", "", "http://host/path..."},
585         {"http", "", "", "host", 0, "/path%2e.%2E", "", "", "http://host/path%2e.%2E"});
586
587     checkRelativeURLDifferences(utf16String(u"http://foo:💩@example.com/bar"), "http://other.com/",
588         {"http", "foo", utf16String(u"💩"), "example.com", 0, "/bar", "", "", "http://foo:%F0%9F%92%A9@example.com/bar"},
589         {"", "", "", "", 0, "", "", "", utf16String(u"http://foo:💩@example.com/bar")});
590     checkRelativeURLDifferences("http://&a:foo(b]c@d:2/", "http://example.org/foo/bar",
591         {"http", "&a", "foo(b]c", "d", 2, "/", "", "", "http://&a:foo(b%5Dc@d:2/"},
592         {"", "", "", "", 0, "", "", "", "http://&a:foo(b]c@d:2/"});
593     checkRelativeURLDifferences("http://`{}:`{}@h/`{}?`{}", "http://doesnotmatter/",
594         {"http", "`{}", "`{}", "h", 0, "/%60%7B%7D", "`{}", "", "http://%60%7B%7D:%60%7B%7D@h/%60%7B%7D?`{}"},
595         {"", "", "", "", 0, "", "", "", "http://`{}:`{}@h/`{}?`{}"});
596     checkURLDifferences("http://[0:f::f::f]",
597         {"", "", "", "", 0, "" , "", "", "http://[0:f::f::f]"},
598         {"http", "", "", "[0:f::f::f]", 0, "/" , "", "", "http://[0:f::f::f]/"});
599     checkURLDifferences("http://123",
600         {"http", "", "", "0.0.0.123", 0, "/", "", "", "http://0.0.0.123/"},
601         {"http", "", "", "123", 0, "/", "", "", "http://123/"});
602     checkURLDifferences("http://123.234/",
603         {"http", "", "", "123.0.0.234", 0, "/", "", "", "http://123.0.0.234/"},
604         {"http", "", "", "123.234", 0, "/", "", "", "http://123.234/"});
605     checkURLDifferences("http://123.234.012",
606         {"http", "", "", "123.234.0.10", 0, "/", "", "", "http://123.234.0.10/"},
607         {"http", "", "", "123.234.012", 0, "/", "", "", "http://123.234.012/"});
608     checkURLDifferences("http://123.234.12",
609         {"http", "", "", "123.234.0.12", 0, "/", "", "", "http://123.234.0.12/"},
610         {"http", "", "", "123.234.12", 0, "/", "", "", "http://123.234.12/"});
611     checkRelativeURLDifferences("file:c:\\foo\\bar.html", "file:///tmp/mock/path",
612         {"file", "", "", "", 0, "/c:/foo/bar.html", "", "", "file:///c:/foo/bar.html"},
613         {"file", "", "", "", 0, "/tmp/mock/c:/foo/bar.html", "", "", "file:///tmp/mock/c:/foo/bar.html"});
614     checkRelativeURLDifferences("  File:c|////foo\\bar.html", "file:///tmp/mock/path",
615         {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
616         {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
617     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",
618         {"file", "", "", "", 0, "/c:////foo/bar.html", "", "", "file:///c:////foo/bar.html"},
619         {"file", "", "", "", 0, "/tmp/mock/c|////foo/bar.html", "", "", "file:///tmp/mock/c|////foo/bar.html"});
620     checkRelativeURLDifferences("C|/foo/bar", "file:///tmp/mock/path",
621         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
622         {"file", "", "", "", 0, "/tmp/mock/C|/foo/bar", "", "", "file:///tmp/mock/C|/foo/bar"});
623     checkRelativeURLDifferences("/C|/foo/bar", "file:///tmp/mock/path",
624         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
625         {"file", "", "", "", 0, "/C|/foo/bar", "", "", "file:///C|/foo/bar"});
626     checkRelativeURLDifferences("https://@test@test@example:800/", "http://doesnotmatter/",
627         {"https", "@test@test", "", "example", 800, "/", "", "", "https://%40test%40test@example:800/"},
628         {"", "", "", "", 0, "", "", "", "https://@test@test@example:800/"});
629     checkRelativeURLDifferences("https://@test@test@example:800/path@end", "http://doesnotmatter/",
630         {"https", "@test@test", "", "example", 800, "/path@end", "", "", "https://%40test%40test@example:800/path@end"},
631         {"", "", "", "", 0, "", "", "", "https://@test@test@example:800/path@end"});
632     checkURLDifferences("notspecial://@test@test@example:800/path@end",
633         {"notspecial", "@test@test", "", "example", 800, "/path@end", "", "", "notspecial://%40test%40test@example:800/path@end"},
634         {"", "", "", "", 0, "", "", "", "notspecial://@test@test@example:800/path@end"});
635     checkURLDifferences("notspecial://@test@test@example:800\\path@end",
636         {"notspecial", "@test@test@example", "800\\path", "end", 0, "/", "", "", "notspecial://%40test%40test%40example:800%5Cpath@end/"},
637         {"", "", "", "", 0, "", "", "", "notspecial://@test@test@example:800\\path@end"});
638     checkRelativeURLDifferences("foo://", "http://example.org/foo/bar",
639         {"foo", "", "", "", 0, "/", "", "", "foo:///"},
640         {"foo", "", "", "", 0, "//", "", "", "foo://"});
641     checkURLDifferences(utf16String(u"http://host?ß😍#ß😍"),
642         {"http", "", "", "host", 0, "/", "%C3%9F%F0%9F%98%8D", utf16String(u"ß😍"), utf16String(u"http://host/?%C3%9F%F0%9F%98%8D#ß😍")},
643         {"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"});
644     checkURLDifferences(utf16String(u"http://host/path#💩\t💩"),
645         {"http", "", "", "host", 0, "/path", "", utf16String(u"💩💩"), utf16String(u"http://host/path#💩💩")},
646         {"http", "", "", "host", 0, "/path", "", "%F0%9F%92%A9%F0%9F%92%A9", "http://host/path#%F0%9F%92%A9%F0%9F%92%A9"});
647     checkURLDifferences("http://%48OsT",
648         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
649         {"http", "", "", "%48ost", 0, "/", "", "", "http://%48ost/"});
650     checkURLDifferences("http://h%4FsT",
651         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
652         {"http", "", "", "h%4fst", 0, "/", "", "", "http://h%4fst/"});
653     checkURLDifferences("http://h%4fsT",
654         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
655         {"http", "", "", "h%4fst", 0, "/", "", "", "http://h%4fst/"});
656     checkURLDifferences("http://h%6fsT",
657         {"http", "", "", "host", 0, "/", "", "", "http://host/"},
658         {"http", "", "", "h%6fst", 0, "/", "", "", "http://h%6fst/"});
659     checkURLDifferences("http://host/`",
660         {"http", "", "", "host", 0, "/%60", "", "", "http://host/%60"},
661         {"http", "", "", "host", 0, "/`", "", "", "http://host/`"});
662     checkURLDifferences("aA://",
663         {"aa", "", "", "", 0, "/", "", "", "aa:///"},
664         {"aa", "", "", "", 0, "//", "", "", "aa://"});
665     checkURLDifferences("A://",
666         {"a", "", "", "", 0, "/", "", "", "a:///"},
667         {"a", "", "", "", 0, "//", "", "", "a://"});
668     checkRelativeURLDifferences("//C|/foo/bar", "file:///tmp/mock/path",
669         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
670         {"", "", "", "", 0, "", "", "", "//C|/foo/bar"});
671     checkRelativeURLDifferences("//C:/foo/bar", "file:///tmp/mock/path",
672         {"file", "", "", "", 0, "/C:/foo/bar", "", "", "file:///C:/foo/bar"},
673         {"file", "", "", "c", 0, "/foo/bar", "", "", "file://c/foo/bar"});
674     checkRelativeURLDifferences("//C|?foo/bar", "file:///tmp/mock/path",
675         {"file", "", "", "", 0, "/C:/", "foo/bar", "", "file:///C:/?foo/bar"},
676         {"", "", "", "", 0, "", "", "", "//C|?foo/bar"});
677     checkRelativeURLDifferences("//C|#foo/bar", "file:///tmp/mock/path",
678         {"file", "", "", "", 0, "/C:/", "", "foo/bar", "file:///C:/#foo/bar"},
679         {"", "", "", "", 0, "", "", "", "//C|#foo/bar"});
680 }
681
682 TEST_F(URLParserTest, DefaultPort)
683 {
684     checkURL("FtP://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
685     checkURL("ftp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
686     checkURL("f\ttp://host:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
687     checkURL("f\ttp://host\t:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
688     checkURL("f\ttp://host:\t21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
689     checkURL("f\ttp://host:2\t1/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
690     checkURL("f\ttp://host:21\t/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
691     checkURL("ftp://host\t:21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
692     checkURL("ftp://host:\t21/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
693     checkURL("ftp://host:2\t1/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
694     checkURL("ftp://host:21\t/", {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"});
695     checkURL("ftp://host:22/", {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"});
696     checkURLDifferences("ftp://host:21",
697         {"ftp", "", "", "host", 0, "/", "", "", "ftp://host/"},
698         {"ftp", "", "", "host", 0, "", "", "", "ftp://host"});
699     checkURLDifferences("ftp://host:22",
700         {"ftp", "", "", "host", 22, "/", "", "", "ftp://host:22/"},
701         {"ftp", "", "", "host", 22, "", "", "", "ftp://host:22"});
702     
703     checkURL("gOpHeR://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
704     checkURL("gopher://host:70/", {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"});
705     checkURL("gopher://host:71/", {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"});
706     // Spec, Chrome, Firefox, and URLParser have "/", URL::parse does not.
707     // Spec, Chrome, URLParser, URL::parse recognize gopher default port, Firefox does not.
708     checkURLDifferences("gopher://host:70",
709         {"gopher", "", "", "host", 0, "/", "", "", "gopher://host/"},
710         {"gopher", "", "", "host", 0, "", "", "", "gopher://host"});
711     checkURLDifferences("gopher://host:71",
712         {"gopher", "", "", "host", 71, "/", "", "", "gopher://host:71/"},
713         {"gopher", "", "", "host", 71, "", "", "", "gopher://host:71"});
714     
715     checkURL("hTtP://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
716     checkURL("http://host:80", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
717     checkURL("http://host:80/", {"http", "", "", "host", 0, "/", "", "", "http://host/"});
718     checkURL("http://host:81", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
719     checkURL("http://host:81/", {"http", "", "", "host", 81, "/", "", "", "http://host:81/"});
720     
721     checkURL("hTtPs://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
722     checkURL("https://host:443", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
723     checkURL("https://host:443/", {"https", "", "", "host", 0, "/", "", "", "https://host/"});
724     checkURL("https://host:444", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
725     checkURL("https://host:444/", {"https", "", "", "host", 444, "/", "", "", "https://host:444/"});
726     
727     checkURL("wS://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
728     checkURL("ws://host:80/", {"ws", "", "", "host", 0, "/", "", "", "ws://host/"});
729     checkURL("ws://host:81/", {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"});
730     // URLParser matches Chrome and Firefox, but not URL::parse
731     checkURLDifferences("ws://host:80",
732         {"ws", "", "", "host", 0, "/", "", "", "ws://host/"},
733         {"ws", "", "", "host", 0, "", "", "", "ws://host"});
734     checkURLDifferences("ws://host:81",
735         {"ws", "", "", "host", 81, "/", "", "", "ws://host:81/"},
736         {"ws", "", "", "host", 81, "", "", "", "ws://host:81"});
737     
738     checkURL("WsS://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
739     checkURL("wss://host:443/", {"wss", "", "", "host", 0, "/", "", "", "wss://host/"});
740     checkURL("wss://host:444/", {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"});
741     // URLParser matches Chrome and Firefox, but not URL::parse
742     checkURLDifferences("wss://host:443",
743         {"wss", "", "", "host", 0, "/", "", "", "wss://host/"},
744         {"wss", "", "", "host", 0, "", "", "", "wss://host"});
745     checkURLDifferences("wss://host:444",
746         {"wss", "", "", "host", 444, "/", "", "", "wss://host:444/"},
747         {"wss", "", "", "host", 444, "", "", "", "wss://host:444"});
748
749     // 990 is the default ftps port in URL::parse, but it's not in the URL spec. Maybe it should be.
750     checkURL("fTpS://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
751     checkURL("ftps://host:990/", {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"});
752     checkURL("ftps://host:991/", {"ftps", "", "", "host", 991, "/", "", "", "ftps://host:991/"});
753     checkURLDifferences("ftps://host:990",
754         {"ftps", "", "", "host", 990, "/", "", "", "ftps://host:990/"},
755         {"ftps", "", "", "host", 990, "", "", "", "ftps://host:990"});
756     checkURLDifferences("ftps://host:991",
757         {"ftps", "", "", "host", 991, "/", "", "", "ftps://host:991/"},
758         {"ftps", "", "", "host", 991, "", "", "", "ftps://host:991"});
759
760     checkURL("uNkNoWn://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
761     checkURL("unknown://host:80/", {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"});
762     checkURL("unknown://host:81/", {"unknown", "", "", "host", 81, "/", "", "", "unknown://host:81/"});
763     checkURLDifferences("unknown://host:80",
764         {"unknown", "", "", "host", 80, "/", "", "", "unknown://host:80/"},
765         {"unknown", "", "", "host", 80, "", "", "", "unknown://host:80"});
766     checkURLDifferences("unknown://host:81",
767         {"unknown", "", "", "host", 81, "/", "", "", "unknown://host:81/"},
768         {"unknown", "", "", "host", 81, "", "", "", "unknown://host:81"});
769 }
770     
771 static void shouldFail(const String& urlString)
772 {
773     checkURL(urlString, {"", "", "", "", 0, "", "", "", urlString});
774 }
775
776 static void shouldFail(const String& urlString, const String& baseString)
777 {
778     checkRelativeURL(urlString, baseString, {"", "", "", "", 0, "", "", "", urlString});
779 }
780
781 TEST_F(URLParserTest, ParserFailures)
782 {
783     shouldFail("    ");
784     shouldFail("  \a  ");
785     shouldFail("");
786     shouldFail(String());
787     shouldFail("", "about:blank");
788     shouldFail(String(), "about:blank");
789     shouldFail("http://127.0.0.1:abc");
790     shouldFail("http://host:abc");
791     shouldFail("http://a:@", "about:blank");
792     shouldFail("http://:b@", "about:blank");
793     shouldFail("http://:@", "about:blank");
794     shouldFail("http://a:@");
795     shouldFail("http://:b@");
796     shouldFail("http://@");
797     shouldFail("http://[0:f::f:f:0:0]:abc");
798     shouldFail("../i", "sc:sd");
799     shouldFail("../i", "sc:sd/sd");
800     shouldFail("/i", "sc:sd");
801     shouldFail("/i", "sc:sd/sd");
802     shouldFail("?i", "sc:sd");
803     shouldFail("?i", "sc:sd/sd");
804     shouldFail("http://example example.com", "http://other.com/");
805     shouldFail("http://[www.example.com]/", "about:blank");
806     shouldFail("http://192.168.0.1 hello", "http://other.com/");
807     shouldFail("http://[example.com]", "http://other.com/");
808     shouldFail("i", "sc:sd");
809     shouldFail("i", "sc:sd/sd");
810     shouldFail("i");
811     shouldFail("asdf");
812     shouldFail("~");
813     shouldFail("~", "about:blank");
814     shouldFail("~~~");
815     shouldFail("://:0/");
816     shouldFail("://:0/", "");
817     shouldFail("://:0/", "about:blank");
818     shouldFail("about~");
819     shouldFail("//C:asdf/foo/bar", "file:///tmp/mock/path");
820 }
821
822 // These are in the spec but not in the web platform tests.
823 TEST_F(URLParserTest, AdditionalTests)
824 {
825     checkURL("about:\a\aabc", {"about", "", "", "", 0, "%07%07abc", "", "", "about:%07%07abc"});
826     checkURL("notspecial:\t\t\n\t", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
827     checkURLDifferences("notspecial\t\t\n\t:\t\t\n\t/\t\t\n\t/\t\t\n\thost",
828         {"notspecial", "", "", "host", 0, "/", "", "", "notspecial://host/"},
829         {"notspecial", "", "", "host", 0, "", "", "", "notspecial://host"});
830     checkRelativeURL("http:", "http://example.org/foo/bar?query#fragment", {"http", "", "", "example.org", 0, "/foo/bar", "query", "", "http://example.org/foo/bar?query"});
831     checkRelativeURLDifferences("ws:", "http://example.org/foo/bar",
832         {"ws", "", "", "", 0, "", "", "", "ws:"},
833         {"ws", "", "", "", 0, "s:", "", "", "ws:s:"});
834     checkRelativeURL("notspecial:", "http://example.org/foo/bar", {"notspecial", "", "", "", 0, "", "", "", "notspecial:"});
835     
836     const wchar_t surrogateBegin = 0xD800;
837     const wchar_t validSurrogateEnd = 0xDD55;
838     const wchar_t invalidSurrogateEnd = 'A';
839     checkURL(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, validSurrogateEnd, '\0'}),
840         {"http", "", "", "w", 0, "/%F0%90%85%95", "", "", "http://w/%F0%90%85%95"});
841     
842     // URLParser matches Chrome and Firefox but not URL::parse.
843     checkURLDifferences(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, invalidSurrogateEnd}),
844         {"http", "", "", "w", 0, "/%EF%BF%BDA", "", "", "http://w/%EF%BF%BDA"},
845         {"http", "", "", "w", 0, "/%ED%A0%80A", "", "", "http://w/%ED%A0%80A"});
846     checkURLDifferences(utf16String<13>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, invalidSurrogateEnd, '\0'}),
847         {"http", "", "", "w", 0, "/", "%EF%BF%BDA", "", "http://w/?%EF%BF%BDA"},
848         {"http", "", "", "w", 0, "/", "%ED%A0%80A", "", "http://w/?%ED%A0%80A"});
849     checkURLDifferences(utf16String<11>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', surrogateBegin, '\0'}),
850         {"http", "", "", "w", 0, "/%EF%BF%BD", "", "", "http://w/%EF%BF%BD"},
851         {"http", "", "", "w", 0, "/%ED%A0%80", "", "", "http://w/%ED%A0%80"});
852     checkURLDifferences(utf16String<12>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, '\0'}),
853         {"http", "", "", "w", 0, "/", "%EF%BF%BD", "", "http://w/?%EF%BF%BD"},
854         {"http", "", "", "w", 0, "/", "%ED%A0%80", "", "http://w/?%ED%A0%80"});
855     checkURLDifferences(utf16String<13>({'h', 't', 't', 'p', ':', '/', '/', 'w', '/', '?', surrogateBegin, ' ', '\0'}),
856         {"http", "", "", "w", 0, "/", "%EF%BF%BD", "", "http://w/?%EF%BF%BD"},
857         {"http", "", "", "w", 0, "/", "%ED%A0%80", "", "http://w/?%ED%A0%80"});
858 }
859
860 static void checkURL(const String& urlString, const TextEncoding& encoding, const ExpectedParts& parts)
861 {
862     URLParser parser(urlString, { }, encoding);
863     auto url = parser.result();
864     EXPECT_TRUE(eq(parts.protocol, url.protocol()));
865     EXPECT_TRUE(eq(parts.user, url.user()));
866     EXPECT_TRUE(eq(parts.password, url.pass()));
867     EXPECT_TRUE(eq(parts.host, url.host()));
868     EXPECT_EQ(parts.port, url.port());
869     EXPECT_TRUE(eq(parts.path, url.path()));
870     EXPECT_TRUE(eq(parts.query, url.query()));
871     EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier()));
872     EXPECT_TRUE(eq(parts.string, url.string()));
873 }
874
875 TEST_F(URLParserTest, QueryEncoding)
876 {
877     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#ß😍")});
878     // FIXME: Add tests with other encodings.
879 }
880
881 } // namespace TestWebKitAPI