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