1 // 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.
8 #include "base/macros.h"
9 #include "testing/gtest/include/gtest/gtest.h"
11 #include "url/scheme_host_port.h"
12 #include "url/url_util.h"
16 class SchemeHostPortTest : public testing::Test {
18 SchemeHostPortTest() = default;
19 ~SchemeHostPortTest() override {
20 // Reset any added schemes.
25 DISALLOW_COPY_AND_ASSIGN(SchemeHostPortTest);
28 void ExpectParsedUrlsEqual(const GURL& a, const GURL& b) {
30 const url::Parsed& a_parsed = a.parsed_for_possibly_invalid_spec();
31 const url::Parsed& b_parsed = b.parsed_for_possibly_invalid_spec();
32 EXPECT_EQ(a_parsed.scheme.begin, b_parsed.scheme.begin);
33 EXPECT_EQ(a_parsed.scheme.len, b_parsed.scheme.len);
34 EXPECT_EQ(a_parsed.username.begin, b_parsed.username.begin);
35 EXPECT_EQ(a_parsed.username.len, b_parsed.username.len);
36 EXPECT_EQ(a_parsed.password.begin, b_parsed.password.begin);
37 EXPECT_EQ(a_parsed.password.len, b_parsed.password.len);
38 EXPECT_EQ(a_parsed.host.begin, b_parsed.host.begin);
39 EXPECT_EQ(a_parsed.host.len, b_parsed.host.len);
40 EXPECT_EQ(a_parsed.port.begin, b_parsed.port.begin);
41 EXPECT_EQ(a_parsed.port.len, b_parsed.port.len);
42 EXPECT_EQ(a_parsed.path.begin, b_parsed.path.begin);
43 EXPECT_EQ(a_parsed.path.len, b_parsed.path.len);
44 EXPECT_EQ(a_parsed.query.begin, b_parsed.query.begin);
45 EXPECT_EQ(a_parsed.query.len, b_parsed.query.len);
46 EXPECT_EQ(a_parsed.ref.begin, b_parsed.ref.begin);
47 EXPECT_EQ(a_parsed.ref.len, b_parsed.ref.len);
50 TEST_F(SchemeHostPortTest, Invalid) {
51 url::SchemeHostPort invalid;
52 EXPECT_EQ("", invalid.scheme());
53 EXPECT_EQ("", invalid.host());
54 EXPECT_EQ(0, invalid.port());
55 EXPECT_TRUE(invalid.IsInvalid());
56 EXPECT_TRUE(invalid.Equals(invalid));
58 const char* urls[] = {
59 "data:text/html,Hello!", "javascript:alert(1)",
60 "file://example.com:443/etc/passwd",
62 // These schemes do not follow the generic URL syntax, so make sure we
63 // treat them as invalid (scheme, host, port) tuples (even though such
64 // URLs' _Origin_ might have a (scheme, host, port) tuple, they themselves
65 // do not). This is only *implicitly* checked in the code, by means of
66 // blob schemes not being standard, and filesystem schemes having type
67 // SCHEME_WITHOUT_AUTHORITY. If conditions change such that the implicit
68 // checks no longer hold, this policy should be made explicit.
69 "blob:https://example.com/uuid-goes-here",
70 "filesystem:https://example.com/temporary/yay.png"};
72 for (auto* test : urls) {
75 url::SchemeHostPort tuple(url);
76 EXPECT_EQ("", tuple.scheme());
77 EXPECT_EQ("", tuple.host());
78 EXPECT_EQ(0, tuple.port());
79 EXPECT_TRUE(tuple.IsInvalid());
80 EXPECT_TRUE(tuple.Equals(tuple));
81 EXPECT_TRUE(tuple.Equals(invalid));
82 EXPECT_TRUE(invalid.Equals(tuple));
83 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
87 TEST_F(SchemeHostPortTest, ExplicitConstruction) {
93 {"http", "example.com", 80},
94 {"http", "example.com", 123},
95 {"https", "example.com", 443},
96 {"https", "example.com", 123},
98 {"file", "example.com", 0},
101 for (const auto& test : cases) {
102 SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
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());
108 EXPECT_FALSE(tuple.IsInvalid());
109 EXPECT_TRUE(tuple.Equals(tuple));
110 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
114 TEST_F(SchemeHostPortTest, InvalidConstruction) {
119 } cases[] = {{"", "", 0},
122 {"filesystem", "", 0},
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},
134 {"http", "example.com", 0},
137 for (const auto& test : cases) {
138 SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
140 url::SchemeHostPort tuple(test.scheme, test.host, test.port);
141 EXPECT_EQ("", tuple.scheme());
142 EXPECT_EQ("", tuple.host());
143 EXPECT_EQ(0, tuple.port());
144 EXPECT_TRUE(tuple.IsInvalid());
145 EXPECT_TRUE(tuple.Equals(tuple));
146 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
150 TEST_F(SchemeHostPortTest, InvalidConstructionWithEmbeddedNulls) {
153 size_t scheme_length;
157 } cases[] = {{"http\0more", 9, "example.com", 11, 80},
158 {"http\0", 5, "example.com", 11, 80},
159 {"\0http", 5, "example.com", 11, 80},
160 {"http", 4, "example.com\0not-example.com", 27, 80},
161 {"http", 4, "example.com\0", 12, 80},
162 {"http", 4, "\0example.com", 12, 80}};
164 for (const auto& test : cases) {
165 SCOPED_TRACE(testing::Message() << test.scheme << "://" << test.host << ":"
167 url::SchemeHostPort tuple(std::string(test.scheme, test.scheme_length),
168 std::string(test.host, test.host_length),
170 EXPECT_EQ("", tuple.scheme());
171 EXPECT_EQ("", tuple.host());
172 EXPECT_EQ(0, tuple.port());
173 EXPECT_TRUE(tuple.IsInvalid());
174 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
178 TEST_F(SchemeHostPortTest, GURLConstruction) {
185 {"http://192.168.9.1/", "http", "192.168.9.1", 80},
186 {"http://[2001:db8::1]/", "http", "[2001:db8::1]", 80},
187 {"http://☃.net/", "http", "xn--n3h.net", 80},
188 {"http://example.com/", "http", "example.com", 80},
189 {"http://example.com:123/", "http", "example.com", 123},
190 {"https://example.com/", "https", "example.com", 443},
191 {"https://example.com:123/", "https", "example.com", 123},
192 {"file:///etc/passwd", "file", "", 0},
193 {"file://example.com/etc/passwd", "file", "example.com", 0},
194 {"http://u:p@example.com/", "http", "example.com", 80},
195 {"http://u:p@example.com/path", "http", "example.com", 80},
196 {"http://u:p@example.com/path?123", "http", "example.com", 80},
197 {"http://u:p@example.com/path?123#hash", "http", "example.com", 80},
200 for (const auto& test : cases) {
201 SCOPED_TRACE(test.url);
203 EXPECT_TRUE(url.is_valid());
204 url::SchemeHostPort tuple(url);
205 EXPECT_EQ(test.scheme, tuple.scheme());
206 EXPECT_EQ(test.host, tuple.host());
207 EXPECT_EQ(test.port, tuple.port());
208 EXPECT_FALSE(tuple.IsInvalid());
209 EXPECT_TRUE(tuple.Equals(tuple));
210 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
214 TEST_F(SchemeHostPortTest, Serialization) {
217 const char* expected;
219 {"http://192.168.9.1/", "http://192.168.9.1"},
220 {"http://[2001:db8::1]/", "http://[2001:db8::1]"},
221 {"http://☃.net/", "http://xn--n3h.net"},
222 {"http://example.com/", "http://example.com"},
223 {"http://example.com:123/", "http://example.com:123"},
224 {"https://example.com/", "https://example.com"},
225 {"https://example.com:123/", "https://example.com:123"},
226 {"file:///etc/passwd", "file://"},
227 {"file://example.com/etc/passwd", "file://example.com"},
230 for (const auto& test : cases) {
231 SCOPED_TRACE(test.url);
233 url::SchemeHostPort tuple(url);
234 EXPECT_EQ(test.expected, tuple.Serialize());
235 ExpectParsedUrlsEqual(GURL(tuple.Serialize()), tuple.GetURL());
239 TEST_F(SchemeHostPortTest, Comparison) {
240 // These tuples are arranged in increasing order:
241 struct SchemeHostPorts {
256 for (size_t i = 0; i < arraysize(tuples); i++) {
257 url::SchemeHostPort current(tuples[i].scheme, tuples[i].host,
259 for (size_t j = i; j < arraysize(tuples); j++) {
260 url::SchemeHostPort to_compare(tuples[j].scheme, tuples[j].host,
262 EXPECT_EQ(i < j, current < to_compare) << i << " < " << j;
263 EXPECT_EQ(j < i, to_compare < current) << j << " < " << i;
268 // 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
271 // SCHEME_WITH_HOST (i.e., without ports) as valid with empty hosts, even though
272 // most are not (e.g. chrome URLs).
273 TEST_F(SchemeHostPortTest, EmptyHostGurlConversion) {
274 url::AddStandardScheme("chrome", url::SCHEME_WITH_HOST);
276 GURL chrome_url("chrome:");
277 EXPECT_FALSE(chrome_url.is_valid());
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());