blob: 3ca8fbb61e61954a178869fe9dc769289a6d61e7 [file] [log] [blame]
// Copyright 2023 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_COOP_RELATED_GROUP_H_
#define CONTENT_BROWSER_COOP_RELATED_GROUP_H_
#include <vector>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "content/browser/url_info.h"
#include "content/browser/web_exposed_isolation_info.h"
#include "content/common/content_export.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/origin.h"
namespace content {
class BrowserContext;
class BrowsingInstance;
class SiteInstanceImpl;
// A CoopRelatedGroup is a set of browsing context groups that can communicate
// with each other via a limited subset of properties
// (currently window.postMessage() and window.closed). Documents in
// BrowsingContexts that are not part of the same CoopRelatedGroup cannot get
// references to each other's Window by any means at all. CoopRelatedGroup,
// browsing context groups (BrowsingInstances) and Agent Clusters (roughly, but
// not strictly equivalent to SiteInstances) provide three tiers of
// communication capabilities:
// - Documents in the same Agent Cluster can synchronously DOM script each
// other.
// - Documents in the same browsing context group can asynchronously interact
// with each other, via cross-origin Window properties.
// - Documents in the same CoopRelatedGroup can only message each
// other and observe window.closed.
//
// These layers have a 1->n relationship pattern: a CoopRelatedGroup contains 1
// or more browsing context groups, itself containing 1 or more agent clusters.
// Each layer is refcounted and therefore kept alive by the layer below it, with
// individual SiteInstances at the base, being kept alive manually.
//
// When no document inside a browsing context group sets COOP:
// restrict-properties, the CoopRelatedGroup contains only a single browsing
// context group. CoopRelatedGroups containing more than a single browsing
// context group occur when COOP: restrict-properties forces a browsing context
// group swap in the same CoopRelatedGroup. It allows retaining a relationship
// to the opener across browsing context groups, hence creating the actual
// communication channel.
//
// Like BrowsingInstance, CoopRelatedGroup has no public members, as it is
// designed to be interacted with only from the BrowsingInstance class, itself
// only reachable from SiteInstance. To get a new SiteInstance that is part of
// the same CoopRelatedGroup but in a different BrowsingInstance, use
// SiteInstanceImpl::GetCoopRelatedSiteInstance. Because of this,
// CoopRelatedGroups are tested in site_instance_impl_unittest.cc.
class CONTENT_EXPORT CoopRelatedGroup final
: public base::RefCounted<CoopRelatedGroup> {
public:
CoopRelatedGroup(const CoopRelatedGroup&) = delete;
CoopRelatedGroup& operator=(const CoopRelatedGroup&) = delete;
private:
friend class base::RefCounted<CoopRelatedGroup>;
friend class BrowsingInstance;
friend class CoopRelatedGroupTest;
explicit CoopRelatedGroup(BrowserContext* browser_context,
bool is_guest,
bool is_fenced);
~CoopRelatedGroup();
// Returns the token uniquely identifying this CoopRelatedGroup.
base::UnguessableToken token() const { return token_; }
// Returns a SiteInstance in this CoopRelatedGroup, depending on the passed
// `url_info`. It might reuse an existing BrowsingInstance that is part of the
// group if one is suitable, given its COOP value, origin and cross-origin
// isolation state. If none is suitable, a new BrowsingInstance with the
// appropriate characteristics will be created.
//
// `allow_default_site_instance` is used to specify whether the returned
// SiteInstance can be the default SiteInstance.
scoped_refptr<SiteInstanceImpl> GetCoopRelatedSiteInstanceForURL(
const UrlInfo& url_info,
bool allow_default_site_instance);
// These functions keep the group informed of the BrowsingInstances that are
// alive and part of it. It is necessary for the BrowsingInstance reuse
// mechanism. They should be called in the constructor and destructor of
// BrowsingInstance.
void RegisterBrowsingInstance(BrowsingInstance* browsing_instance);
void UnregisterBrowsingInstance(BrowsingInstance* browsing_instance);
// Internal helpers that return a BrowsingInstance for a given COOP "Policy"
// which includes whether COOP: restrict-properties was set and from which
// origin, as well as whether it was augmented with COEP.
// `FindSuitableBrowsingInstanceForCoopPolicy` only returns an existing
// BrowsingInstance with the given Policy, while
// `GetOrCreateBrowsingInstanceForCoopPolicy` will create a new one if no
// suitable BrowsingInstance exists in this group.
scoped_refptr<BrowsingInstance> FindSuitableBrowsingInstanceForCoopPolicy(
const absl::optional<url::Origin>& common_coop_origin,
const WebExposedIsolationInfo& web_exposed_isolation_info);
scoped_refptr<BrowsingInstance> GetOrCreateBrowsingInstanceForCoopPolicy(
const absl::optional<url::Origin>& common_coop_origin,
const WebExposedIsolationInfo& web_exposed_isolation_info);
// Tracks the number of WebContents currently in this CoopRelatedGroup.
// Note: We also separately track the number of WebContents in specific
// BrowsingInstances, for validity checks.
size_t active_contents_count() const { return active_contents_count_; }
void increment_active_contents_count() { active_contents_count_++; }
void decrement_active_contents_count() {
DCHECK_LT(0u, active_contents_count_);
active_contents_count_--;
}
// Recorded with the first BrowsingInstance and used to create new
// BrowsingInstances. All BrowsingInstances in a CoopRelatedGroup should share
// the same BrowserContext, therefore recording it at creation time is fine.
raw_ptr<BrowserContext, DanglingUntriaged> browser_context_;
// Whether all the documents presented in this CoopRelatedGroup are for guest
// views.
bool is_guest_;
// Whether all the documents presented in this CoopRelatedGroup are for a
// fenced frame.
bool is_fenced_;
// All the BrowsingInstances belonging to this CoopRelatedGroup. They are not
// owned by this group, but collectively own it instead. To keep track of the
// group members we therefore use raw_ptrs, and add or delete members of the
// group via the RegisterBrowsingInstance and UnregisterBrowsingInstance
// methods. These are called from the BrowsingInstance constructor and
// destructor respectively.
//
// There exists at most one BrowsingInstance hosting documents with the same
// "Policy", namely a combination of whether COOP: restrict-properties was set
// and from which origin, and whether it set COEP as well. This gives us three
// types of BrowsingInstances:
// - The ones with COOP: restrict-properties set from a given origin.
// - The ones with COOP: restrict-properties-plus-COEP set from a given
// origin.
// - A single BrowsingInstance for all the rest.
//
// We make sure we do not create two BrowsingInstances with the same
// Policy when running RegisterBrowsingInstance.
std::vector<raw_ptr<BrowsingInstance>> coop_related_browsing_instances_;
// Number of all WebContents currently using any of the BrowsingInstances in
// this group. This is used to determine if there are multiple windows in the
// group, to know whether certain actions (e.g. putting a page into the
// BFCache) are allowed.
size_t active_contents_count_{0u};
// A token uniquely identifying this CoopRelatedGroup. This can be sent to the
// renderer process if needed, without security risks.
const base::UnguessableToken token_ = base::UnguessableToken::Create();
};
} // namespace content
#endif // CONTENT_BROWSER_COOP_RELATED_GROUP_H_;