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

content / browser / security / coop / coop_related_group.cc [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.

#include "content/browser/security/coop/coop_related_group.h"

#include "content/browser/browsing_instance.h"
#include "content/browser/site_instance_impl.h"

#include "base/logging.h"

namespace content {

CoopRelatedGroup::CoopRelatedGroup(BrowserContext* browser_context,
                                   bool is_guest,
                                   bool is_fenced,
                                   bool is_fixed_storage_partition)
    : browser_context_(browser_context),
      is_guest_(is_guest),
      is_fenced_(is_fenced),
      is_fixed_storage_partition_(is_fixed_storage_partition) {
  if (is_guest_) {
    CHECK(is_fixed_storage_partition_);
  }
}

CoopRelatedGroup::~CoopRelatedGroup() = default;

scoped_refptr<BrowsingInstance>
CoopRelatedGroup::FindSuitableBrowsingInstanceForCoopPolicy(
    const std::optional<url::Origin>& common_coop_origin,
    const WebExposedIsolationInfo& web_exposed_isolation_info) {
  for (BrowsingInstance* current_browsing_instance :
       coop_related_browsing_instances_) {
    // Note: We don't need to know if the common_coop_origin value is the result
    // of COOP: same-origin or COOP: restrict-properties. We will only ever
    // reach this function when doing a swap within the CoopRelatedGroup, so it
    // is necessarily for COOP: restrict-properties. WebExposedIsolationInfo is
    // used to know if COEP was set together with it or not.
    if ((current_browsing_instance->common_coop_origin() ==
         common_coop_origin) &&
        (current_browsing_instance->web_exposed_isolation_info() ==
         web_exposed_isolation_info)) {
      return base::WrapRefCounted<BrowsingInstance>(current_browsing_instance);
    }
  }

  return nullptr;
}

scoped_refptr<BrowsingInstance>
CoopRelatedGroup::GetOrCreateBrowsingInstanceForCoopPolicy(
    const std::optional<url::Origin>& common_coop_origin,
    const WebExposedIsolationInfo& web_exposed_isolation_info) {
  scoped_refptr<BrowsingInstance> browsing_instance =
      FindSuitableBrowsingInstanceForCoopPolicy(common_coop_origin,
                                                web_exposed_isolation_info);

  if (browsing_instance.get()) {
    return browsing_instance;
  }

  return base::WrapRefCounted<BrowsingInstance>(new BrowsingInstance(
      browser_context_, web_exposed_isolation_info, is_guest_, is_fenced_,
      is_fixed_storage_partition_, base::WrapRefCounted<CoopRelatedGroup>(this),
      common_coop_origin));
}

void CoopRelatedGroup::RegisterBrowsingInstance(
    BrowsingInstance* browsing_instance) {
  // We should never register the same BrowsingInstance twice. If that happens,
  // we're not reusing the BrowsingInstance via GetBrowsingInstanceForCoop()
  // somewhere when we should be doing so.
  auto it = find(coop_related_browsing_instances_.begin(),
                 coop_related_browsing_instances_.end(), browsing_instance);
  CHECK(it == coop_related_browsing_instances_.end());

  // We should also never record a second BrowsingInstance with the same Policy
  // as an existing BrowsingInstance.
  scoped_refptr<BrowsingInstance> duplicated_policy_browsing_instance =
      FindSuitableBrowsingInstanceForCoopPolicy(
          browsing_instance->common_coop_origin(),
          browsing_instance->web_exposed_isolation_info());
  CHECK(duplicated_policy_browsing_instance.get() == nullptr);

  CHECK(browsing_instance->is_fixed_storage_partition() ==
        is_fixed_storage_partition_);

  coop_related_browsing_instances_.push_back(browsing_instance);
}

void CoopRelatedGroup::UnregisterBrowsingInstance(
    BrowsingInstance* browsing_instance) {
  auto it = find(coop_related_browsing_instances_.begin(),
                 coop_related_browsing_instances_.end(), browsing_instance);
  CHECK(it != coop_related_browsing_instances_.end());

  coop_related_browsing_instances_.erase(it);
}

scoped_refptr<SiteInstanceImpl>
CoopRelatedGroup::GetCoopRelatedSiteInstanceForURL(const UrlInfo& url_info,
                                                   bool allow_default_si) {
  // Fenced frames should never be able to request other SiteInstances in the
  // same CoopRelatedGroup, as they cannot open popups without noopener and COOP
  // is not enforced within the frame.
  DCHECK(!is_fenced_);
  scoped_refptr<BrowsingInstance> target_browsing_instance =
      GetOrCreateBrowsingInstanceForCoopPolicy(
          url_info.common_coop_origin,
          url_info.web_exposed_isolation_info.value_or(
              WebExposedIsolationInfo::CreateNonIsolated()));
  return target_browsing_instance->GetSiteInstanceForURL(url_info,
                                                         allow_default_si);
}

}  // namespace content