• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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