1 // Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "libcef/browser/net_service/resource_request_handler_wrapper.h"
6
7 #include "libcef/browser/browser_host_base.h"
8 #include "libcef/browser/context.h"
9 #include "libcef/browser/iothread_state.h"
10 #include "libcef/browser/net_service/cookie_helper.h"
11 #include "libcef/browser/net_service/proxy_url_loader_factory.h"
12 #include "libcef/browser/net_service/resource_handler_wrapper.h"
13 #include "libcef/browser/net_service/response_filter_wrapper.h"
14 #include "libcef/browser/prefs/browser_prefs.h"
15 #include "libcef/browser/thread_util.h"
16 #include "libcef/common/app_manager.h"
17 #include "libcef/common/net/scheme_registration.h"
18 #include "libcef/common/net_service/net_service_util.h"
19 #include "libcef/common/request_impl.h"
20 #include "libcef/common/response_impl.h"
21
22 #include "chrome/browser/profiles/profile.h"
23 #include "components/language/core/browser/pref_names.h"
24 #include "components/prefs/pref_service.h"
25 #include "content/browser/renderer_host/frame_tree_node.h"
26 #include "content/browser/renderer_host/render_frame_host_impl.h"
27 #include "content/browser/storage_partition_impl.h"
28 #include "content/public/browser/browser_context.h"
29 #include "content/public/browser/render_frame_host.h"
30 #include "content/public/browser/render_process_host.h"
31 #include "content/public/browser/render_view_host.h"
32 #include "content/public/browser/web_contents.h"
33 #include "net/base/load_flags.h"
34 #include "net/http/http_status_code.h"
35 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
36 #include "ui/base/page_transition_types.h"
37 #include "url/origin.h"
38
39 namespace net_service {
40
41 namespace {
42
43 const int kLoadNoCookiesFlags =
44 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
45
46 class RequestCallbackWrapper : public CefCallback {
47 public:
48 using Callback = base::OnceCallback<void(bool /* allow */)>;
RequestCallbackWrapper(Callback callback)49 explicit RequestCallbackWrapper(Callback callback)
50 : callback_(std::move(callback)),
51 work_thread_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
52
53 RequestCallbackWrapper(const RequestCallbackWrapper&) = delete;
54 RequestCallbackWrapper& operator=(const RequestCallbackWrapper&) = delete;
55
~RequestCallbackWrapper()56 ~RequestCallbackWrapper() override {
57 if (!callback_.is_null()) {
58 // Make sure it executes on the correct thread.
59 work_thread_task_runner_->PostTask(
60 FROM_HERE, base::BindOnce(std::move(callback_), true));
61 }
62 }
63
Continue()64 void Continue() override { ContinueNow(true); }
65
Cancel()66 void Cancel() override { ContinueNow(false); }
67
68 private:
ContinueNow(bool allow)69 void ContinueNow(bool allow) {
70 if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
71 work_thread_task_runner_->PostTask(
72 FROM_HERE,
73 base::BindOnce(&RequestCallbackWrapper::ContinueNow, this, allow));
74 return;
75 }
76 if (!callback_.is_null()) {
77 std::move(callback_).Run(allow);
78 }
79 }
80
81 Callback callback_;
82
83 scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
84
85 IMPLEMENT_REFCOUNTING(RequestCallbackWrapper);
86 };
87
88 class InterceptedRequestHandlerWrapper : public InterceptedRequestHandler {
89 public:
90 struct RequestState {
RequestStatenet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::RequestState91 RequestState() {}
92
Resetnet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::RequestState93 void Reset(CefRefPtr<CefResourceRequestHandler> handler,
94 CefRefPtr<CefSchemeHandlerFactory> scheme_factory,
95 CefRefPtr<CefRequestImpl> request,
96 bool request_was_redirected,
97 CancelRequestCallback cancel_callback) {
98 handler_ = handler;
99 scheme_factory_ = scheme_factory;
100 cookie_filter_ = nullptr;
101 pending_request_ = request;
102 pending_response_ = nullptr;
103 request_was_redirected_ = request_was_redirected;
104 was_custom_handled_ = false;
105 cancel_callback_ = std::move(cancel_callback);
106 }
107
108 CefRefPtr<CefResourceRequestHandler> handler_;
109 CefRefPtr<CefSchemeHandlerFactory> scheme_factory_;
110 CefRefPtr<CefCookieAccessFilter> cookie_filter_;
111 CefRefPtr<CefRequestImpl> pending_request_;
112 CefRefPtr<CefResponseImpl> pending_response_;
113 bool request_was_redirected_ = false;
114 bool was_custom_handled_ = false;
115 CancelRequestCallback cancel_callback_;
116 };
117
118 struct PendingRequest {
PendingRequestnet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::PendingRequest119 PendingRequest(int32_t request_id,
120 network::ResourceRequest* request,
121 bool request_was_redirected,
122 OnBeforeRequestResultCallback callback,
123 CancelRequestCallback cancel_callback)
124 : id_(request_id),
125 request_(request),
126 request_was_redirected_(request_was_redirected),
127 callback_(std::move(callback)),
128 cancel_callback_(std::move(cancel_callback)) {}
129
~PendingRequestnet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::PendingRequest130 ~PendingRequest() {
131 if (cancel_callback_) {
132 std::move(cancel_callback_).Run(net::ERR_ABORTED);
133 }
134 }
135
Runnet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::PendingRequest136 void Run(InterceptedRequestHandlerWrapper* self) {
137 self->OnBeforeRequest(id_, request_, request_was_redirected_,
138 std::move(callback_), std::move(cancel_callback_));
139 }
140
141 const int32_t id_;
142 network::ResourceRequest* const request_;
143 const bool request_was_redirected_;
144 OnBeforeRequestResultCallback callback_;
145 CancelRequestCallback cancel_callback_;
146 };
147
148 // Observer to receive notification of CEF context or associated browser
149 // destruction. Only one of the *Destroyed() methods will be called.
150 class DestructionObserver : public CefBrowserHostBase::Observer,
151 public CefContext::Observer {
152 public:
DestructionObserver(CefBrowserHostBase * browser)153 explicit DestructionObserver(CefBrowserHostBase* browser) {
154 if (browser) {
155 browser_info_ = browser->browser_info();
156 browser->AddObserver(this);
157 } else {
158 CefContext::Get()->AddObserver(this);
159 }
160 }
161
162 DestructionObserver(const DestructionObserver&) = delete;
163 DestructionObserver& operator=(const DestructionObserver&) = delete;
164
~DestructionObserver()165 virtual ~DestructionObserver() {
166 CEF_REQUIRE_UIT();
167 if (!registered_)
168 return;
169
170 // Verify that the browser or context still exists before attempting to
171 // remove the observer.
172 if (browser_info_) {
173 auto browser = browser_info_->browser();
174 if (browser)
175 browser->RemoveObserver(this);
176 } else if (CefContext::Get()) {
177 // Network requests may be torn down during shutdown, so we can't check
178 // CONTEXT_STATE_VALID() here.
179 CefContext::Get()->RemoveObserver(this);
180 }
181 }
182
SetWrapper(base::WeakPtr<InterceptedRequestHandlerWrapper> wrapper)183 void SetWrapper(base::WeakPtr<InterceptedRequestHandlerWrapper> wrapper) {
184 CEF_REQUIRE_IOT();
185 wrapper_ = wrapper;
186 }
187
OnBrowserDestroyed(CefBrowserHostBase * browser)188 void OnBrowserDestroyed(CefBrowserHostBase* browser) override {
189 CEF_REQUIRE_UIT();
190 browser->RemoveObserver(this);
191 registered_ = false;
192 browser_info_ = nullptr;
193 NotifyOnDestroyed();
194 }
195
OnContextDestroyed()196 void OnContextDestroyed() override {
197 CEF_REQUIRE_UIT();
198 CefContext::Get()->RemoveObserver(this);
199 registered_ = false;
200 NotifyOnDestroyed();
201 }
202
203 private:
NotifyOnDestroyed()204 void NotifyOnDestroyed() {
205 if (wrapper_.MaybeValid()) {
206 // This will be a no-op if the WeakPtr is invalid.
207 CEF_POST_TASK(
208 CEF_IOT,
209 base::BindOnce(&InterceptedRequestHandlerWrapper::OnDestroyed,
210 wrapper_));
211 }
212 }
213
214 scoped_refptr<CefBrowserInfo> browser_info_;
215 bool registered_ = true;
216
217 base::WeakPtr<InterceptedRequestHandlerWrapper> wrapper_;
218 };
219
220 // Holds state information for InterceptedRequestHandlerWrapper. State is
221 // initialized on the UI thread and later passed to the *Wrapper object on
222 // the IO thread.
223 struct InitState {
InitStatenet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitState224 InitState() {}
225
~InitStatenet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitState226 ~InitState() {
227 if (destruction_observer_) {
228 if (initialized_) {
229 // Clear the reference added in
230 // InterceptedRequestHandlerWrapper::SetInitialized().
231 destruction_observer_->SetWrapper(nullptr);
232 }
233 DeleteDestructionObserver();
234 }
235 }
236
Initializenet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitState237 void Initialize(content::BrowserContext* browser_context,
238 CefRefPtr<CefBrowserHostBase> browser,
239 CefRefPtr<CefFrame> frame,
240 const content::GlobalRenderFrameHostId& global_id,
241 bool is_navigation,
242 bool is_download,
243 const url::Origin& request_initiator,
244 const base::RepeatingClosure& unhandled_request_callback) {
245 CEF_REQUIRE_UIT();
246
247 auto profile = Profile::FromBrowserContext(browser_context);
248 auto cef_browser_context = CefBrowserContext::FromProfile(profile);
249 browser_context_getter_ = cef_browser_context->getter();
250 iothread_state_ = cef_browser_context->iothread_state();
251 CHECK(iothread_state_);
252 cookieable_schemes_ = cef_browser_context->GetCookieableSchemes();
253
254 // We register to be notified of CEF context or browser destruction so
255 // that we can stop accepting new requests and cancel pending/in-progress
256 // requests in a timely manner (e.g. before we start asserting about
257 // leaked objects during CEF shutdown).
258 destruction_observer_.reset(new DestructionObserver(browser.get()));
259
260 if (browser) {
261 // These references will be released in OnDestroyed().
262 browser_ = browser;
263 frame_ = frame;
264 }
265
266 global_id_ = global_id;
267 is_navigation_ = is_navigation;
268 is_download_ = is_download;
269 request_initiator_ = request_initiator.Serialize();
270 unhandled_request_callback_ = unhandled_request_callback;
271
272 // Default values for standard headers.
273 accept_language_ = browser_prefs::GetAcceptLanguageList(
274 cef_browser_context, browser.get(), /*expand=*/true);
275 DCHECK(!accept_language_.empty());
276 user_agent_ =
277 CefAppManager::Get()->GetContentClient()->browser()->GetUserAgent();
278 DCHECK(!user_agent_.empty());
279 }
280
DeleteDestructionObservernet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitState281 void DeleteDestructionObserver() {
282 DCHECK(destruction_observer_);
283 CEF_POST_TASK(
284 CEF_UIT,
285 base::BindOnce(&InitState::DeleteDestructionObserverOnUIThread,
286 std::move(destruction_observer_)));
287 }
288
DeleteDestructionObserverOnUIThreadnet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitState289 static void DeleteDestructionObserverOnUIThread(
290 std::unique_ptr<DestructionObserver> observer) {}
291
292 // Only accessed on the UI thread.
293 CefBrowserContext::Getter browser_context_getter_;
294
295 bool initialized_ = false;
296
297 CefRefPtr<CefBrowserHostBase> browser_;
298 CefRefPtr<CefFrame> frame_;
299 scoped_refptr<CefIOThreadState> iothread_state_;
300 CefBrowserContext::CookieableSchemes cookieable_schemes_;
301 content::GlobalRenderFrameHostId global_id_;
302 bool is_navigation_ = true;
303 bool is_download_ = false;
304 CefString request_initiator_;
305 base::RepeatingClosure unhandled_request_callback_;
306
307 // Default values for standard headers.
308 std::string accept_language_;
309 std::string user_agent_;
310
311 // Used to route authentication and certificate callbacks through the
312 // associated StoragePartition instance.
313 mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
314 url_loader_network_observer_;
315 bool did_try_create_url_loader_network_observer_ = false;
316
317 // Used to receive destruction notification.
318 std::unique_ptr<DestructionObserver> destruction_observer_;
319 };
320
321 // Manages InterceptedRequestHandlerWrapper initialization. The *Wrapper
322 // object is owned by ProxyURLLoaderFactory and may be deleted before
323 // SetInitialized() is called.
324 struct InitHelper : base::RefCountedThreadSafe<InitHelper> {
325 public:
InitHelpernet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitHelper326 explicit InitHelper(InterceptedRequestHandlerWrapper* wrapper)
327 : wrapper_(wrapper) {}
328
329 InitHelper(const InitHelper&) = delete;
330 InitHelper& operator=(const InitHelper&) = delete;
331
MaybeSetInitializednet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitHelper332 void MaybeSetInitialized(std::unique_ptr<InitState> init_state) {
333 CEF_POST_TASK(CEF_IOT, base::BindOnce(&InitHelper::SetInitialized, this,
334 std::move(init_state)));
335 }
336
Disconnectnet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitHelper337 void Disconnect() {
338 base::AutoLock lock_scope(lock_);
339 wrapper_ = nullptr;
340 }
341
342 private:
SetInitializednet_service::__anon63677a4d0111::InterceptedRequestHandlerWrapper::InitHelper343 void SetInitialized(std::unique_ptr<InitState> init_state) {
344 base::AutoLock lock_scope(lock_);
345 // May be nullptr if the InterceptedRequestHandlerWrapper has already
346 // been deleted.
347 if (!wrapper_)
348 return;
349 wrapper_->SetInitialized(std::move(init_state));
350 wrapper_ = nullptr;
351 }
352
353 base::Lock lock_;
354 InterceptedRequestHandlerWrapper* wrapper_;
355 };
356
InterceptedRequestHandlerWrapper()357 InterceptedRequestHandlerWrapper()
358 : init_helper_(base::MakeRefCounted<InitHelper>(this)),
359 weak_ptr_factory_(this) {}
360
361 InterceptedRequestHandlerWrapper(const InterceptedRequestHandlerWrapper&) =
362 delete;
363 InterceptedRequestHandlerWrapper& operator=(
364 const InterceptedRequestHandlerWrapper&) = delete;
365
~InterceptedRequestHandlerWrapper()366 ~InterceptedRequestHandlerWrapper() override {
367 CEF_REQUIRE_IOT();
368
369 // There should be no in-progress requests during destruction.
370 DCHECK(request_map_.empty());
371
372 // Don't continue with initialization if we get deleted before
373 // SetInitialized is called asynchronously.
374 init_helper_->Disconnect();
375 }
376
init_helper() const377 scoped_refptr<InitHelper> init_helper() const { return init_helper_; }
378
SetInitialized(std::unique_ptr<InitState> init_state)379 void SetInitialized(std::unique_ptr<InitState> init_state) {
380 CEF_REQUIRE_IOT();
381 DCHECK(!init_state_);
382 init_state_ = std::move(init_state);
383
384 // Check that the CEF context or associated browser was not destroyed
385 // between the calls to Initialize and SetInitialized, in which case
386 // we won't get an OnDestroyed callback from DestructionObserver.
387 if (init_state_->browser_) {
388 if (!init_state_->browser_->browser_info()->browser()) {
389 OnDestroyed();
390 return;
391 }
392 } else if (!CONTEXT_STATE_VALID()) {
393 OnDestroyed();
394 return;
395 }
396
397 init_state_->initialized_ = true;
398 init_state_->destruction_observer_->SetWrapper(
399 weak_ptr_factory_.GetWeakPtr());
400
401 // Continue any pending requests.
402 if (!pending_requests_.empty()) {
403 for (const auto& request : pending_requests_)
404 request->Run(this);
405 pending_requests_.clear();
406 }
407 }
408
TryCreateURLLoaderNetworkObserver(std::unique_ptr<PendingRequest> pending_request,CefRefPtr<CefFrame> frame,const CefBrowserContext::Getter & browser_context_getter,base::WeakPtr<InterceptedRequestHandlerWrapper> self)409 static void TryCreateURLLoaderNetworkObserver(
410 std::unique_ptr<PendingRequest> pending_request,
411 CefRefPtr<CefFrame> frame,
412 const CefBrowserContext::Getter& browser_context_getter,
413 base::WeakPtr<InterceptedRequestHandlerWrapper> self) {
414 CEF_REQUIRE_UIT();
415
416 mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
417 url_loader_network_observer;
418
419 if (frame) {
420 // The request will be associated with this frame/browser if it's valid,
421 // otherwise the request will be canceled.
422 content::RenderFrameHost* rfh =
423 static_cast<CefFrameHostImpl*>(frame.get())->GetRenderFrameHost();
424 if (rfh) {
425 url_loader_network_observer =
426 static_cast<content::RenderFrameHostImpl*>(rfh)
427 ->CreateURLLoaderNetworkObserver();
428 }
429 } else {
430 auto cef_browser_context = browser_context_getter.Run();
431 auto browser_context = cef_browser_context
432 ? cef_browser_context->AsBrowserContext()
433 : nullptr;
434 if (browser_context) {
435 url_loader_network_observer =
436 static_cast<content::StoragePartitionImpl*>(
437 browser_context->GetDefaultStoragePartition())
438 ->CreateAuthCertObserverForServiceWorker();
439 }
440 }
441
442 CEF_POST_TASK(CEF_IOT,
443 base::BindOnce(&InterceptedRequestHandlerWrapper::
444 ContinueCreateURLLoaderNetworkObserver,
445 self, std::move(pending_request),
446 std::move(url_loader_network_observer)));
447 }
448
ContinueCreateURLLoaderNetworkObserver(std::unique_ptr<PendingRequest> pending_request,mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver> url_loader_network_observer)449 void ContinueCreateURLLoaderNetworkObserver(
450 std::unique_ptr<PendingRequest> pending_request,
451 mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
452 url_loader_network_observer) {
453 CEF_REQUIRE_IOT();
454
455 DCHECK(!init_state_->did_try_create_url_loader_network_observer_);
456 init_state_->did_try_create_url_loader_network_observer_ = true;
457 init_state_->url_loader_network_observer_ =
458 std::move(url_loader_network_observer);
459 pending_request->Run(this);
460 }
461
462 // InterceptedRequestHandler methods:
OnBeforeRequest(int32_t request_id,network::ResourceRequest * request,bool request_was_redirected,OnBeforeRequestResultCallback callback,CancelRequestCallback cancel_callback)463 void OnBeforeRequest(int32_t request_id,
464 network::ResourceRequest* request,
465 bool request_was_redirected,
466 OnBeforeRequestResultCallback callback,
467 CancelRequestCallback cancel_callback) override {
468 CEF_REQUIRE_IOT();
469
470 if (shutting_down_) {
471 // Abort immediately.
472 std::move(cancel_callback).Run(net::ERR_ABORTED);
473 return;
474 }
475
476 if (!init_state_) {
477 // Queue requests until we're initialized.
478 pending_requests_.push_back(std::make_unique<PendingRequest>(
479 request_id, request, request_was_redirected, std::move(callback),
480 std::move(cancel_callback)));
481 return;
482 }
483
484 if (request->trusted_params &&
485 !request->trusted_params->url_loader_network_observer &&
486 !init_state_->did_try_create_url_loader_network_observer_) {
487 // Restarted/redirected requests won't already have an observer, so we
488 // need to create one.
489 CEF_POST_TASK(
490 CEF_UIT,
491 base::BindOnce(&InterceptedRequestHandlerWrapper::
492 TryCreateURLLoaderNetworkObserver,
493 std::make_unique<PendingRequest>(
494 request_id, request, request_was_redirected,
495 std::move(callback), std::move(cancel_callback)),
496 init_state_->frame_,
497 init_state_->browser_context_getter_,
498 weak_ptr_factory_.GetWeakPtr()));
499 return;
500 }
501
502 // State may already exist for restarted requests.
503 RequestState* state = GetOrCreateState(request_id);
504
505 if (init_state_->did_try_create_url_loader_network_observer_) {
506 if (init_state_->url_loader_network_observer_) {
507 request->trusted_params->url_loader_network_observer =
508 std::move(init_state_->url_loader_network_observer_);
509 }
510
511 // Reset state so that the observer will be recreated on the next
512 // restart/redirect.
513 init_state_->did_try_create_url_loader_network_observer_ = false;
514 }
515
516 // Add standard headers, if currently unspecified.
517 request->headers.SetHeaderIfMissing(
518 net::HttpRequestHeaders::kAcceptLanguage,
519 init_state_->accept_language_);
520 request->headers.SetHeaderIfMissing(net::HttpRequestHeaders::kUserAgent,
521 init_state_->user_agent_);
522
523 const bool is_external = IsExternalRequest(request);
524
525 // External requests will not have a default handler.
526 bool intercept_only = is_external;
527
528 CefRefPtr<CefRequestImpl> requestPtr;
529 CefRefPtr<CefResourceRequestHandler> handler =
530 GetHandler(request_id, request, &intercept_only, requestPtr);
531
532 CefRefPtr<CefSchemeHandlerFactory> scheme_factory =
533 init_state_->iothread_state_->GetSchemeHandlerFactory(request->url);
534 if (scheme_factory && !requestPtr) {
535 requestPtr = MakeRequest(request, request_id, true);
536 }
537
538 // True if there's a possibility that the client might handle the request.
539 const bool maybe_intercept_request = handler || scheme_factory;
540 if (!maybe_intercept_request && requestPtr)
541 requestPtr = nullptr;
542
543 // May have a handler and/or scheme factory.
544 state->Reset(handler, scheme_factory, requestPtr, request_was_redirected,
545 std::move(cancel_callback));
546
547 if (handler) {
548 state->cookie_filter_ = handler->GetCookieAccessFilter(
549 init_state_->browser_, init_state_->frame_, requestPtr.get());
550 }
551
552 auto exec_callback =
553 base::BindOnce(std::move(callback), maybe_intercept_request,
554 is_external ? true : intercept_only);
555
556 if (!maybe_intercept_request) {
557 // Cookies will be handled by the NetworkService.
558 std::move(exec_callback).Run();
559 return;
560 }
561
562 MaybeLoadCookies(request_id, state, request, std::move(exec_callback));
563 }
564
MaybeLoadCookies(int32_t request_id,RequestState * state,network::ResourceRequest * request,base::OnceClosure callback)565 void MaybeLoadCookies(int32_t request_id,
566 RequestState* state,
567 network::ResourceRequest* request,
568 base::OnceClosure callback) {
569 CEF_REQUIRE_IOT();
570
571 if (!cookie_helper::IsCookieableScheme(request->url,
572 init_state_->cookieable_schemes_)) {
573 // The scheme does not support cookies.
574 std::move(callback).Run();
575 return;
576 }
577
578 // We need to load/save cookies ourselves for custom-handled requests, or
579 // if we're using a cookie filter.
580 auto allow_cookie_callback =
581 state->cookie_filter_
582 ? base::BindRepeating(
583 &InterceptedRequestHandlerWrapper::AllowCookieLoad,
584 weak_ptr_factory_.GetWeakPtr(), request_id)
585 : base::BindRepeating(
586 &InterceptedRequestHandlerWrapper::AllowCookieAlways);
587 auto done_cookie_callback = base::BindOnce(
588 &InterceptedRequestHandlerWrapper::ContinueWithLoadedCookies,
589 weak_ptr_factory_.GetWeakPtr(), request_id, request,
590 std::move(callback));
591 cookie_helper::LoadCookies(init_state_->browser_context_getter_, *request,
592 allow_cookie_callback,
593 std::move(done_cookie_callback));
594 }
595
AllowCookieAlways(const net::CanonicalCookie & cookie,bool * allow)596 static void AllowCookieAlways(const net::CanonicalCookie& cookie,
597 bool* allow) {
598 *allow = true;
599 }
600
AllowCookieLoad(int32_t request_id,const net::CanonicalCookie & cookie,bool * allow)601 void AllowCookieLoad(int32_t request_id,
602 const net::CanonicalCookie& cookie,
603 bool* allow) {
604 CEF_REQUIRE_IOT();
605
606 RequestState* state = GetState(request_id);
607 if (!state) {
608 // The request may have been canceled while the async callback was
609 // pending.
610 return;
611 }
612
613 DCHECK(state->cookie_filter_);
614
615 CefCookie cef_cookie;
616 if (net_service::MakeCefCookie(cookie, cef_cookie)) {
617 *allow = state->cookie_filter_->CanSendCookie(
618 init_state_->browser_, init_state_->frame_,
619 state->pending_request_.get(), cef_cookie);
620 }
621 }
622
ContinueWithLoadedCookies(int32_t request_id,network::ResourceRequest * request,base::OnceClosure callback,int total_count,net::CookieList allowed_cookies)623 void ContinueWithLoadedCookies(int32_t request_id,
624 network::ResourceRequest* request,
625 base::OnceClosure callback,
626 int total_count,
627 net::CookieList allowed_cookies) {
628 CEF_REQUIRE_IOT();
629
630 RequestState* state = GetState(request_id);
631 if (!state) {
632 // The request may have been canceled while the async callback was
633 // pending.
634 return;
635 }
636
637 if (state->cookie_filter_) {
638 // Also add/save cookies ourselves for default-handled network requests
639 // so that we can filter them. This will be a no-op for custom-handled
640 // requests.
641 request->load_flags |= kLoadNoCookiesFlags;
642 }
643
644 if (!allowed_cookies.empty()) {
645 const std::string& cookie_line =
646 net::CanonicalCookie::BuildCookieLine(allowed_cookies);
647 request->headers.SetHeader(net::HttpRequestHeaders::kCookie, cookie_line);
648
649 state->pending_request_->SetReadOnly(false);
650 state->pending_request_->SetHeaderByName(net::HttpRequestHeaders::kCookie,
651 cookie_line, true);
652 state->pending_request_->SetReadOnly(true);
653 }
654
655 std::move(callback).Run();
656 }
657
ShouldInterceptRequest(int32_t request_id,network::ResourceRequest * request,ShouldInterceptRequestResultCallback callback)658 void ShouldInterceptRequest(
659 int32_t request_id,
660 network::ResourceRequest* request,
661 ShouldInterceptRequestResultCallback callback) override {
662 CEF_REQUIRE_IOT();
663
664 RequestState* state = GetState(request_id);
665 if (!state) {
666 // The request may have been canceled during destruction.
667 return;
668 }
669
670 // Must have a handler and/or scheme factory.
671 DCHECK(state->handler_ || state->scheme_factory_);
672 DCHECK(state->pending_request_);
673
674 if (state->handler_) {
675 // The client may modify |pending_request_| before executing the callback.
676 state->pending_request_->SetReadOnly(false);
677 state->pending_request_->SetTrackChanges(true,
678 true /* backup_on_change */);
679
680 CefRefPtr<RequestCallbackWrapper> callbackPtr =
681 new RequestCallbackWrapper(base::BindOnce(
682 &InterceptedRequestHandlerWrapper::ContinueShouldInterceptRequest,
683 weak_ptr_factory_.GetWeakPtr(), request_id,
684 base::Unretained(request), std::move(callback)));
685
686 cef_return_value_t retval = state->handler_->OnBeforeResourceLoad(
687 init_state_->browser_, init_state_->frame_,
688 state->pending_request_.get(), callbackPtr.get());
689 if (retval != RV_CONTINUE_ASYNC) {
690 if (retval == RV_CONTINUE) {
691 // Continue the request immediately.
692 callbackPtr->Continue();
693 } else {
694 // Cancel the request immediately.
695 callbackPtr->Cancel();
696 }
697 }
698 } else {
699 // The scheme factory may choose to handle it.
700 ContinueShouldInterceptRequest(request_id, request, std::move(callback),
701 true);
702 }
703 }
704
ContinueShouldInterceptRequest(int32_t request_id,network::ResourceRequest * request,ShouldInterceptRequestResultCallback callback,bool allow)705 void ContinueShouldInterceptRequest(
706 int32_t request_id,
707 network::ResourceRequest* request,
708 ShouldInterceptRequestResultCallback callback,
709 bool allow) {
710 CEF_REQUIRE_IOT();
711
712 RequestState* state = GetState(request_id);
713 if (!state) {
714 // The request may have been canceled while the async callback was
715 // pending.
716 return;
717 }
718
719 // Must have a handler and/or scheme factory.
720 DCHECK(state->handler_ || state->scheme_factory_);
721 DCHECK(state->pending_request_);
722
723 if (state->handler_) {
724 if (allow) {
725 // Apply any |requestPtr| changes to |request|.
726 state->pending_request_->Get(request, true /* changed_only */);
727 }
728
729 const bool redirect =
730 (state->pending_request_->GetChanges() & CefRequestImpl::kChangedUrl);
731 if (redirect) {
732 // Revert any changes for now. We'll get them back after the redirect.
733 state->pending_request_->RevertChanges();
734 }
735
736 state->pending_request_->SetReadOnly(true);
737 state->pending_request_->SetTrackChanges(false);
738
739 if (!allow) {
740 // Cancel the request.
741 if (state->cancel_callback_) {
742 std::move(state->cancel_callback_).Run(net::ERR_ABORTED);
743 }
744 return;
745 }
746
747 if (redirect) {
748 // Performing a redirect.
749 std::move(callback).Run(nullptr);
750 return;
751 }
752 }
753
754 CefRefPtr<CefResourceHandler> resource_handler;
755
756 if (state->handler_) {
757 // Does the client want to handle the request?
758 resource_handler = state->handler_->GetResourceHandler(
759 init_state_->browser_, init_state_->frame_,
760 state->pending_request_.get());
761 }
762 if (!resource_handler && state->scheme_factory_) {
763 // Does the scheme factory want to handle the request?
764 resource_handler = state->scheme_factory_->Create(
765 init_state_->browser_, init_state_->frame_, request->url.scheme(),
766 state->pending_request_.get());
767 }
768
769 std::unique_ptr<ResourceResponse> resource_response;
770 if (resource_handler) {
771 resource_response = CreateResourceResponse(request_id, resource_handler);
772 DCHECK(resource_response);
773 state->was_custom_handled_ = true;
774 } else {
775 // The request will be handled by the NetworkService. Remove the
776 // "Accept-Language" header here so that it can be re-added in
777 // URLRequestHttpJob::AddExtraHeaders with correct ordering applied.
778 request->headers.RemoveHeader(net::HttpRequestHeaders::kAcceptLanguage);
779 }
780
781 // Continue the request.
782 std::move(callback).Run(std::move(resource_response));
783 }
784
ProcessResponseHeaders(int32_t request_id,const network::ResourceRequest & request,const GURL & redirect_url,net::HttpResponseHeaders * headers)785 void ProcessResponseHeaders(int32_t request_id,
786 const network::ResourceRequest& request,
787 const GURL& redirect_url,
788 net::HttpResponseHeaders* headers) override {
789 CEF_REQUIRE_IOT();
790
791 RequestState* state = GetState(request_id);
792 if (!state) {
793 // The request may have been canceled during destruction.
794 return;
795 }
796
797 if (!state->handler_)
798 return;
799
800 if (!state->pending_response_)
801 state->pending_response_ = new CefResponseImpl();
802 else
803 state->pending_response_->SetReadOnly(false);
804
805 if (headers)
806 state->pending_response_->SetResponseHeaders(*headers);
807
808 state->pending_response_->SetReadOnly(true);
809 }
810
OnRequestResponse(int32_t request_id,network::ResourceRequest * request,net::HttpResponseHeaders * headers,absl::optional<net::RedirectInfo> redirect_info,OnRequestResponseResultCallback callback)811 void OnRequestResponse(int32_t request_id,
812 network::ResourceRequest* request,
813 net::HttpResponseHeaders* headers,
814 absl::optional<net::RedirectInfo> redirect_info,
815 OnRequestResponseResultCallback callback) override {
816 CEF_REQUIRE_IOT();
817
818 RequestState* state = GetState(request_id);
819 if (!state) {
820 // The request may have been canceled during destruction.
821 return;
822 }
823
824 if (state->cookie_filter_) {
825 // Remove the flags that were added in ContinueWithLoadedCookies.
826 request->load_flags &= ~kLoadNoCookiesFlags;
827 }
828
829 if (!state->handler_) {
830 // Cookies may come from a scheme handler.
831 MaybeSaveCookies(
832 request_id, state, request, headers,
833 base::BindOnce(
834 std::move(callback), ResponseMode::CONTINUE, nullptr,
835 redirect_info.has_value() ? redirect_info->new_url : GURL()));
836 return;
837 }
838
839 DCHECK(state->pending_request_);
840 DCHECK(state->pending_response_);
841
842 if (redirect_info.has_value()) {
843 HandleRedirect(request_id, state, request, headers, *redirect_info,
844 std::move(callback));
845 } else {
846 HandleResponse(request_id, state, request, headers, std::move(callback));
847 }
848 }
849
HandleRedirect(int32_t request_id,RequestState * state,network::ResourceRequest * request,net::HttpResponseHeaders * headers,const net::RedirectInfo & redirect_info,OnRequestResponseResultCallback callback)850 void HandleRedirect(int32_t request_id,
851 RequestState* state,
852 network::ResourceRequest* request,
853 net::HttpResponseHeaders* headers,
854 const net::RedirectInfo& redirect_info,
855 OnRequestResponseResultCallback callback) {
856 GURL new_url = redirect_info.new_url;
857 CefString newUrl = redirect_info.new_url.spec();
858 CefString oldUrl = newUrl;
859 bool url_changed = false;
860 state->handler_->OnResourceRedirect(
861 init_state_->browser_, init_state_->frame_,
862 state->pending_request_.get(), state->pending_response_.get(), newUrl);
863 if (newUrl != oldUrl) {
864 // Also support relative URLs.
865 const GURL& url = redirect_info.new_url.Resolve(newUrl.ToString());
866 if (url.is_valid()) {
867 url_changed = true;
868 new_url = url;
869 }
870 }
871
872 // Update the |pending_request_| object with the new info.
873 state->pending_request_->SetReadOnly(false);
874 state->pending_request_->Set(redirect_info);
875 if (url_changed) {
876 state->pending_request_->SetURL(new_url.spec());
877 }
878 state->pending_request_->SetReadOnly(true);
879
880 auto exec_callback = base::BindOnce(
881 std::move(callback), ResponseMode::CONTINUE, nullptr, new_url);
882
883 MaybeSaveCookies(request_id, state, request, headers,
884 std::move(exec_callback));
885 }
886
HandleResponse(int32_t request_id,RequestState * state,network::ResourceRequest * request,net::HttpResponseHeaders * headers,OnRequestResponseResultCallback callback)887 void HandleResponse(int32_t request_id,
888 RequestState* state,
889 network::ResourceRequest* request,
890 net::HttpResponseHeaders* headers,
891 OnRequestResponseResultCallback callback) {
892 // The client may modify |pending_request_| in OnResourceResponse.
893 state->pending_request_->SetReadOnly(false);
894 state->pending_request_->SetTrackChanges(true, true /* backup_on_change */);
895
896 auto response_mode = ResponseMode::CONTINUE;
897 GURL new_url;
898
899 if (state->handler_->OnResourceResponse(
900 init_state_->browser_, init_state_->frame_,
901 state->pending_request_.get(), state->pending_response_.get())) {
902 // The request may have been modified.
903 const auto changes = state->pending_request_->GetChanges();
904 if (changes) {
905 state->pending_request_->Get(request, true /* changed_only */);
906
907 if (changes & CefRequestImpl::kChangedUrl) {
908 // Redirect to the new URL.
909 new_url = GURL(state->pending_request_->GetURL().ToString());
910 } else {
911 // Restart the request.
912 response_mode = ResponseMode::RESTART;
913 }
914 }
915 }
916
917 // Revert any changes for now. We'll get them back after the redirect or
918 // restart.
919 state->pending_request_->RevertChanges();
920
921 state->pending_request_->SetReadOnly(true);
922 state->pending_request_->SetTrackChanges(false);
923
924 auto exec_callback =
925 base::BindOnce(std::move(callback), response_mode, nullptr, new_url);
926
927 if (response_mode == ResponseMode::RESTART) {
928 // Get any cookies after the restart.
929 std::move(exec_callback).Run();
930 return;
931 }
932
933 MaybeSaveCookies(request_id, state, request, headers,
934 std::move(exec_callback));
935 }
936
MaybeSaveCookies(int32_t request_id,RequestState * state,network::ResourceRequest * request,net::HttpResponseHeaders * headers,base::OnceClosure callback)937 void MaybeSaveCookies(int32_t request_id,
938 RequestState* state,
939 network::ResourceRequest* request,
940 net::HttpResponseHeaders* headers,
941 base::OnceClosure callback) {
942 CEF_REQUIRE_IOT();
943
944 if (!state->cookie_filter_ && !state->was_custom_handled_) {
945 // The NetworkService saves the cookies for default-handled requests.
946 std::move(callback).Run();
947 return;
948 }
949
950 if (!cookie_helper::IsCookieableScheme(request->url,
951 init_state_->cookieable_schemes_)) {
952 // The scheme does not support cookies.
953 std::move(callback).Run();
954 return;
955 }
956
957 // We need to load/save cookies ourselves for custom-handled requests, or
958 // if we're using a cookie filter.
959 auto allow_cookie_callback =
960 state->cookie_filter_
961 ? base::BindRepeating(
962 &InterceptedRequestHandlerWrapper::AllowCookieSave,
963 weak_ptr_factory_.GetWeakPtr(), request_id)
964 : base::BindRepeating(
965 &InterceptedRequestHandlerWrapper::AllowCookieAlways);
966 auto done_cookie_callback = base::BindOnce(
967 &InterceptedRequestHandlerWrapper::ContinueWithSavedCookies,
968 weak_ptr_factory_.GetWeakPtr(), request_id, std::move(callback));
969 cookie_helper::SaveCookies(init_state_->browser_context_getter_, *request,
970 headers, allow_cookie_callback,
971 std::move(done_cookie_callback));
972 }
973
AllowCookieSave(int32_t request_id,const net::CanonicalCookie & cookie,bool * allow)974 void AllowCookieSave(int32_t request_id,
975 const net::CanonicalCookie& cookie,
976 bool* allow) {
977 CEF_REQUIRE_IOT();
978
979 RequestState* state = GetState(request_id);
980 if (!state) {
981 // The request may have been canceled while the async callback was
982 // pending.
983 return;
984 }
985
986 DCHECK(state->cookie_filter_);
987
988 CefCookie cef_cookie;
989 if (net_service::MakeCefCookie(cookie, cef_cookie)) {
990 *allow = state->cookie_filter_->CanSaveCookie(
991 init_state_->browser_, init_state_->frame_,
992 state->pending_request_.get(), state->pending_response_.get(),
993 cef_cookie);
994 }
995 }
996
ContinueWithSavedCookies(int32_t request_id,base::OnceClosure callback,int total_count,net::CookieList allowed_cookies)997 void ContinueWithSavedCookies(int32_t request_id,
998 base::OnceClosure callback,
999 int total_count,
1000 net::CookieList allowed_cookies) {
1001 CEF_REQUIRE_IOT();
1002 std::move(callback).Run();
1003 }
1004
OnFilterResponseBody(int32_t request_id,const network::ResourceRequest & request,mojo::ScopedDataPipeConsumerHandle body)1005 mojo::ScopedDataPipeConsumerHandle OnFilterResponseBody(
1006 int32_t request_id,
1007 const network::ResourceRequest& request,
1008 mojo::ScopedDataPipeConsumerHandle body) override {
1009 CEF_REQUIRE_IOT();
1010
1011 RequestState* state = GetState(request_id);
1012 if (!state) {
1013 // The request may have been canceled during destruction.
1014 return body;
1015 }
1016
1017 if (state->handler_) {
1018 auto filter = state->handler_->GetResourceResponseFilter(
1019 init_state_->browser_, init_state_->frame_,
1020 state->pending_request_.get(), state->pending_response_.get());
1021 if (filter) {
1022 return CreateResponseFilterHandler(
1023 filter, std::move(body),
1024 base::BindOnce(&InterceptedRequestHandlerWrapper::OnFilterError,
1025 weak_ptr_factory_.GetWeakPtr(), request_id));
1026 }
1027 }
1028
1029 return body;
1030 }
1031
OnFilterError(int32_t request_id)1032 void OnFilterError(int32_t request_id) {
1033 CEF_REQUIRE_IOT();
1034
1035 RequestState* state = GetState(request_id);
1036 if (!state) {
1037 // The request may have been canceled while the async callback was
1038 // pending.
1039 return;
1040 }
1041
1042 if (state->cancel_callback_) {
1043 std::move(state->cancel_callback_).Run(net::ERR_CONTENT_DECODING_FAILED);
1044 }
1045 }
1046
OnRequestComplete(int32_t request_id,const network::ResourceRequest & request,const network::URLLoaderCompletionStatus & status)1047 void OnRequestComplete(
1048 int32_t request_id,
1049 const network::ResourceRequest& request,
1050 const network::URLLoaderCompletionStatus& status) override {
1051 CEF_REQUIRE_IOT();
1052
1053 RequestState* state = GetState(request_id);
1054 if (!state) {
1055 // The request may have been aborted during initialization or canceled
1056 // during destruction. This method will always be called before a request
1057 // is deleted, so if the request is currently pending also remove it from
1058 // the list.
1059 if (!pending_requests_.empty()) {
1060 PendingRequests::iterator it = pending_requests_.begin();
1061 for (; it != pending_requests_.end(); ++it) {
1062 if ((*it)->id_ == request_id) {
1063 pending_requests_.erase(it);
1064 break;
1065 }
1066 }
1067 }
1068 return;
1069 }
1070
1071 const bool is_external = IsExternalRequest(&request);
1072
1073 // Redirection of standard custom schemes is handled with a restart, so we
1074 // get completion notifications for both the original (redirected) request
1075 // and the final request. Don't report completion of the redirected request.
1076 const bool ignore_result = is_external && request.url.IsStandard() &&
1077 status.error_code == net::ERR_ABORTED &&
1078 state->pending_response_.get() &&
1079 net::HttpResponseHeaders::IsRedirectResponseCode(
1080 state->pending_response_->GetStatus());
1081
1082 if (state->handler_ && !ignore_result) {
1083 DCHECK(state->pending_request_);
1084
1085 CallHandlerOnComplete(state, status);
1086
1087 if (status.error_code != 0 && status.error_code != ERR_ABORTED &&
1088 is_external) {
1089 bool allow_os_execution = false;
1090 state->handler_->OnProtocolExecution(
1091 init_state_->browser_, init_state_->frame_,
1092 state->pending_request_.get(), allow_os_execution);
1093 if (allow_os_execution && init_state_->unhandled_request_callback_) {
1094 init_state_->unhandled_request_callback_.Run();
1095 }
1096 }
1097 }
1098
1099 RemoveState(request_id);
1100 }
1101
1102 private:
CallHandlerOnComplete(RequestState * state,const network::URLLoaderCompletionStatus & status)1103 void CallHandlerOnComplete(RequestState* state,
1104 const network::URLLoaderCompletionStatus& status) {
1105 if (!state->handler_ || !state->pending_request_)
1106 return;
1107
1108 // The request object may be currently flagged as writable in cases where we
1109 // abort a request that is waiting on a pending callack.
1110 if (!state->pending_request_->IsReadOnly()) {
1111 state->pending_request_->SetReadOnly(true);
1112 }
1113
1114 if (!state->pending_response_) {
1115 // If the request failed there may not be a response object yet.
1116 state->pending_response_ = new CefResponseImpl();
1117 } else {
1118 state->pending_response_->SetReadOnly(false);
1119 }
1120 state->pending_response_->SetError(
1121 static_cast<cef_errorcode_t>(status.error_code));
1122 state->pending_response_->SetReadOnly(true);
1123
1124 state->handler_->OnResourceLoadComplete(
1125 init_state_->browser_, init_state_->frame_,
1126 state->pending_request_.get(), state->pending_response_.get(),
1127 status.error_code == 0 ? UR_SUCCESS : UR_FAILED,
1128 status.encoded_body_length);
1129 }
1130
1131 // Returns the handler, if any, that should be used for this request.
GetHandler(int32_t request_id,network::ResourceRequest * request,bool * intercept_only,CefRefPtr<CefRequestImpl> & requestPtr) const1132 CefRefPtr<CefResourceRequestHandler> GetHandler(
1133 int32_t request_id,
1134 network::ResourceRequest* request,
1135 bool* intercept_only,
1136 CefRefPtr<CefRequestImpl>& requestPtr) const {
1137 CefRefPtr<CefResourceRequestHandler> handler;
1138
1139 if (init_state_->browser_) {
1140 // Maybe the browser's client wants to handle it?
1141 CefRefPtr<CefClient> client =
1142 init_state_->browser_->GetHost()->GetClient();
1143 if (client) {
1144 CefRefPtr<CefRequestHandler> request_handler =
1145 client->GetRequestHandler();
1146 if (request_handler) {
1147 requestPtr = MakeRequest(request, request_id, true);
1148
1149 handler = request_handler->GetResourceRequestHandler(
1150 init_state_->browser_, init_state_->frame_, requestPtr.get(),
1151 init_state_->is_navigation_, init_state_->is_download_,
1152 init_state_->request_initiator_, *intercept_only);
1153 }
1154 }
1155 }
1156
1157 if (!handler) {
1158 // Maybe the request context wants to handle it?
1159 CefRefPtr<CefRequestContextHandler> context_handler =
1160 init_state_->iothread_state_->GetHandler(
1161 init_state_->global_id_, /*require_frame_match=*/false);
1162 if (context_handler) {
1163 if (!requestPtr)
1164 requestPtr = MakeRequest(request, request_id, true);
1165
1166 handler = context_handler->GetResourceRequestHandler(
1167 init_state_->browser_, init_state_->frame_, requestPtr.get(),
1168 init_state_->is_navigation_, init_state_->is_download_,
1169 init_state_->request_initiator_, *intercept_only);
1170 }
1171 }
1172
1173 return handler;
1174 }
1175
GetOrCreateState(int32_t request_id)1176 RequestState* GetOrCreateState(int32_t request_id) {
1177 RequestState* state = GetState(request_id);
1178 if (!state) {
1179 state = new RequestState();
1180 request_map_.insert(std::make_pair(request_id, base::WrapUnique(state)));
1181 }
1182 return state;
1183 }
1184
GetState(int32_t request_id) const1185 RequestState* GetState(int32_t request_id) const {
1186 RequestMap::const_iterator it = request_map_.find(request_id);
1187 if (it != request_map_.end())
1188 return it->second.get();
1189 return nullptr;
1190 }
1191
RemoveState(int32_t request_id)1192 void RemoveState(int32_t request_id) {
1193 RequestMap::iterator it = request_map_.find(request_id);
1194 DCHECK(it != request_map_.end());
1195 if (it != request_map_.end())
1196 request_map_.erase(it);
1197 }
1198
1199 // Stop accepting new requests and cancel pending/in-flight requests when the
1200 // CEF context or associated browser is destroyed.
OnDestroyed()1201 void OnDestroyed() {
1202 CEF_REQUIRE_IOT();
1203 DCHECK(init_state_);
1204
1205 init_state_->DeleteDestructionObserver();
1206
1207 // Stop accepting new requests.
1208 shutting_down_ = true;
1209
1210 // Stop the delivery of pending callbacks.
1211 weak_ptr_factory_.InvalidateWeakPtrs();
1212
1213 // Take ownership of any pending requests.
1214 PendingRequests pending_requests;
1215 pending_requests.swap(pending_requests_);
1216
1217 // Take ownership of any in-progress requests.
1218 RequestMap request_map;
1219 request_map.swap(request_map_);
1220
1221 // Notify handlers for in-progress requests.
1222 for (const auto& pair : request_map) {
1223 CallHandlerOnComplete(
1224 pair.second.get(),
1225 network::URLLoaderCompletionStatus(net::ERR_ABORTED));
1226 }
1227
1228 if (init_state_->browser_) {
1229 // Clear objects that reference the browser.
1230 init_state_->browser_ = nullptr;
1231 init_state_->frame_ = nullptr;
1232 }
1233
1234 // Execute cancel callbacks and delete pending and in-progress requests.
1235 // This may result in the request being torn down sooner, or it may be
1236 // ignored if the request is already in the process of being torn down. When
1237 // the last callback is executed it may result in |this| being deleted.
1238 pending_requests.clear();
1239
1240 for (auto& pair : request_map) {
1241 auto state = std::move(pair.second);
1242 if (state->cancel_callback_) {
1243 std::move(state->cancel_callback_).Run(net::ERR_ABORTED);
1244 }
1245 }
1246 }
1247
MakeRequest(const network::ResourceRequest * request,int64 request_id,bool read_only)1248 static CefRefPtr<CefRequestImpl> MakeRequest(
1249 const network::ResourceRequest* request,
1250 int64 request_id,
1251 bool read_only) {
1252 CefRefPtr<CefRequestImpl> requestPtr = new CefRequestImpl();
1253 requestPtr->Set(request, request_id);
1254 if (read_only)
1255 requestPtr->SetReadOnly(true);
1256 else
1257 requestPtr->SetTrackChanges(true);
1258 return requestPtr;
1259 }
1260
1261 // Returns true if |request| cannot be handled internally.
IsExternalRequest(const network::ResourceRequest * request)1262 static bool IsExternalRequest(const network::ResourceRequest* request) {
1263 return !scheme::IsInternalHandledScheme(request->url.scheme());
1264 }
1265
1266 scoped_refptr<InitHelper> init_helper_;
1267 std::unique_ptr<InitState> init_state_;
1268
1269 bool shutting_down_ = false;
1270
1271 using RequestMap = std::map<int32_t, std::unique_ptr<RequestState>>;
1272 RequestMap request_map_;
1273
1274 using PendingRequests = std::vector<std::unique_ptr<PendingRequest>>;
1275 PendingRequests pending_requests_;
1276
1277 base::WeakPtrFactory<InterceptedRequestHandlerWrapper> weak_ptr_factory_;
1278 };
1279
1280 } // namespace
1281
CreateInterceptedRequestHandler(content::BrowserContext * browser_context,content::RenderFrameHost * frame,int render_process_id,bool is_navigation,bool is_download,const url::Origin & request_initiator)1282 std::unique_ptr<InterceptedRequestHandler> CreateInterceptedRequestHandler(
1283 content::BrowserContext* browser_context,
1284 content::RenderFrameHost* frame,
1285 int render_process_id,
1286 bool is_navigation,
1287 bool is_download,
1288 const url::Origin& request_initiator) {
1289 CEF_REQUIRE_UIT();
1290 CHECK(browser_context);
1291
1292 CefRefPtr<CefBrowserHostBase> browserPtr;
1293 CefRefPtr<CefFrame> framePtr;
1294
1295 // Default to handlers for the same process in case |frame| doesn't have an
1296 // associated CefBrowserHost.
1297 content::GlobalRenderFrameHostId global_id(render_process_id,
1298 MSG_ROUTING_NONE);
1299
1300 // |frame| may be nullptr for service worker requests.
1301 if (frame) {
1302 // May return nullptr for requests originating from guest views.
1303 browserPtr = CefBrowserHostBase::GetBrowserForHost(frame);
1304 if (browserPtr) {
1305 framePtr = browserPtr->GetFrameForHost(frame);
1306 CHECK(framePtr);
1307 global_id = frame->GetGlobalId();
1308 }
1309 }
1310
1311 auto init_state =
1312 std::make_unique<InterceptedRequestHandlerWrapper::InitState>();
1313 init_state->Initialize(browser_context, browserPtr, framePtr, global_id,
1314 is_navigation, is_download, request_initiator,
1315 base::RepeatingClosure());
1316
1317 auto wrapper = std::make_unique<InterceptedRequestHandlerWrapper>();
1318 wrapper->init_helper()->MaybeSetInitialized(std::move(init_state));
1319
1320 return wrapper;
1321 }
1322
CreateInterceptedRequestHandler(content::WebContents::Getter web_contents_getter,int frame_tree_node_id,const network::ResourceRequest & request,const base::RepeatingClosure & unhandled_request_callback)1323 std::unique_ptr<InterceptedRequestHandler> CreateInterceptedRequestHandler(
1324 content::WebContents::Getter web_contents_getter,
1325 int frame_tree_node_id,
1326 const network::ResourceRequest& request,
1327 const base::RepeatingClosure& unhandled_request_callback) {
1328 CEF_REQUIRE_UIT();
1329
1330 content::WebContents* web_contents = web_contents_getter.Run();
1331 CHECK(web_contents);
1332
1333 content::BrowserContext* browser_context = web_contents->GetBrowserContext();
1334 CHECK(browser_context);
1335
1336 content::RenderFrameHost* frame = nullptr;
1337
1338 if (request.is_main_frame ||
1339 static_cast<blink::mojom::ResourceType>(request.resource_type) ==
1340 blink::mojom::ResourceType::kMainFrame) {
1341 frame = web_contents->GetMainFrame();
1342 CHECK(frame);
1343 } else {
1344 // May return nullptr for frames in inner WebContents.
1345 auto node = content::FrameTreeNode::GloballyFindByID(frame_tree_node_id);
1346 if (node) {
1347 frame = node->current_frame_host();
1348
1349 // RFHs can move between FrameTreeNodes. Make sure this one hasn't. See
1350 // documentation on RenderFrameHost::GetFrameTreeNodeId() for background.
1351 if (content::WebContents::FromRenderFrameHost(frame) != web_contents) {
1352 frame = nullptr;
1353 }
1354 }
1355
1356 if (!frame) {
1357 // Use the main frame for the CefBrowserHost.
1358 frame = web_contents->GetMainFrame();
1359 CHECK(frame);
1360 }
1361 }
1362
1363 CefRefPtr<CefBrowserHostBase> browserPtr;
1364 CefRefPtr<CefFrame> framePtr;
1365
1366 // Default to handlers for the same process in case |frame| doesn't have an
1367 // associated CefBrowserHost.
1368 content::GlobalRenderFrameHostId global_id(frame->GetProcess()->GetID(),
1369 MSG_ROUTING_NONE);
1370
1371 // May return nullptr for requests originating from guest views.
1372 browserPtr = CefBrowserHostBase::GetBrowserForHost(frame);
1373 if (browserPtr) {
1374 framePtr = browserPtr->GetFrameForHost(frame);
1375 DCHECK(framePtr);
1376 global_id = frame->GetGlobalId();
1377 }
1378
1379 const bool is_navigation = ui::PageTransitionIsNewNavigation(
1380 static_cast<ui::PageTransition>(request.transition_type));
1381 // TODO(navigation): Can we determine the |is_download| value?
1382 const bool is_download = false;
1383 url::Origin request_initiator;
1384 if (request.request_initiator.has_value())
1385 request_initiator = *request.request_initiator;
1386
1387 auto init_state =
1388 std::make_unique<InterceptedRequestHandlerWrapper::InitState>();
1389 init_state->Initialize(browser_context, browserPtr, framePtr, global_id,
1390 is_navigation, is_download, request_initiator,
1391 unhandled_request_callback);
1392
1393 auto wrapper = std::make_unique<InterceptedRequestHandlerWrapper>();
1394 wrapper->init_helper()->MaybeSetInitialized(std::move(init_state));
1395
1396 return wrapper;
1397 }
1398
1399 } // namespace net_service
1400