1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
  227
  228
  229
  230
  231
  232
  233
  234
  235
  236
  237
  238
  239
  240
  241
  242
  243
  244
  245
  246
  247
  248
  249
  250
  251
  252
  253
  254
  255
  256
  257
  258
  259
  260
  261
  262
  263
  264
  265
  266
  267
  268
  269
  270
  271
  272
  273
  274
  275
  276
  277
  278
  279
  280
  281
  282
  283
  284
  285
  286
  287
  288
  289
  290
  291
  292
  293
  294
  295
  296
  297
  298
  299
  300
  301
  302
  303

content / public / browser / site_instance.h [blame]

// 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 <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>;
using SiteInstanceGroupId = base::IdType32<class SiteInstanceGroupIdTag>;

///////////////////////////////////////////////////////////////////////////////
// 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;

  // Returns the ID of the SiteInstanceGroup this SiteInstance belongs to. If
  // the SiteInstance has no group, return 0, which is an invalid
  // SiteInstanceGroup ID.
  virtual SiteInstanceGroupId GetSiteInstanceGroupId() = 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 that have a form of communication with each other.
  // This include all the WebContents for documents in the same BrowsingInstance
  // as well as all the BrowsingInstances in the same CoopRelatedGroup. The
  // latter is useful to include because some interactions (e.g., messaging) are
  // allowed across such BrowsingInstances.
  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;

  // Returns true if the SiteInstance is for a process-isolated sandboxed
  // documents only.
  virtual bool IsSandboxed() = 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);

  // Factory method to create a SiteInstance in a new BrowsingInstance with a
  // custom StoragePartition that is preserved across navigations.
  // `partition_config` needs to be for a non-default StoragePartition.
  static scoped_refptr<SiteInstance> CreateForFixedStoragePartition(
      BrowserContext* browser_context,
      const GURL& url,
      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.
  //
  // Note that this API shouldn't be used for cases where about:blank has an
  // inherited origin, because that origin may influence the outcome of this
  // call.  See the content-internal ShouldAssignSiteForUrlInfo() for more
  // information.
  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_