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