0

[Extensions] Remove webRequest data when a BrowserContext is destroyed.

The ExtensionWebRequestRouter is a singleton object that can outlive
a BrowserContext. This CL clears any data related to a BrowserContext
when it's destroyed.

Bug: 1024211
Change-Id: Idd77a089c284037c08e8737b36402fcaf4bd4646
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3445250
Reviewed-by: Devlin Cronin <rdevlin.cronin@chromium.org>
Commit-Queue: David Bertoni <dbertoni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#969698}
This commit is contained in:
David Bertoni
2022-02-11 00:04:12 +00:00
committed by Chromium LUCI CQ
parent 1e13a54982
commit 016d88efc2
3 changed files with 90 additions and 16 deletions
chrome/browser/extensions/api/web_request
extensions/browser/api/web_request

@ -190,6 +190,83 @@ TEST_F(ExtensionWebRequestTest, AddAndRemoveListeners) {
&profile_, kEventName));
}
// Tests that when a browser_context shuts down, all data keyed to that
// context is removed.
TEST_F(ExtensionWebRequestTest, BrowserContextShutdown) {
ExtensionWebRequestEventRouter* const event_router =
ExtensionWebRequestEventRouter::GetInstance();
ASSERT_TRUE(event_router);
std::string ext_id("abcdefghijklmnopabcdefghijklmnop");
ExtensionWebRequestEventRouter::RequestFilter filter;
const std::string kEventName(web_request::OnBeforeRequest::kEventName);
const std::string kSubEventName = kEventName + "/1";
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(&profile_, kEventName));
EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(&profile_));
// Add two listeners for the main profile.
event_router->AddEventListener(
&profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
filter, 0, 1 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->AddEventListener(
&profile_, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
filter, 0, 2 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->IncrementExtraHeadersListenerCount(&profile_);
EXPECT_EQ(2u,
event_router->GetListenerCountForTesting(&profile_, kEventName));
EXPECT_TRUE(event_router->HasAnyExtraHeadersListenerImpl(&profile_));
// Create an off-the-record profile.
auto otr_profile_id = Profile::OTRProfileID::CreateUniqueForTesting();
Profile* const otr_profile =
profile_.GetOffTheRecordProfile(otr_profile_id,
/*create_if_needed=*/true);
ASSERT_TRUE(otr_profile);
// Because the ExtensionWebRequestEventRouter is a singleton, there are hooks
// in the off-the-record profile for notifying it when an OTR profile is
// created and destroyed. Unfortunately, that doesn't work with test profiles,
// so the test needs to simulate those calls
event_router->OnOTRBrowserContextCreated(&profile_, otr_profile);
EXPECT_EQ(2u, event_router->cross_browser_context_map_.size());
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
// Add two listeners for the otr profile.
event_router->AddEventListener(
otr_profile, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
filter, 0, 1 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->AddEventListener(
otr_profile, ext_id, ext_id, events::FOR_TEST, kEventName, kSubEventName,
filter, 0, 2 /* render_process_id */, 0, extensions::kMainThreadId,
blink::mojom::kInvalidServiceWorkerVersionId);
event_router->IncrementExtraHeadersListenerCount(otr_profile);
EXPECT_EQ(2u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
EXPECT_TRUE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
// Simulate the OTR being destroyed.
event_router->OnOTRBrowserContextDestroyed(&profile_, otr_profile);
EXPECT_EQ(0u, event_router->cross_browser_context_map_.size());
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(otr_profile, kEventName));
EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(otr_profile));
// We can't just delete the profile, because the call comes through the
// WebRequestAPI instance for that profile, and creating that requires
// more infrastucture than it's worth. Instead, simulate it with a call
// into the event router directly.
event_router->OnBrowserContextShutdown(&profile_);
EXPECT_EQ(0u,
event_router->GetListenerCountForTesting(&profile_, kEventName));
EXPECT_FALSE(event_router->HasAnyExtraHeadersListenerImpl(&profile_));
}
namespace {
void TestInitFromValue(content::BrowserContext* browser_context,

@ -649,6 +649,8 @@ void WebRequestAPI::Shutdown() {
proxies_.reset();
EventRouter::Get(browser_context_)->UnregisterObserver(this);
extensions::ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
ExtensionWebRequestEventRouter::GetInstance()->OnBrowserContextShutdown(
browser_context_);
}
static base::LazyInstance<
@ -1818,6 +1820,7 @@ void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
content::BrowserContext* otr_browser_context) {
cross_browser_context_map_.erase(otr_browser_context);
cross_browser_context_map_.erase(original_browser_context);
OnBrowserContextShutdown(otr_browser_context);
}
void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
@ -1875,7 +1878,6 @@ void ExtensionWebRequestEventRouter::IncrementExtraHeadersListenerCount(
// We only keep values greater than 0 in the map.
DCHECK_GT(result.first->second, 0);
result.first->second++;
return;
}
}
@ -1891,6 +1893,12 @@ void ExtensionWebRequestEventRouter::DecrementExtraHeadersListenerCount(
extra_headers_listener_count_.erase(it);
}
void ExtensionWebRequestEventRouter::OnBrowserContextShutdown(
content::BrowserContext* browser_context) {
listeners_.erase(browser_context);
extra_headers_listener_count_.erase(browser_context);
}
bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListenerImpl(
content::BrowserContext* browser_context) {
return base::Contains(extra_headers_listener_count_, browser_context);

@ -534,25 +534,14 @@ class ExtensionWebRequestEventRouter {
void DecrementExtraHeadersListenerCount(
content::BrowserContext* browser_context);
// Called when a BrowserContext is being destroyed.
void OnBrowserContextShutdown(content::BrowserContext* browser_context);
private:
friend class WebRequestAPI;
friend class base::NoDestructor<ExtensionWebRequestEventRouter>;
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest,
BlockingEventPrecedenceRedirect);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest,
BlockingEventPrecedenceCancel);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest,
SimulateChancelWhileBlocked);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, AccessRequestBodyData);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest,
MinimalAccessRequestBodyData);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest,
ProperFilteringInPublicSession);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, NoAccessRequestBodyData);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, AddAndRemoveListeners);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, BlockedRequestsAreRemoved);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestHeaderModificationTest,
TestModifications);
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, BrowserContextShutdown);
struct EventListener {
// TODO(rdevlin.cronin): There are two types of EventListeners - those