• 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 #include "net/base/schemeful_site.h"
6 
7 #include <string_view>
8 
9 #include "base/check.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/trace_event/memory_usage_estimator.h"
12 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
13 #include "net/base/url_util.h"
14 #include "url/gurl.h"
15 #include "url/url_canon.h"
16 #include "url/url_constants.h"
17 
18 namespace net {
19 
20 struct SchemefulSite::ObtainASiteResult {
21   // This is only set if the supplied origin differs from calculated one.
22   std::optional<url::Origin> origin;
23   bool used_registerable_domain;
24 };
25 
26 // Return a tuple containing:
27 // * a new origin using the registerable domain of `origin` if possible and
28 //   a port of 0; otherwise, the passed-in origin.
29 // * a bool indicating whether `origin` had a non-null registerable domain.
30 //   (False if `origin` was opaque.)
31 //
32 // Follows steps specified in
33 // https://html.spec.whatwg.org/multipage/origin.html#obtain-a-site
ObtainASite(const url::Origin & origin)34 SchemefulSite::ObtainASiteResult SchemefulSite::ObtainASite(
35     const url::Origin& origin) {
36   // 1. If origin is an opaque origin, then return origin.
37   if (origin.opaque()) {
38     return {std::nullopt, false /* used_registerable_domain */};
39   }
40 
41   int port = url::DefaultPortForScheme(origin.scheme());
42 
43   // Provide a default port of 0 for non-standard schemes.
44   if (port == url::PORT_UNSPECIFIED) {
45     port = 0;
46   }
47 
48   std::string_view registerable_domain;
49 
50   // Non-normative step.
51   // We only lookup the registerable domain for schemes with network hosts, this
52   // is non-normative. Other schemes for non-opaque origins do not
53   // meaningfully have a registerable domain for their host, so they are
54   // skipped.
55   if (IsStandardSchemeWithNetworkHost(origin.scheme())) {
56     registerable_domain = GetDomainAndRegistryAsStringPiece(
57         origin, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
58     if (!registerable_domain.empty() &&
59         registerable_domain.size() == origin.host().size() &&
60         origin.port() == port) {
61       return {std::nullopt, /* used_registerable_domain */ true};
62     }
63   }
64 
65   // If origin's host's registrable domain is null, then return (origin's
66   // scheme, origin's host).
67   //
68   // `GetDomainAndRegistry()` returns an empty string for IP literals and
69   // effective TLDs.
70   //
71   // Note that `registerable_domain` could still end up empty, since the
72   // `origin` might have a scheme that permits empty hostnames, such as "file".
73   bool used_registerable_domain = !registerable_domain.empty();
74   if (!used_registerable_domain)
75     registerable_domain = origin.host();
76 
77   return {url::Origin::CreateFromNormalizedTuple(
78               origin.scheme(), std::string(registerable_domain), port),
79           used_registerable_domain};
80 }
81 
SchemefulSite(ObtainASiteResult result,const url::Origin & origin)82 SchemefulSite::SchemefulSite(ObtainASiteResult result,
83                              const url::Origin& origin) {
84   if (result.origin) {
85     site_as_origin_ = std::move(*(result.origin));
86   } else {
87     site_as_origin_ = origin;
88   }
89 }
90 
SchemefulSite(const url::Origin & origin)91 SchemefulSite::SchemefulSite(const url::Origin& origin)
92     : SchemefulSite(ObtainASite(origin), origin) {}
93 
SchemefulSite(const GURL & url)94 SchemefulSite::SchemefulSite(const GURL& url)
95     : SchemefulSite(url::Origin::Create(url)) {}
96 
97 SchemefulSite::SchemefulSite(const SchemefulSite& other) = default;
98 SchemefulSite::SchemefulSite(SchemefulSite&& other) noexcept = default;
99 
100 SchemefulSite& SchemefulSite::operator=(const SchemefulSite& other) = default;
101 SchemefulSite& SchemefulSite::operator=(SchemefulSite&& other) noexcept =
102     default;
103 
104 // static
FromWire(const url::Origin & site_as_origin,SchemefulSite * out)105 bool SchemefulSite::FromWire(const url::Origin& site_as_origin,
106                              SchemefulSite* out) {
107   // The origin passed into this constructor may not match the
108   // `site_as_origin_` used as the internal representation of the schemeful
109   // site. However, a valid SchemefulSite's internal origin should result in a
110   // match if used to construct another SchemefulSite. Thus, if there is a
111   // mismatch here, we must indicate a failure.
112   SchemefulSite candidate(site_as_origin);
113   if (candidate.site_as_origin_ != site_as_origin)
114     return false;
115 
116   *out = std::move(candidate);
117   return true;
118 }
119 
CreateIfHasRegisterableDomain(const url::Origin & origin)120 std::optional<SchemefulSite> SchemefulSite::CreateIfHasRegisterableDomain(
121     const url::Origin& origin) {
122   ObtainASiteResult result = ObtainASite(origin);
123   if (!result.used_registerable_domain) {
124     return std::nullopt;
125   }
126   return SchemefulSite(std::move(result), origin);
127 }
128 
ConvertWebSocketToHttp()129 void SchemefulSite::ConvertWebSocketToHttp() {
130   if (site_as_origin_.scheme() == url::kWsScheme ||
131       site_as_origin_.scheme() == url::kWssScheme) {
132     site_as_origin_ = url::Origin::Create(
133         ChangeWebSocketSchemeToHttpScheme(site_as_origin_.GetURL()));
134   }
135 }
136 
137 // static
Deserialize(std::string_view value)138 SchemefulSite SchemefulSite::Deserialize(std::string_view value) {
139   return SchemefulSite(GURL(value));
140 }
141 
Serialize() const142 std::string SchemefulSite::Serialize() const {
143   return site_as_origin_.Serialize();
144 }
145 
SerializeFileSiteWithHost() const146 std::string SchemefulSite::SerializeFileSiteWithHost() const {
147   DCHECK_EQ(url::kFileScheme, site_as_origin_.scheme());
148   return site_as_origin_.GetTupleOrPrecursorTupleIfOpaque().Serialize();
149 }
150 
GetDebugString() const151 std::string SchemefulSite::GetDebugString() const {
152   return site_as_origin_.GetDebugString();
153 }
154 
GetURL() const155 GURL SchemefulSite::GetURL() const {
156   return site_as_origin_.GetURL();
157 }
158 
GetInternalOriginForTesting() const159 const url::Origin& SchemefulSite::GetInternalOriginForTesting() const {
160   return site_as_origin_;
161 }
162 
EstimateMemoryUsage() const163 size_t SchemefulSite::EstimateMemoryUsage() const {
164   return base::trace_event::EstimateMemoryUsage(site_as_origin_);
165 }
166 
operator ==(const SchemefulSite & other) const167 bool SchemefulSite::operator==(const SchemefulSite& other) const {
168   return site_as_origin_ == other.site_as_origin_;
169 }
170 
operator !=(const SchemefulSite & other) const171 bool SchemefulSite::operator!=(const SchemefulSite& other) const {
172   return !(*this == other);
173 }
174 
175 // Allows SchemefulSite to be used as a key in STL containers (for example, a
176 // std::set or std::map).
operator <(const SchemefulSite & other) const177 bool SchemefulSite::operator<(const SchemefulSite& other) const {
178   return site_as_origin_ < other.site_as_origin_;
179 }
180 
181 // static
DeserializeWithNonce(base::PassKey<NetworkAnonymizationKey>,std::string_view value)182 std::optional<SchemefulSite> SchemefulSite::DeserializeWithNonce(
183     base::PassKey<NetworkAnonymizationKey>,
184     std::string_view value) {
185   return DeserializeWithNonce(value);
186 }
187 
188 // static
DeserializeWithNonce(std::string_view value)189 std::optional<SchemefulSite> SchemefulSite::DeserializeWithNonce(
190     std::string_view value) {
191   std::optional<url::Origin> result = url::Origin::Deserialize(value);
192   if (!result)
193     return std::nullopt;
194   return SchemefulSite(result.value());
195 }
196 
SerializeWithNonce(base::PassKey<NetworkAnonymizationKey>)197 std::optional<std::string> SchemefulSite::SerializeWithNonce(
198     base::PassKey<NetworkAnonymizationKey>) {
199   return SerializeWithNonce();
200 }
201 
SerializeWithNonce()202 std::optional<std::string> SchemefulSite::SerializeWithNonce() {
203   return site_as_origin_.SerializeWithNonceAndInitIfNeeded();
204 }
205 
SchemelesslyEqual(const SchemefulSite & other) const206 bool SchemefulSite::SchemelesslyEqual(const SchemefulSite& other) const {
207   return site_as_origin_.host() == other.site_as_origin_.host();
208 }
209 
operator <<(std::ostream & os,const SchemefulSite & ss)210 std::ostream& operator<<(std::ostream& os, const SchemefulSite& ss) {
211   os << ss.Serialize();
212   return os;
213 }
214 
215 }  // namespace net
216