910e62b5创建于 1月15日历史提交
// 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/storage_access/storage_access_handle.h"

#include "base/byte_count.h"
#include "base/functional/callback_helpers.h"
#include "base/types/pass_key.h"
#include "content/browser/broadcast_channel/broadcast_channel_provider.h"
#include "content/browser/broadcast_channel/broadcast_channel_service.h"
#include "content/browser/file_system_access/file_system_access_manager_impl.h"
#include "content/browser/network/cross_origin_embedder_policy_reporter.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/browser/worker_host/shared_worker_connector_impl.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/permission_descriptor_util.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
#include "storage/browser/blob/blob_url_registry.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"

namespace content {

using PassKey = base::PassKey<StorageAccessHandle>;

namespace {

void EstimateImplAfterGetBucketUsageAndQuota(
    StorageAccessHandle::EstimateCallback callback,
    blink::mojom::QuotaStatusCode code,
    int64_t usage,
    int64_t quota) {
  if (code != blink::mojom::QuotaStatusCode::kOk) {
    std::move(callback).Run(/*usage=*/base::ByteCount(0),
                            /*quota=*/base::ByteCount(0), /*success=*/false);
    return;
  }
  std::move(callback).Run(base::ByteCount(usage), base::ByteCount(quota),
                          /*success=*/true);
}

}  // namespace

// static
void StorageAccessHandle::Create(
    RenderFrameHost* host,
    mojo::PendingReceiver<blink::mojom::StorageAccessHandle> receiver) {
  CHECK(host);
  if (!host->IsFullCookieAccessAllowed()) {
#if DCHECK_IS_ON()
    mojo::ReportBadMessage(
        "Binding a StorageAccessHandle requires third-party cookie access.");
#endif
    return;
  }
  new StorageAccessHandle(*host, std::move(receiver));
}

void StorageAccessHandle::BindIndexedDB(
    mojo::PendingReceiver<blink::mojom::IDBFactory> receiver) {
  render_frame_host().GetProcess()->BindIndexedDB(
      blink::StorageKey::CreateFirstParty(
          render_frame_host().GetStorageKey().origin()),
      static_cast<RenderFrameHostImpl&>(render_frame_host()),
      std::move(receiver));
}

void StorageAccessHandle::BindLocks(
    mojo::PendingReceiver<blink::mojom::LockManager> receiver) {
  render_frame_host().GetProcess()->CreateLockManager(
      blink::StorageKey::CreateFirstParty(
          render_frame_host().GetStorageKey().origin()),
      std::move(receiver));
}

void StorageAccessHandle::BindCaches(
    mojo::PendingReceiver<blink::mojom::CacheStorage> receiver) {
  RenderFrameHostImpl& host =
      static_cast<RenderFrameHostImpl&>(render_frame_host());
  mojo::PendingRemote<network::mojom::CrossOriginEmbedderPolicyReporter>
      coep_reporter_remote;
  if (host.coep_reporter()) {
    host.coep_reporter()->Clone(
        coep_reporter_remote.InitWithNewPipeAndPassReceiver());
  }
  mojo::PendingRemote<network::mojom::DocumentIsolationPolicyReporter>
      dip_reporter_remote;
  if (host.dip_reporter()) {
    host.dip_reporter()->Clone(
        dip_reporter_remote.InitWithNewPipeAndPassReceiver());
  }
  host.GetProcess()->BindCacheStorage(
      host.cross_origin_embedder_policy(), std::move(coep_reporter_remote),
      host.policy_container_host()->policies().document_isolation_policy,
      std::move(dip_reporter_remote),
      storage::BucketLocator::ForDefaultBucket(
          blink::StorageKey::CreateFirstParty(host.GetStorageKey().origin())),
      std::move(receiver));
}

void StorageAccessHandle::GetDirectory(GetDirectoryCallback callback) {
  static_cast<RenderFrameHostImpl&>(render_frame_host())
      .GetStoragePartition()
      ->GetFileSystemAccessManager()
      ->GetSandboxedFileSystem(
          FileSystemAccessManagerImpl::BindingContext(
              blink::StorageKey::CreateFirstParty(
                  render_frame_host().GetStorageKey().origin()),
              render_frame_host().GetLastCommittedURL(),
              render_frame_host().GetGlobalId()),
          /*bucket=*/std::nullopt,
          /*directory_path_components=*/{}, std::move(callback));
}

void StorageAccessHandle::Estimate(EstimateCallback callback) {
  static_cast<RenderFrameHostImpl&>(render_frame_host())
      .GetStoragePartition()
      ->GetQuotaManagerProxy()
      ->GetBucketsForStorageKey(
          blink::StorageKey::CreateFirstParty(
              render_frame_host().GetStorageKey().origin()),
          /*delete_expired=*/false,
          base::SequencedTaskRunner::GetCurrentDefault(),
          base::BindOnce(&StorageAccessHandle::EstimateImpl,
                         weak_factory_.GetWeakPtr(), std::move(callback)));
}

void StorageAccessHandle::EstimateImpl(
    EstimateCallback callback,
    storage::QuotaErrorOr<std::set<storage::BucketInfo>> bucket_set) const {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (!bucket_set.has_value()) {
    std::move(callback).Run(/*usage=*/base::ByteCount(0),
                            /*quota=*/base::ByteCount(0), /*success=*/false);
    return;
  }
  storage::BucketInfo bucket_info;
  for (const storage::BucketInfo& info : *bucket_set) {
    if (info.is_default()) {
      bucket_info = info;
      break;
    }
  }
  if (bucket_info.is_null()) {
    std::move(callback).Run(/*usage=*/base::ByteCount(0),
                            /*quota=*/base::ByteCount(0), /*success=*/true);
    return;
  }
  static_cast<RenderFrameHostImpl&>(render_frame_host())
      .GetStoragePartition()
      ->GetQuotaManagerProxy()
      ->GetBucketUsageAndReportedQuota(
          bucket_info.id, base::SequencedTaskRunner::GetCurrentDefault(),
          base::BindOnce(&EstimateImplAfterGetBucketUsageAndQuota,
                         std::move(callback)));
}

void StorageAccessHandle::BindBlobStorage(
    mojo::PendingAssociatedReceiver<blink::mojom::BlobURLStore> receiver) {
  static_cast<RenderFrameHostImpl&>(render_frame_host())
      .GetStoragePartition()
      ->GetBlobUrlRegistry()
      ->AddReceiver(
          blink::StorageKey::CreateFirstParty(
              render_frame_host().GetStorageKey().origin()),
          render_frame_host().GetLastCommittedOrigin(),
          render_frame_host().GetProcess()->GetDeprecatedID(),
          std::move(receiver),
          /*partitioning_blob_url_closure=*/base::DoNothing(),
          // In the case that a context is granted storage access, the
          // StorageAccessHandle context still shouldn't bypass the partitioning
          // check (e.g. using a Blob URL created with URL.createObjectURL in
          // the third-party context with the StorageAccessHandle's SharedWorker
          // constructor.)
          /*storage_access_check_callback=*/
          base::BindRepeating([]() -> bool { return false; }),
          // A StorageAccessHandle is not a top-level blob document, so always
          // pass std::nullopt here.
          /*top_level_blob_document_url=*/std::nullopt,
          /*context_type_for_debugging=*/"StorageAccessHandle",
          base::BindRepeating(
              [](base::WeakPtr<StorageAccessHandle> handle) -> std::string {
                if (!handle) {
                  return "destroyed StorageAccessHandle";
                }
                return handle->render_frame_host()
                    .GetStorageKey()
                    .GetDebugString();
              },
              weak_factory_.GetWeakPtr()),
          /*partitioning_disabled_by_policy=*/false);
}

void StorageAccessHandle::BindBroadcastChannel(
    mojo::PendingAssociatedReceiver<blink::mojom::BroadcastChannelProvider>
        receiver) {
  BroadcastChannelService* service =
      static_cast<RenderFrameHostImpl&>(render_frame_host())
          .GetStoragePartition()
          ->GetBroadcastChannelService();
  service->AddAssociatedReceiver(
      std::make_unique<BroadcastChannelProvider>(
          service, blink::StorageKey::CreateFirstParty(
                       render_frame_host().GetStorageKey().origin())),
      std::move(receiver));
}

void StorageAccessHandle::BindSharedWorker(
    mojo::PendingReceiver<blink::mojom::SharedWorkerConnector> receiver) {
  SharedWorkerConnectorImpl::Create(
      PassKey(), render_frame_host().GetGlobalId(),
      blink::StorageKey::CreateFirstParty(
          render_frame_host().GetStorageKey().origin()),
      std::move(receiver));
}

StorageAccessHandle::StorageAccessHandle(
    RenderFrameHost& host,
    mojo::PendingReceiver<blink::mojom::StorageAccessHandle> receiver)
    : DocumentService(host, std::move(receiver)) {}

StorageAccessHandle::~StorageAccessHandle() = default;

}  // namespace content