// Copyright 2012 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_PUBLIC_BROWSER_SITE_INSTANCE_H_ #define CONTENT_PUBLIC_BROWSER_SITE_INSTANCE_H_ #include #include #include "base/memory/ref_counted.h" #include "base/types/id_type.h" #include "content/common/content_export.h" #include "content/public/browser/browsing_instance_id.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/site_instance_process_assignment.h" #include "content/public/browser/storage_partition_config.h" #include "url/gurl.h" namespace perfetto::protos::pbzero { class SiteInstance; } // namespace perfetto::protos::pbzero namespace content { class BrowserContext; class RenderProcessHost; class StoragePartitionConfig; using SiteInstanceId = base::IdType32; /////////////////////////////////////////////////////////////////////////////// // SiteInstance interface. // // In an ideal sense, a SiteInstance represents a group of documents and workers // that can share memory with each other, and thus must live in the same // renderer process. In the spec, this roughly corresponds to an agent cluster. // Documents that are able to synchronously script each other will always be // placed in the same SiteInstance. // // A document's SiteInstance is determined by a combination of where the // document comes from (i.e., a principal based on its "site") and which frames // have references to it (i.e., the browsing context group, or "instance"). The // site part groups together documents that can script each other, while the // instance part allows independent copies of such documents to safely live in // different processes. // // The principal is usually based on the site of the document's URL: the scheme // and "registrable domain" (i.e., eTLD+1), not the full origin. For example, // https://dev.chromium.org would have a site of https://chromium.org. This // preserves compatibility with document.domain modifications, which allow // similar origin pages to script each other. (Note that there are many // exceptions, and the policy for determining site URLs is complex.) Meanwhile, // an "instance" is represented by the BrowsingInstance class, which includes // all frames that can find each other based on how they were created (e.g., // window.open or targeted links). // // In practice, a SiteInstance may contain documents from more than a single // site, usually for compatibility or performance reasons. For example, on // platforms that do not support out-of-process iframes, cross-site iframes must // necessarily be loaded in the same process as their parent document. Chrome's // process model uses SiteInstance as the basic primitive for assigning // documents to processes, and the process model's behavior is tuned primarily // by changing how SiteInstance principals (e.g., site URLs) are defined. // // Various process models are currently supported: // // FULL SITE ISOLATION (the current default for desktop platforms): Every // document from the web uses a SiteInstance whose process is strictly locked to // a single site (scheme + eTLD+1), such that the renderer process can be // prevented from loading documents outside that site. Cross-site navigations // always change SiteInstances (usually within the same BrowsingInstance, // although sometimes the BrowsingInstance changes as well). Subframes from // other sites will use different SiteInstances (always within the same // BrowsingInstance), and thus out-of-process iframes. // // PARTIAL SITE ISOLATION (the current Google Chrome default on most Android // devices): Documents from sites that are most likely to involve login use // SiteInstances that are strictly locked to such sites, while one shared // SiteInstance within each BrowsingInstance is used for the remaining documents // from other less sensitive sites. This avoids out-of-process iframes in the // common case for performance reasons, while protecting the sites that are most // likely to be targeted in attacks. // // NO SITE ISOLATION (the current Google Chrome default on low-end Android // devices and Android WebView): No documents from the web use locked processes, // and no out-of-process iframes are created. The shared SiteInstance for each // BrowsingInstance is always used for documents from the web. // // In each model, there are many exceptions, such as always requiring locked // processes for chrome:// URLs, or allowing some special cases to share // processes with each other (e.g., file:// URLs). // // In terms of lifetime, each RenderFrameHost tracks the SiteInstance it is // associated with, to identify its principal and determine its process. Each // FrameNavigationEntry also tracks the SiteInstance that rendered it, to // prevent loading attacker-controlled data into the wrong process on a session // history navigation. A SiteInstance is jointly owned by these references and // is only alive as long as it is accessible, either from current documents or // from session history. // /////////////////////////////////////////////////////////////////////////////// class CONTENT_EXPORT SiteInstance : public base::RefCounted { public: // Returns a unique ID for this SiteInstance. virtual SiteInstanceId GetId() = 0; // Returns a unique ID for the BrowsingInstance (i.e., group of related // browsing contexts) to which this SiteInstance belongs. This allows callers // to identify which SiteInstances can asynchronously script each other. virtual BrowsingInstanceId GetBrowsingInstanceId() = 0; // Whether this SiteInstance has a running process associated with it. // This may return true before the first call to GetProcess(), in cases where // we use process-per-site and there is an existing process available. virtual bool HasProcess() = 0; // Returns the current RenderProcessHost being used to render pages for this // SiteInstance. If there is no RenderProcessHost (because either none has // yet been created or there was one but it was cleanly destroyed (e.g. when // it is not actively being used), then this method will create a new // RenderProcessHost (and a new ID). Note that renderer process crashes leave // the current RenderProcessHost (and ID) in place. // // For sites that require process-per-site mode (e.g., NTP), this will // ensure only one RenderProcessHost for the site exists within the // BrowserContext. virtual RenderProcessHost* GetProcess() = 0; // Browser context to which this SiteInstance (and all related // SiteInstances) belongs. virtual BrowserContext* GetBrowserContext() = 0; // Get the web site that this SiteInstance is rendering pages for. This // includes the scheme and registered domain, but not the port. // // NOTE: In most cases, code should be performing checks against the origin // returned by |RenderFrameHost::GetLastCommittedOrigin()|. In contrast, the // GURL returned by |GetSiteURL()| should not be considered authoritative // because: // - a SiteInstance can host pages from multiple sites if "site per process" // is not enabled and the SiteInstance isn't hosting pages that require // process isolation (e.g. WebUI or extensions) // - even with site per process, the site URL is not an origin: while often // derived from the origin, it only contains the scheme and the eTLD + 1, // i.e. an origin with the host "deeply.nested.subdomain.example.com" // corresponds to a site URL with the host "example.com". virtual const GURL& GetSiteURL() = 0; // Get the StoragePartitionConfig used by this SiteInstance. virtual const StoragePartitionConfig& GetStoragePartitionConfig() = 0; // Gets a SiteInstance for the given URL that shares the current // BrowsingInstance, creating a new SiteInstance if necessary. This ensures // that a BrowsingInstance only has one SiteInstance per site, so that pages // in a BrowsingInstance have the ability to script each other. virtual scoped_refptr GetRelatedSiteInstance( const GURL& url) = 0; // Returns whether the given SiteInstance is in the same BrowsingInstance as // this one. If so, JavaScript interactions that are permitted across // origins (e.g., postMessage) should be supported. virtual bool IsRelatedSiteInstance(const SiteInstance* instance) = 0; // Returns the total active WebContents count for this SiteInstance and all // related SiteInstances in the same BrowsingInstance. virtual size_t GetRelatedActiveContentsCount() = 0; // Returns true if this SiteInstance is for a site that requires a dedicated // process. This only returns true under the "site per process" process model. virtual bool RequiresDedicatedProcess() = 0; // Returns true if this SiteInstance is for a process-isolated origin with its // own OriginAgentCluster. virtual bool RequiresOriginKeyedProcess() = 0; // Return whether this SiteInstance and the provided |url| are part of the // same web site, for the purpose of assigning them to processes accordingly. // The decision is currently based on the registered domain of the URLs // (google.com, bbc.co.uk), as well as the scheme (https, http). This ensures // that two pages will be in the same process if they can communicate with // other via JavaScript. (e.g., docs.google.com and mail.google.com have DOM // access to each other if they both set their document.domain properties to // google.com.) Note that if the destination is a blank page, we consider // that to be part of the same web site for the purposes for process // assignment. virtual bool IsSameSiteWithURL(const GURL& url) = 0; // Returns true if this object is used for a guest. virtual bool IsGuest() = 0; // Returns how this SiteInstance was assigned to a renderer process the most // recent time that such an assignment was done. This allows the content // embedder to collect metrics on how renderer process starting or reuse // affects performance. virtual SiteInstanceProcessAssignment GetLastProcessAssignmentOutcome() = 0; using TraceProto = perfetto::protos::pbzero::SiteInstance; // Write a representation of this object into a trace. virtual void WriteIntoTrace(perfetto::TracedProto context) = 0; // Estimates the overhead in terms of process count due to OriginAgentCluster // (OAC) SiteInstances in the BrowsingInstance related to this SiteInstance. // The estimate is based on counting SiteInstances where OAC is on, and // subtracting from it the count of SiteInstances that would exist without // OAC. If we assume that we don't coalesce SiteInstances from different // BrowsingInstances into a single RenderProcess, this roughly corresponds to // the number of renderer processes engendered by OAC. virtual int EstimateOriginAgentClusterOverheadForMetrics() = 0; // Factory method to create a new SiteInstance. This will create a new // BrowsingInstance, so it should only be used when creating a new tab from // scratch (or similar circumstances). // // The render process host factory may be nullptr. See SiteInstance // constructor. static scoped_refptr Create(BrowserContext* browser_context); // Factory method to get the appropriate SiteInstance for the given URL, in // a new BrowsingInstance. Use this instead of Create when you know the URL, // since it allows special site grouping rules to be applied (for example, to // obey process-per-site for sites that require it, such as NTP, or to use a // default SiteInstance for sites that don't require a dedicated process on // Android). static scoped_refptr CreateForURL( BrowserContext* browser_context, const GURL& url); // Factory method to create a SiteInstance for a guest in a new // BrowsingInstance. A guest requires a non-default StoragePartitionConfig // which should be passed in via `partition_config`. static scoped_refptr CreateForGuest( BrowserContext* browser_context, const StoragePartitionConfig& partition_config); // Determine if a URL should "use up" a site. URLs such as about:blank or // chrome-native:// leave the site unassigned. static bool ShouldAssignSiteForURL(const GURL& url); // Starts requiring a dedicated process for |url|'s site. On platforms where // strict site isolation is disabled, this may be used as a runtime signal // that a certain site should become process-isolated, because its security // is important to the user (e.g., if the user has typed a password or logged // in via OAuth on that site). The site will be determined from |url|'s // scheme and eTLD+1. If |context| is non-null, the site will be isolated // only within that BrowserContext; if |context| is null, the site will be // isolated globally for all BrowserContexts. |source| specifies why the new // site is being isolated. // // Note that this has no effect if site isolation is turned off, such as via // the kDisableSiteIsolation cmdline flag or enterprise policy -- see also // SiteIsolationPolicy::AreDynamicIsolatedOriginsEnabled(). // // The |should_persist| parameter controls whether the site is added // *persistently*. When true (this is the default), this function will ask // the embedder to save the site as part of profile data for |context|, so // that it survives restarts. The site will be cleared from profile data if // the user clears browsing data. When false, the isolation will last only // until the end of the current browsing session. This is appropriate if the // site's persistence is not desired or is managed separately (e.g., sites // isolated due to OAuth logins are saved and in another component). static void StartIsolatingSite( BrowserContext* context, const GURL& url, ChildProcessSecurityPolicy::IsolatedOriginSource source, bool should_persist = true); protected: friend class base::RefCounted; SiteInstance() {} virtual ~SiteInstance() {} }; } // namespace content. #endif // CONTENT_PUBLIC_BROWSER_SITE_INSTANCE_H_