• 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 #ifndef NET_BASE_SCHEMEFUL_SITE_H_
6 #define NET_BASE_SCHEMEFUL_SITE_H_
7 
8 #include <ostream>
9 #include <string>
10 
11 #include "base/gtest_prod_util.h"
12 #include "net/base/net_export.h"
13 #include "third_party/abseil-cpp/absl/types/optional.h"
14 #include "url/origin.h"
15 
16 class GURL;
17 
18 namespace blink {
19 class BlinkSchemefulSite;
20 class StorageKey;
21 }  // namespace blink
22 
23 namespace IPC {
24 template <class P>
25 struct ParamTraits;
26 }  // namespace IPC
27 
28 namespace network::mojom {
29 class SchemefulSiteDataView;
30 }  // namespace network::mojom
31 
32 namespace mojo {
33 template <typename DataViewType, typename T>
34 struct StructTraits;
35 }  // namespace mojo
36 
37 namespace net {
38 
39 class SiteForCookies;
40 
41 // Class which represents a scheme and etld+1 for an origin, as specified by
42 // https://html.spec.whatwg.org/multipage/origin.html#obtain-a-site.
43 //
44 // A SchemefulSite is obtained from an input origin by normalizing, such that:
45 // 1. Opaque origins have distinct SchemefulSites.
46 // 2. Origins whose schemes have network hosts have the same SchemefulSite iff
47 //    they share a scheme, and share a hostname or registrable domain. Origins
48 //    whose schemes have network hosts include http, https, ws, wss, file, etc.
49 // 3. Origins whose schemes do not have a network host have the same
50 //    SchemefulSite iff they share a scheme and host.
51 // 4. Origins which differ only by port have the same SchemefulSite.
52 // 5. Websocket origins cannot have a SchemefulSite (they trigger a DCHECK).
53 //
54 // Note that blink::BlinkSchemefulSite mirrors this class and needs to be kept
55 // in sync with any data member changes.
56 class NET_EXPORT SchemefulSite {
57  public:
58   SchemefulSite() = default;
59 
60   // The passed `origin` may not match the resulting internal representation in
61   // certain circumstances. See the comment, below, on the `site_as_origin_`
62   // member.
63   explicit SchemefulSite(const url::Origin& origin);
64 
65   // Using the origin constructor is preferred as this is less efficient.
66   // Should only be used if the origin for a given GURL is not readily
67   // available.
68   explicit SchemefulSite(const GURL& url);
69 
70   SchemefulSite(const SchemefulSite& other);
71   SchemefulSite(SchemefulSite&& other) noexcept;
72 
73   SchemefulSite& operator=(const SchemefulSite& other);
74   SchemefulSite& operator=(SchemefulSite&& other) noexcept;
75 
76   // Tries to construct an instance from a (potentially untrusted) value of the
77   // internal `site_as_origin_` that got received over an RPC.
78   //
79   // Returns whether successful or not. Doesn't touch |*out| if false is
80   // returned.  This returning |true| does not mean that whoever sent the values
81   // did not lie, merely that they are well-formed.
82   static bool FromWire(const url::Origin& site_as_origin, SchemefulSite* out);
83 
84   // Creates a SchemefulSite iff the passed-in origin has a registerable domain.
85   static absl::optional<SchemefulSite> CreateIfHasRegisterableDomain(
86       const url::Origin&);
87 
88   // If the scheme is ws or wss, it is converted to http or https, respectively.
89   // Has no effect on SchemefulSites with any other schemes.
90   //
91   // See Step 1 of algorithm "establish a WebSocket connection" in
92   // https://fetch.spec.whatwg.org/#websocket-opening-handshake.
93   void ConvertWebSocketToHttp();
94 
95   // Deserializes a string obtained from `Serialize()` to a `SchemefulSite`.
96   // Returns an opaque `SchemefulSite` if the value was invalid in any way.
97   static SchemefulSite Deserialize(const std::string& value);
98 
99   // Returns a serialized version of `site_as_origin_`. If the underlying origin
100   // is invalid, returns an empty string. If serialization of opaque origins
101   // with their associated nonce is necessary, see `SerializeWithNonce()`.
102   std::string Serialize() const;
103 
104   // Serializes `site_as_origin_` in cases when it has a 'file' scheme but
105   // we want to preserve the Origin's host.
106   // This was added to serialize cookie partition keys, which may contain
107   // file origins with a host.
108   std::string SerializeFileSiteWithHost() const;
109 
110   std::string GetDebugString() const;
111 
112   // Gets the underlying site as a GURL. If the internal Origin is opaque,
113   // returns an empty GURL.
114   GURL GetURL() const;
115 
opaque()116   bool opaque() const { return site_as_origin_.opaque(); }
117 
has_registrable_domain_or_host()118   bool has_registrable_domain_or_host() const {
119     return !registrable_domain_or_host().empty();
120   }
121 
122   // Testing only function which allows tests to access the underlying
123   // `site_as_origin_` in order to verify behavior.
124   const url::Origin& GetInternalOriginForTesting() const;
125 
126   // Testing-only function which allows access to the private
127   // `registrable_domain_or_host` method.
registrable_domain_or_host_for_testing()128   std::string registrable_domain_or_host_for_testing() const {
129     return registrable_domain_or_host();
130   }
131 
132   bool operator==(const SchemefulSite& other) const;
133 
134   bool operator!=(const SchemefulSite& other) const;
135 
136   bool operator<(const SchemefulSite& other) const;
137 
138  private:
139   // IPC serialization code needs to access internal origin.
140   friend struct mojo::StructTraits<network::mojom::SchemefulSiteDataView,
141                                    SchemefulSite>;
142   friend struct IPC::ParamTraits<net::SchemefulSite>;
143 
144   friend class blink::BlinkSchemefulSite;
145 
146   // Create SiteForCookies from SchemefulSite needs to access internal origin,
147   // and SiteForCookies needs to access private method SchemelesslyEqual.
148   friend class SiteForCookies;
149 
150   // Needed to serialize opaque and non-transient NetworkIsolationKeys, which
151   // use opaque origins.
152   friend class NetworkIsolationKey;
153 
154   // Needed to serialize opaque and non-transient NetworkAnonymizationKeys,
155   // which use opaque origins.
156   friend class NetworkAnonymizationKey;
157 
158   // Needed to create a bogus origin from a site.
159   // TODO(https://crbug.com/1148927): Give IsolationInfos empty origins instead,
160   // in this case, and unfriend IsolationInfo.
161   friend class IsolationInfo;
162 
163   // Needed to create a bogus origin from a site.
164   friend class URLRequest;
165 
166   // Needed because cookies do not account for scheme.
167   friend class CookieMonster;
168 
169   // Needed for access to nonce for serialization.
170   friend class blink::StorageKey;
171 
172   FRIEND_TEST_ALL_PREFIXES(SchemefulSiteTest, OpaqueSerialization);
173   FRIEND_TEST_ALL_PREFIXES(SchemefulSiteTest, InternalValue);
174 
175   struct ObtainASiteResult {
176     url::Origin origin;
177     bool used_registerable_domain;
178   };
179 
180   static ObtainASiteResult ObtainASite(const url::Origin&);
181 
182   explicit SchemefulSite(ObtainASiteResult);
183 
184   // Deserializes a string obtained from `SerializeWithNonce()` to a
185   // `SchemefulSite`. Returns nullopt if the value was invalid in any way.
186   static absl::optional<SchemefulSite> DeserializeWithNonce(
187       const std::string& value);
188 
189   // Returns a serialized version of `site_as_origin_`. For an opaque
190   // `site_as_origin_`, this serializes with the nonce.  See
191   // `url::origin::SerializeWithNonce()` for usage information.
192   absl::optional<std::string> SerializeWithNonce();
193 
194   // Returns whether `this` and `other` share a host or registrable domain.
195   // Should NOT be used to check equality or equivalence. This is only used
196   // for legacy same-site cookie logic that does not check schemes. Private to
197   // restrict usage.
198   bool SchemelesslyEqual(const SchemefulSite& other) const;
199 
200   // Returns the host of the underlying `origin`, which will usually be the
201   // registrable domain. This is private because if it were public, it would
202   // trivially allow circumvention of the "Schemeful"-ness of this class.
203   // However, the CookieMonster currently needs access to this, since it ignores
204   // the schemes of domains.
205   std::string registrable_domain_or_host() const {
206     return site_as_origin_.host();
207   }
208 
209   // This should not be used casually, it's an opaque Origin or an scheme+eTLD+1
210   // packed into an Origin. If you extract this value SchemefulSite is not
211   // responsible for any unexpected friction you might encounter.
212   const url::Origin& internal_value() const { return site_as_origin_; }
213 
214   // Origin which stores the result of running the steps documented at
215   // https://html.spec.whatwg.org/multipage/origin.html#obtain-a-site.
216   // This is not an arbitrary origin. It must either be an opaque origin, or a
217   // scheme + eTLD+1 + default port.
218   //
219   // The `origin` passed into the SchemefulSite(const url::Origin&) constructor
220   // might not match this internal representation used by this class to track
221   // the scheme and eTLD+1 representing a schemeful site. This may be the case
222   // if, e.g., the passed `origin` has an eTLD+1 that is not equal to its
223   // hostname, or if the port number is not the default port for its scheme.
224   //
225   // In general, this `site_as_origin_` used for the internal representation
226   // should NOT be used directly by SchemefulSite consumers.
227   url::Origin site_as_origin_;
228 };
229 
230 // Provided to allow gtest to create more helpful error messages, instead of
231 // printing hex.
232 //
233 // Also used so that SchemefulSites can be the arguments of DCHECK_EQ.
234 NET_EXPORT std::ostream& operator<<(std::ostream& os, const SchemefulSite& ss);
235 
236 }  // namespace net
237 
238 #endif  // NET_BASE_SCHEMEFUL_SITE_H_
239