blob: 0f3913b50dc08a44bb1e41ff3bfab212e98d59be [file] [log] [blame]
mkwst28c7c112015-07-14 22:41:061// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
avic0c60312015-12-21 21:03:505#include <stddef.h>
6#include <stdint.h>
7
Avi Drissmana92b3be2018-12-24 21:55:298#include "base/stl_util.h"
mkwst28c7c112015-07-14 22:41:069#include "testing/gtest/include/gtest/gtest.h"
10#include "url/gurl.h"
11#include "url/scheme_host_port.h"
Charles Harrison60f0c532018-03-12 17:30:5512#include "url/url_util.h"
mkwst28c7c112015-07-14 22:41:0613
14namespace {
15
Nick Carter123ca192018-03-30 23:25:3616class SchemeHostPortTest : public testing::Test {
17 public:
18 SchemeHostPortTest() = default;
Michael Thiessen2add7d442020-02-05 13:49:3819 ~SchemeHostPortTest() override = default;
Nick Carter123ca192018-03-30 23:25:3620
21 private:
Michael Thiessen2add7d442020-02-05 13:49:3822 url::ScopedSchemeRegistryForTests scoped_registry_;
23
Nick Carter123ca192018-03-30 23:25:3624 DISALLOW_COPY_AND_ASSIGN(SchemeHostPortTest);
25};
26
csharrison6fbc9fa2016-10-08 03:31:5027void ExpectParsedUrlsEqual(const GURL& a, const GURL& b) {
28 EXPECT_EQ(a, b);
29 const url::Parsed& a_parsed = a.parsed_for_possibly_invalid_spec();
30 const url::Parsed& b_parsed = b.parsed_for_possibly_invalid_spec();
31 EXPECT_EQ(a_parsed.scheme.begin, b_parsed.scheme.begin);
32 EXPECT_EQ(a_parsed.scheme.len, b_parsed.scheme.len);
33 EXPECT_EQ(a_parsed.username.begin, b_parsed.username.begin);
34 EXPECT_EQ(a_parsed.username.len, b_parsed.username.len);
35 EXPECT_EQ(a_parsed.password.begin, b_parsed.password.begin);
36 EXPECT_EQ(a_parsed.password.len, b_parsed.password.len);
37 EXPECT_EQ(a_parsed.host.begin, b_parsed.host.begin);
38 EXPECT_EQ(a_parsed.host.len, b_parsed.host.len);
39 EXPECT_EQ(a_parsed.port.begin, b_parsed.port.begin);
40 EXPECT_EQ(a_parsed.port.len, b_parsed.port.len);
41 EXPECT_EQ(a_parsed.path.begin, b_parsed.path.begin);
42 EXPECT_EQ(a_parsed.path.len, b_parsed.path.len);
43 EXPECT_EQ(a_parsed.query.begin, b_parsed.query.begin);
44 EXPECT_EQ(a_parsed.query.len, b_parsed.query.len);
45 EXPECT_EQ(a_parsed.ref.begin, b_parsed.ref.begin);
46 EXPECT_EQ(a_parsed.ref.len, b_parsed.ref.len);
47}
48
Nick Carter123ca192018-03-30 23:25:3649TEST_F(SchemeHostPortTest, Invalid) {
mkwst28c7c112015-07-14 22:41:0650 url::SchemeHostPort invalid;
51 EXPECT_EQ("", invalid.scheme());
52 EXPECT_EQ("", invalid.host());
53 EXPECT_EQ(0, invalid.port());
Nasko Oskov55119382020-01-17 18:22:1854 EXPECT_FALSE(invalid.IsValid());
Nasko Oskov9277dfc2018-09-17 23:20:5455 EXPECT_EQ(invalid, invalid);
mkwst28c7c112015-07-14 22:41:0656
csharrison39a260f92017-01-09 22:24:1457 const char* urls[] = {
58 "data:text/html,Hello!", "javascript:alert(1)",
59 "file://example.com:443/etc/passwd",
60
61 // These schemes do not follow the generic URL syntax, so make sure we
62 // treat them as invalid (scheme, host, port) tuples (even though such
63 // URLs' _Origin_ might have a (scheme, host, port) tuple, they themselves
64 // do not). This is only *implicitly* checked in the code, by means of
65 // blob schemes not being standard, and filesystem schemes having type
66 // SCHEME_WITHOUT_AUTHORITY. If conditions change such that the implicit
67 // checks no longer hold, this policy should be made explicit.
68 "blob:https://example.com/uuid-goes-here",
69 "filesystem:https://example.com/temporary/yay.png"};
mkwst28c7c112015-07-14 22:41:0670
vmpstr981aa5a2016-07-14 01:05:0871 for (auto* test : urls) {
mkwst28c7c112015-07-14 22:41:0672 SCOPED_TRACE(test);
73 GURL url(test);
74 url::SchemeHostPort tuple(url);
75 EXPECT_EQ("", tuple.scheme());
76 EXPECT_EQ("", tuple.host());
77 EXPECT_EQ(0, tuple.port());
Nasko Oskov55119382020-01-17 18:22:1878 EXPECT_FALSE(tuple.IsValid());
Nasko Oskov9277dfc2018-09-17 23:20:5479 EXPECT_EQ(tuple, tuple);
80 EXPECT_EQ(tuple, invalid);
81 EXPECT_EQ(invalid, tuple);
csharrison6fbc9fa2016-10-08 03:31:5082 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
mkwst28c7c112015-07-14 22:41:0683 }
84}
85
Nick Carter123ca192018-03-30 23:25:3686TEST_F(SchemeHostPortTest, ExplicitConstruction) {
mkwst28c7c112015-07-14 22:41:0687 struct TestCases {
88 const char* scheme;
89 const char* host;
avic0c60312015-12-21 21:03:5090 uint16_t port;
mkwst28c7c112015-07-14 22:41:0691 } cases[] = {
92 {"http", "example.com", 80},
93 {"http", "example.com", 123},
Lukasz Anforowiczc664e8b2020-04-13 20:08:5594 {"http", "example.com", 0}, // 0 is a valid port for http.
mkwst28c7c112015-07-14 22:41:0695 {"https", "example.com", 443},
96 {"https", "example.com", 123},
Lukasz Anforowiczc664e8b2020-04-13 20:08:5597 {"file", "", 0}, // 0 indicates "no port" for file: scheme.
mkwst28c7c112015-07-14 22:41:0698 {"file", "example.com", 0},
99 };
100
101 for (const auto& test : cases) {
102 SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
103 << test.port);
104 url::SchemeHostPort tuple(test.scheme, test.host, test.port);
105 EXPECT_EQ(test.scheme, tuple.scheme());
106 EXPECT_EQ(test.host, tuple.host());
107 EXPECT_EQ(test.port, tuple.port());
Nasko Oskov55119382020-01-17 18:22:18108 EXPECT_TRUE(tuple.IsValid());
Nasko Oskov9277dfc2018-09-17 23:20:54109 EXPECT_EQ(tuple, tuple);
csharrison6fbc9fa2016-10-08 03:31:50110 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
mkwst28c7c112015-07-14 22:41:06111 }
112}
113
Nick Carter123ca192018-03-30 23:25:36114TEST_F(SchemeHostPortTest, InvalidConstruction) {
mkwstd8335d982015-07-25 05:18:48115 struct TestCases {
116 const char* scheme;
117 const char* host;
avic0c60312015-12-21 21:03:50118 uint16_t port;
mkwstd8335d982015-07-25 05:18:48119 } cases[] = {{"", "", 0},
120 {"data", "", 0},
121 {"blob", "", 0},
122 {"filesystem", "", 0},
123 {"http", "", 80},
124 {"data", "example.com", 80},
125 {"http", "☃.net", 80},
126 {"http\nmore", "example.com", 80},
127 {"http\rmore", "example.com", 80},
128 {"http\n", "example.com", 80},
129 {"http\r", "example.com", 80},
130 {"http", "example.com\nnot-example.com", 80},
131 {"http", "example.com\rnot-example.com", 80},
132 {"http", "example.com\n", 80},
133 {"http", "example.com\r", 80},
Lukasz Anforowiczc664e8b2020-04-13 20:08:55134 {"file", "", 80}}; // Can''t have a port for file: scheme.
mkwstd8335d982015-07-25 05:18:48135
136 for (const auto& test : cases) {
137 SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
138 << test.port);
139 url::SchemeHostPort tuple(test.scheme, test.host, test.port);
140 EXPECT_EQ("", tuple.scheme());
141 EXPECT_EQ("", tuple.host());
142 EXPECT_EQ(0, tuple.port());
Nasko Oskov55119382020-01-17 18:22:18143 EXPECT_FALSE(tuple.IsValid());
Nasko Oskov9277dfc2018-09-17 23:20:54144 EXPECT_EQ(tuple, tuple);
csharrison6fbc9fa2016-10-08 03:31:50145 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
mkwstd8335d982015-07-25 05:18:48146 }
147}
148
Nick Carter123ca192018-03-30 23:25:36149TEST_F(SchemeHostPortTest, InvalidConstructionWithEmbeddedNulls) {
mkwstd8335d982015-07-25 05:18:48150 struct TestCases {
151 const char* scheme;
152 size_t scheme_length;
153 const char* host;
154 size_t host_length;
avic0c60312015-12-21 21:03:50155 uint16_t port;
mkwstd8335d982015-07-25 05:18:48156 } cases[] = {{"http\0more", 9, "example.com", 11, 80},
157 {"http\0", 5, "example.com", 11, 80},
158 {"\0http", 5, "example.com", 11, 80},
159 {"http", 4, "example.com\0not-example.com", 27, 80},
160 {"http", 4, "example.com\0", 12, 80},
161 {"http", 4, "\0example.com", 12, 80}};
162
163 for (const auto& test : cases) {
164 SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
165 << test.port);
166 url::SchemeHostPort tuple(std::string(test.scheme, test.scheme_length),
167 std::string(test.host, test.host_length),
168 test.port);
169 EXPECT_EQ("", tuple.scheme());
170 EXPECT_EQ("", tuple.host());
171 EXPECT_EQ(0, tuple.port());
Nasko Oskov55119382020-01-17 18:22:18172 EXPECT_FALSE(tuple.IsValid());
csharrison6fbc9fa2016-10-08 03:31:50173 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
mkwstd8335d982015-07-25 05:18:48174 }
175}
176
Nick Carter123ca192018-03-30 23:25:36177TEST_F(SchemeHostPortTest, GURLConstruction) {
mkwst28c7c112015-07-14 22:41:06178 struct TestCases {
179 const char* url;
180 const char* scheme;
181 const char* host;
avic0c60312015-12-21 21:03:50182 uint16_t port;
mkwst28c7c112015-07-14 22:41:06183 } cases[] = {
184 {"http://192.168.9.1/", "http", "192.168.9.1", 80},
185 {"http://[2001:db8::1]/", "http", "[2001:db8::1]", 80},
186 {"http://☃.net/", "http", "xn--n3h.net", 80},
187 {"http://example.com/", "http", "example.com", 80},
188 {"http://example.com:123/", "http", "example.com", 123},
189 {"https://example.com/", "https", "example.com", 443},
190 {"https://example.com:123/", "https", "example.com", 123},
191 {"file:///etc/passwd", "file", "", 0},
192 {"file://example.com/etc/passwd", "file", "example.com", 0},
193 {"http://u:[email protected]/", "http", "example.com", 80},
194 {"http://u:[email protected]/path", "http", "example.com", 80},
195 {"http://u:[email protected]/path?123", "http", "example.com", 80},
196 {"http://u:[email protected]/path?123#hash", "http", "example.com", 80},
197 };
198
199 for (const auto& test : cases) {
200 SCOPED_TRACE(test.url);
201 GURL url(test.url);
202 EXPECT_TRUE(url.is_valid());
203 url::SchemeHostPort tuple(url);
204 EXPECT_EQ(test.scheme, tuple.scheme());
205 EXPECT_EQ(test.host, tuple.host());
206 EXPECT_EQ(test.port, tuple.port());
Nasko Oskov55119382020-01-17 18:22:18207 EXPECT_TRUE(tuple.IsValid());
Nasko Oskov9277dfc2018-09-17 23:20:54208 EXPECT_EQ(tuple, tuple);
csharrison6fbc9fa2016-10-08 03:31:50209 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
mkwst28c7c112015-07-14 22:41:06210 }
211}
212
Nick Carter123ca192018-03-30 23:25:36213TEST_F(SchemeHostPortTest, Serialization) {
mkwst28c7c112015-07-14 22:41:06214 struct TestCases {
215 const char* url;
216 const char* expected;
217 } cases[] = {
218 {"http://192.168.9.1/", "http://192.168.9.1"},
219 {"http://[2001:db8::1]/", "http://[2001:db8::1]"},
220 {"http://☃.net/", "http://xn--n3h.net"},
221 {"http://example.com/", "http://example.com"},
222 {"http://example.com:123/", "http://example.com:123"},
223 {"https://example.com/", "https://example.com"},
224 {"https://example.com:123/", "https://example.com:123"},
225 {"file:///etc/passwd", "file://"},
226 {"file://example.com/etc/passwd", "file://example.com"},
David Van Cleve1fb932c2020-11-21 01:45:26227 {"https://example.com:0/", "https://example.com:0"},
mkwst28c7c112015-07-14 22:41:06228 };
229
230 for (const auto& test : cases) {
231 SCOPED_TRACE(test.url);
232 GURL url(test.url);
233 url::SchemeHostPort tuple(url);
234 EXPECT_EQ(test.expected, tuple.Serialize());
csharrison6fbc9fa2016-10-08 03:31:50235 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
mkwst28c7c112015-07-14 22:41:06236 }
237}
238
Nick Carter123ca192018-03-30 23:25:36239TEST_F(SchemeHostPortTest, Comparison) {
mkwst28c7c112015-07-14 22:41:06240 // These tuples are arranged in increasing order:
241 struct SchemeHostPorts {
242 const char* scheme;
243 const char* host;
avic0c60312015-12-21 21:03:50244 uint16_t port;
mkwst28c7c112015-07-14 22:41:06245 } tuples[] = {
246 {"http", "a", 80},
247 {"http", "b", 80},
248 {"https", "a", 80},
249 {"https", "b", 80},
250 {"http", "a", 81},
251 {"http", "b", 81},
252 {"https", "a", 81},
253 {"https", "b", 81},
254 };
255
Avi Drissmana92b3be2018-12-24 21:55:29256 for (size_t i = 0; i < base::size(tuples); i++) {
mkwst28c7c112015-07-14 22:41:06257 url::SchemeHostPort current(tuples[i].scheme, tuples[i].host,
258 tuples[i].port);
Avi Drissmana92b3be2018-12-24 21:55:29259 for (size_t j = i; j < base::size(tuples); j++) {
mkwst28c7c112015-07-14 22:41:06260 url::SchemeHostPort to_compare(tuples[j].scheme, tuples[j].host,
261 tuples[j].port);
262 EXPECT_EQ(i < j, current < to_compare) << i << " < " << j;
263 EXPECT_EQ(j < i, to_compare < current) << j << " < " << i;
264 }
265 }
266}
267
Charles Harrison60f0c532018-03-12 17:30:55268// Some schemes have optional authority. Make sure that GURL conversion from
269// SchemeHostPort is not opinionated in that regard. For more info, See
270// crbug.com/820194, where we considered all SchemeHostPorts with
Nick Carter123ca192018-03-30 23:25:36271// SCHEME_WITH_HOST (i.e., without ports) as valid with empty hosts, even though
272// most are not (e.g. chrome URLs).
273TEST_F(SchemeHostPortTest, EmptyHostGurlConversion) {
274 url::AddStandardScheme("chrome", url::SCHEME_WITH_HOST);
Charles Harrison60f0c532018-03-12 17:30:55275
276 GURL chrome_url("chrome:");
277 EXPECT_FALSE(chrome_url.is_valid());
278
279 url::SchemeHostPort chrome_tuple("chrome", "", 0);
280 EXPECT_FALSE(chrome_tuple.GetURL().is_valid());
281 ExpectParsedUrlsEqual(GURL(chrome_tuple.Serialize()), chrome_tuple.GetURL());
282 ExpectParsedUrlsEqual(chrome_url, chrome_tuple.GetURL());
283}
284
mkwst28c7c112015-07-14 22:41:06285} // namespace url