| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef NET_BASE_NETWORK_ISOLATION_KEY_H_ |
| #define NET_BASE_NETWORK_ISOLATION_KEY_H_ |
| |
| #include <string> |
| |
| #include "base/gtest_prod_util.h" |
| #include "base/unguessable_token.h" |
| #include "net/base/net_export.h" |
| #include "net/base/schemeful_site.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace url { |
| class Origin; |
| } |
| |
| namespace network::mojom { |
| class FrameSiteEnabledNetworkIsolationKeyDataView; |
| class CrossSiteFlagEnabledNetworkIsolationKeyDataView; |
| } |
| |
| namespace net { |
| class CookiePartitionKey; |
| } |
| |
| namespace net { |
| |
| // Key used to isolate shared network stack resources used by requests based on |
| // the context on which they were made. |
| class NET_EXPORT NetworkIsolationKey { |
| public: |
| class SerializationPasskey { |
| private: |
| friend struct mojo::StructTraits< |
| network::mojom::FrameSiteEnabledNetworkIsolationKeyDataView, |
| NetworkIsolationKey>; |
| friend struct mojo::StructTraits< |
| network::mojom::CrossSiteFlagEnabledNetworkIsolationKeyDataView, |
| NetworkIsolationKey>; |
| SerializationPasskey() = default; |
| ~SerializationPasskey() = default; |
| }; |
| |
| class CookiePartitionKeyPasskey { |
| private: |
| friend class CookiePartitionKey; |
| CookiePartitionKeyPasskey() = default; |
| ~CookiePartitionKeyPasskey() = default; |
| }; |
| |
| // This constructor is used for deserialization when `GetMode()` returns |
| // `kCrossSiteFlagEnabled`. |
| NetworkIsolationKey(SerializationPasskey, |
| SchemefulSite top_frame_site, |
| SchemefulSite frame_site, |
| bool is_cross_site, |
| absl::optional<base::UnguessableToken> nonce); |
| |
| // Full constructor. When a request is initiated by the top frame, it must |
| // also populate the |frame_site| parameter when calling this constructor. |
| NetworkIsolationKey( |
| const SchemefulSite& top_frame_site, |
| const SchemefulSite& frame_site, |
| const absl::optional<base::UnguessableToken>& nonce = absl::nullopt); |
| |
| // Alternative constructor that takes ownership of arguments, to save copies. |
| NetworkIsolationKey( |
| SchemefulSite&& top_frame_site, |
| SchemefulSite&& frame_site, |
| absl::optional<base::UnguessableToken>&& nonce = absl::nullopt); |
| |
| // Legacy constructor. |
| // TODO(https://crbug.com/1145294): Remove this in favor of above |
| // constructor. |
| NetworkIsolationKey(const url::Origin& top_frame_origin, |
| const url::Origin& frame_origin); |
| |
| // Construct an empty key. |
| NetworkIsolationKey(); |
| |
| NetworkIsolationKey(const NetworkIsolationKey& network_isolation_key); |
| NetworkIsolationKey(NetworkIsolationKey&& network_isolation_key); |
| |
| ~NetworkIsolationKey(); |
| |
| NetworkIsolationKey& operator=( |
| const NetworkIsolationKey& network_isolation_key); |
| NetworkIsolationKey& operator=(NetworkIsolationKey&& network_isolation_key); |
| |
| // Creates a transient non-empty NetworkIsolationKey by creating an opaque |
| // origin. This prevents the NetworkIsolationKey from sharing data with other |
| // NetworkIsolationKeys. Data for transient NetworkIsolationKeys is not |
| // persisted to disk. |
| static NetworkIsolationKey CreateTransient(); |
| |
| // Creates a new key using |top_frame_site_| and |new_frame_site|. |
| NetworkIsolationKey CreateWithNewFrameSite( |
| const SchemefulSite& new_frame_site) const; |
| |
| // Intended for temporary use in locations that should be using main frame and |
| // frame origin, but are currently only using frame origin, because the |
| // creating object may be shared across main frame objects. Having a special |
| // constructor for these methods makes it easier to keep track of locating |
| // callsites that need to have their NetworkIsolationKey filled in. |
| static NetworkIsolationKey ToDoUseTopFrameOriginAsWell( |
| const url::Origin& incorrectly_used_frame_origin) { |
| return NetworkIsolationKey(incorrectly_used_frame_origin, |
| incorrectly_used_frame_origin); |
| } |
| |
| // Compare keys for equality, true if all enabled fields are equal. |
| bool operator==(const NetworkIsolationKey& other) const { |
| if (GetMode() != Mode::kFrameSiteEnabled) { |
| return std::tie(top_frame_site_, is_cross_site_, nonce_) == |
| std::tie(other.top_frame_site_, other.is_cross_site_, |
| other.nonce_); |
| } |
| return std::tie(top_frame_site_, frame_site_, is_cross_site_, nonce_) == |
| std::tie(other.top_frame_site_, other.frame_site_, |
| other.is_cross_site_, other.nonce_); |
| } |
| |
| // Compare keys for inequality, true if any enabled field varies. |
| bool operator!=(const NetworkIsolationKey& other) const { |
| return !(*this == other); |
| } |
| |
| // Provide an ordering for keys based on all enabled fields. |
| bool operator<(const NetworkIsolationKey& other) const { |
| if (GetMode() != Mode::kFrameSiteEnabled) { |
| return std::tie(top_frame_site_, is_cross_site_, nonce_) < |
| std::tie(other.top_frame_site_, other.is_cross_site_, |
| other.nonce_); |
| } |
| return std::tie(top_frame_site_, frame_site_, is_cross_site_, nonce_) < |
| std::tie(other.top_frame_site_, other.frame_site_, |
| other.is_cross_site_, other.nonce_); |
| } |
| |
| // Returns the string representation of the key for use in string-keyed disk |
| // cache. This is the string representation of each piece of the key separated |
| // by spaces. Returns nullopt if the network isolation key is transient, in |
| // which case, nothing should typically be saved to disk using the key. |
| absl::optional<std::string> ToCacheKeyString() const; |
| |
| // Returns string for debugging. Difference from ToString() is that transient |
| // entries may be distinguishable from each other. |
| std::string ToDebugString() const; |
| |
| // Returns true if all parts of the key are non-empty. |
| bool IsFullyPopulated() const; |
| |
| // Returns true if this key's lifetime is short-lived, or if |
| // IsFullyPopulated() returns true. It may not make sense to persist state to |
| // disk related to it (e.g., disk cache). |
| bool IsTransient() const; |
| |
| // Getters for the top frame and frame sites. These accessors are primarily |
| // intended for IPC calls, and to be able to create an IsolationInfo from a |
| // NetworkIsolationKey. |
| const absl::optional<SchemefulSite>& GetTopFrameSite() const { |
| return top_frame_site_; |
| } |
| |
| enum class Mode { |
| // This scheme indicates that "triple-key" NetworkIsolationKeys are used to |
| // partition the HTTP cache. This key will have the following properties: |
| // `top_frame_site` -> the schemeful site of the top level page. |
| // `frame_site ` -> the schemeful site of the frame. |
| // `is_cross_site` -> absl::nullopt. |
| kFrameSiteEnabled, |
| // This scheme indicates that "2.5-key" NetworkIsolationKeys are used to |
| // partition the HTTP cache. This key will have the following properties: |
| // `top_frame_site_` -> the schemeful site of the top level page. |
| // `frame_site_` -> should only be accessed for serialization or building |
| // nonced CookiePartitionKeys. |
| // `is_cross_site_` -> a boolean indicating whether the frame site is |
| // schemefully cross-site from the top-level site. |
| kCrossSiteFlagEnabled, |
| }; |
| |
| // Returns the cache key scheme currently in use. |
| static Mode GetMode(); |
| |
| // Getter for `frame_site_`. Will return absl::nullopt if the |
| // `NetworkIsolationKey` is empty. |
| // Note: This will CHECK if `GetMode()` does not return `kFrameSiteEnabled`. |
| const absl::optional<SchemefulSite>& GetFrameSite() const; |
| |
| // Do not use outside of testing. Returns the `frame_site_`. |
| const absl::optional<SchemefulSite> GetFrameSiteForTesting() const { |
| if (GetMode() == Mode::kCrossSiteFlagEnabled) { |
| return absl::nullopt; |
| } |
| return frame_site_; |
| } |
| |
| // Getter for the boolean indicating that `frame_site_` is cross-site from |
| // `top_frame_site_`. If the `NetworkIsolationKey` is empty, this will return |
| // absl::nullopt. |
| // Note: This will CHECK if `GetMode()` does not return |
| // `kCrossSiteFlagEnabled`. |
| absl::optional<bool> GetIsCrossSite() const; |
| |
| // When serializing a NIK for sending via mojo we want to access the frame |
| // site directly. We don't want to expose this broadly, though, hence the |
| // passkey. |
| const absl::optional<SchemefulSite>& GetFrameSiteForSerialization( |
| SerializationPasskey) const { |
| CHECK(!IsEmpty()); |
| return frame_site_; |
| } |
| // We also need to access the frame site directly when constructing |
| // CookiePartitionKey for nonced partitions. We also use a passkey for this |
| // case. |
| const absl::optional<SchemefulSite>& GetFrameSiteForCookiePartitionKey( |
| CookiePartitionKeyPasskey) const { |
| CHECK(!IsEmpty()); |
| return frame_site_; |
| } |
| |
| // Same as above but for the is-cross-site bit. |
| const absl::optional<bool>& GetIsCrossSiteForSerialization( |
| SerializationPasskey) const { |
| CHECK(!IsEmpty()); |
| CHECK_EQ(GetMode(), Mode::kCrossSiteFlagEnabled); |
| return is_cross_site_; |
| } |
| |
| // Getter for the nonce. |
| const absl::optional<base::UnguessableToken>& GetNonce() const { |
| return nonce_; |
| } |
| |
| // Returns true if all parts of the key are empty. |
| bool IsEmpty() const; |
| |
| private: |
| // Whether this key has opaque origins or a nonce. |
| bool IsOpaque() const; |
| |
| // The origin/etld+1 of the top frame of the page making the request. |
| absl::optional<SchemefulSite> top_frame_site_; |
| |
| // The origin/etld+1 of the frame that initiates the request. |
| absl::optional<SchemefulSite> frame_site_; |
| |
| // A boolean indicating whether the frame origin is cross-site from the |
| // top-level origin. This will be used for experiments to determine the |
| // the difference in performance between partitioning the HTTP cache using the |
| // top-level origin and frame origin ("triple-keying") vs. the top-level |
| // origin and an is-cross-site bit ("2.5-keying") like the |
| // `NetworkAnonymizationKey` uses for network state partitioning. This will be |
| // absl::nullopt when `GetMode()` returns `Mode::kFrameSiteEnabled`, or for an |
| // empty `NetworkIsolationKey`. |
| absl::optional<bool> is_cross_site_; |
| |
| // Having a nonce is a way to force a transient opaque `NetworkIsolationKey` |
| // for non-opaque origins. |
| absl::optional<base::UnguessableToken> nonce_; |
| }; |
| |
| } // namespace net |
| |
| #endif // NET_BASE_NETWORK_ISOLATION_KEY_H_ |