blob: 408a0765330317d510f806e092b1b87b7728d587 [file] [log] [blame]
// 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_