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_store_impl.h",
|
||||||
"blob/blob_url_utils.cc",
|
"blob/blob_url_utils.cc",
|
||||||
"blob/blob_url_utils.h",
|
"blob/blob_url_utils.h",
|
||||||
|
"blob/features.cc",
|
||||||
|
"blob/features.h",
|
||||||
"blob/mojo_blob_reader.cc",
|
"blob/mojo_blob_reader.cc",
|
||||||
"blob/mojo_blob_reader.h",
|
"blob/mojo_blob_reader.h",
|
||||||
"blob/scoped_file.cc",
|
"blob/scoped_file.cc",
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "storage/browser/blob/blob_url_loader_factory.h"
|
#include "storage/browser/blob/blob_url_loader_factory.h"
|
||||||
#include "storage/browser/blob/blob_url_registry.h"
|
#include "storage/browser/blob/blob_url_registry.h"
|
||||||
#include "storage/browser/blob/blob_url_utils.h"
|
#include "storage/browser/blob/blob_url_utils.h"
|
||||||
|
#include "storage/browser/blob/features.h"
|
||||||
#include "url/url_util.h"
|
#include "url/url_util.h"
|
||||||
|
|
||||||
namespace storage {
|
namespace storage {
|
||||||
@ -122,9 +123,21 @@ void BlobURLStoreImpl::ResolveAsURLLoaderFactory(
|
|||||||
std::move(callback).Run(std::nullopt, std::nullopt);
|
std::move(callback).Run(std::nullopt, std::nullopt);
|
||||||
return;
|
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,
|
BlobURLLoaderFactory::Create(registry_->GetBlobFromUrl(url), url,
|
||||||
std::move(receiver));
|
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),
|
std::move(callback).Run(registry_->GetUnsafeAgentClusterID(url),
|
||||||
registry_->GetUnsafeTopLevelSite(url));
|
registry_->GetUnsafeTopLevelSite(url));
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "storage/browser/blob/blob_impl.h"
|
#include "storage/browser/blob/blob_impl.h"
|
||||||
#include "storage/browser/blob/blob_storage_context.h"
|
#include "storage/browser/blob/blob_storage_context.h"
|
||||||
#include "storage/browser/blob/blob_url_registry.h"
|
#include "storage/browser/blob/blob_url_registry.h"
|
||||||
|
#include "storage/browser/blob/features.h"
|
||||||
#include "testing/gtest/include/gtest/gtest.h"
|
#include "testing/gtest/include/gtest/gtest.h"
|
||||||
|
|
||||||
using blink::mojom::BlobURLStore;
|
using blink::mojom::BlobURLStore;
|
||||||
@ -30,10 +31,9 @@ namespace storage {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum class PartitionedBlobUrlTestCase {
|
enum class PartitionedBlobUrlTestCase {
|
||||||
kPartitioningDisabledWithSupportDisabled,
|
kPartitioningDisabled,
|
||||||
kPartitioningDisabledWithSupportEnabled,
|
kBlockCrossPartitionBlobUrlFetchingEnabled,
|
||||||
kPartitioningEnabledWithSupportDisabled,
|
kBlockCrossPartitionBlobUrlFetchingDisabled,
|
||||||
kPartitioningEnabledWithSupportEnabled,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BlobURLStoreImplTestP
|
class BlobURLStoreImplTestP
|
||||||
@ -51,14 +51,17 @@ class BlobURLStoreImplTestP
|
|||||||
&BlobURLStoreImplTestP::OnBadMessage, base::Unretained(this)));
|
&BlobURLStoreImplTestP::OnBadMessage, base::Unretained(this)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown() override {
|
|
||||||
mojo::SetDefaultProcessErrorHandler(base::NullCallback());
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeScopedFeatureList() {
|
void InitializeScopedFeatureList() {
|
||||||
std::vector<base::test::FeatureRef> enabled_features{};
|
std::vector<base::test::FeatureRef> enabled_features{};
|
||||||
std::vector<base::test::FeatureRef> disabled_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()) {
|
if (StoragePartitioningEnabled()) {
|
||||||
enabled_features.push_back(net::features::kThirdPartyStoragePartitioning);
|
enabled_features.push_back(net::features::kThirdPartyStoragePartitioning);
|
||||||
} else {
|
} else {
|
||||||
@ -69,16 +72,26 @@ class BlobURLStoreImplTestP
|
|||||||
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
|
scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StoragePartitioningEnabled() {
|
bool BlockCrossPartitionBlobUrlFetchingEnabled() {
|
||||||
switch (test_case_) {
|
switch (test_case_) {
|
||||||
case PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportDisabled:
|
case PartitionedBlobUrlTestCase::
|
||||||
case PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportEnabled:
|
kBlockCrossPartitionBlobUrlFetchingDisabled:
|
||||||
|
case PartitionedBlobUrlTestCase::
|
||||||
|
kBlockCrossPartitionBlobUrlFetchingEnabled:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StoragePartitioningEnabled() {
|
||||||
|
return test_case_ != PartitionedBlobUrlTestCase::kPartitioningDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
mojo::SetDefaultProcessErrorHandler(base::NullCallback());
|
||||||
|
}
|
||||||
|
|
||||||
void OnBadMessage(const std::string& error) {
|
void OnBadMessage(const std::string& error) {
|
||||||
bad_messages_.push_back(error);
|
bad_messages_.push_back(error);
|
||||||
}
|
}
|
||||||
@ -386,6 +399,110 @@ TEST_P(BlobURLStoreImplTestP, ResolveAsURLLoaderFactory) {
|
|||||||
download_loop.Run();
|
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) {
|
TEST_P(BlobURLStoreImplTestP, ResolveForNavigation) {
|
||||||
mojo::PendingRemote<blink::mojom::Blob> blob =
|
mojo::PendingRemote<blink::mojom::Blob> blob =
|
||||||
CreateBlobFromString(kId, "hello world");
|
CreateBlobFromString(kId, "hello world");
|
||||||
@ -428,11 +545,22 @@ TEST_P(BlobURLStoreImplTestP, ResolveForNavigation) {
|
|||||||
INSTANTIATE_TEST_SUITE_P(
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
BlobURLStoreImplTests,
|
BlobURLStoreImplTests,
|
||||||
BlobURLStoreImplTestP,
|
BlobURLStoreImplTestP,
|
||||||
::testing::Values(
|
testing::Values(
|
||||||
PartitionedBlobUrlTestCase::kPartitioningDisabledWithSupportDisabled,
|
PartitionedBlobUrlTestCase::kPartitioningDisabled,
|
||||||
PartitionedBlobUrlTestCase::kPartitioningDisabledWithSupportEnabled,
|
PartitionedBlobUrlTestCase::kBlockCrossPartitionBlobUrlFetchingDisabled,
|
||||||
PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportDisabled,
|
PartitionedBlobUrlTestCase::kBlockCrossPartitionBlobUrlFetchingEnabled),
|
||||||
PartitionedBlobUrlTestCase::kPartitioningEnabledWithSupportEnabled));
|
[](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
|
||||||
} // namespace storage
|
} // 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"]
|
"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 ",
|
"isInputPending requires threaded compositing and layerized iframes, so ",
|
||||||
"these tests are run exclusively with a virtual test suite that never ",
|
"these tests are run exclusively with a virtual test suite that never ",
|
||||||
"expires.",
|
"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