blob: d60a6eaf7701b31817629d459dc3abc84f2a8259 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef STORAGE_BROWSER_BLOB_BLOB_URL_REGISTRY_H_
#define STORAGE_BROWSER_BLOB_BLOB_URL_REGISTRY_H_
#include <map>
#include "base/component_export.h"
#include "base/functional/callback.h"
#include "base/sequence_checker.h"
#include "base/unguessable_token.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/unique_associated_receiver_set.h"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"
#include "storage/browser/blob/blob_storage_constants.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/blob/blob.mojom.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom.h"
class GURL;
namespace storage {
// This class stores the mapping of blob Urls to blobs.
class COMPONENT_EXPORT(STORAGE_BROWSER) BlobUrlRegistry {
public:
explicit BlobUrlRegistry(base::WeakPtr<BlobUrlRegistry> fallback = nullptr);
BlobUrlRegistry(const BlobUrlRegistry&) = delete;
BlobUrlRegistry& operator=(const BlobUrlRegistry&) = delete;
~BlobUrlRegistry();
enum class MappingStatus {
kIsMapped,
// This refers to a third-party context attempting to access a Blob URL
// created in a first-party context.
kNotMappedCrossPartitionSameOriginAccessFirstPartyBlobURL,
// This refers to either a first-party or different third-party context
// attempting to access a Blob URL created in a third-party context.
kNotMappedCrossPartitionSameOriginAccessThirdPartyBlobURL,
kNotMappedOther
};
// Binds receivers corresponding to connections from renderer frame
// contexts and stores them in `frame_receivers_`.
// `partitioning_blob_url_closure` runs when the storage_key check fails
// in `BlobURLStoreImpl::ResolveAsURLLoaderFactory` and increments the use
// counter. `top_level_blob_document_url` should be set to the frame URL if
// this method is called for a top-level blob URL document context.
void AddReceiver(
const blink::StorageKey& storage_key,
const url::Origin& renderer_origin,
int render_process_host_id,
mojo::PendingAssociatedReceiver<blink::mojom::BlobURLStore> receiver,
base::RepeatingCallback<
void(const GURL&,
std::optional<blink::mojom::PartitioningBlobURLInfo>)>
partitioning_blob_url_closure,
base::RepeatingCallback<bool()> storage_access_check_callback,
std::optional<GURL> top_level_blob_document_url,
const char* context_type_for_debugging,
base::RepeatingCallback<std::string()> storage_key_debug_string_callback,
bool partitioning_disabled_by_policy = false);
// Binds receivers corresponding to connections from renderer worker
// contexts and threaded worklet contexts, storing them in
// `worker_receivers_`.
void AddReceiver(
const blink::StorageKey& storage_key,
const url::Origin& renderer_origin,
int render_process_host_id,
mojo::PendingReceiver<blink::mojom::BlobURLStore> receiver,
const char* context_type_for_debugging,
base::RepeatingCallback<std::string()> storage_key_debug_string_callback,
base::RepeatingCallback<bool()> storage_access_check_callback =
base::BindRepeating([]() -> bool { return false; }),
bool partitioning_disabled_by_policy = false,
BlobURLValidityCheckBehavior validity_check_behavior =
BlobURLValidityCheckBehavior::DEFAULT);
// Returns the receivers corresponding to renderer frame contexts for use in
// tests.
auto& receivers_for_testing() { return frame_receivers_; }
// Creates a URL mapping from blob to the given URL. Returns false if
// there already is a map for the URL. The URL mapping will be associated with
// the `storage_key`, and most subsequent URL lookup attempts will require a
// matching StorageKey to succeed. `origin` is the origin of the Blob URL, and
// `render_process_host_id` is the ID of the process where the blob URL
// registration comes from.
bool AddUrlMapping(const GURL& url,
mojo::PendingRemote<blink::mojom::Blob> blob,
const blink::StorageKey& storage_key,
const url::Origin& renderer_origin,
int render_process_host_id);
// Removes the given URL mapping associated with `storage_key`. Returns false
// if the URL wasn't mapped.
bool RemoveUrlMapping(const GURL& url, const blink::StorageKey& storage_key);
// Returns whether the URL is mapped to a blob and whether the URL is
// associated with `storage_key`.
MappingStatus IsUrlMapped(const GURL& blob_url,
const blink::StorageKey& storage_key) const;
// Returns the blob from the given url. Returns a null remote if the mapping
// doesn't exist.
mojo::PendingRemote<blink::mojom::Blob> GetBlobFromUrl(const GURL& url);
size_t url_count() const { return url_to_data_.size(); }
void AddTokenMapping(const base::UnguessableToken& token,
const GURL& url,
mojo::PendingRemote<blink::mojom::Blob> blob);
void RemoveTokenMapping(const base::UnguessableToken& token);
bool GetTokenMapping(const base::UnguessableToken& token,
GURL* url,
mojo::PendingRemote<blink::mojom::Blob>* blob);
// Returns the origin for a Blob URL navigation to `url`, given the precursor
// origin and target process information.
url::Origin GetOriginForNavigation(
const GURL& url,
const url::Origin& precursor_origin,
std::optional<int> target_render_process_host_id);
// Support adding a handler to be run when AddReceiver is called. This allows
// browser tests to intercept incoming BlobURLStore connections and swap in
// arbitrary BlobURLs to ensure that attempting to register certain blobs
// causes the renderer to be terminated.
using URLStoreCreationHook =
base::RepeatingCallback<void(BlobUrlRegistry*, mojo::ReceiverId)>;
static void SetURLStoreCreationHookForTesting(URLStoreCreationHook* hook);
base::WeakPtr<BlobUrlRegistry> AsWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
SEQUENCE_CHECKER(sequence_checker_);
// Optional fallback BlobUrlRegistry. If lookups for URLs in this registry
// fail, they are retried in the fallback registry. This is used to allow
// "child" storage partitions to resolve URLs created by their "parent", while
// not allowing the reverse.
base::WeakPtr<BlobUrlRegistry> fallback_;
struct BlobUrlData {
BlobUrlData();
~BlobUrlData();
BlobUrlData(BlobUrlData&&);
BlobUrlData& operator=(BlobUrlData&&);
mojo::PendingRemote<blink::mojom::Blob> blob;
blink::StorageKey storage_key;
url::Origin origin;
int render_process_host_id;
};
std::map<GURL, BlobUrlData> url_to_data_;
std::map<base::UnguessableToken,
std::pair<GURL, mojo::PendingRemote<blink::mojom::Blob>>>
token_to_url_and_blob_;
// When the renderer uses the BlobUrlRegistry from a frame context or from a
// main thread worklet context, a navigation-associated interface is used to
// preserve message ordering. The receiver corresponding to that connection is
// an AssociatedReceiver and gets stored in `frame_receivers_`. For workers
// and threaded worklets, the receiver is a Receiver and gets stored in
// `worker_receivers_`.
mojo::UniqueAssociatedReceiverSet<blink::mojom::BlobURLStore>
frame_receivers_;
mojo::UniqueReceiverSet<blink::mojom::BlobURLStore> worker_receivers_;
base::WeakPtrFactory<BlobUrlRegistry> weak_ptr_factory_{this};
};
} // namespace storage
#endif // STORAGE_BROWSER_BLOB_BLOB_URL_REGISTRY_H_