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