| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CONTENT_BROWSER_URL_INFO_H_ |
| #define CONTENT_BROWSER_URL_INFO_H_ |
| |
| #include <optional> |
| |
| #include "base/tracing/protos/chrome_track_event.pbzero.h" |
| #include "content/browser/agent_cluster_key.h" |
| #include "content/browser/web_exposed_isolation_info.h" |
| #include "content/common/content_export.h" |
| #include "content/public/browser/storage_partition_config.h" |
| #include "third_party/perfetto/include/perfetto/tracing/traced_proto.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| namespace content { |
| |
| // This struct is used to package a GURL together with extra state required to |
| // make SiteInstance/process allocation decisions, e.g. whether the url's |
| // origin or site is requesting isolation as determined by response headers in |
| // the corresponding NavigationRequest. The extra state is generally most |
| // relevant when navigation to the URL is in progress, since once placed into a |
| // SiteInstance, the extra state will be available via SiteInfo. Otherwise, |
| // most callsites requiring a UrlInfo can create with a GURL, specifying kNone |
| // for |origin_isolation_request|. Some examples of where passing kNone for |
| // |origin_isolation_request| is safe are: |
| // * at DidCommitNavigation time, since at that point the SiteInstance has |
| // already been picked and the navigation can be considered finished, |
| // * before a response is received (the only way to request isolation is via |
| // response headers), and |
| // * outside of a navigation. |
| // |
| // If UrlInfo::origin_isolation_request is kNone, that does *not* imply that |
| // the URL's origin will not be isolated, and vice versa. The isolation |
| // decision involves both response headers and consistency within a |
| // BrowsingInstance, and once we decide on the isolation outcome for an origin, |
| // it won't change for the lifetime of the BrowsingInstance. |
| // |
| // To check whether a frame ends up in a site-isolated process, use |
| // SiteInfo::RequiresDedicatedProcess() on its SiteInstance's SiteInfo. To |
| // check whether a frame ends up being origin-isolated in a separate process |
| // (e.g., due to the Origin-Agent-Cluster header), use |
| // SiteInfo::requires_origin_keyed_process(). |
| // |
| // Note: it is not expected that this struct will be exposed in content/public. |
| class IsolationContext; |
| class UrlInfoInit; |
| |
| struct CONTENT_EXPORT UrlInfo { |
| public: |
| // Bitmask representing one or more isolation requests. |
| enum OriginIsolationRequest { |
| // No isolation has been requested, so the default isolation state for the |
| // current BrowsingInstance should be used. |
| kDefault = 0, |
| // Explicitly requests no isolation. |
| kNone = (1 << 0), |
| // The Origin-Agent-Cluster header is requesting OAC isolation for `url`'s |
| // origin in the renderer. If granted, this is tracked for consistency in |
| // ChildProcessSecurityPolicyImpl. If kRequiresOriginKeyedProcessByHeader is |
| // not set, then this only affects the renderer. |
| kOriginAgentClusterByHeader = (1 << 1), |
| // If kOriginAgentClusterByHeader is set, the following bit triggers an |
| // origin-keyed process for `url`'s origin. If |
| // kRequiresOriginKeyedProcessByHeader is not set and |
| // kOriginAgentClusterByHeader is, then OAC will be logical only, i.e. |
| // implemented in the renderer via a separate AgentCluster. |
| kRequiresOriginKeyedProcessByHeader = (1 << 2), |
| }; |
| |
| // For isolated sandboxed iframes, when per-document mode is used, we |
| // assign each sandboxed SiteInstance a unique identifier to prevent other |
| // same-site/same-origin frames from re-using the same SiteInstance. This |
| // identifier is used to indicate that the sandbox id is not in use. |
| static const int64_t kInvalidUniqueSandboxId; |
| |
| UrlInfo(); // Needed for inclusion in SiteInstanceDescriptor. |
| UrlInfo(const UrlInfo& other); |
| explicit UrlInfo(const UrlInfoInit& init); |
| ~UrlInfo(); |
| |
| // Used to convert GURL to UrlInfo in tests where opt-in isolation is not |
| // being tested. |
| static UrlInfo CreateForTesting(const GURL& url_in, |
| std::optional<StoragePartitionConfig> |
| storage_partition_config = std::nullopt); |
| |
| // Depending on enabled features (some of which can change at runtime), |
| // default can be no isolation, requests origin agent cluster only, or |
| // requests origin agent cluster with origin keyed process. BrowsingInstances |
| // store a copy of the default isolation state at the time of their creation |
| // to make sure the default value stays constant over the lifetime of the |
| // BrowsingInstance. |
| bool requests_default_origin_agent_cluster_isolation() const { |
| return origin_isolation_request == OriginIsolationRequest::kDefault; |
| } |
| // Returns whether this UrlInfo is requesting an origin-keyed agent cluster |
| // for `url`'s origin due to the OriginAgentCluster header. |
| bool requests_origin_agent_cluster_by_header() const { |
| return (origin_isolation_request & |
| OriginIsolationRequest::kOriginAgentClusterByHeader); |
| } |
| |
| // Returns whether this UrlInfo is requesting an origin-keyed process for |
| // `url`'s origin due to the OriginAgentCluster header. |
| bool requests_origin_keyed_process_by_header() const { |
| return (origin_isolation_request & |
| OriginIsolationRequest::kRequiresOriginKeyedProcessByHeader); |
| } |
| |
| // Returns whether this UrlInfo is requesting an origin-keyed process for |
| // `url`'s origin due to the OriginAgentCluster header, or whether it should |
| // try to use an origin-keyed process by default within the given `context`, |
| // in cases without an explicit header. |
| bool RequestsOriginKeyedProcess(const IsolationContext& context) const; |
| |
| // Returns whether this UrlInfo is requesting site isolation for its site in |
| // response to the Cross-Origin-Opener-Policy header. See |
| // https://chromium.googlesource.com/chromium/src/+/main/docs/process_model_and_site_isolation.md#Partial-Site-Isolation |
| // for details. |
| bool requests_coop_isolation() const { return is_coop_isolation_requested; } |
| |
| // Returns whether this UrlInfo is for a page that should be cross-origin |
| // isolated. |
| bool IsIsolated() const; |
| |
| using TraceProto = perfetto::protos::pbzero::UrlInfo; |
| void WriteIntoTrace(perfetto::TracedProto<TraceProto> proto) const; |
| |
| GURL url; |
| |
| // This field indicates whether the URL is requesting additional process |
| // isolation during the current navigation (e.g., via OriginAgentCluster). If |
| // URL did not explicitly request any isolation, this will be set to kDefault. |
| // This field is only relevant (1) during a navigation request, (2) up to the |
| // point where the origin is placed into a SiteInstance. Other than these |
| // cases, this should be set to kDefault. |
| OriginIsolationRequest origin_isolation_request = |
| OriginIsolationRequest::kDefault; |
| |
| // True if the Cross-Origin-Opener-Policy header has triggered a hint to turn |
| // on site isolation for `url`'s site. |
| bool is_coop_isolation_requested = false; |
| |
| // True if this resource is served from the prefetch cache, and its success |
| // may have been influenced by cross-site state. Such responses may require |
| // special handling to make it harder to detect that this has happened. |
| bool is_prefetch_with_cross_site_contamination = false; |
| |
| // This allows overriding the origin of |url| for process assignment purposes |
| // in certain very special cases. |
| // - The navigation to |url| is through loadDataWithBaseURL (e.g., in a |
| // <webview> tag or on Android Webview): this will be the base origin |
| // provided via that API. |
| // - For renderer-initiated about:blank navigations: this will be the |
| // initiator's origin that about:blank should inherit. |
| // - data: URLs that will be rendered (e.g. not downloads) that do NOT use |
| // loadDataWithBaseURL: this will be the value of the tentative origin to |
| // commit, which we will use to keep the nonce of the opaque origin |
| // consistent across a navigation. |
| // - All other cases: this will be nullopt. |
| // |
| // TODO(alexmos): Currently, this is also used to hold the origin committed |
| // by the renderer at DidCommitNavigation() time, for use in commit-time URL |
| // and origin checks that require a UrlInfo. Investigate whether there's a |
| // cleaner way to organize these checks. See https://crbug.com/1320402. |
| std::optional<url::Origin> origin; |
| |
| // If url is being loaded in a frame that is in a origin-restricted sandboxed, |
| // then this flag will be true. |
| bool is_sandboxed = false; |
| |
| // Only used when `is_sandboxed` is true, this unique identifier allows for |
| // per-document SiteInfo grouping. |
| int64_t unique_sandbox_id = kInvalidUniqueSandboxId; |
| |
| // The StoragePartitionConfig that should be used when loading content from |
| // |url|. If absent, ContentBrowserClient::GetStoragePartitionConfig will be |
| // used to determine which StoragePartitionConfig to use. |
| // |
| // If present, this value will be used as the StoragePartitionConfig in the |
| // SiteInfo, regardless of its validity. SiteInstances created from a UrlInfo |
| // containing a StoragePartitionConfig that isn't compatible with the |
| // BrowsingInstance that the SiteInstance should belong to will lead to a |
| // CHECK failure. |
| std::optional<StoragePartitionConfig> storage_partition_config; |
| |
| // Pages may choose to isolate themselves more strongly than the web's |
| // default, thus allowing access to APIs that would be difficult to |
| // safely expose otherwise. "Cross-origin isolation", for example, requires |
| // assertion of a Cross-Origin-Opener-Policy and |
| // Cross-Origin-Embedder-Policy, and unlocks SharedArrayBuffer. |
| // When we haven't yet been to the network or inherited properties that are |
| // sufficient to know the future isolation state - we are in a speculative |
| // state - this member will be empty. |
| std::optional<WebExposedIsolationInfo> web_exposed_isolation_info; |
| |
| // Indicates that the URL directs to PDF content, which should be isolated |
| // from other types of content. On Android, this can only be true when a PDF |
| // NativePage is created for a main frame navigation. |
| bool is_pdf = false; |
| |
| // The CrossOriginIsolationKey to use for the navigation. This represents the |
| // isolation requested by the page itself through the use of COOP, COEP and |
| // DIP. Right now, this is only set when DocumentIsolationPolicy is enabled, |
| // but it should eventually for COOP and COEP. It will eventually replace |
| // WebExposedIsolationInfo. |
| std::optional<AgentClusterKey::CrossOriginIsolationKey> |
| cross_origin_isolation_key; |
| |
| // Any new UrlInfo fields should be added to UrlInfoInit as well, and the |
| // UrlInfo constructor that takes a UrlInfoInit should be updated as well. |
| }; |
| |
| class CONTENT_EXPORT UrlInfoInit { |
| public: |
| UrlInfoInit() = delete; |
| explicit UrlInfoInit(const GURL& url); |
| explicit UrlInfoInit(const UrlInfo& base); |
| ~UrlInfoInit(); |
| |
| UrlInfoInit& operator=(const UrlInfoInit&) = delete; |
| |
| UrlInfoInit& WithOriginIsolationRequest( |
| UrlInfo::OriginIsolationRequest origin_isolation_request); |
| UrlInfoInit& WithCOOPSiteIsolation(bool requests_coop_isolation); |
| UrlInfoInit& WithCrossSitePrefetchContamination(bool contaminated); |
| UrlInfoInit& WithOrigin(const url::Origin& origin); |
| UrlInfoInit& WithSandbox(bool is_sandboxed); |
| UrlInfoInit& WithUniqueSandboxId(int unique_sandbox_id); |
| UrlInfoInit& WithStoragePartitionConfig( |
| std::optional<StoragePartitionConfig> storage_partition_config); |
| UrlInfoInit& WithWebExposedIsolationInfo( |
| std::optional<WebExposedIsolationInfo> web_exposed_isolation_info); |
| UrlInfoInit& WithIsPdf(bool is_pdf); |
| UrlInfoInit& WithCrossOriginIsolationKey( |
| const std::optional<AgentClusterKey::CrossOriginIsolationKey>& |
| cross_origin_isolation_key); |
| |
| const std::optional<url::Origin>& origin() { return origin_; } |
| |
| private: |
| UrlInfoInit(UrlInfoInit&); |
| |
| friend UrlInfo; |
| |
| GURL url_; |
| UrlInfo::OriginIsolationRequest origin_isolation_request_ = |
| UrlInfo::OriginIsolationRequest::kDefault; |
| bool requests_coop_isolation_ = false; |
| bool is_prefetch_with_cross_site_contamination_ = false; |
| std::optional<url::Origin> origin_; |
| bool is_sandboxed_ = false; |
| int64_t unique_sandbox_id_ = UrlInfo::kInvalidUniqueSandboxId; |
| std::optional<StoragePartitionConfig> storage_partition_config_; |
| std::optional<WebExposedIsolationInfo> web_exposed_isolation_info_; |
| bool is_pdf_ = false; |
| std::optional<AgentClusterKey::CrossOriginIsolationKey> |
| cross_origin_isolation_key_; |
| |
| // Any new fields should be added to the UrlInfoInit(UrlInfo) constructor. |
| }; // class UrlInfoInit |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_URL_INFO_H_ |