| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // 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 <stddef.h> |
| #include <stdint.h> |
| |
| #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<class SiteInstanceIdTag>; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // 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<SiteInstance> { |
| 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<SiteInstance> 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 <webview> 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<TraceProto> 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<SiteInstance> 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<SiteInstance> CreateForURL( |
| BrowserContext* browser_context, |
| const GURL& url); |
| |
| // Factory method to create a SiteInstance for a <webview> guest in a new |
| // BrowsingInstance. A guest requires a non-default StoragePartitionConfig |
| // which should be passed in via `partition_config`. |
| static scoped_refptr<SiteInstance> 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>; |
| |
| SiteInstance() {} |
| virtual ~SiteInstance() {} |
| }; |
| |
| } // namespace content. |
| |
| #endif // CONTENT_PUBLIC_BROWSER_SITE_INSTANCE_H_ |