Add Fetching Implementation with Cross-Partitioned Blob URL
Bug: 357484649 Change-Id: I074b15fd78114185f1d7bfddc2647e2dd76bbed7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5762280 Commit-Queue: Janice Liu <janiceliu@chromium.org> Reviewed-by: Ayu Ishii <ayui@chromium.org> Auto-Submit: Janice Liu <janiceliu@chromium.org> Reviewed-by: David Baron <dbaron@chromium.org> Cr-Commit-Position: refs/heads/main@{#1344948}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
66aba9fe13
commit
d9e47c7277
storage/browser
third_party/blink/web_tests
@ -47,6 +47,8 @@ component("browser") {
|
||||
"blob/blob_url_store_impl.h",
|
||||
"blob/blob_url_utils.cc",
|
||||
"blob/blob_url_utils.h",
|
||||
"blob/features.cc",
|
||||
"blob/features.h",
|
||||
"blob/mojo_blob_reader.cc",
|
||||
"blob/mojo_blob_reader.h",
|
||||
"blob/scoped_file.cc",
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "storage/browser/blob/blob_url_loader_factory.h"
|
||||
#include "storage/browser/blob/blob_url_registry.h"
|
||||
#include "storage/browser/blob/blob_url_utils.h"
|
||||
#include "storage/browser/blob/features.h"
|
||||
#include "url/url_util.h"
|
||||
|
||||
namespace storage {
|
||||
@ -122,9 +123,21 @@ void BlobURLStoreImpl::ResolveAsURLLoaderFactory(
|
||||
std::move(callback).Run(std::nullopt, std::nullopt);
|
||||
return;
|
||||
}
|
||||
if (base::FeatureList::IsEnabled(
|
||||
features::kBlockCrossPartitionBlobUrlFetching) &&
|
||||
!registry_->IsUrlMapped(BlobUrlUtils::ClearUrlFragment(url),
|
||||
storage_key_)) {
|
||||
BlobURLLoaderFactory::Create(mojo::NullRemote(), url, std::move(receiver));
|
||||
std::move(callback).Run(std::nullopt, std::nullopt);
|
||||
return;
|
||||
}
|
||||
|
||||
BlobURLLoaderFactory::Create(registry_->GetBlobFromUrl(url), url,
|
||||
std::move(receiver));
|
||||
// When a fragment URL is present, registry_->GetUnsafeAgentClusterID(url) and
|
||||
// registry_->GetUnsafeTopLevelSite(url) will return nullopt because their
|
||||
// implementations don't remove the fragment and only support fragmentless
|
||||
// URLs (crbug.com/40775506).
|
||||
std::move(callback).Run(registry_->GetUnsafeAgentClusterID(url),
|
||||
registry_->GetUnsafeTopLevelSite(url));
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "storage/browser/blob/blob_impl.h"
|
||||
#include "storage/browser/blob/blob_storage_context.h"
|
||||
#include "storage/browser/blob/blob_url_registry.h"
|
||||
#include "storage/browser/blob/features.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
using blink::mojom::BlobURLStore;
|
||||
@ -30,10 +31,9 @@ namespace storage {
|
||||
namespace {
|
||||
|
||||
enum class PartitionedBlobUrlTestCase {
|
||||
kPartitioningDisabledWithSupportDisabled,
|
||||
kPartitioningDisabledWithSupportEnabled,
|
||||
kPartitioningEnabledWithSupportDisabled,
|
||||
kPartitioningEnabledWithSupportEnabled,
|
||||
kPartitioningDisabled,
|
||||
kBlockCrossPartitionBlobUrlFetchingEnabled,
|
||||
kBlockCrossPartitionBlobUrlFetchingDisabled,
|
||||
};
|
||||
|
||||
class BlobURLStoreImplTestP
|
||||
@ -51,14 +51,17 @@ class BlobURLStoreImplTestP
|
||||
&BlobURLStoreImplTestP::OnBadMessage, base::Unretained(this)));
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
mojo::SetDefaultProcessErrorHandler(base::NullCallback());
|
||||
}
|
||||
|
||||
void InitializeScopedFeatureList() {
|
||||
std::vector<base::test::FeatureRef> enabled_features{};
|
||||
std::vector<base::test::FeatureRef> disabled_features{};
|
||||
|
||||
if (BlockCrossPartitionBlobUrlFetchingEnabled()) {
|
||||
enabled_features.push_back(features::kBlockCrossPartitionBlobUrlFetching);
|
||||
} else {
|
||||
disabled_features.push_back(
|
||||
features::kBlockCrossPartitionBlobUrlFetching);
|
||||
}
|
||||
|
||||
if (StoragePartitioningEnabled()) {
|
||||
enabled_features.push_back(net::features::kThirdPartyStoragePartitioning);
|
||||
} else {
|
||||
@ -69,16 +72,26 @@ class BlobURLStoreImplTestP
|
||||
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
|
||||
}
|
||||
|
||||
bool StoragePartitioningEnabled() {
|
||||
bool BlockCrossPartitionBlobUrlFetchingEnabled() {
|
||||
switch (test_case_) {
|
||||
case PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportDisabled:
|
||||
case PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportEnabled:
|
||||
case PartitionedBlobUrlTestCase::
|
||||
kBlockCrossPartitionBlobUrlFetchingDisabled:
|
||||
case PartitionedBlobUrlTestCase::
|
||||
kBlockCrossPartitionBlobUrlFetchingEnabled:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool StoragePartitioningEnabled() {
|
||||
return test_case_ != PartitionedBlobUrlTestCase::kPartitioningDisabled;
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
mojo::SetDefaultProcessErrorHandler(base::NullCallback());
|
||||
}
|
||||
|
||||
void OnBadMessage(const std::string& error) {
|
||||
bad_messages_.push_back(error);
|
||||
}
|
||||
@ -386,6 +399,110 @@ TEST_P(BlobURLStoreImplTestP, ResolveAsURLLoaderFactory) {
|
||||
download_loop.Run();
|
||||
}
|
||||
|
||||
TEST_P(BlobURLStoreImplTestP,
|
||||
ResolveAsURLLoaderFactoryWithSeparateStorageKeys) {
|
||||
const blink::StorageKey kWrongStorageKey = blink::StorageKey::Create(
|
||||
kOrigin, kWrongTopLevelSite, blink::mojom::AncestorChainBit::kCrossSite);
|
||||
|
||||
mojo::PendingRemote<blink::mojom::Blob> blob =
|
||||
CreateBlobFromString(kId, "hello world");
|
||||
|
||||
BlobURLStoreImpl url_store1(kStorageKey, kStorageKey.origin(), /*rph_id=*/0,
|
||||
url_registry_.AsWeakPtr());
|
||||
BlobURLStoreImpl url_store2(kWrongStorageKey, kStorageKey.origin(),
|
||||
/*rph_id=*/0, url_registry_.AsWeakPtr());
|
||||
|
||||
RegisterURL(&url_store1, std::move(blob), kValidUrl);
|
||||
|
||||
mojo::Remote<network::mojom::URLLoaderFactory> factory;
|
||||
base::RunLoop resolve_loop;
|
||||
url_store2.ResolveAsURLLoaderFactory(
|
||||
kValidUrl, factory.BindNewPipeAndPassReceiver(),
|
||||
base::BindLambdaForTesting(
|
||||
[&](const std::optional<base::UnguessableToken>&
|
||||
unsafe_agent_cluster_id,
|
||||
const std::optional<net::SchemefulSite>& unsafe_top_level_site) {
|
||||
if (BlockCrossPartitionBlobUrlFetchingEnabled()) {
|
||||
EXPECT_FALSE(unsafe_agent_cluster_id.has_value());
|
||||
EXPECT_FALSE(unsafe_top_level_site.has_value());
|
||||
} else {
|
||||
EXPECT_EQ(*unsafe_agent_cluster_id, agent_cluster_id_);
|
||||
}
|
||||
resolve_loop.Quit();
|
||||
}));
|
||||
|
||||
resolve_loop.Run();
|
||||
auto request = std::make_unique<network::ResourceRequest>();
|
||||
request->url = kValidUrl;
|
||||
auto loader = network::SimpleURLLoader::Create(std::move(request),
|
||||
TRAFFIC_ANNOTATION_FOR_TESTS);
|
||||
base::RunLoop download_loop;
|
||||
loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
|
||||
factory.get(), base::BindLambdaForTesting(
|
||||
[&](std::unique_ptr<std::string> response_body) {
|
||||
download_loop.Quit();
|
||||
if (BlockCrossPartitionBlobUrlFetchingEnabled()) {
|
||||
EXPECT_FALSE(response_body);
|
||||
} else {
|
||||
ASSERT_TRUE(response_body);
|
||||
EXPECT_EQ("hello world", *response_body);
|
||||
}
|
||||
}));
|
||||
download_loop.Run();
|
||||
}
|
||||
|
||||
TEST_P(BlobURLStoreImplTestP, ResolveAsURLLoaderFactoryWithFragmentUrl) {
|
||||
const blink::StorageKey kWrongStorageKey = blink::StorageKey::Create(
|
||||
kOrigin, kWrongTopLevelSite, blink::mojom::AncestorChainBit::kCrossSite);
|
||||
|
||||
mojo::PendingRemote<blink::mojom::Blob> blob =
|
||||
CreateBlobFromString(kId, "hello world");
|
||||
|
||||
BlobURLStoreImpl url_store1(kWrongStorageKey, kStorageKey.origin(),
|
||||
/*rph_id=*/0, url_registry_.AsWeakPtr());
|
||||
mojo::Remote<BlobURLStore> url_store2(CreateURLStore());
|
||||
RegisterURL(url_store2.get(), std::move(blob), kFragmentUrl);
|
||||
|
||||
mojo::Remote<network::mojom::URLLoaderFactory> factory;
|
||||
base::RunLoop resolve_loop;
|
||||
url_store1.ResolveAsURLLoaderFactory(
|
||||
kFragmentUrl, factory.BindNewPipeAndPassReceiver(),
|
||||
base::BindLambdaForTesting(
|
||||
[&](const std::optional<base::UnguessableToken>&
|
||||
unsafe_agent_cluster_id,
|
||||
const std::optional<net::SchemefulSite>& unsafe_top_level_site) {
|
||||
// TODO(crbug.com/40775506): Fix fragment URL bug.
|
||||
if (BlockCrossPartitionBlobUrlFetchingEnabled() ||
|
||||
!StoragePartitioningEnabled()) {
|
||||
EXPECT_FALSE(unsafe_agent_cluster_id.has_value());
|
||||
EXPECT_FALSE(unsafe_top_level_site.has_value());
|
||||
} else {
|
||||
EXPECT_EQ(*unsafe_agent_cluster_id, agent_cluster_id_);
|
||||
}
|
||||
resolve_loop.Quit();
|
||||
}));
|
||||
|
||||
resolve_loop.Run();
|
||||
auto request = std::make_unique<network::ResourceRequest>();
|
||||
request->url = kFragmentUrl;
|
||||
auto loader = network::SimpleURLLoader::Create(std::move(request),
|
||||
TRAFFIC_ANNOTATION_FOR_TESTS);
|
||||
base::RunLoop download_loop;
|
||||
loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
|
||||
factory.get(), base::BindLambdaForTesting(
|
||||
[&](std::unique_ptr<std::string> response_body) {
|
||||
download_loop.Quit();
|
||||
if (BlockCrossPartitionBlobUrlFetchingEnabled() ||
|
||||
!StoragePartitioningEnabled()) {
|
||||
EXPECT_FALSE(response_body);
|
||||
} else {
|
||||
ASSERT_TRUE(response_body);
|
||||
EXPECT_EQ("hello world", *response_body);
|
||||
}
|
||||
}));
|
||||
download_loop.Run();
|
||||
}
|
||||
|
||||
TEST_P(BlobURLStoreImplTestP, ResolveForNavigation) {
|
||||
mojo::PendingRemote<blink::mojom::Blob> blob =
|
||||
CreateBlobFromString(kId, "hello world");
|
||||
@ -428,11 +545,22 @@ TEST_P(BlobURLStoreImplTestP, ResolveForNavigation) {
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
BlobURLStoreImplTests,
|
||||
BlobURLStoreImplTestP,
|
||||
::testing::Values(
|
||||
PartitionedBlobUrlTestCase::kPartitioningDisabledWithSupportDisabled,
|
||||
PartitionedBlobUrlTestCase::kPartitioningDisabledWithSupportEnabled,
|
||||
PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportDisabled,
|
||||
PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportEnabled));
|
||||
testing::Values(
|
||||
PartitionedBlobUrlTestCase::kPartitioningDisabled,
|
||||
PartitionedBlobUrlTestCase::kBlockCrossPartitionBlobUrlFetchingDisabled,
|
||||
PartitionedBlobUrlTestCase::kBlockCrossPartitionBlobUrlFetchingEnabled),
|
||||
[](const testing::TestParamInfo<PartitionedBlobUrlTestCase>& info) {
|
||||
switch (info.param) {
|
||||
case PartitionedBlobUrlTestCase::kPartitioningDisabled:
|
||||
return "PartitioningDisabled";
|
||||
case PartitionedBlobUrlTestCase::
|
||||
kBlockCrossPartitionBlobUrlFetchingDisabled:
|
||||
return "BlockCrossPartitionBlobUrlFetchingDisabled";
|
||||
case PartitionedBlobUrlTestCase::
|
||||
kBlockCrossPartitionBlobUrlFetchingEnabled:
|
||||
return "BlockCrossPartitionBlobUrlFetchingEnabled";
|
||||
}
|
||||
});
|
||||
|
||||
} // namespace
|
||||
} // namespace storage
|
||||
|
16
storage/browser/blob/features.cc
Normal file
16
storage/browser/blob/features.cc
Normal file
@ -0,0 +1,16 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "storage/browser/blob/features.h"
|
||||
|
||||
namespace features {
|
||||
|
||||
// Please keep features in alphabetical order.
|
||||
BASE_FEATURE(kBlockCrossPartitionBlobUrlFetching,
|
||||
"BlockCrossPartitionBlobUrlFetching",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
// Please keep features in alphabetical order.
|
||||
|
||||
} // namespace features
|
22
storage/browser/blob/features.h
Normal file
22
storage/browser/blob/features.h
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2024 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_FEATURES_H_
|
||||
#define STORAGE_BROWSER_BLOB_FEATURES_H_
|
||||
|
||||
#include "base/component_export.h"
|
||||
#include "base/features.h"
|
||||
|
||||
namespace features {
|
||||
|
||||
// Please keep features in alphabetical order.
|
||||
// Enables blob URL fetches to fail when cross-partition.
|
||||
COMPONENT_EXPORT(STORAGE_BROWSER)
|
||||
BASE_DECLARE_FEATURE(kBlockCrossPartitionBlobUrlFetching);
|
||||
|
||||
// Please keep features in alphabetical order.
|
||||
|
||||
} // namespace features
|
||||
|
||||
#endif // STORAGE_BROWSER_BLOB_FEATURES_H_
|
10
third_party/blink/web_tests/VirtualTestSuites
vendored
10
third_party/blink/web_tests/VirtualTestSuites
vendored
@ -1150,6 +1150,16 @@
|
||||
"owners": ["arichiv@chromium.org", "bingler@chromium.org"]
|
||||
},
|
||||
|
||||
{
|
||||
"prefix": "block-cross-partition-blob-url-fetching",
|
||||
"platforms": ["Linux"],
|
||||
"bases": [
|
||||
"external/wpt/FileAPI/BlobURL/cross-partition.tentative.https.html"],
|
||||
"args": ["--enable-features=BlockCrossPartitionBlobUrlFetching"],
|
||||
"expires": "Feb 4, 2025",
|
||||
"owners": ["janiceliu@chromium.org"]
|
||||
},
|
||||
|
||||
"isInputPending requires threaded compositing and layerized iframes, so ",
|
||||
"these tests are run exclusively with a virtual test suite that never ",
|
||||
"expires.",
|
||||
|
1
third_party/blink/web_tests/virtual/block-cross-partition-blob-url-fetching/README.md
vendored
Normal file
1
third_party/blink/web_tests/virtual/block-cross-partition-blob-url-fetching/README.md
vendored
Normal file
@ -0,0 +1 @@
|
||||
This directory is for tests that need the Block Cross Partition Blob URL Fetching feature enabled.
|
3
third_party/blink/web_tests/virtual/block-cross-partition-blob-url-fetching/external/wpt/FileAPI/BlobURL/cross-partition.tentative.https-expected.txt
vendored
Normal file
3
third_party/blink/web_tests/virtual/block-cross-partition-blob-url-fetching/external/wpt/FileAPI/BlobURL/cross-partition.tentative.https-expected.txt
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
This is a testharness.js-based test.
|
||||
Harness: the test ran to completion.
|
||||
|
Reference in New Issue
Block a user