Skip to content

Commit 61a92ca

Browse files
committed
Fix web request proxy crash by moving ownership to ResourceContext
The web request proxies will now be owned completely on the IO thread by ResourceContext. This should prevent any handlers from being run after the ResourceContext is destroyed. Bug: 878366 Change-Id: I629d81597ee3ab3835a63ebe47cb97fa4497b36a Reviewed-on: https://chromium-review.googlesource.com/1205470 Reviewed-by: Ken Rockot <rockot@chromium.org> Reviewed-by: Reilly Grant <reillyg@chromium.org> Commit-Queue: Clark DuVall <cduvall@chromium.org> Cr-Original-Commit-Position: refs/heads/master@{#588692}(cherry picked from commit 86bc694) Reviewed-on: https://chromium-review.googlesource.com/1207354 Reviewed-by: Clark DuVall <cduvall@chromium.org> Cr-Commit-Position: refs/branch-heads/3538@{#50} Cr-Branched-From: 79f7c91-refs/heads/master@{#587811}
1 parent b982894 commit 61a92ca

File tree

6 files changed

+52
-75
lines changed

6 files changed

+52
-75
lines changed

extensions/browser/api/web_request/web_request_api.cc

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "content/public/browser/browser_thread.h"
3131
#include "content/public/browser/render_frame_host.h"
3232
#include "content/public/browser/render_process_host.h"
33+
#include "content/public/browser/resource_context.h"
3334
#include "content/public/browser/resource_request_info.h"
3435
#include "content/public/browser/storage_partition.h"
3536
#include "content/public/browser/web_contents.h"
@@ -141,6 +142,10 @@ const char* const kWebRequestEvents[] = {
141142
keys::kOnHeadersReceivedEvent,
142143
};
143144

145+
// User data key for WebRequestAPI::ProxySet.
146+
const void* const kWebRequestProxySetUserDataKey =
147+
&kWebRequestProxySetUserDataKey;
148+
144149
const char* GetRequestStageAsString(
145150
ExtensionWebRequestEventRouter::EventTypes type) {
146151
switch (type) {
@@ -387,6 +392,19 @@ std::unique_ptr<WebRequestEventDetails> CreateEventDetails(
387392
return std::make_unique<WebRequestEventDetails>(request, extra_info_spec);
388393
}
389394

395+
void MaybeProxyAuthRequestOnIO(
396+
content::ResourceContext* resource_context,
397+
net::AuthChallengeInfo* auth_info,
398+
scoped_refptr<net::HttpResponseHeaders> response_headers,
399+
const content::GlobalRequestID& request_id,
400+
WebRequestAPI::AuthRequestCallback callback) {
401+
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
402+
auto* proxies =
403+
WebRequestAPI::ProxySet::GetFromResourceContext(resource_context);
404+
proxies->MaybeProxyAuthRequest(auth_info, std::move(response_headers),
405+
request_id, std::move(callback));
406+
}
407+
390408
} // namespace
391409

392410
void WebRequestAPI::Proxy::HandleAuthRequest(
@@ -401,16 +419,25 @@ void WebRequestAPI::Proxy::HandleAuthRequest(
401419
}
402420

403421
WebRequestAPI::ProxySet::ProxySet() {
404-
DCHECK_CURRENTLY_ON(BrowserThread::UI);
422+
DCHECK_CURRENTLY_ON(BrowserThread::IO);
405423
}
406424

407425
WebRequestAPI::ProxySet::~ProxySet() {
408426
DCHECK_CURRENTLY_ON(BrowserThread::IO);
409427
}
410428

429+
WebRequestAPI::ProxySet* WebRequestAPI::ProxySet::GetFromResourceContext(
430+
content::ResourceContext* resource_context) {
431+
if (!resource_context->GetUserData(kWebRequestProxySetUserDataKey)) {
432+
resource_context->SetUserData(kWebRequestProxySetUserDataKey,
433+
std::make_unique<WebRequestAPI::ProxySet>());
434+
}
435+
return static_cast<WebRequestAPI::ProxySet*>(
436+
resource_context->GetUserData(kWebRequestProxySetUserDataKey));
437+
}
438+
411439
void WebRequestAPI::ProxySet::AddProxy(std::unique_ptr<Proxy> proxy) {
412440
DCHECK_CURRENTLY_ON(BrowserThread::IO);
413-
DCHECK(!is_shutdown_);
414441

415442
proxies_.insert(std::move(proxy));
416443
}
@@ -430,13 +457,6 @@ void WebRequestAPI::ProxySet::RemoveProxy(Proxy* proxy) {
430457
proxies_.erase(proxy_it);
431458
}
432459

433-
void WebRequestAPI::ProxySet::Shutdown() {
434-
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
435-
is_shutdown_ = true;
436-
437-
proxies_.clear();
438-
}
439-
440460
void WebRequestAPI::ProxySet::AssociateProxyWithRequestId(
441461
Proxy* proxy,
442462
const content::GlobalRequestID& id) {
@@ -490,7 +510,6 @@ void WebRequestAPI::ProxySet::MaybeProxyAuthRequest(
490510
WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
491511
: browser_context_(context),
492512
info_map_(ExtensionSystem::Get(browser_context_)->info_map()),
493-
proxies_(base::MakeRefCounted<ProxySet>()),
494513
request_id_generator_(base::MakeRefCounted<RequestIDGenerator>()),
495514
may_have_proxies_(MayHaveProxies()),
496515
rules_monitor_observer_(this),
@@ -516,10 +535,6 @@ WebRequestAPI::WebRequestAPI(content::BrowserContext* context)
516535
}
517536

518537
WebRequestAPI::~WebRequestAPI() {
519-
proxies_->SetAPIDestroyed();
520-
BrowserThread::PostTask(
521-
BrowserThread::IO, FROM_HERE,
522-
base::BindOnce(&ProxySet::Shutdown, std::move(proxies_)));
523538
}
524539

525540
void WebRequestAPI::Shutdown() {
@@ -614,7 +629,7 @@ bool WebRequestAPI::MaybeProxyURLLoaderFactory(
614629
is_for_browser_initiated_requests ? -1 : frame->GetProcess()->GetID(),
615630
request_id_generator_, std::move(navigation_ui_data),
616631
base::Unretained(info_map_), std::move(proxied_request),
617-
std::move(target_factory_info), proxies_));
632+
std::move(target_factory_info)));
618633
return true;
619634
}
620635

@@ -632,7 +647,8 @@ bool WebRequestAPI::MaybeProxyAuthRequest(
632647
proxied_request_id.child_id = -1;
633648
BrowserThread::PostTask(
634649
BrowserThread::IO, FROM_HERE,
635-
base::BindOnce(&ProxySet::MaybeProxyAuthRequest, proxies_,
650+
base::BindOnce(&MaybeProxyAuthRequestOnIO,
651+
browser_context_->GetResourceContext(),
636652
base::RetainedRef(auth_info), std::move(response_headers),
637653
proxied_request_id, std::move(callback)));
638654
return true;
@@ -660,8 +676,7 @@ void WebRequestAPI::MaybeProxyWebSocket(
660676
frame->GetProcess()->GetBrowserContext(),
661677
frame->GetProcess()->GetBrowserContext()->GetResourceContext(),
662678
base::Unretained(info_map_), std::move(proxied_socket_ptr_info),
663-
std::move(proxied_request), std::move(authentication_request),
664-
proxies_));
679+
std::move(proxied_request), std::move(authentication_request)));
665680
}
666681

667682
bool WebRequestAPI::MayHaveProxies() const {

extensions/browser/api/web_request/web_request_api.h

Lines changed: 9 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -105,31 +105,21 @@ class WebRequestAPI
105105
};
106106

107107
// A ProxySet is a set of proxies used by WebRequestAPI: It holds Proxy
108-
// instances, and removes all proxies when the WebRequestAPI instance is
109-
// gone, on the IO thread.
110-
// This proxy set is created on the UI thread but anything else other than
111-
// AddRef() and Release() including destruction will be done in the IO thread.
112-
class ProxySet : public base::RefCountedThreadSafe<
113-
ProxySet,
114-
content::BrowserThread::DeleteOnIOThread> {
108+
// instances, and removes all proxies when the ResourceContext it is bound to
109+
// is destroyed.
110+
class ProxySet : public base::SupportsUserData::Data {
115111
public:
116112
ProxySet();
113+
~ProxySet() override;
117114

118-
// Add a Proxy. This can be called only when |is_shutdown()| is false.
115+
// Gets or creates a ProxySet from the given ResourceContext.
116+
static ProxySet* GetFromResourceContext(
117+
content::ResourceContext* resource_context);
118+
119+
// Add a Proxy.
119120
void AddProxy(std::unique_ptr<Proxy> proxy);
120121
// Remove a Proxy. The removed proxy is deleted upon this call.
121122
void RemoveProxy(Proxy* proxy);
122-
// Set is_shutdown_ and deletes app proxies.
123-
void Shutdown();
124-
bool is_shutdown() const {
125-
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
126-
return is_shutdown_;
127-
}
128-
129-
// Threadsafe methods to check and set if the WebRequestAPI has been
130-
// destroyed.
131-
void SetAPIDestroyed() { api_destroyed_.Set(); }
132-
bool IsAPIDestroyed() { return api_destroyed_.IsSet(); }
133123

134124
// Associates |proxy| with |id|. |proxy| must already be registered within
135125
// this ProxySet.
@@ -153,31 +143,16 @@ class WebRequestAPI
153143
AuthRequestCallback callback);
154144

155145
private:
156-
friend struct content::BrowserThread::DeleteOnThread<
157-
content::BrowserThread::IO>;
158-
friend class base::DeleteHelper<ProxySet>;
159-
160-
~ProxySet();
161-
162146
// Although these members are initialized on the UI thread, we expect at
163147
// least one memory barrier before actually calling Generate in the IO
164148
// thread, so we don't protect them with a lock.
165149
std::set<std::unique_ptr<Proxy>, base::UniquePtrComparator> proxies_;
166-
bool is_shutdown_ = false;
167150

168151
// Bi-directional mapping between request ID and Proxy for faster lookup.
169152
std::map<content::GlobalRequestID, Proxy*> request_id_to_proxy_map_;
170153
std::map<Proxy*, std::set<content::GlobalRequestID>>
171154
proxy_to_request_id_map_;
172155

173-
// Tracks whether the WebRequestAPI has been destroyed. Since WebRequestAPI
174-
// is destroyed on the UI thread, and ProxySet is destroyed on the IO
175-
// thread, there may be race conditions where a Proxy mojo pipe receives a
176-
// connection error after WebRequestAPI is destroyed but before the ProxySet
177-
// has been destroyed. Before running any error handlers, make sure to check
178-
// this flag.
179-
base::AtomicFlag api_destroyed_;
180-
181156
DISALLOW_COPY_AND_ASSIGN(ProxySet);
182157
};
183158

@@ -276,9 +251,6 @@ class WebRequestAPI
276251
content::BrowserContext* const browser_context_;
277252
InfoMap* const info_map_;
278253

279-
// Active proxies. Only used when the Network Service is enabled.
280-
scoped_refptr<ProxySet> proxies_;
281-
282254
scoped_refptr<RequestIDGenerator> request_id_generator_;
283255

284256
// Stores the last result of |MayHaveProxies()|, so it can be used in

extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -522,9 +522,6 @@ void WebRequestProxyingURLLoaderFactory::InProgressRequest::
522522
}
523523
void WebRequestProxyingURLLoaderFactory::InProgressRequest::OnRequestError(
524524
const network::URLLoaderCompletionStatus& status) {
525-
if (factory_->proxies_->IsAPIDestroyed())
526-
return;
527-
528525
if (!request_completed_) {
529526
target_client_->OnComplete(status);
530527
ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(
@@ -587,16 +584,15 @@ void WebRequestProxyingURLLoaderFactory::StartProxying(
587584
std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
588585
InfoMap* info_map,
589586
network::mojom::URLLoaderFactoryRequest loader_request,
590-
network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
591-
scoped_refptr<WebRequestAPI::ProxySet> proxies) {
587+
network::mojom::URLLoaderFactoryPtrInfo target_factory_info) {
592588
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
593-
if (proxies->is_shutdown())
594-
return;
589+
auto* proxies =
590+
WebRequestAPI::ProxySet::GetFromResourceContext(resource_context);
595591

596592
auto proxy = std::make_unique<WebRequestProxyingURLLoaderFactory>(
597593
browser_context, resource_context, render_process_id,
598594
std::move(request_id_generator), std::move(navigation_ui_data), info_map,
599-
std::move(loader_request), std::move(target_factory_info), proxies.get());
595+
std::move(loader_request), std::move(target_factory_info), proxies);
600596

601597
proxies->AddProxy(std::move(proxy));
602598
}

extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,7 @@ class WebRequestProxyingURLLoaderFactory
169169
std::unique_ptr<ExtensionNavigationUIData> navigation_ui_data,
170170
InfoMap* info_map,
171171
network::mojom::URLLoaderFactoryRequest loader_request,
172-
network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
173-
scoped_refptr<WebRequestAPI::ProxySet> proxies);
172+
network::mojom::URLLoaderFactoryPtrInfo target_factory_info);
174173

175174
// network::mojom::URLLoaderFactory:
176175
void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader_request,

extensions/browser/api/web_request/web_request_proxying_websocket.cc

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -265,17 +265,16 @@ void WebRequestProxyingWebSocket::StartProxying(
265265
InfoMap* info_map,
266266
network::mojom::WebSocketPtrInfo proxied_socket_ptr_info,
267267
network::mojom::WebSocketRequest proxied_request,
268-
network::mojom::AuthenticationHandlerRequest auth_request,
269-
scoped_refptr<WebRequestAPI::ProxySet> proxies) {
268+
network::mojom::AuthenticationHandlerRequest auth_request) {
270269
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
271-
if (proxies->is_shutdown())
272-
return;
270+
auto* proxies =
271+
WebRequestAPI::ProxySet::GetFromResourceContext(resource_context);
273272

274273
auto proxy = std::make_unique<WebRequestProxyingWebSocket>(
275274
process_id, render_frame_id, origin, browser_context, resource_context,
276275
info_map, std::move(request_id_generator),
277276
network::mojom::WebSocketPtr(std::move(proxied_socket_ptr_info)),
278-
std::move(proxied_request), std::move(auth_request), proxies.get());
277+
std::move(proxied_request), std::move(auth_request), proxies);
279278

280279
proxies->AddProxy(std::move(proxy));
281280
}
@@ -400,9 +399,6 @@ void WebRequestProxyingWebSocket::ResumeIncomingMethodCallProcessing() {
400399
}
401400

402401
void WebRequestProxyingWebSocket::OnError(int error_code) {
403-
if (proxies_->IsAPIDestroyed())
404-
return;
405-
406402
if (!is_done_) {
407403
is_done_ = true;
408404
ExtensionWebRequestEventRouter::GetInstance()->OnErrorOccurred(

extensions/browser/api/web_request/web_request_proxying_websocket.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ class WebRequestProxyingWebSocket
9494
InfoMap* info_map,
9595
network::mojom::WebSocketPtrInfo proxied_socket_ptr_info,
9696
network::mojom::WebSocketRequest proxied_request,
97-
network::mojom::AuthenticationHandlerRequest auth_request,
98-
scoped_refptr<WebRequestAPI::ProxySet> proxies);
97+
network::mojom::AuthenticationHandlerRequest auth_request);
9998

10099
private:
101100
void OnBeforeRequestComplete(int error_code);

0 commit comments

Comments
 (0)