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
|
// 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 "net/base/schemeful_site.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.
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,
bool partitioning_disabled_by_policy = false);
// Binds receivers corresponding to connections from renderer worker
// contexts and stores 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,
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,
// TODO(crbug.com/40775506): Remove these once experiment is over.
const base::UnguessableToken& unsafe_agent_cluster_id,
const std::optional<net::SchemefulSite>& unsafe_top_level_site);
// 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;
// TODO(crbug.com/40775506): Remove this once experiment is over.
std::optional<base::UnguessableToken> GetUnsafeAgentClusterID(
const GURL& blob_url) const;
std::optional<net::SchemefulSite> GetUnsafeTopLevelSite(
const GURL& blob_url) 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_blob_.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_;
std::map<GURL, mojo::PendingRemote<blink::mojom::Blob>> url_to_blob_;
// TODO(crbug.com/40775506): Remove this once experiment is over.
std::map<GURL, base::UnguessableToken> url_to_unsafe_agent_cluster_id_;
std::map<GURL, net::SchemefulSite> url_to_unsafe_top_level_site_;
std::map<base::UnguessableToken,
std::pair<GURL, mojo::PendingRemote<blink::mojom::Blob>>>
token_to_url_and_blob_;
std::map<GURL, blink::StorageKey> url_to_storage_key_;
std::map<GURL, url::Origin> url_to_origin_;
std::map<GURL, int> url_to_render_process_host_id_;
// 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_
|