0
Files
src/content/browser/storage_partition_impl_unittest.cc
Ayu Ishii 775cb04295 Quota: Cleanup StorageType from QuotaManagerImpl methods
This change removes usages of StorageType in QuotaManager methods.
After StorageType::kSyncable deprecation, all other storage types
except kTemporary are deprecated. So we no longer need to specify
StorageType. Data that was previously associated with kSyncable
is now part of kTemporary.

Main part of this change is in
storage/browser/quota/quota_manager_impl.cc. All other files
are either updating calls to QuotaManager or updates the
overridden functionality.

Further cleanup to remove usage in QuotaDatabase and QuotaClients
will be done in a follow-up.

Bug: 40211051
Change-Id: Id7232aa518bba8097559200fde2f330488dd2fa1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6350696
Commit-Queue: Ayu Ishii <ayui@chromium.org>
Reviewed-by: Christian Dullweber <dullweber@chromium.org>
Reviewed-by: Tsuyoshi Horo <horo@chromium.org>
Reviewed-by: Bo Liu <boliu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1434297}
2025-03-18 11:39:36 -07:00

2507 lines
101 KiB
C++

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef UNSAFE_BUFFERS_BUILD
// TODO(crbug.com/342213636): Remove this and spanify to fix the errors.
#pragma allow_unsafe_buffers
#endif
#include "content/browser/storage_partition_impl.h"
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/span.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/run_loop.h"
#include "base/scoped_observation.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/services/storage/dom_storage/async_dom_storage_database.h"
#include "components/services/storage/dom_storage/dom_storage_database.h"
#include "components/services/storage/dom_storage/local_storage_database.pb.h"
#include "components/services/storage/public/cpp/constants.h"
#include "components/services/storage/public/mojom/local_storage_control.mojom.h"
#include "components/services/storage/public/mojom/partition.mojom.h"
#include "components/services/storage/public/mojom/storage_service.mojom.h"
#include "components/services/storage/public/mojom/storage_usage_info.mojom.h"
#include "components/services/storage/shared_storage/async_shared_storage_database_impl.h"
#include "components/services/storage/shared_storage/shared_storage_manager.h"
#include "components/services/storage/shared_storage/shared_storage_options.h"
#include "components/services/storage/storage_service_impl.h"
#include "content/browser/aggregation_service/aggregation_service_test_utils.h"
#include "content/browser/attribution_reporting/test/mock_attribution_manager.h"
#include "content/browser/code_cache/generated_code_cache.h"
#include "content/browser/code_cache/generated_code_cache_context.h"
#include "content/browser/gpu/gpu_disk_cache_factory.h"
#include "content/browser/interest_group/interest_group_manager_impl.h"
#include "content/browser/interest_group/interest_group_permissions_cache.h"
#include "content/browser/interest_group/interest_group_permissions_checker.h"
#include "content/browser/private_aggregation/private_aggregation_manager.h"
#include "content/browser/private_aggregation/private_aggregation_test_utils.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browsing_data_filter_builder.h"
#include "content/public/browser/generated_code_cache_settings.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/storage_usage_info.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_utils.h"
#include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom.h"
#include "net/base/network_isolation_key.h"
#include "net/base/schemeful_site.h"
#include "net/base/test_completion_callback.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_access_params.h"
#include "net/cookies/cookie_access_result.h"
#include "net/cookies/cookie_inclusion_status.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/network/cookie_manager.h"
#include "services/network/public/cpp/features.h"
#include "services/network/test/mock_device_bound_session_manager.h"
#include "storage/browser/quota/quota_client_type.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/browser/quota/quota_manager_proxy.h"
#include "storage/browser/test/mock_quota_client.h"
#include "storage/browser/test/mock_quota_manager.h"
#include "storage/browser/test/mock_special_storage_policy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/interest_group/interest_group.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/interest_group/interest_group_types.mojom.h"
#include "third_party/blink/public/mojom/quota/quota_types.mojom-shared.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "url/gurl.h"
#include "url/origin.h"
#if BUILDFLAG(IS_ANDROID)
#include "content/public/browser/android/java_interfaces.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#endif // BUILDFLAG(IS_ANDROID)
using net::CanonicalCookie;
using CookieDeletionFilter = network::mojom::CookieDeletionFilter;
using CookieDeletionFilterPtr = network::mojom::CookieDeletionFilterPtr;
using ::testing::_;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::Invoke;
using ::testing::SaveArgPointee;
using ::testing::WithArg;
namespace content {
namespace {
const char kCacheKey[] = "key";
const char kCacheValue[] = "cached value";
const storage::QuotaClientType kClientFile =
storage::QuotaClientType::kFileSystem;
const uint32_t kAllQuotaRemoveMask =
StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS |
StoragePartition::REMOVE_DATA_MASK_INDEXEDDB |
StoragePartition::REMOVE_DATA_MASK_WEBSQL;
class RemoveCookieTester {
public:
explicit RemoveCookieTester(StoragePartition* storage_partition)
: storage_partition_(storage_partition) {}
RemoveCookieTester(const RemoveCookieTester&) = delete;
RemoveCookieTester& operator=(const RemoveCookieTester&) = delete;
// Returns true, if the given cookie exists in the cookie store.
bool ContainsCookie(const url::Origin& origin,
std::optional<net::CookiePartitionKey>
cookie_partition_key = std::nullopt) {
get_cookie_success_ = false;
base::RunLoop loop;
storage_partition_->GetCookieManagerForBrowserProcess()->GetCookieList(
origin.GetURL(), net::CookieOptions::MakeAllInclusive(),
net::CookiePartitionKeyCollection::FromOptional(cookie_partition_key),
base::BindOnce(&RemoveCookieTester::GetCookieListCallback,
base::Unretained(this), loop.QuitClosure()));
loop.Run();
return get_cookie_success_;
}
void AddCookie(const url::Origin& origin,
std::optional<net::CookiePartitionKey> cookie_partition_key =
std::nullopt) {
net::CookieInclusionStatus status;
std::string cookie_str = "A=1";
if (cookie_partition_key) {
cookie_str += ";Partitioned;Secure;";
}
std::unique_ptr<net::CanonicalCookie> cc(
net::CanonicalCookie::CreateForTesting(
origin.GetURL(), cookie_str, base::Time::Now(),
/*server_time=*/std::nullopt, cookie_partition_key,
net::CookieSourceType::kUnknown, &status));
base::RunLoop loop;
storage_partition_->GetCookieManagerForBrowserProcess()->SetCanonicalCookie(
*cc, origin.GetURL(), net::CookieOptions::MakeAllInclusive(),
base::BindOnce(&RemoveCookieTester::SetCookieCallback,
base::Unretained(this), loop.QuitClosure()));
loop.Run();
}
private:
void GetCookieListCallback(
base::OnceClosure quit_closure,
const net::CookieAccessResultList& cookie_list,
const net::CookieAccessResultList& excluded_cookies) {
std::string cookie_line =
net::CanonicalCookie::BuildCookieLine(cookie_list);
if (cookie_line == "A=1") {
get_cookie_success_ = true;
} else if (cookie_line == "A=1; A=1") {
EXPECT_NE(cookie_list[0].cookie.IsPartitioned(),
cookie_list[1].cookie.IsPartitioned());
get_cookie_success_ = true;
} else {
EXPECT_EQ("", cookie_line);
get_cookie_success_ = false;
}
std::move(quit_closure).Run();
}
void SetCookieCallback(base::OnceClosure quit_closure,
net::CookieAccessResult result) {
ASSERT_TRUE(result.status.IsInclude());
std::move(quit_closure).Run();
}
bool get_cookie_success_;
raw_ptr<StoragePartition> storage_partition_;
};
class RemoveInterestGroupTester {
public:
explicit RemoveInterestGroupTester(StoragePartitionImpl* storage_partition)
: storage_partition_(storage_partition) {}
RemoveInterestGroupTester(const RemoveInterestGroupTester&) = delete;
RemoveInterestGroupTester& operator=(const RemoveInterestGroupTester&) =
delete;
// Returns true, if the given interest group owner has any interest groups in
// InterestGroupStorage.
bool ContainsInterestGroupOwner(const url::Origin& origin) {
get_interest_group_success_ = false;
EXPECT_TRUE(storage_partition_->GetInterestGroupManager());
base::RunLoop loop;
static_cast<InterestGroupManagerImpl*>(
storage_partition_->GetInterestGroupManager())
->GetInterestGroupsForOwner(
/*devtools_auction_id=*/std::nullopt, origin,
base::BindOnce(
&RemoveInterestGroupTester::GetInterestGroupsCallback,
base::Unretained(this), loop.QuitClosure()));
loop.Run();
return get_interest_group_success_;
}
bool ContainsInterestGroupKAnon(const url::Origin& origin) {
contains_kanon_ = false;
EXPECT_TRUE(storage_partition_->GetInterestGroupManager());
base::RunLoop loop;
static_cast<InterestGroupManagerImpl*>(
storage_partition_->GetInterestGroupManager())
->GetLastKAnonymityReported(
k_anon_key,
base::BindOnce(
&RemoveInterestGroupTester::GetLastKAnonymityReportedCallback,
base::Unretained(this), loop.QuitClosure()));
loop.Run();
return contains_kanon_;
}
void AddInterestGroup(const url::Origin& origin) {
EXPECT_TRUE(storage_partition_->GetInterestGroupManager());
blink::InterestGroup group;
group.owner = origin;
group.name = "Name";
group.expiry = base::Time::Now() + base::Days(30);
group.bidding_url = origin.GetURL().Resolve("/bidding.js");
group.ads.emplace();
group.ads->push_back(blink::InterestGroup::Ad(
GURL("https://owner.example.com/ad1"), "metadata"));
InterestGroupManagerImpl* interest_group_manager =
static_cast<InterestGroupManagerImpl*>(
storage_partition_->GetInterestGroupManager());
interest_group_manager->JoinInterestGroup(group, origin.GetURL());
// Update the K-anonymity so that we can tell when it gets removed.
k_anon_key = HashedKAnonKeyForAdBid(
group, GURL("https://owner.example.com/ad1").spec());
interest_group_manager->UpdateLastKAnonymityReported(k_anon_key);
}
private:
void GetInterestGroupsCallback(base::OnceClosure quit_closure,
scoped_refptr<StorageInterestGroups> groups) {
get_interest_group_success_ = groups->size() > 0;
std::move(quit_closure).Run();
}
void GetLastKAnonymityReportedCallback(
base::OnceClosure quit_closure,
std::optional<base::Time> last_reported) {
contains_kanon_ =
last_reported.has_value() && last_reported.value() > base::Time::Min();
std::move(quit_closure).Run();
}
bool get_interest_group_success_ = false;
bool contains_kanon_ = false;
std::string k_anon_key;
raw_ptr<StoragePartitionImpl> storage_partition_;
};
class RemoveLocalStorageTester {
public:
RemoveLocalStorageTester(content::BrowserTaskEnvironment* task_environment,
TestBrowserContext* browser_context)
: task_environment_(task_environment),
storage_partition_(browser_context->GetDefaultStoragePartition()),
dom_storage_context_(storage_partition_->GetDOMStorageContext()) {}
RemoveLocalStorageTester(const RemoveLocalStorageTester&) = delete;
RemoveLocalStorageTester& operator=(const RemoveLocalStorageTester&) = delete;
~RemoveLocalStorageTester() {
// Tests which bring up a real Local Storage context need to shut it down
// and wait for the database to be closed before terminating; otherwise the
// TestBrowserContext may fail to delete its temp dir, and it will not be
// happy about that.
static_cast<DOMStorageContextWrapper*>(dom_storage_context_)->Shutdown();
task_environment_->RunUntilIdle();
}
// Returns true, if the given origin URL exists.
bool DOMStorageExistsForOrigin(const url::Origin& origin) {
GetLocalStorageUsage();
for (size_t i = 0; i < infos_.size(); ++i) {
if (origin == infos_[i].storage_key.origin())
return true;
}
return false;
}
void AddDOMStorageTestData(const url::Origin& origin1,
const url::Origin& origin2,
const url::Origin& origin3) {
// NOTE: Tests which call this method depend on implementation details of
// how exactly the Local Storage subsystem stores persistent data.
base::RunLoop open_loop;
auto database = storage::AsyncDomStorageDatabase::OpenDirectory(
storage_partition_->GetPath().Append(storage::kLocalStoragePath),
storage::kLocalStorageLeveldbName, std::nullopt,
base::SingleThreadTaskRunner::GetCurrentDefault(),
base::BindLambdaForTesting([&](leveldb::Status status) {
ASSERT_TRUE(status.ok());
open_loop.Quit();
}));
open_loop.Run();
base::RunLoop populate_loop;
database->database().PostTaskWithThisObject(
base::BindLambdaForTesting([&](const storage::DomStorageDatabase& db) {
PopulateDatabase(db, origin1, origin2, origin3);
populate_loop.Quit();
}));
populate_loop.Run();
// Ensure that this database is fully closed before returning.
database.reset();
task_environment_->RunUntilIdle();
EXPECT_TRUE(DOMStorageExistsForOrigin(origin1));
EXPECT_TRUE(DOMStorageExistsForOrigin(origin2));
EXPECT_TRUE(DOMStorageExistsForOrigin(origin3));
}
static void PopulateDatabase(const storage::DomStorageDatabase& db,
const url::Origin& origin1,
const url::Origin& origin2,
const url::Origin& origin3) {
storage::LocalStorageAreaAccessMetaData access_data;
storage::LocalStorageAreaWriteMetaData write_data;
std::map<std::vector<uint8_t>, std::vector<uint8_t>> entries;
base::Time now = base::Time::Now();
access_data.set_last_accessed(now.ToInternalValue());
write_data.set_last_modified(now.ToInternalValue());
write_data.set_size_bytes(16);
ASSERT_TRUE(db.Put(CreateAccessMetaDataKey(origin1),
base::as_byte_span(access_data.SerializeAsString()))
.ok());
ASSERT_TRUE(db.Put(CreateWriteMetaDataKey(origin1),
base::as_byte_span(write_data.SerializeAsString()))
.ok());
ASSERT_TRUE(db.Put(CreateDataKey(origin1), {}).ok());
base::Time one_day_ago = now - base::Days(1);
access_data.set_last_accessed(one_day_ago.ToInternalValue());
write_data.set_last_modified(one_day_ago.ToInternalValue());
ASSERT_TRUE(db.Put(CreateAccessMetaDataKey(origin2),
base::as_byte_span(access_data.SerializeAsString()))
.ok());
ASSERT_TRUE(db.Put(CreateWriteMetaDataKey(origin2),
base::as_byte_span((write_data.SerializeAsString())))
.ok());
ASSERT_TRUE(db.Put(CreateDataKey(origin2), {}).ok());
base::Time sixty_days_ago = now - base::Days(60);
access_data.set_last_accessed(sixty_days_ago.ToInternalValue());
write_data.set_last_modified(sixty_days_ago.ToInternalValue());
ASSERT_TRUE(db.Put(CreateAccessMetaDataKey(origin3),
base::as_byte_span(access_data.SerializeAsString()))
.ok());
ASSERT_TRUE(db.Put(CreateWriteMetaDataKey(origin3),
base::as_byte_span(write_data.SerializeAsString()))
.ok());
ASSERT_TRUE(db.Put(CreateDataKey(origin3), {}).ok());
}
private:
static std::vector<uint8_t> CreateDataKey(const url::Origin& origin) {
auto origin_str = origin.Serialize();
std::vector<uint8_t> serialized_origin(origin_str.begin(),
origin_str.end());
std::vector<uint8_t> key = {'_'};
key.insert(key.end(), serialized_origin.begin(), serialized_origin.end());
key.push_back(0);
key.push_back('X');
return key;
}
static std::vector<uint8_t> CreateAccessMetaDataKey(
const url::Origin& origin) {
const uint8_t kMetaPrefix[] = {'M', 'E', 'T', 'A', 'A', 'C',
'C', 'E', 'S', 'S', ':'};
auto origin_str = origin.Serialize();
std::vector<uint8_t> serialized_origin(origin_str.begin(),
origin_str.end());
std::vector<uint8_t> key;
key.reserve(std::size(kMetaPrefix) + serialized_origin.size());
key.insert(key.end(), kMetaPrefix, kMetaPrefix + std::size(kMetaPrefix));
key.insert(key.end(), serialized_origin.begin(), serialized_origin.end());
return key;
}
static std::vector<uint8_t> CreateWriteMetaDataKey(
const url::Origin& origin) {
const uint8_t kMetaPrefix[] = {'M', 'E', 'T', 'A', ':'};
auto origin_str = origin.Serialize();
std::vector<uint8_t> serialized_origin(origin_str.begin(),
origin_str.end());
std::vector<uint8_t> key;
key.reserve(std::size(kMetaPrefix) + serialized_origin.size());
key.insert(key.end(), kMetaPrefix, kMetaPrefix + std::size(kMetaPrefix));
key.insert(key.end(), serialized_origin.begin(), serialized_origin.end());
return key;
}
void GetLocalStorageUsage() {
base::RunLoop loop;
dom_storage_context_->GetLocalStorageUsage(
base::BindOnce(&RemoveLocalStorageTester::OnGotLocalStorageUsage,
base::Unretained(this), loop.QuitClosure()));
loop.Run();
}
void OnGotLocalStorageUsage(
base::OnceClosure quit_closure,
const std::vector<content::StorageUsageInfo>& infos) {
infos_ = infos;
std::move(quit_closure).Run();
}
// We don't own these pointers.
const raw_ptr<BrowserTaskEnvironment> task_environment_;
const raw_ptr<StoragePartition> storage_partition_;
raw_ptr<DOMStorageContext> dom_storage_context_;
std::vector<content::StorageUsageInfo> infos_;
};
class RemoveCodeCacheTester {
public:
explicit RemoveCodeCacheTester(GeneratedCodeCacheContext* code_cache_context)
: code_cache_context_(code_cache_context) {}
RemoveCodeCacheTester(const RemoveCodeCacheTester&) = delete;
RemoveCodeCacheTester& operator=(const RemoveCodeCacheTester&) = delete;
enum Cache { kJs, kWebAssembly, kWebUiJs };
bool ContainsEntry(Cache cache, const GURL& url, const GURL& origin_lock) {
entry_exists_ = false;
base::RunLoop loop;
GeneratedCodeCacheContext::RunOrPostTask(
code_cache_context_.get(), FROM_HERE,
base::BindOnce(&RemoveCodeCacheTester::ContainsEntryOnThread,
base::Unretained(this), cache, url, origin_lock,
loop.QuitClosure()));
loop.Run();
return entry_exists_;
}
void ContainsEntryOnThread(Cache cache,
const GURL& url,
const GURL& origin_lock,
base::OnceClosure quit) {
GeneratedCodeCache::ReadDataCallback callback =
base::BindOnce(&RemoveCodeCacheTester::FetchEntryCallback,
base::Unretained(this), std::move(quit));
GetCache(cache)->FetchEntry(url, origin_lock, net::NetworkIsolationKey(),
std::move(callback));
}
void AddEntry(Cache cache,
const GURL& url,
const GURL& origin_lock,
const std::string& data) {
base::RunLoop loop;
GeneratedCodeCacheContext::RunOrPostTask(
code_cache_context_.get(), FROM_HERE,
base::BindOnce(&RemoveCodeCacheTester::AddEntryOnThread,
base::Unretained(this), cache, url, origin_lock, data,
loop.QuitClosure()));
loop.Run();
}
void AddEntryOnThread(Cache cache,
const GURL& url,
const GURL& origin_lock,
const std::string& data,
base::OnceClosure quit) {
GetCache(cache)->WriteEntry(url, origin_lock, net::NetworkIsolationKey(),
base::Time::Now(), base::as_byte_span(data));
std::move(quit).Run();
}
void SetLastUseTime(Cache cache,
const GURL& url,
const GURL& origin_lock,
base::Time time) {
base::RunLoop loop;
GeneratedCodeCacheContext::RunOrPostTask(
code_cache_context_.get(), FROM_HERE,
base::BindOnce(&RemoveCodeCacheTester::SetLastUseTimeOnThread,
base::Unretained(this), cache, url, origin_lock, time,
loop.QuitClosure()));
loop.Run();
}
void SetLastUseTimeOnThread(Cache cache,
const GURL& url,
const GURL& origin_lock,
base::Time time,
base::OnceClosure quit) {
GetCache(cache)->SetLastUsedTimeForTest(
url, origin_lock, net::NetworkIsolationKey(), time, std::move(quit));
}
std::string received_data() { return received_data_; }
private:
GeneratedCodeCache* GetCache(Cache cache) {
if (cache == kJs)
return code_cache_context_->generated_js_code_cache();
else if (cache == kWebAssembly)
return code_cache_context_->generated_wasm_code_cache();
else
return code_cache_context_->generated_webui_js_code_cache();
}
void FetchEntryCallback(base::OnceClosure quit,
const base::Time& response_time,
mojo_base::BigBuffer data) {
if (!response_time.is_null()) {
entry_exists_ = true;
received_data_ = std::string(data.data(), data.data() + data.size());
} else {
entry_exists_ = false;
}
std::move(quit).Run();
}
bool entry_exists_;
raw_ptr<GeneratedCodeCacheContext> code_cache_context_;
std::string received_data_;
};
class MockDataRemovalObserver : public StoragePartition::DataRemovalObserver {
public:
explicit MockDataRemovalObserver(StoragePartition* partition) {
observation_.Observe(partition);
}
MOCK_METHOD4(OnStorageKeyDataCleared,
void(uint32_t,
content::StoragePartition::StorageKeyMatcherFunction,
base::Time,
base::Time));
private:
base::ScopedObservation<StoragePartition,
StoragePartition::DataRemovalObserver>
observation_{this};
};
bool IsWebSafeSchemeForTest(const std::string& scheme) {
return scheme == url::kHttpScheme;
}
bool DoesOriginMatchForUnprotectedWeb(
const blink::StorageKey& storage_key,
storage::SpecialStoragePolicy* special_storage_policy) {
if (IsWebSafeSchemeForTest(storage_key.origin().scheme())) {
return !special_storage_policy->IsStorageProtected(
storage_key.origin().GetURL());
}
return false;
}
bool DoesOriginMatchForBothProtectedAndUnprotectedWeb(
const blink::StorageKey& storage_key,
storage::SpecialStoragePolicy* special_storage_policy) {
return true;
}
bool DoesOriginMatchUnprotected(
const url::Origin& desired_origin,
const blink::StorageKey& storage_key,
storage::SpecialStoragePolicy* special_storage_policy) {
return storage_key.origin().scheme() != desired_origin.scheme();
}
void ClearQuotaData(content::StoragePartition* partition,
base::RunLoop* loop_to_quit) {
partition->ClearData(kAllQuotaRemoveMask,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
blink::StorageKey(), base::Time(), base::Time::Max(),
loop_to_quit->QuitClosure());
}
void ClearQuotaDataWithOriginMatcher(
content::StoragePartition* partition,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
const base::Time delete_begin,
base::RunLoop* loop_to_quit) {
partition->ClearData(
kAllQuotaRemoveMask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
/*filter_builder=*/nullptr, std::move(storage_key_matcher), nullptr,
false, delete_begin, base::Time::Max(), loop_to_quit->QuitClosure());
}
void ClearQuotaDataForOrigin(content::StoragePartition* partition,
const GURL& remove_origin,
const base::Time delete_begin,
base::RunLoop* loop_to_quit) {
partition->ClearData(
kAllQuotaRemoveMask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
blink::StorageKey::CreateFirstParty(url::Origin::Create(remove_origin)),
delete_begin, base::Time::Max(), loop_to_quit->QuitClosure());
}
void ClearQuotaDataTime(content::StoragePartition* partition,
const base::Time delete_begin,
base::RunLoop* loop_to_quit) {
partition->ClearData(kAllQuotaRemoveMask,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_TEMPORARY,
blink::StorageKey(), delete_begin, base::Time::Max(),
loop_to_quit->QuitClosure());
}
void ClearCookies(content::StoragePartition* partition,
const base::Time delete_begin,
const base::Time delete_end,
base::RunLoop* run_loop) {
partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
blink::StorageKey(), delete_begin, delete_end,
run_loop->QuitClosure());
}
void ClearCookiesMatchingInfo(content::StoragePartition* partition,
CookieDeletionFilterPtr delete_filter,
base::RunLoop* run_loop) {
base::Time delete_begin;
if (delete_filter->created_after_time.has_value())
delete_begin = delete_filter->created_after_time.value();
base::Time delete_end;
if (delete_filter->created_before_time.has_value())
delete_end = delete_filter->created_before_time.value();
partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
/*filter_builder=*/nullptr,
StoragePartition::StorageKeyPolicyMatcherFunction(),
std::move(delete_filter), false, delete_begin,
delete_end, run_loop->QuitClosure());
}
void ClearStuff(
uint32_t remove_mask,
content::StoragePartition* partition,
const base::Time delete_begin,
const base::Time delete_end,
BrowsingDataFilterBuilder* filter_builder,
StoragePartition::StorageKeyPolicyMatcherFunction storage_key_matcher,
base::RunLoop* run_loop) {
partition->ClearData(
remove_mask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
filter_builder, std::move(storage_key_matcher), nullptr, false,
delete_begin, delete_end, run_loop->QuitClosure());
}
void ClearData(content::StoragePartition* partition, base::RunLoop* run_loop) {
base::Time time;
partition->ClearData(StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
blink::StorageKey(), time, time,
run_loop->QuitClosure());
}
void ClearDataForOrigin(uint32_t remove_mask,
content::StoragePartition* partition,
const GURL& origin,
base::RunLoop* run_loop) {
partition->ClearDataForOrigin(
remove_mask, StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, origin,
run_loop->QuitClosure());
}
void ClearCodeCache(content::StoragePartition* partition,
base::Time begin_time,
base::Time end_time,
base::RepeatingCallback<bool(const GURL&)> url_predicate,
base::RunLoop* run_loop) {
partition->ClearCodeCaches(begin_time, end_time, url_predicate,
run_loop->QuitClosure());
}
bool FilterURL(const GURL& filter_url, const GURL& url) {
return url == filter_url;
}
void ClearInterestGroups(content::StoragePartition* partition,
const base::Time delete_begin,
const base::Time delete_end,
base::RunLoop* run_loop) {
partition->ClearData(StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
blink::StorageKey(), delete_begin, delete_end,
run_loop->QuitClosure());
}
void ClearInterestGroupsAndKAnon(content::StoragePartition* partition,
const base::Time delete_begin,
const base::Time delete_end,
base::RunLoop* run_loop) {
partition->ClearData(
StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS |
StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUPS_INTERNAL,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, blink::StorageKey(),
delete_begin, delete_end, run_loop->QuitClosure());
}
void ClearInterestGroupPermissionsCache(content::StoragePartition* partition,
const base::Time delete_begin,
const base::Time delete_end,
base::RunLoop* run_loop) {
partition->ClearData(
StoragePartition::REMOVE_DATA_MASK_INTEREST_GROUP_PERMISSIONS_CACHE,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL, blink::StorageKey(),
delete_begin, delete_end, run_loop->QuitClosure());
}
bool FilterMatchesCookie(const CookieDeletionFilterPtr& filter,
const net::CanonicalCookie& cookie) {
return network::DeletionFilterToInfo(filter.Clone())
.Matches(cookie, net::CookieAccessParams{
net::CookieAccessSemantics::NONLEGACY,
net::CookieScopeSemantics::UNKNOWN, false});
}
} // namespace
class StoragePartitionImplTest : public testing::Test {
public:
StoragePartitionImplTest()
: task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP,
base::test::TaskEnvironment::TimeSource::MOCK_TIME),
browser_context_(new TestBrowserContext()) {
feature_list_.InitWithFeatures({network::features::kInterestGroupStorage,
network::features::kSharedStorageAPI},
{});
}
StoragePartitionImplTest(const StoragePartitionImplTest&) = delete;
StoragePartitionImplTest& operator=(const StoragePartitionImplTest&) = delete;
storage::MockQuotaManager* GetMockManager() {
if (!quota_manager_.get()) {
quota_manager_ = base::MakeRefCounted<storage::MockQuotaManager>(
browser_context_->IsOffTheRecord(), browser_context_->GetPath(),
GetIOThreadTaskRunner({}).get(),
browser_context_->GetSpecialStoragePolicy());
mojo::PendingRemote<storage::mojom::QuotaClient> quota_client;
mojo::MakeSelfOwnedReceiver(
std::make_unique<storage::MockQuotaClient>(
quota_manager_->proxy(), storage::QuotaClientType::kFileSystem),
quota_client.InitWithNewPipeAndPassReceiver());
quota_manager_->proxy()->RegisterClient(
std::move(quota_client), storage::QuotaClientType::kFileSystem);
}
return quota_manager_.get();
}
TestBrowserContext* browser_context() { return browser_context_.get(); }
content::BrowserTaskEnvironment* task_environment() {
return &task_environment_;
}
private:
base::test::ScopedCommandLine command_line_;
base::test::ScopedFeatureList feature_list_;
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestBrowserContext> browser_context_;
scoped_refptr<storage::MockQuotaManager> quota_manager_;
};
class StoragePartitionShaderClearTest : public testing::Test {
public:
StoragePartitionShaderClearTest()
: task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP),
browser_context_(new TestBrowserContext()) {
InitGpuDiskCacheFactorySingleton();
gpu::GpuDiskCacheType type = gpu::GpuDiskCacheType::kGlShaders;
auto handle = GetGpuDiskCacheFactorySingleton()->GetCacheHandle(
type, browser_context()->GetDefaultStoragePartition()->GetPath().Append(
gpu::GetGpuDiskCacheSubdir(type)));
cache_ =
GetGpuDiskCacheFactorySingleton()->Create(handle, base::DoNothing());
}
~StoragePartitionShaderClearTest() override { cache_ = nullptr; }
void InitCache() {
net::TestCompletionCallback available_cb;
int rv = cache_->SetAvailableCallback(available_cb.callback());
ASSERT_EQ(net::OK, available_cb.GetResult(rv));
EXPECT_EQ(0, cache_->Size());
cache_->Cache(kCacheKey, kCacheValue);
net::TestCompletionCallback complete_cb;
rv = cache_->SetCacheCompleteCallback(complete_cb.callback());
ASSERT_EQ(net::OK, complete_cb.GetResult(rv));
}
size_t Size() { return cache_->Size(); }
TestBrowserContext* browser_context() { return browser_context_.get(); }
private:
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<TestBrowserContext> browser_context_;
scoped_refptr<gpu::GpuDiskCache> cache_;
};
// Tests ---------------------------------------------------------------------
TEST_F(StoragePartitionShaderClearTest, ClearShaderCache) {
InitCache();
EXPECT_EQ(1u, Size());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearData,
browser_context()->GetDefaultStoragePartition(),
&run_loop));
run_loop.Run();
EXPECT_EQ(0u, Size());
}
TEST_F(StoragePartitionImplTest, QuotaClientTypesGeneration) {
EXPECT_THAT(
StoragePartitionImpl::GenerateQuotaClientTypes(
StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS),
testing::UnorderedElementsAre(storage::QuotaClientType::kFileSystem));
EXPECT_THAT(StoragePartitionImpl::GenerateQuotaClientTypes(
StoragePartition::REMOVE_DATA_MASK_WEBSQL),
testing::ElementsAre(storage::QuotaClientType::kDatabase));
EXPECT_THAT(StoragePartitionImpl::GenerateQuotaClientTypes(
StoragePartition::REMOVE_DATA_MASK_INDEXEDDB),
testing::ElementsAre(storage::QuotaClientType::kIndexedDatabase));
EXPECT_THAT(
StoragePartitionImpl::GenerateQuotaClientTypes(kAllQuotaRemoveMask),
testing::UnorderedElementsAre(
storage::QuotaClientType::kFileSystem,
storage::QuotaClientType::kDatabase,
storage::QuotaClientType::kIndexedDatabase));
}
storage::BucketInfo AddQuotaManagedBucket(
storage::MockQuotaManager* manager,
const blink::StorageKey& storage_key,
const std::string& bucket_name,
base::Time modified = base::Time::Now()) {
storage::BucketInfo bucket =
manager->CreateBucket({storage_key, bucket_name});
manager->AddBucket(bucket, {kClientFile}, modified);
EXPECT_TRUE(manager->BucketHasData(bucket, kClientFile));
return bucket;
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForever) {
const blink::StorageKey kStorageKey1 =
blink::StorageKey::CreateFromStringForTesting("http://host1:1/");
const blink::StorageKey kStorageKey2 =
blink::StorageKey::CreateFromStringForTesting("http://host2:1/");
AddQuotaManagedBucket(GetMockManager(), kStorageKey1,
storage::kDefaultBucketName);
AddQuotaManagedBucket(GetMockManager(), kStorageKey2,
storage::kDefaultBucketName);
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearQuotaData, partition, &run_loop));
run_loop.Run();
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0);
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForeverNone) {
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearQuotaData, partition, &run_loop));
run_loop.Run();
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0);
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForeverSpecificOrigin) {
const blink::StorageKey kStorageKey1 =
blink::StorageKey::CreateFromStringForTesting("http://host1:1/");
const blink::StorageKey kStorageKey2 =
blink::StorageKey::CreateFromStringForTesting("http://host2:1/");
storage::BucketInfo host1_bucket = AddQuotaManagedBucket(
GetMockManager(), kStorageKey1, storage::kDefaultBucketName);
storage::BucketInfo host2_bucket = AddQuotaManagedBucket(
GetMockManager(), kStorageKey2, storage::kDefaultBucketName);
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearQuotaDataForOrigin, partition,
kStorageKey1.origin().GetURL(), base::Time(), &run_loop));
run_loop.Run();
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1);
EXPECT_FALSE(GetMockManager()->BucketHasData(host1_bucket, kClientFile));
EXPECT_TRUE(GetMockManager()->BucketHasData(host2_bucket, kClientFile));
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForLastHour) {
const blink::StorageKey kStorageKey1 =
blink::StorageKey::CreateFromStringForTesting("http://host1:1/");
const blink::StorageKey kStorageKey2 =
blink::StorageKey::CreateFromStringForTesting("http://host2:1/");
const blink::StorageKey kStorageKey3 =
blink::StorageKey::CreateFromStringForTesting("http://host3:1/");
// Buckets modified now.
base::Time now = base::Time::Now();
storage::BucketInfo host1_bucket_now =
AddQuotaManagedBucket(GetMockManager(), kStorageKey1, "bucket_now", now);
storage::BucketInfo host2_bucket_now =
AddQuotaManagedBucket(GetMockManager(), kStorageKey2, "bucket_now", now);
// Buckets modified a day ago.
base::Time yesterday = now - base::Days(1);
storage::BucketInfo host1_bucket_yesterday = AddQuotaManagedBucket(
GetMockManager(), kStorageKey1, "bucket_yesterday", yesterday);
storage::BucketInfo host2_bucket_yesterday = AddQuotaManagedBucket(
GetMockManager(), kStorageKey2, "bucket_yesterday", yesterday);
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 4);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearQuotaDataForOrigin, partition, GURL(),
base::Time::Now() - base::Hours(1), &run_loop));
run_loop.Run();
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2);
EXPECT_FALSE(GetMockManager()->BucketHasData(host1_bucket_now, kClientFile));
EXPECT_FALSE(GetMockManager()->BucketHasData(host2_bucket_now, kClientFile));
EXPECT_TRUE(
GetMockManager()->BucketHasData(host1_bucket_yesterday, kClientFile));
EXPECT_TRUE(
GetMockManager()->BucketHasData(host2_bucket_yesterday, kClientFile));
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedDataForLastWeek) {
const blink::StorageKey kStorageKey =
blink::StorageKey::CreateFromStringForTesting("http://host1:1/");
// Buckets modified yesterday.
base::Time now = base::Time::Now();
base::Time yesterday = now - base::Days(1);
storage::BucketInfo bucket_yesterday = AddQuotaManagedBucket(
GetMockManager(), kStorageKey, "bucket_yesterday", yesterday);
// Buckets modified 10 days ago.
base::Time ten_days_ago = now - base::Days(10);
storage::BucketInfo bucket_ten_days_ago = AddQuotaManagedBucket(
GetMockManager(), kStorageKey, "bucket_ten_days_ago", ten_days_ago);
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2);
base::RunLoop run_loop;
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearQuotaDataTime, partition,
base::Time::Now() - base::Days(7), &run_loop));
run_loop.Run();
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1);
EXPECT_FALSE(GetMockManager()->BucketHasData(bucket_yesterday, kClientFile));
EXPECT_TRUE(
GetMockManager()->BucketHasData(bucket_ten_days_ago, kClientFile));
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedUnprotectedOrigins) {
const blink::StorageKey kStorageKey1 =
blink::StorageKey::CreateFromStringForTesting("http://host1:1/");
const blink::StorageKey kStorageKey2 =
blink::StorageKey::CreateFromStringForTesting("http://host2:1/");
storage::BucketInfo host1_bucket = AddQuotaManagedBucket(
GetMockManager(), kStorageKey1, storage::kDefaultBucketName);
storage::BucketInfo host2_bucket = AddQuotaManagedBucket(
GetMockManager(), kStorageKey2, storage::kDefaultBucketName);
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2);
// Protect kStorageKey1.
auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
mock_policy->AddProtected(kStorageKey1.origin().GetURL());
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearQuotaDataWithOriginMatcher, partition,
base::BindRepeating(&DoesOriginMatchForUnprotectedWeb),
base::Time(), &run_loop));
run_loop.Run();
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1);
EXPECT_TRUE(GetMockManager()->BucketHasData(host1_bucket, kClientFile));
EXPECT_FALSE(GetMockManager()->BucketHasData(host2_bucket, kClientFile));
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedProtectedOrigins) {
const blink::StorageKey kStorageKey1 =
blink::StorageKey::CreateFromStringForTesting("http://host1:1/");
const blink::StorageKey kStorageKey2 =
blink::StorageKey::CreateFromStringForTesting("http://host2:1/");
AddQuotaManagedBucket(GetMockManager(), kStorageKey1,
storage::kDefaultBucketName);
AddQuotaManagedBucket(GetMockManager(), kStorageKey2,
storage::kDefaultBucketName);
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 2);
// Protect kStorageKey1.
auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
mock_policy->AddProtected(kStorageKey1.origin().GetURL());
// Try to remove kStorageKey1. Expect success.
base::RunLoop run_loop;
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearQuotaDataWithOriginMatcher, partition,
base::BindRepeating(
&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
base::Time(), &run_loop));
run_loop.Run();
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 0);
}
TEST_F(StoragePartitionImplTest, RemoveQuotaManagedIgnoreDevTools) {
const blink::StorageKey kStorageKey =
blink::StorageKey::CreateFromStringForTesting(
"devtools://abcdefghijklmnopqrstuvw/");
storage::BucketInfo bucket = AddQuotaManagedBucket(
GetMockManager(), kStorageKey, storage::kDefaultBucketName, base::Time());
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1);
base::RunLoop run_loop;
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideQuotaManagerForTesting(GetMockManager());
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearQuotaDataWithOriginMatcher, partition,
base::BindRepeating(&DoesOriginMatchUnprotected,
kStorageKey.origin()),
base::Time(), &run_loop));
run_loop.Run();
// Check that devtools data isn't removed.
EXPECT_EQ(GetMockManager()->BucketDataCount(kClientFile), 1);
EXPECT_TRUE(GetMockManager()->BucketHasData(bucket, kClientFile));
}
TEST_F(StoragePartitionImplTest, RemoveCookieForever) {
const url::Origin kOrigin = url::Origin::Create(GURL("http://host1:1/"));
StoragePartition* partition = browser_context()->GetDefaultStoragePartition();
RemoveCookieTester tester(partition);
tester.AddCookie(kOrigin);
ASSERT_TRUE(tester.ContainsCookie(kOrigin));
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearCookies, partition, base::Time(),
base::Time::Max(), &run_loop));
run_loop.Run();
EXPECT_FALSE(tester.ContainsCookie(kOrigin));
}
TEST_F(StoragePartitionImplTest, RemoveCookieLastHour) {
const url::Origin kOrigin = url::Origin::Create(GURL("http://host1:1/"));
StoragePartition* partition = browser_context()->GetDefaultStoragePartition();
RemoveCookieTester tester(partition);
tester.AddCookie(kOrigin);
ASSERT_TRUE(tester.ContainsCookie(kOrigin));
base::Time an_hour_ago = base::Time::Now() - base::Hours(1);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearCookies, partition, an_hour_ago,
base::Time::Max(), &run_loop));
run_loop.Run();
EXPECT_FALSE(tester.ContainsCookie(kOrigin));
}
TEST_F(StoragePartitionImplTest, RemoveCookieWithDeleteInfo) {
const url::Origin kOrigin = url::Origin::Create(GURL("http://host1:1/"));
StoragePartition* partition = browser_context()->GetDefaultStoragePartition();
RemoveCookieTester tester(partition);
tester.AddCookie(kOrigin);
ASSERT_TRUE(tester.ContainsCookie(kOrigin));
base::RunLoop run_loop2;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearCookiesMatchingInfo, partition,
CookieDeletionFilter::New(), &run_loop2));
run_loop2.RunUntilIdle();
EXPECT_FALSE(tester.ContainsCookie(kOrigin));
}
TEST_F(StoragePartitionImplTest, RemoveInterestGroupForever) {
const url::Origin kOrigin = url::Origin::Create(GURL("https://host1:1/"));
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
RemoveInterestGroupTester tester(partition);
tester.AddInterestGroup(kOrigin);
ASSERT_TRUE(tester.ContainsInterestGroupOwner(kOrigin));
{
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearInterestGroups, partition, base::Time(),
base::Time::Max(), &run_loop));
run_loop.Run();
}
EXPECT_FALSE(tester.ContainsInterestGroupOwner(kOrigin));
EXPECT_TRUE(tester.ContainsInterestGroupKAnon(kOrigin));
{
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearInterestGroupsAndKAnon, partition,
base::Time(), base::Time::Max(), &run_loop));
run_loop.Run();
}
EXPECT_FALSE(tester.ContainsInterestGroupOwner(kOrigin));
EXPECT_FALSE(tester.ContainsInterestGroupKAnon(kOrigin));
}
TEST_F(StoragePartitionImplTest, RemoveInterestGroupPermissionsCacheForever) {
const url::Origin kFrameOrigin =
url::Origin::Create(GURL("https://host1.test:1/"));
const url::Origin kInterestGroupOrigin =
url::Origin::Create(GURL("https://host2.test:2/"));
const net::SchemefulSite kFrameSite =
net::SchemefulSite(GURL("https://host1.test:1/"));
const net::NetworkIsolationKey kNetworkIsolationKey(kFrameSite, kFrameSite);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
ASSERT_TRUE(partition->GetInterestGroupManager());
InterestGroupPermissionsCache& permissions_cache =
static_cast<InterestGroupManagerImpl*>(
partition->GetInterestGroupManager())
->permissions_checker_for_testing()
.cache_for_testing();
permissions_cache.CachePermissions(InterestGroupPermissionsCache::Permissions{
/*can_join=*/true, /*can_leave=*/true},
kFrameOrigin, kInterestGroupOrigin,
kNetworkIsolationKey);
EXPECT_TRUE(permissions_cache.GetPermissions(
kFrameOrigin, kInterestGroupOrigin, kNetworkIsolationKey));
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(&ClearInterestGroupPermissionsCache, partition,
base::Time(), base::Time::Max(), &run_loop));
run_loop.Run();
EXPECT_FALSE(permissions_cache.GetPermissions(
kFrameOrigin, kInterestGroupOrigin, kNetworkIsolationKey));
}
TEST_F(StoragePartitionImplTest, RemoveUnprotectedLocalStorageForever) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
// Protect kOrigin1.
auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
mock_policy->AddProtected(kOrigin1.GetURL());
RemoveLocalStorageTester tester(task_environment(), browser_context());
tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
partition, base::Time(), base::Time::Max(),
/*filter_builder=*/nullptr,
base::BindRepeating(&DoesOriginMatchForUnprotectedWeb), &run_loop));
run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin1));
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplTest, RemoveProtectedLocalStorageForever) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
// Protect kOrigin1.
auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
mock_policy->AddProtected(kOrigin1.GetURL());
RemoveLocalStorageTester tester(task_environment(), browser_context());
tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->OverrideSpecialStoragePolicyForTesting(mock_policy.get());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearStuff,
StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
partition, base::Time(), base::Time::Max(),
/*filter_builder=*/nullptr,
base::BindRepeating(
&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
&run_loop));
run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
// Even if kOrigin1 is protected, it will be deleted since we specify
// ClearData to delete protected data.
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplTest, RemoveLocalStorageForLastWeek) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
RemoveLocalStorageTester tester(task_environment(), browser_context());
tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
base::Time a_week_ago = base::Time::Now() - base::Days(7);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearStuff,
StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
partition, a_week_ago, base::Time::Max(),
/*filter_builder=*/nullptr,
base::BindRepeating(
&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
&run_loop));
run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
// kOrigin1 and kOrigin2 do not have age more than a week.
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplTest, RemoveLocalStorageForOrigins) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
RemoveLocalStorageTester tester(task_environment(), browser_context());
tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
auto filter_builder = BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kDelete);
filter_builder->AddOrigin(kOrigin1);
filter_builder->AddOrigin(kOrigin2);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
partition, base::Time::Min(), base::Time::Max(), filter_builder.get(),
StoragePartition::StorageKeyPolicyMatcherFunction(), &run_loop));
run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
// kOrigin3 is not filtered by the filter builder.
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin2));
EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplTest, RemoveLocalStorageForOneOrigin) {
const GURL kUrl1 = GURL("http://host1:1/");
const url::Origin kOrigin1 = url::Origin::Create(kUrl1);
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
RemoveLocalStorageTester tester(task_environment(), browser_context());
tester.AddDOMStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearDataForOrigin,
StoragePartitionImpl::REMOVE_DATA_MASK_LOCAL_STORAGE,
partition, kUrl1, &run_loop));
run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
// kOrigin1 should be cleared.
EXPECT_FALSE(tester.DOMStorageExistsForOrigin(kOrigin1));
EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin2));
EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplTest, ClearCodeCache) {
const GURL kResourceURL("http://host4/script.js");
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
// Ensure code cache is initialized.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr);
RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
GURL origin = GURL("http://host1:1/");
std::string data("SomeData");
tester.AddEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin, data);
EXPECT_TRUE(
tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin));
EXPECT_EQ(tester.received_data(), data);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(),
base::RepeatingCallback<bool(const GURL&)>(), &run_loop));
run_loop.Run();
EXPECT_FALSE(
tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin));
// Make sure there isn't a second invalid callback sitting in the queue.
// (this used to be a bug).
base::RunLoop().RunUntilIdle();
}
TEST_F(StoragePartitionImplTest, ClearCodeCacheSpecificURL) {
const GURL kResourceURL("http://host4/script.js");
const GURL kFilterResourceURLForCodeCache("http://host5/script.js");
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
// Ensure code cache is initialized.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr);
RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
GURL origin = GURL("http://host1:1/");
std::string data("SomeData");
tester.AddEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin, data);
tester.AddEntry(RemoveCodeCacheTester::kJs, kFilterResourceURLForCodeCache,
origin, data);
EXPECT_TRUE(
tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin));
EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kJs,
kFilterResourceURLForCodeCache, origin));
EXPECT_EQ(tester.received_data(), data);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&ClearCodeCache, partition, base::Time(), base::Time(),
base::BindRepeating(&FilterURL, kFilterResourceURLForCodeCache),
&run_loop));
run_loop.Run();
EXPECT_TRUE(
tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin));
EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kJs,
kFilterResourceURLForCodeCache, origin));
// Make sure there isn't a second invalid callback sitting in the queue.
// (this used to be a bug).
base::RunLoop().RunUntilIdle();
}
TEST_F(StoragePartitionImplTest, ClearCodeCacheDateRange) {
const GURL kResourceURL("http://host4/script.js");
const GURL kFilterResourceURLForCodeCache("http://host5/script.js");
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
// Ensure code cache is initialized.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr);
RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
base::Time current_time = base::Time::NowFromSystemTime();
base::Time out_of_range_time = current_time - base::Hours(3);
base::Time begin_time = current_time - base::Hours(2);
base::Time in_range_time = current_time - base::Hours(1);
GURL origin = GURL("http://host1:1/");
std::string data("SomeData");
tester.AddEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin, data);
EXPECT_TRUE(
tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin));
EXPECT_EQ(tester.received_data(), data);
tester.SetLastUseTime(RemoveCodeCacheTester::kJs, kResourceURL, origin,
out_of_range_time);
// Add a new entry.
tester.AddEntry(RemoveCodeCacheTester::kJs, kFilterResourceURLForCodeCache,
origin, data);
EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kJs,
kFilterResourceURLForCodeCache, origin));
tester.SetLastUseTime(RemoveCodeCacheTester::kJs,
kFilterResourceURLForCodeCache, origin, in_range_time);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&ClearCodeCache, partition, begin_time, current_time,
base::BindRepeating(&FilterURL, kFilterResourceURLForCodeCache),
&run_loop));
run_loop.Run();
EXPECT_TRUE(
tester.ContainsEntry(RemoveCodeCacheTester::kJs, kResourceURL, origin));
EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kJs,
kFilterResourceURLForCodeCache, origin));
// Make sure there isn't a second invalid callback sitting in the queue.
// (this used to be a bug).
base::RunLoop().RunUntilIdle();
}
TEST_F(StoragePartitionImplTest, ClearWasmCodeCache) {
const GURL kResourceURL("http://host4/script.js");
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
// Ensure code cache is initialized.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr);
RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
GURL origin = GURL("http://host1:1/");
std::string data("SomeData.wasm");
tester.AddEntry(RemoveCodeCacheTester::kWebAssembly, kResourceURL, origin,
data);
EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kWebAssembly,
kResourceURL, origin));
EXPECT_EQ(tester.received_data(), data);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(),
base::RepeatingCallback<bool(const GURL&)>(), &run_loop));
run_loop.Run();
EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kWebAssembly,
kResourceURL, origin));
// Make sure there isn't a second invalid callback sitting in the queue.
// (this used to be a bug).
base::RunLoop().RunUntilIdle();
}
TEST_F(StoragePartitionImplTest, ClearWebUICodeCache) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(features::kWebUICodeCache);
const GURL kResourceURL("chrome://host4/script.js");
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
// Ensure code cache is initialized.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr);
RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
GURL origin = GURL("chrome://host1:1/");
std::string data("SomeData");
tester.AddEntry(RemoveCodeCacheTester::kWebUiJs, kResourceURL, origin, data);
EXPECT_TRUE(tester.ContainsEntry(RemoveCodeCacheTester::kWebUiJs,
kResourceURL, origin));
EXPECT_EQ(tester.received_data(), data);
base::RunLoop run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(),
base::RepeatingCallback<bool(const GURL&)>(), &run_loop));
run_loop.Run();
EXPECT_FALSE(tester.ContainsEntry(RemoveCodeCacheTester::kWebUiJs,
kResourceURL, origin));
// Make sure there isn't a second invalid callback sitting in the queue.
// (this used to be a bug).
base::RunLoop().RunUntilIdle();
}
TEST_F(StoragePartitionImplTest, WebUICodeCacheDisabled) {
base::test::ScopedFeatureList features;
features.InitAndDisableFeature(features::kWebUICodeCache);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
// Ensure code cache is initialized.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(partition->GetGeneratedCodeCacheContext() != nullptr);
base::RunLoop run_loop;
auto* context = partition->GetGeneratedCodeCacheContext();
GeneratedCodeCacheContext::RunOrPostTask(
context, FROM_HERE, base::BindLambdaForTesting([&]() {
EXPECT_EQ(partition->GetGeneratedCodeCacheContext()
->generated_webui_js_code_cache(),
nullptr);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(StoragePartitionImplTest, ClearCodeCacheIncognito) {
browser_context()->set_is_off_the_record(true);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
base::RunLoop().RunUntilIdle();
// We should not create GeneratedCodeCacheContext for off the record mode.
EXPECT_EQ(nullptr, partition->GetGeneratedCodeCacheContext());
base::RunLoop run_loop;
// This shouldn't crash.
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearCodeCache, partition, base::Time(), base::Time(),
base::RepeatingCallback<bool(const GURL&)>(), &run_loop));
run_loop.Run();
}
TEST(StoragePartitionImplStaticTest, CreatePredicateForHostCookies) {
GURL url("http://www.example.com/");
GURL url2("https://www.example.com/");
GURL url3("https://www.google.com/");
std::optional<base::Time> server_time = std::nullopt;
CookieDeletionFilterPtr deletion_filter = CookieDeletionFilter::New();
deletion_filter->host_name = url.host();
base::Time now = base::Time::Now();
std::vector<std::unique_ptr<CanonicalCookie>> valid_cookies;
valid_cookies.push_back(
CanonicalCookie::CreateForTesting(url, "A=B", now, server_time));
valid_cookies.push_back(
CanonicalCookie::CreateForTesting(url, "C=F", now, server_time));
// We should match a different scheme with the same host.
valid_cookies.push_back(
CanonicalCookie::CreateForTesting(url2, "A=B", now, server_time));
std::vector<std::unique_ptr<CanonicalCookie>> invalid_cookies;
// We don't match domain cookies.
invalid_cookies.push_back(CanonicalCookie::CreateForTesting(
url2, "A=B;domain=.example.com", now, server_time));
invalid_cookies.push_back(
CanonicalCookie::CreateForTesting(url3, "A=B", now, server_time));
for (const auto& cookie : valid_cookies) {
EXPECT_TRUE(FilterMatchesCookie(deletion_filter, *cookie))
<< cookie->DebugString();
}
for (const auto& cookie : invalid_cookies) {
EXPECT_FALSE(FilterMatchesCookie(deletion_filter, *cookie))
<< cookie->DebugString();
}
}
TEST_F(StoragePartitionImplTest, AttributionManagerCreatedInIncognito) {
browser_context()->set_is_off_the_record(true);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
EXPECT_TRUE(partition->GetAttributionManager());
}
TEST_F(StoragePartitionImplTest, AttributionReportingClearData) {
using ::testing::_;
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
const base::Time kDeleteBegin = base::Time::Now();
const base::Time kDeleteEnd = kDeleteBegin + base::Days(1);
const auto kStorageKeyA = blink::StorageKey::CreateFirstParty(
url::Origin::Create(GURL("https://a.test")));
const auto kStorageKeyB = blink::StorageKey::CreateFirstParty(
url::Origin::Create(GURL("https://b.test")));
const struct {
const char* name;
uint32_t mask;
bool expected_delete_rate_limit_data;
} kTestCases[] = {
{
.name = "no_internal",
.mask = 0,
.expected_delete_rate_limit_data = false,
},
{
.name = "internal",
.mask =
StoragePartition::REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_INTERNAL,
.expected_delete_rate_limit_data = true,
},
};
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(test_case.name);
auto attribution_manager = std::make_unique<MockAttributionManager>();
EXPECT_CALL(*attribution_manager,
ClearData(kDeleteBegin, kDeleteEnd,
/*filter=*/_,
/*filter_builder=*/_,
test_case.expected_delete_rate_limit_data,
/*done=*/_))
.WillOnce(::testing::DoAll(
::testing::WithArg<2>(
[&](StoragePartition::StorageKeyMatcherFunction f) {
EXPECT_TRUE(f.Run(kStorageKeyA));
EXPECT_FALSE(f.Run(kStorageKeyB));
}),
base::test::RunOnceClosure<5>()));
partition->OverrideAttributionManagerForTesting(
std::move(attribution_manager));
base::RunLoop run_loop;
partition->ClearData(
StoragePartition::REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_SITE_CREATED |
test_case.mask,
/*quota_storage_remove_mask=*/0, kStorageKeyA, kDeleteBegin, kDeleteEnd,
run_loop.QuitClosure());
run_loop.Run();
}
}
TEST_F(StoragePartitionImplTest, AttributionReportingClearDataWrongMask) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
auto attribution_manager = std::make_unique<MockAttributionManager>();
EXPECT_CALL(*attribution_manager, ClearData).Times(0);
partition->OverrideAttributionManagerForTesting(
std::move(attribution_manager));
base::RunLoop run_loop;
// Arbitrary irrelevant mask.
partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES,
/*quota_storage_remove_mask=*/0, blink::StorageKey(),
/*begin=*/base::Time::Min(), /*end=*/base::Time::Max(),
run_loop.QuitClosure());
run_loop.Run();
}
TEST_F(StoragePartitionImplTest, AttributionReportingClearDataForFilter) {
using ::testing::_;
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
const auto kFilterBuilder = BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kPreserve);
auto attribution_manager = std::make_unique<MockAttributionManager>();
EXPECT_CALL(*attribution_manager,
ClearData(/*delete_begin=*/_,
/*delete_end=*/_,
/*filter=*/_,
/*filter_builder=*/kFilterBuilder.get(),
/*delete_rate_limit_data=*/false,
/*done=*/_))
.WillOnce(base::test::RunOnceClosure<5>());
partition->OverrideAttributionManagerForTesting(
std::move(attribution_manager));
base::RunLoop run_loop;
StoragePartition::StorageKeyPolicyMatcherFunction func =
base::BindRepeating([](const blink::StorageKey&,
storage::SpecialStoragePolicy*) { return true; });
partition->ClearData(
StoragePartition::REMOVE_DATA_MASK_ATTRIBUTION_REPORTING_SITE_CREATED,
/*quota_storage_remove_mask=*/0, kFilterBuilder.get(), func,
/*cookie_deletion_filter=*/nullptr, /*perform_storage_cleanup=*/false,
/*begin=*/base::Time::Min(), /*end=*/base::Time::Max(),
run_loop.QuitClosure());
run_loop.Run();
}
TEST_F(StoragePartitionImplTest, DataRemovalObserver) {
const uint32_t kTestClearMask =
content::StoragePartition::REMOVE_DATA_MASK_INDEXEDDB |
content::StoragePartition::REMOVE_DATA_MASK_WEBSQL;
const uint32_t kTestQuotaClearMask = 0;
const auto kTestOrigin = GURL("https://example.com");
const auto kBeginTime = base::Time() + base::Hours(1);
const auto kEndTime = base::Time() + base::Hours(2);
const auto storage_key_callback_valid =
[&](content::StoragePartition::StorageKeyMatcherFunction callback) {
return callback.Run(blink::StorageKey::CreateFirstParty(
url::Origin::Create(kTestOrigin)));
};
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
MockDataRemovalObserver observer(partition);
// Confirm that each of the StoragePartition interfaces for clearing origin
// based data notify observers appropriately.
EXPECT_CALL(observer,
OnStorageKeyDataCleared(
kTestClearMask, testing::Truly(storage_key_callback_valid),
base::Time(), base::Time::Max()));
base::RunLoop run_loop;
partition->ClearDataForOrigin(kTestClearMask, kTestQuotaClearMask,
kTestOrigin, run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(&observer);
EXPECT_CALL(observer,
OnStorageKeyDataCleared(
kTestClearMask, testing::Truly(storage_key_callback_valid),
kBeginTime, kEndTime));
partition->ClearData(
kTestClearMask, kTestQuotaClearMask,
blink::StorageKey::CreateFirstParty(url::Origin::Create(kTestOrigin)),
kBeginTime, kEndTime, base::DoNothing());
testing::Mock::VerifyAndClearExpectations(&observer);
EXPECT_CALL(observer,
OnStorageKeyDataCleared(
kTestClearMask, testing::Truly(storage_key_callback_valid),
kBeginTime, kEndTime));
partition->ClearData(
kTestClearMask, kTestQuotaClearMask,
/*filter_builder=*/nullptr,
base::BindLambdaForTesting([&](const blink::StorageKey& storage_key,
storage::SpecialStoragePolicy* policy) {
return storage_key == blink::StorageKey::CreateFirstParty(
url::Origin::Create(kTestOrigin));
}),
/*cookie_deletion_filter=*/nullptr, /*perform_storage_cleanup=*/false,
kBeginTime, kEndTime, base::DoNothing());
}
TEST_F(StoragePartitionImplTest, RemoveAggregationServiceData) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
auto aggregation_service = std::make_unique<MockAggregationService>();
auto* aggregation_service_ptr = aggregation_service.get();
partition->OverrideAggregationServiceForTesting(
std::move(aggregation_service));
const uint32_t kTestClearMask =
StoragePartition::REMOVE_DATA_MASK_AGGREGATION_SERVICE;
const uint32_t kTestQuotaClearMask =
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
const auto kTestOrigin = GURL("https://example.com");
const auto kOtherOrigin = GURL("https://example.net");
const auto kBeginTime = base::Time() + base::Hours(1);
const auto kEndTime = base::Time() + base::Hours(2);
const auto invoke_callback =
[](base::Time delete_begin, base::Time delete_end,
StoragePartition::StorageKeyMatcherFunction filter,
base::OnceClosure done) { std::move(done).Run(); };
const auto is_test_origin_valid =
[&kTestOrigin](
content::StoragePartition::StorageKeyMatcherFunction filter) {
return filter.Run(blink::StorageKey::CreateFirstParty(
url::Origin::Create(kTestOrigin)));
};
const auto is_other_origin_valid =
[&kOtherOrigin](
content::StoragePartition::StorageKeyMatcherFunction filter) {
return filter.Run(blink::StorageKey::CreateFirstParty(
url::Origin::Create(kOtherOrigin)));
};
const auto is_filter_null =
[&](content::StoragePartition::StorageKeyMatcherFunction filter) {
return filter.is_null();
};
// Verify that each of the StoragePartition interfaces for clearing origin
// based data calls aggregation service appropriately.
EXPECT_CALL(
*aggregation_service_ptr,
ClearData(
base::Time(), base::Time::Max(),
testing::AllOf(testing::Truly(is_test_origin_valid),
testing::Not(testing::Truly(is_other_origin_valid))),
testing::_))
.WillOnce(invoke_callback);
{
base::RunLoop run_loop;
partition->ClearDataForOrigin(kTestClearMask, kTestQuotaClearMask,
kTestOrigin, run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr);
}
EXPECT_CALL(
*aggregation_service_ptr,
ClearData(
kBeginTime, kEndTime,
testing::AllOf(testing::Truly(is_test_origin_valid),
testing::Not(testing::Truly(is_other_origin_valid))),
testing::_))
.WillOnce(testing::Invoke(invoke_callback));
{
base::RunLoop run_loop;
partition->ClearData(
kTestClearMask, kTestQuotaClearMask,
blink::StorageKey::CreateFirstParty(url::Origin::Create(kTestOrigin)),
kBeginTime, kEndTime, run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr);
}
EXPECT_CALL(
*aggregation_service_ptr,
ClearData(
kBeginTime, kEndTime,
testing::AllOf(testing::Truly(is_test_origin_valid),
testing::Not(testing::Truly(is_other_origin_valid))),
testing::_))
.WillOnce(testing::Invoke(invoke_callback));
{
base::RunLoop run_loop;
partition->ClearData(
kTestClearMask, kTestQuotaClearMask,
/*filter_builder=*/nullptr,
base::BindLambdaForTesting([&](const blink::StorageKey& storage_key,
storage::SpecialStoragePolicy* policy) {
return storage_key == blink::StorageKey::CreateFirstParty(
url::Origin::Create(kTestOrigin));
}),
/*cookie_deletion_filter=*/nullptr,
/*perform_storage_cleanup=*/false, kBeginTime, kEndTime,
run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr);
}
EXPECT_CALL(
*aggregation_service_ptr,
ClearData(
kBeginTime, kEndTime,
testing::AllOf(testing::Truly(is_test_origin_valid),
testing::Not(testing::Truly(is_other_origin_valid))),
testing::_))
.WillOnce(testing::Invoke(invoke_callback));
{
base::RunLoop run_loop;
auto filter_builder = BrowsingDataFilterBuilder::Create(
BrowsingDataFilterBuilder::Mode::kDelete);
filter_builder->AddOrigin(url::Origin::Create(kTestOrigin));
partition->ClearData(kTestClearMask, kTestQuotaClearMask,
filter_builder.get(),
StoragePartition::StorageKeyPolicyMatcherFunction(),
/*cookie_deletion_filter=*/nullptr,
/*perform_storage_cleanup=*/false, kBeginTime,
kEndTime, run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(aggregation_service_ptr);
}
EXPECT_CALL(*aggregation_service_ptr,
ClearData(kBeginTime, kEndTime, testing::Truly(is_filter_null),
testing::_))
.WillOnce(testing::Invoke(invoke_callback));
{
base::RunLoop run_loop;
partition->ClearData(kTestClearMask, kTestQuotaClearMask,
blink::StorageKey(), kBeginTime, kEndTime,
run_loop.QuitClosure());
run_loop.Run();
}
}
TEST_F(StoragePartitionImplTest, RemovePrivateAggregationData) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
auto private_aggregation_manager =
std::make_unique<MockPrivateAggregationManagerImpl>(partition);
auto* private_aggregation_manager_ptr = private_aggregation_manager.get();
partition->OverridePrivateAggregationManagerForTesting(
std::move(private_aggregation_manager));
const uint32_t kTestClearMask =
StoragePartition::REMOVE_DATA_MASK_PRIVATE_AGGREGATION_INTERNAL;
const uint32_t kTestQuotaClearMask =
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL;
const auto kTestOrigin = GURL("https://example.com");
const auto kOtherOrigin = GURL("https://example.net");
const auto kBeginTime = base::Time() + base::Hours(1);
const auto kEndTime = base::Time() + base::Hours(2);
const auto invoke_callback =
[](base::Time delete_begin, base::Time delete_end,
StoragePartition::StorageKeyMatcherFunction filter,
base::OnceClosure done) { std::move(done).Run(); };
const auto is_test_origin_valid =
[&kTestOrigin](
content::StoragePartition::StorageKeyMatcherFunction filter) {
return filter.Run(blink::StorageKey::CreateFirstParty(
url::Origin::Create(kTestOrigin)));
};
const auto is_other_origin_valid =
[&kOtherOrigin](
content::StoragePartition::StorageKeyMatcherFunction filter) {
return filter.Run(blink::StorageKey::CreateFirstParty(
url::Origin::Create(kOtherOrigin)));
};
const auto is_filter_null =
[&](content::StoragePartition::StorageKeyMatcherFunction filter) {
return filter.is_null();
};
// Verify that each of the StoragePartition interfaces for clearing origin
// based data calls aggregation service appropriately.
EXPECT_CALL(
*private_aggregation_manager_ptr,
ClearBudgetData(
base::Time(), base::Time::Max(),
testing::AllOf(testing::Truly(is_test_origin_valid),
testing::Not(testing::Truly(is_other_origin_valid))),
testing::_))
.WillOnce(invoke_callback);
{
base::RunLoop run_loop;
partition->ClearDataForOrigin(kTestClearMask, kTestQuotaClearMask,
kTestOrigin, run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(private_aggregation_manager_ptr);
}
EXPECT_CALL(
*private_aggregation_manager_ptr,
ClearBudgetData(
kBeginTime, kEndTime,
testing::AllOf(testing::Truly(is_test_origin_valid),
testing::Not(testing::Truly(is_other_origin_valid))),
testing::_))
.WillOnce(testing::Invoke(invoke_callback));
{
base::RunLoop run_loop;
partition->ClearData(
kTestClearMask, kTestQuotaClearMask,
blink::StorageKey::CreateFirstParty(url::Origin::Create(kTestOrigin)),
kBeginTime, kEndTime, run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(private_aggregation_manager_ptr);
}
EXPECT_CALL(
*private_aggregation_manager_ptr,
ClearBudgetData(
kBeginTime, kEndTime,
testing::AllOf(testing::Truly(is_test_origin_valid),
testing::Not(testing::Truly(is_other_origin_valid))),
testing::_))
.WillOnce(testing::Invoke(invoke_callback));
{
base::RunLoop run_loop;
partition->ClearData(
kTestClearMask, kTestQuotaClearMask,
/*filter_builder=*/nullptr,
base::BindLambdaForTesting([&](const blink::StorageKey& storage_key,
storage::SpecialStoragePolicy* policy) {
return storage_key == blink::StorageKey::CreateFirstParty(
url::Origin::Create(kTestOrigin));
}),
/*cookie_deletion_filter=*/nullptr,
/*perform_storage_cleanup=*/false, kBeginTime, kEndTime,
run_loop.QuitClosure());
run_loop.Run();
testing::Mock::VerifyAndClearExpectations(private_aggregation_manager_ptr);
}
EXPECT_CALL(*private_aggregation_manager_ptr,
ClearBudgetData(kBeginTime, kEndTime,
testing::Truly(is_filter_null), testing::_))
.WillOnce(testing::Invoke(invoke_callback));
{
base::RunLoop run_loop;
partition->ClearData(kTestClearMask, kTestQuotaClearMask,
blink::StorageKey(), kBeginTime, kEndTime,
run_loop.QuitClosure());
run_loop.Run();
}
}
// https://crbug.com/1221382
// Make sure StorageServiceImpl can be stored in a SequenceLocalStorageSlot and
// that it can be safely destroyed when the thread terminates.
TEST(StorageServiceImplOnSequenceLocalStorage, ThreadDestructionDoesNotFail) {
mojo::Remote<storage::mojom::StorageService> remote_service;
mojo::Remote<storage::mojom::Partition> persistent_partition;
mojo::Remote<storage::mojom::LocalStorageControl> storage_control;
// These remotes must outlive the thread, otherwise PartitionImpl cleanup will
// not happen in the ~StorageServiceImpl but on the mojo error handler.
{
// When this variable gets out of scope the IO thread will be destroyed
// along with all objects stored in a SequenceLocalStorageSlot.
content::BrowserTaskEnvironment task_environment(
content::BrowserTaskEnvironment::REAL_IO_THREAD);
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(
[](mojo::PendingReceiver<storage::mojom::StorageService> receiver) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
static base::SequenceLocalStorageSlot<
std::unique_ptr<storage::StorageServiceImpl>>
service_storage_slot;
service_storage_slot.GetOrCreateValue() =
std::make_unique<storage::StorageServiceImpl>(
std::move(receiver),
/*io_task_runner=*/nullptr);
},
remote_service.BindNewPipeAndPassReceiver()));
// Make sure PartitionImpl gets to destroy a LocalStorageImpl object.
base::ScopedTempDir temp_dir;
CHECK(temp_dir.CreateUniqueTempDir());
remote_service->BindPartition(
temp_dir.GetPath(), persistent_partition.BindNewPipeAndPassReceiver());
persistent_partition->BindLocalStorageControl(
storage_control.BindNewPipeAndPassReceiver());
storage_control.FlushForTesting();
}
}
#if BUILDFLAG(ENABLE_DEVICE_BOUND_SESSIONS)
TEST_F(StoragePartitionImplTest, RemoveDeviceBoundSessions) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
auto device_bound_session_manager =
std::make_unique<network::MockDeviceBoundSessionManager>();
network::MockDeviceBoundSessionManager* device_bound_session_manager_raw =
device_bound_session_manager.get();
partition->OverrideDeviceBoundSessionManagerForTesting(
std::move(device_bound_session_manager));
base::Time created_before_time = base::Time::Now() - base::Days(1);
base::Time created_after_time = base::Time::Now() - base::Days(3);
EXPECT_CALL(
*device_bound_session_manager_raw,
DeleteAllSessions(Eq(created_after_time), Eq(created_before_time), _, _))
.WillOnce(WithArg<3>(Invoke([](base::OnceClosure completion_closure) {
std::move(completion_closure).Run();
})));
base::RunLoop run_loop;
partition->ClearData(StoragePartition::REMOVE_DATA_MASK_DEVICE_BOUND_SESSIONS,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
blink::StorageKey(), created_after_time,
created_before_time, run_loop.QuitClosure());
run_loop.Run();
}
#endif
class StoragePartitionImplSharedStorageTest : public StoragePartitionImplTest {
public:
StoragePartitionImplSharedStorageTest()
: storage_partition_(browser_context()->GetDefaultStoragePartition()),
shared_storage_manager_(
static_cast<StoragePartitionImpl*>(storage_partition_)
->GetSharedStorageManager()) {
feature_list_.InitWithFeatures({network::features::kInterestGroupStorage,
network::features::kSharedStorageAPI},
{});
}
StoragePartitionImplSharedStorageTest(
const StoragePartitionImplSharedStorageTest&) = delete;
StoragePartitionImplSharedStorageTest& operator=(
const StoragePartitionImplSharedStorageTest&) = delete;
~StoragePartitionImplSharedStorageTest() override {
task_environment()->RunUntilIdle();
}
scoped_refptr<storage::SpecialStoragePolicy> GetSpecialStoragePolicy() {
return base::WrapRefCounted<storage::SpecialStoragePolicy>(
static_cast<content::StoragePartitionImpl*>(storage_partition_)
->browser_context()
->GetSpecialStoragePolicy());
}
// Returns true, if the given origin URL exists.
bool SharedStorageExistsForOrigin(const url::Origin& origin) {
for (const auto& info : GetSharedStorageUsage()) {
if (origin == info->storage_key.origin())
return true;
}
return false;
}
void AddSharedStorageTestData(const url::Origin& origin1,
const url::Origin& origin2,
const url::Origin& origin3) {
base::FilePath path =
storage_partition_->GetPath().Append(storage::kSharedStoragePath);
std::unique_ptr<storage::AsyncSharedStorageDatabase> database =
storage::AsyncSharedStorageDatabaseImpl::Create(
path,
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::WithBaseSyncPrimitives(),
base::TaskShutdownBehavior::BLOCK_SHUTDOWN}),
GetSpecialStoragePolicy(),
storage::SharedStorageOptions::Create()->GetDatabaseOptions());
// Add a key for origin1.
{
base::test::TestFuture<storage::SharedStorageDatabase::OperationResult>
future;
database->Set(origin1, u"key1", u"value1", future.GetCallback());
EXPECT_EQ(storage::SharedStorageDatabase::OperationResult::kSet,
future.Get());
}
// Add a key for origin2.
{
base::test::TestFuture<storage::SharedStorageDatabase::OperationResult>
future;
database->Set(origin2, u"key1", u"value1", future.GetCallback());
EXPECT_EQ(storage::SharedStorageDatabase::OperationResult::kSet,
future.Get());
}
task_environment()->AdvanceClock(base::Milliseconds(10));
// Add a key for origin3.
{
base::test::TestFuture<storage::SharedStorageDatabase::OperationResult>
future;
database->Set(origin3, u"key1", u"value1", future.GetCallback());
EXPECT_EQ(storage::SharedStorageDatabase::OperationResult::kSet,
future.Get());
}
// Ensure that this database is fully closed before checking for existence.
database.reset();
task_environment()->RunUntilIdle();
EXPECT_TRUE(SharedStorageExistsForOrigin(origin1));
EXPECT_TRUE(SharedStorageExistsForOrigin(origin2));
EXPECT_TRUE(SharedStorageExistsForOrigin(origin3));
task_environment()->RunUntilIdle();
}
private:
std::vector<storage::mojom::StorageUsageInfoPtr> GetSharedStorageUsage() {
DCHECK(shared_storage_manager_);
base::test::TestFuture<std::vector<storage::mojom::StorageUsageInfoPtr>>
future;
shared_storage_manager_->FetchOrigins(future.GetCallback());
return future.Take();
}
base::test::ScopedFeatureList feature_list_;
// We don't own these pointers.
const raw_ptr<StoragePartition> storage_partition_;
raw_ptr<storage::SharedStorageManager> shared_storage_manager_;
};
TEST_F(StoragePartitionImplSharedStorageTest,
RemoveUnprotectedSharedStorageForever) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
// Protect kOrigin1.
auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
mock_policy->AddProtected(kOrigin1.GetURL());
AddSharedStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->GetSharedStorageManager()->OverrideSpecialStoragePolicyForTesting(
mock_policy.get());
base::RunLoop clear_run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearStuff,
StoragePartitionImpl::REMOVE_DATA_MASK_SHARED_STORAGE,
partition, base::Time(), base::Time::Max(),
/*filter_builder=*/nullptr,
base::BindRepeating(&DoesOriginMatchForUnprotectedWeb),
&clear_run_loop));
clear_run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(SharedStorageExistsForOrigin(kOrigin1));
EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin2));
EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplSharedStorageTest,
RemoveProtectedSharedStorageForever) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
// Protect kOrigin1.
auto mock_policy = base::MakeRefCounted<storage::MockSpecialStoragePolicy>();
mock_policy->AddProtected(kOrigin1.GetURL());
AddSharedStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
partition->GetSharedStorageManager()->OverrideSpecialStoragePolicyForTesting(
mock_policy.get());
base::RunLoop clear_run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&ClearStuff,
StoragePartitionImpl::REMOVE_DATA_MASK_SHARED_STORAGE,
partition, base::Time(), base::Time::Max(),
/*filter_builder=*/nullptr,
base::BindRepeating(
&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
&clear_run_loop));
clear_run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
// Even if kOrigin1 is protected, it will be deleted since we specify
// ClearData to delete protected data.
EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin1));
EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin2));
EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplSharedStorageTest, RemoveSharedStorageRecent) {
const url::Origin kOrigin1 = url::Origin::Create(GURL("http://host1:1/"));
const url::Origin kOrigin2 = url::Origin::Create(GURL("http://host2:1/"));
const url::Origin kOrigin3 = url::Origin::Create(GURL("http://host3:1/"));
base::Time start = base::Time::Now();
AddSharedStorageTestData(kOrigin1, kOrigin2, kOrigin3);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
DCHECK(partition);
// Origins 1 and 2 wrote their keys at time start, origin 3 wrote its key
// at time start+10. Delete from start+5 -> infinity.
base::RunLoop clear_run_loop;
base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(
&ClearStuff, StoragePartitionImpl::REMOVE_DATA_MASK_SHARED_STORAGE,
partition, start + base::Milliseconds(5), base::Time::Max(),
/*filter_builder=*/nullptr,
base::BindRepeating(
&DoesOriginMatchForBothProtectedAndUnprotectedWeb),
&clear_run_loop));
clear_run_loop.Run();
// ClearData only guarantees that tasks to delete data are scheduled when its
// callback is invoked. It doesn't guarantee data has actually been cleared.
// So run all scheduled tasks to make sure data is cleared.
base::RunLoop().RunUntilIdle();
// Only kOrigin3 should have been cleared.
EXPECT_TRUE(SharedStorageExistsForOrigin(kOrigin1));
EXPECT_TRUE(SharedStorageExistsForOrigin(kOrigin2));
EXPECT_FALSE(SharedStorageExistsForOrigin(kOrigin3));
}
TEST_F(StoragePartitionImplTest, PrivateNetworkAccessPermission) {
base::test::ScopedFeatureList features;
features.InitAndEnableFeature(
network::features::kPrivateNetworkAccessPermissionPrompt);
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
mojo::Remote<network::mojom::URLLoaderNetworkServiceObserver> observer(
partition->CreateAuthCertObserverForServiceWorker(
network::mojom::kBrowserProcessId));
base::test::TestFuture<bool> grant_permission;
observer->OnPrivateNetworkAccessPermissionRequired(
GURL(), net::IPAddress(192, 163, 1, 1), "test-id", "test-name",
base::BindOnce(grant_permission.GetCallback()));
EXPECT_FALSE(grant_permission.Get());
}
TEST_F(StoragePartitionImplTest, ClearDataStorageKeyDeletesPartitionedCookies) {
StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
browser_context()->GetDefaultStoragePartition());
RemoveCookieTester tester(partition);
const auto kOrigin = url::Origin::Create(GURL("https://example.com"));
const auto kPartitionKey =
net::CookiePartitionKey::FromURLForTesting(GURL("https://a.com"));
const auto kOtherPartitionKey =
net::CookiePartitionKey::FromURLForTesting(GURL("https://b.com"));
// Unpartitioned cookie.
tester.AddCookie(kOrigin);
// Partitioned cookie with two keys.
tester.AddCookie(kOrigin, kPartitionKey);
tester.AddCookie(kOrigin, kOtherPartitionKey);
ASSERT_TRUE(tester.ContainsCookie(kOrigin));
ASSERT_TRUE(tester.ContainsCookie(kOrigin, kPartitionKey));
ASSERT_TRUE(tester.ContainsCookie(kOrigin, kOtherPartitionKey));
blink::StorageKey storage_key = blink::StorageKey::Create(
kOrigin, net::SchemefulSite(GURL("https://a.com")),
blink::mojom::AncestorChainBit::kCrossSite);
ASSERT_EQ(storage_key.ToCookiePartitionKey(), kPartitionKey);
base::RunLoop run_loop;
partition->ClearData(StoragePartition::REMOVE_DATA_MASK_COOKIES,
StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
storage_key, base::Time(), base::Time::Max(),
run_loop.QuitClosure());
run_loop.Run();
// Should delete unpartitioned cookies and those in matching partition.
EXPECT_FALSE(tester.ContainsCookie(kOrigin));
EXPECT_FALSE(tester.ContainsCookie(kOrigin, kPartitionKey));
// Should not delete cookies in other partitions.
EXPECT_TRUE(tester.ContainsCookie(kOrigin, kOtherPartitionKey));
}
} // namespace content