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