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