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