[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:

committed by
Chromium LUCI CQ

parent
1e13a54982
commit
016d88efc2
chrome/browser/extensions/api/web_request
extensions/browser/api/web_request
@@ -190,6 +190,83 @@ TEST_F(ExtensionWebRequestTest, AddAndRemoveListeners) {
|
|||||||
&profile_, kEventName));
|
&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 {
|
namespace {
|
||||||
|
|
||||||
void TestInitFromValue(content::BrowserContext* browser_context,
|
void TestInitFromValue(content::BrowserContext* browser_context,
|
||||||
|
@@ -649,6 +649,8 @@ void WebRequestAPI::Shutdown() {
|
|||||||
proxies_.reset();
|
proxies_.reset();
|
||||||
EventRouter::Get(browser_context_)->UnregisterObserver(this);
|
EventRouter::Get(browser_context_)->UnregisterObserver(this);
|
||||||
extensions::ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
|
extensions::ExtensionRegistry::Get(browser_context_)->RemoveObserver(this);
|
||||||
|
ExtensionWebRequestEventRouter::GetInstance()->OnBrowserContextShutdown(
|
||||||
|
browser_context_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static base::LazyInstance<
|
static base::LazyInstance<
|
||||||
@@ -1818,6 +1820,7 @@ void ExtensionWebRequestEventRouter::OnOTRBrowserContextDestroyed(
|
|||||||
content::BrowserContext* otr_browser_context) {
|
content::BrowserContext* otr_browser_context) {
|
||||||
cross_browser_context_map_.erase(otr_browser_context);
|
cross_browser_context_map_.erase(otr_browser_context);
|
||||||
cross_browser_context_map_.erase(original_browser_context);
|
cross_browser_context_map_.erase(original_browser_context);
|
||||||
|
OnBrowserContextShutdown(otr_browser_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
|
void ExtensionWebRequestEventRouter::AddCallbackForPageLoad(
|
||||||
@@ -1875,7 +1878,6 @@ void ExtensionWebRequestEventRouter::IncrementExtraHeadersListenerCount(
|
|||||||
// We only keep values greater than 0 in the map.
|
// We only keep values greater than 0 in the map.
|
||||||
DCHECK_GT(result.first->second, 0);
|
DCHECK_GT(result.first->second, 0);
|
||||||
result.first->second++;
|
result.first->second++;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1891,6 +1893,12 @@ void ExtensionWebRequestEventRouter::DecrementExtraHeadersListenerCount(
|
|||||||
extra_headers_listener_count_.erase(it);
|
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(
|
bool ExtensionWebRequestEventRouter::HasAnyExtraHeadersListenerImpl(
|
||||||
content::BrowserContext* browser_context) {
|
content::BrowserContext* browser_context) {
|
||||||
return base::Contains(extra_headers_listener_count_, browser_context);
|
return base::Contains(extra_headers_listener_count_, browser_context);
|
||||||
|
@@ -534,25 +534,14 @@ class ExtensionWebRequestEventRouter {
|
|||||||
void DecrementExtraHeadersListenerCount(
|
void DecrementExtraHeadersListenerCount(
|
||||||
content::BrowserContext* browser_context);
|
content::BrowserContext* browser_context);
|
||||||
|
|
||||||
|
// Called when a BrowserContext is being destroyed.
|
||||||
|
void OnBrowserContextShutdown(content::BrowserContext* browser_context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class WebRequestAPI;
|
friend class WebRequestAPI;
|
||||||
friend class base::NoDestructor<ExtensionWebRequestEventRouter>;
|
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, AddAndRemoveListeners);
|
||||||
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, BlockedRequestsAreRemoved);
|
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestTest, BrowserContextShutdown);
|
||||||
FRIEND_TEST_ALL_PREFIXES(ExtensionWebRequestHeaderModificationTest,
|
|
||||||
TestModifications);
|
|
||||||
|
|
||||||
struct EventListener {
|
struct EventListener {
|
||||||
// TODO(rdevlin.cronin): There are two types of EventListeners - those
|
// TODO(rdevlin.cronin): There are two types of EventListeners - those
|
||||||
|
Reference in New Issue
Block a user