• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/base/schemeful_site.h"
11 
12 #include "base/test/metrics/histogram_tester.h"
13 #include "net/base/url_util.h"
14 #include "testing/gmock/include/gmock/gmock-matchers.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "url/gurl.h"
17 #include "url/origin.h"
18 #include "url/url_util.h"
19 
20 namespace net {
21 
TEST(SchemefulSiteTest,DifferentOriginSameRegisterableDomain)22 TEST(SchemefulSiteTest, DifferentOriginSameRegisterableDomain) {
23   // List of origins which should all share a schemeful site.
24   url::Origin kTestOrigins[] = {
25       url::Origin::Create(GURL("http://a.foo.test")),
26       url::Origin::Create(GURL("http://b.foo.test")),
27       url::Origin::Create(GURL("http://foo.test")),
28       url::Origin::Create(GURL("http://a.b.foo.test"))};
29 
30   for (const auto& origin_a : kTestOrigins) {
31     for (const auto& origin_b : kTestOrigins) {
32       EXPECT_EQ(SchemefulSite(origin_a), SchemefulSite(origin_b));
33     }
34   }
35 }
36 
TEST(SchemefulSiteTest,Operators)37 TEST(SchemefulSiteTest, Operators) {
38   // Create a list of origins that should all have different schemeful sites.
39   // These are in ascending order.
40   url::Origin kTestOrigins[] = {
41       url::Origin::Create(GURL("data:text/html,<body>Hello World</body>")),
42       url::Origin::Create(GURL("file://foo")),
43       url::Origin::Create(GURL("http://a.bar.test")),
44       url::Origin::Create(GURL("http://c.test")),
45       url::Origin::Create(GURL("http://d.test")),
46       url::Origin::Create(GURL("http://a.foo.test")),
47       url::Origin::Create(GURL("https://a.bar.test")),
48       url::Origin::Create(GURL("https://c.test")),
49       url::Origin::Create(GURL("https://d.test")),
50       url::Origin::Create(GURL("https://a.foo.test"))};
51 
52   // Compare each origin to every other origin and ensure the operators work as
53   // expected.
54   for (size_t first = 0; first < std::size(kTestOrigins); ++first) {
55     SchemefulSite site1 = SchemefulSite(kTestOrigins[first]);
56     SCOPED_TRACE(site1.GetDebugString());
57 
58     EXPECT_EQ(site1, site1);
59     EXPECT_FALSE(site1 < site1);
60 
61     // Check the operators work on copies.
62     SchemefulSite site1_copy = site1;
63     EXPECT_EQ(site1, site1_copy);
64     EXPECT_FALSE(site1 < site1_copy);
65 
66     for (size_t second = first + 1; second < std::size(kTestOrigins);
67          ++second) {
68       SchemefulSite site2 = SchemefulSite(kTestOrigins[second]);
69       SCOPED_TRACE(site2.GetDebugString());
70 
71       EXPECT_TRUE(site1 < site2);
72       EXPECT_FALSE(site2 < site1);
73       EXPECT_FALSE(site1 == site2);
74       EXPECT_FALSE(site2 == site1);
75     }
76   }
77 }
78 
TEST(SchemefulSiteTest,SchemeUsed)79 TEST(SchemefulSiteTest, SchemeUsed) {
80   url::Origin origin_a = url::Origin::Create(GURL("https://foo.test"));
81   url::Origin origin_b = url::Origin::Create(GURL("http://foo.test"));
82   EXPECT_NE(SchemefulSite(origin_a), SchemefulSite(origin_b));
83 }
84 
TEST(SchemefulSiteTest,PortIgnored)85 TEST(SchemefulSiteTest, PortIgnored) {
86   // Both origins are non-opaque.
87   url::Origin origin_a = url::Origin::Create(GURL("https://foo.test:80"));
88   url::Origin origin_b = url::Origin::Create(GURL("https://foo.test:2395"));
89 
90   EXPECT_EQ(SchemefulSite(origin_a), SchemefulSite(origin_b));
91 }
92 
TEST(SchemefulSiteTest,TopLevelDomainsNotModified)93 TEST(SchemefulSiteTest, TopLevelDomainsNotModified) {
94   url::Origin origin_tld = url::Origin::Create(GURL("https://com"));
95   EXPECT_EQ(url::Origin::Create(GURL("https://com")),
96             SchemefulSite(origin_tld).GetInternalOriginForTesting());
97 
98   // Unknown TLD's should not be modified.
99   url::Origin origin_tld_unknown =
100       url::Origin::Create(GURL("https://bar:1234"));
101   EXPECT_EQ(url::Origin::Create(GURL("https://bar")),
102             SchemefulSite(origin_tld_unknown).GetInternalOriginForTesting());
103 
104   // Check for two-part TLDs.
105   url::Origin origin_two_part_tld = url::Origin::Create(GURL("http://a.co.uk"));
106   EXPECT_EQ(url::Origin::Create(GURL("http://a.co.uk")),
107             SchemefulSite(origin_two_part_tld).GetInternalOriginForTesting());
108 }
109 
TEST(SchemefulSiteTest,NonStandardScheme)110 TEST(SchemefulSiteTest, NonStandardScheme) {
111   url::ScopedSchemeRegistryForTests scoped_registry;
112   url::AddStandardScheme("foo", url::SCHEME_WITH_HOST);
113   url::Origin origin = url::Origin::Create(GURL("foo://a.b.test"));
114   EXPECT_FALSE(origin.opaque());
115 
116   // We should not use registerable domains for non-standard schemes, even if
117   // one exists for the host.
118   EXPECT_EQ(url::Origin::Create(GURL("foo://a.b.test")),
119             SchemefulSite(origin).GetInternalOriginForTesting());
120 }
121 
TEST(SchemefulSiteTest,IPBasedOriginsRemovePort)122 TEST(SchemefulSiteTest, IPBasedOriginsRemovePort) {
123   // IPv4 and IPv6 origins should not be modified, except for removing their
124   // ports.
125   url::Origin origin_ipv4_a =
126       url::Origin::Create(GURL("http://127.0.0.1:1234"));
127   url::Origin origin_ipv4_b = url::Origin::Create(GURL("http://127.0.0.1"));
128   EXPECT_EQ(url::Origin::Create(GURL("http://127.0.0.1")),
129             SchemefulSite(origin_ipv4_a).GetInternalOriginForTesting());
130   EXPECT_EQ(SchemefulSite(origin_ipv4_a), SchemefulSite(origin_ipv4_b));
131 
132   url::Origin origin_ipv6 = url::Origin::Create(GURL("https://[::1]"));
133   EXPECT_EQ(url::Origin::Create(GURL("https://[::1]")),
134             SchemefulSite(origin_ipv6).GetInternalOriginForTesting());
135 }
136 
TEST(SchemefulSiteTest,LocalhostOriginsRemovePort)137 TEST(SchemefulSiteTest, LocalhostOriginsRemovePort) {
138   // Localhost origins should not be modified, except for removing their ports.
139   url::Origin localhost_http =
140       url::Origin::Create(GURL("http://localhost:1234"));
141   EXPECT_EQ(url::Origin::Create(GURL("http://localhost")),
142             SchemefulSite(localhost_http).GetInternalOriginForTesting());
143 
144   url::Origin localhost_https =
145       url::Origin::Create(GURL("https://localhost:1234"));
146   EXPECT_EQ(url::Origin::Create(GURL("https://localhost")),
147             SchemefulSite(localhost_https).GetInternalOriginForTesting());
148 }
149 
TEST(SchemefulSiteTest,OpaqueOrigins)150 TEST(SchemefulSiteTest, OpaqueOrigins) {
151   url::Origin opaque_origin_a =
152       url::Origin::Create(GURL("data:text/html,<body>Hello World</body>"));
153 
154   // The schemeful site of an opaque origin should always equal other schemeful
155   // site instances of the same origin.
156   EXPECT_EQ(SchemefulSite(opaque_origin_a), SchemefulSite(opaque_origin_a));
157 
158   url::Origin opaque_origin_b =
159       url::Origin::Create(GURL("data:text/html,<body>Hello World</body>"));
160 
161   // Two different opaque origins should never have the same SchemefulSite.
162   EXPECT_NE(SchemefulSite(opaque_origin_a), SchemefulSite(opaque_origin_b));
163 }
164 
TEST(SchemefulSiteTest,FileOriginWithoutHostname)165 TEST(SchemefulSiteTest, FileOriginWithoutHostname) {
166   SchemefulSite site1(url::Origin::Create(GURL("file:///")));
167   SchemefulSite site2(url::Origin::Create(GURL("file:///path/")));
168 
169   EXPECT_EQ(site1, site2);
170   EXPECT_TRUE(site1.GetInternalOriginForTesting().host().empty());
171 }
172 
TEST(SchemefulSiteTest,SchemeWithNetworkHost)173 TEST(SchemefulSiteTest, SchemeWithNetworkHost) {
174   url::ScopedSchemeRegistryForTests scheme_registry;
175   AddStandardScheme("network", url::SCHEME_WITH_HOST_PORT_AND_USER_INFORMATION);
176   AddStandardScheme("non-network", url::SCHEME_WITH_HOST);
177 
178   ASSERT_TRUE(IsStandardSchemeWithNetworkHost("network"));
179   ASSERT_FALSE(IsStandardSchemeWithNetworkHost("non-network"));
180 
181   std::optional<SchemefulSite> network_host_site =
182       SchemefulSite::CreateIfHasRegisterableDomain(
183           url::Origin::Create(GURL("network://site.example.test:1337")));
184   EXPECT_TRUE(network_host_site.has_value());
185   EXPECT_EQ("network",
186             network_host_site->GetInternalOriginForTesting().scheme());
187   EXPECT_EQ("example.test",
188             network_host_site->GetInternalOriginForTesting().host());
189 
190   std::optional<SchemefulSite> non_network_host_site_null =
191       SchemefulSite::CreateIfHasRegisterableDomain(
192           url::Origin::Create(GURL("non-network://site.example.test")));
193   EXPECT_FALSE(non_network_host_site_null.has_value());
194   SchemefulSite non_network_host_site(GURL("non-network://site.example.test"));
195   EXPECT_EQ("non-network",
196             non_network_host_site.GetInternalOriginForTesting().scheme());
197   // The host is used as-is, without attempting to get a registrable domain.
198   EXPECT_EQ("site.example.test",
199             non_network_host_site.GetInternalOriginForTesting().host());
200 }
201 
TEST(SchemefulSiteTest,FileSchemeHasRegistrableDomain)202 TEST(SchemefulSiteTest, FileSchemeHasRegistrableDomain) {
203   // Test file origin without host.
204   url::Origin origin_file =
205       url::Origin::Create(GURL("file:///dir1/dir2/file.txt"));
206   EXPECT_TRUE(origin_file.host().empty());
207   SchemefulSite site_file(origin_file);
208   EXPECT_EQ(url::Origin::Create(GURL("file:///")),
209             site_file.GetInternalOriginForTesting());
210 
211   // Test file origin with host (with registrable domain).
212   url::Origin origin_file_with_host =
213       url::Origin::Create(GURL("file://host.example.test/file"));
214   ASSERT_EQ("host.example.test", origin_file_with_host.host());
215   SchemefulSite site_file_with_host(origin_file_with_host);
216   EXPECT_EQ(url::Origin::Create(GURL("file://example.test")),
217             site_file_with_host.GetInternalOriginForTesting());
218 
219   // Test file origin with host same as registrable domain.
220   url::Origin origin_file_registrable_domain =
221       url::Origin::Create(GURL("file://example.test/file"));
222   ASSERT_EQ("example.test", origin_file_registrable_domain.host());
223   SchemefulSite site_file_registrable_domain(origin_file_registrable_domain);
224   EXPECT_EQ(url::Origin::Create(GURL("file://example.test")),
225             site_file_registrable_domain.GetInternalOriginForTesting());
226 
227   EXPECT_NE(site_file, site_file_with_host);
228   EXPECT_NE(site_file, site_file_registrable_domain);
229   EXPECT_EQ(site_file_with_host, site_file_registrable_domain);
230 }
231 
TEST(SchemefulSiteTest,SerializationConsistent)232 TEST(SchemefulSiteTest, SerializationConsistent) {
233   url::ScopedSchemeRegistryForTests scoped_registry;
234   url::AddStandardScheme("chrome", url::SCHEME_WITH_HOST);
235 
236   // List of origins which should all share a schemeful site.
237   SchemefulSite kTestSites[] = {
238       SchemefulSite(url::Origin::Create(GURL("http://a.foo.test"))),
239       SchemefulSite(url::Origin::Create(GURL("https://b.foo.test"))),
240       SchemefulSite(url::Origin::Create(GURL("http://b.foo.test"))),
241       SchemefulSite(url::Origin::Create(GURL("http://a.b.foo.test"))),
242       SchemefulSite(url::Origin::Create(GURL("chrome://a.b.test")))};
243 
244   for (const auto& site : kTestSites) {
245     SCOPED_TRACE(site.GetDebugString());
246     EXPECT_FALSE(site.GetInternalOriginForTesting().opaque());
247 
248     std::optional<SchemefulSite> deserialized_site =
249         SchemefulSite::Deserialize(site.Serialize());
250     EXPECT_TRUE(deserialized_site);
251     EXPECT_EQ(site, deserialized_site);
252   }
253 }
254 
TEST(SchemefulSiteTest,SerializationFileSiteWithHost)255 TEST(SchemefulSiteTest, SerializationFileSiteWithHost) {
256   const struct {
257     SchemefulSite site;
258     std::string expected;
259   } kTestCases[] = {
260       {SchemefulSite(GURL("file:///etc/passwd")), "file://"},
261       {SchemefulSite(GURL("file://example.com/etc/passwd")),
262        "file://example.com"},
263       {SchemefulSite(GURL("file://example.com")), "file://example.com"},
264   };
265 
266   for (const auto& test_case : kTestCases) {
267     SCOPED_TRACE(test_case.site.GetDebugString());
268     std::string serialized_site = test_case.site.SerializeFileSiteWithHost();
269     EXPECT_EQ(test_case.expected, serialized_site);
270     std::optional<SchemefulSite> deserialized_site =
271         SchemefulSite::Deserialize(serialized_site);
272     EXPECT_TRUE(deserialized_site);
273     EXPECT_EQ(test_case.site, deserialized_site);
274   }
275 }
276 
TEST(SchemefulSiteTest,FileURLWithHostEquality)277 TEST(SchemefulSiteTest, FileURLWithHostEquality) {
278   // Two file URLs with different hosts should result in unequal SchemefulSites.
279   SchemefulSite site1(GURL("file://foo/some/path.txt"));
280   SchemefulSite site2(GURL("file://bar/some/path.txt"));
281   EXPECT_NE(site1, site2);
282 
283   // Two file URLs with the same host should result in equal SchemefulSites.
284   SchemefulSite site3(GURL("file://foo/another/path.pdf"));
285   EXPECT_EQ(site1, site3);
286 }
287 
TEST(SchemefulSiteTest,OpaqueSerialization)288 TEST(SchemefulSiteTest, OpaqueSerialization) {
289   // List of origins which should all share a schemeful site.
290   SchemefulSite kTestSites[] = {
291       SchemefulSite(), SchemefulSite(url::Origin()),
292       SchemefulSite(GURL("data:text/html,<body>Hello World</body>"))};
293 
294   for (auto& site : kTestSites) {
295     std::optional<SchemefulSite> deserialized_site =
296         SchemefulSite::DeserializeWithNonce(*site.SerializeWithNonce());
297     EXPECT_TRUE(deserialized_site);
298     EXPECT_EQ(site, *deserialized_site);
299   }
300 }
301 
TEST(SchemefulSiteTest,FromWire)302 TEST(SchemefulSiteTest, FromWire) {
303   SchemefulSite out;
304 
305   // Opaque origin.
306   EXPECT_TRUE(SchemefulSite::FromWire(url::Origin(), &out));
307   EXPECT_TRUE(out.opaque());
308 
309   // Valid origin.
310   EXPECT_TRUE(SchemefulSite::FromWire(
311       url::Origin::Create(GURL("https://example.test")), &out));
312   EXPECT_EQ(SchemefulSite(url::Origin::Create(GURL("https://example.test"))),
313             out);
314 
315   // Invalid origin (not a registrable domain).
316   EXPECT_FALSE(SchemefulSite::FromWire(
317       url::Origin::Create(GURL("https://sub.example.test")), &out));
318 
319   // Invalid origin (non-default port).
320   EXPECT_FALSE(SchemefulSite::FromWire(
321       url::Origin::Create(GURL("https://example.test:1337")), &out));
322 }
323 
TEST(SchemefulSiteTest,CreateIfHasRegisterableDomain)324 TEST(SchemefulSiteTest, CreateIfHasRegisterableDomain) {
325   for (const auto& site : std::initializer_list<std::string>{
326            "http://a.bar.test",
327            "http://c.test",
328            "http://a.foo.test",
329            "https://a.bar.test",
330            "https://c.test",
331            "https://a.foo.test",
332        }) {
333     url::Origin origin = url::Origin::Create(GURL(site));
334     EXPECT_THAT(SchemefulSite::CreateIfHasRegisterableDomain(origin),
335                 testing::Optional(SchemefulSite(origin)))
336         << "site = \"" << site << "\"";
337   }
338 
339   for (const auto& site : std::initializer_list<std::string>{
340            "data:text/html,<body>Hello World</body>",
341            "file:///",
342            "file://foo",
343            "http://127.0.0.1:1234",
344            "https://127.0.0.1:1234",
345        }) {
346     url::Origin origin = url::Origin::Create(GURL(site));
347     EXPECT_EQ(SchemefulSite::CreateIfHasRegisterableDomain(origin),
348               std::nullopt)
349         << "site = \"" << site << "\"";
350   }
351 }
352 
TEST(SchemefulSiteTest,ConvertWebSocketToHttp)353 TEST(SchemefulSiteTest, ConvertWebSocketToHttp) {
354   SchemefulSite ws_site(url::Origin::Create(GURL("ws://site.example.test")));
355   SchemefulSite http_site(
356       url::Origin::Create(GURL("http://site.example.test")));
357   SchemefulSite wss_site(url::Origin::Create(GURL("wss://site.example.test")));
358   SchemefulSite https_site(
359       url::Origin::Create(GURL("https://site.example.test")));
360 
361   ASSERT_NE(ws_site, wss_site);
362   ASSERT_NE(ws_site, http_site);
363   ASSERT_NE(ws_site, https_site);
364   ASSERT_NE(wss_site, http_site);
365   ASSERT_NE(wss_site, https_site);
366 
367   ws_site.ConvertWebSocketToHttp();
368   wss_site.ConvertWebSocketToHttp();
369 
370   EXPECT_EQ(ws_site, http_site);
371   EXPECT_EQ(wss_site, https_site);
372 
373   // Does not change non-WebSocket sites.
374   SchemefulSite http_site_copy(http_site);
375   http_site_copy.ConvertWebSocketToHttp();
376   EXPECT_EQ(http_site, http_site_copy);
377   EXPECT_EQ(url::kHttpScheme,
378             http_site_copy.GetInternalOriginForTesting().scheme());
379 
380   SchemefulSite file_site(url::Origin::Create(GURL("file:///")));
381   file_site.ConvertWebSocketToHttp();
382   EXPECT_EQ(url::kFileScheme, file_site.GetInternalOriginForTesting().scheme());
383 }
384 
TEST(SchemefulSiteTest,GetGURL)385 TEST(SchemefulSiteTest, GetGURL) {
386   struct {
387     url::Origin origin;
388     GURL wantGURL;
389   } kTestCases[] = {
390       {
391           url::Origin::Create(GURL("data:text/html,<body>Hello World</body>")),
392           GURL(),
393       },
394       {url::Origin::Create(GURL("file://foo")), GURL("file:///")},
395       {url::Origin::Create(GURL("http://a.bar.test")), GURL("http://bar.test")},
396       {url::Origin::Create(GURL("http://c.test")), GURL("http://c.test")},
397       {url::Origin::Create(GURL("http://c.test:8000")), GURL("http://c.test")},
398       {
399           url::Origin::Create(GURL("https://a.bar.test")),
400           GURL("https://bar.test"),
401       },
402       {
403           url::Origin::Create(GURL("https://c.test")),
404           GURL("https://c.test"),
405       },
406       {
407           url::Origin::Create(GURL("https://c.test:1337")),
408           GURL("https://c.test"),
409       },
410   };
411 
412   for (const auto& testcase : kTestCases) {
413     SchemefulSite site(testcase.origin);
414     EXPECT_EQ(site.GetURL(), testcase.wantGURL);
415   }
416 }
417 
TEST(SchemefulSiteTest,InternalValue)418 TEST(SchemefulSiteTest, InternalValue) {
419   url::Origin origin = url::Origin::Create(GURL("https://example.com"));
420   SchemefulSite site(origin);
421   EXPECT_EQ(site.internal_value(), origin);
422   url::Origin opaque_origin;
423   SchemefulSite opaque_site(opaque_origin);
424   EXPECT_EQ(opaque_site.internal_value(), opaque_origin);
425 }
426 
427 }  // namespace net
428