• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
2 // Copyright (c) 2018 The Chromium Authors. All rights reserved. Use of this
3 // source code is governed by a BSD-style license that can be found in the
4 // LICENSE file.
5 
6 #include "libcef/browser/net_service/proxy_url_loader_factory.h"
7 
8 #include <tuple>
9 
10 #include "libcef/browser/context.h"
11 #include "libcef/browser/origin_whitelist_impl.h"
12 #include "libcef/browser/thread_util.h"
13 #include "libcef/common/cef_switches.h"
14 #include "libcef/common/net/scheme_registration.h"
15 #include "libcef/common/net_service/net_service_util.h"
16 
17 #include "base/barrier_closure.h"
18 #include "base/command_line.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "components/safe_browsing/core/common/safebrowsing_constants.h"
21 #include "content/public/browser/browser_context.h"
22 #include "content/public/browser/render_frame_host.h"
23 #include "content/public/browser/resource_context.h"
24 #include "content/public/browser/web_contents.h"
25 #include "mojo/public/cpp/base/big_buffer.h"
26 #include "mojo/public/cpp/bindings/receiver.h"
27 #include "net/http/http_status_code.h"
28 #include "net/url_request/redirect_util.h"
29 #include "net/url_request/url_request.h"
30 #include "services/network/public/cpp/cors/cors.h"
31 #include "services/network/public/cpp/features.h"
32 #include "services/network/public/mojom/early_hints.mojom.h"
33 
34 namespace net_service {
35 
36 namespace {
37 
38 // User data key for ResourceContextData.
39 const void* const kResourceContextUserDataKey = &kResourceContextUserDataKey;
40 
GetHeaderString(const net::HttpResponseHeaders * headers,const std::string & header_name)41 absl::optional<std::string> GetHeaderString(
42     const net::HttpResponseHeaders* headers,
43     const std::string& header_name) {
44   std::string header_value;
45   if (!headers || !headers->GetNormalizedHeader(header_name, &header_value)) {
46     return absl::nullopt;
47   }
48   return header_value;
49 }
50 
CreateProxyHelper(content::WebContents::Getter web_contents_getter,mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,std::unique_ptr<InterceptedRequestHandler> request_handler)51 void CreateProxyHelper(
52     content::WebContents::Getter web_contents_getter,
53     mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
54     std::unique_ptr<InterceptedRequestHandler> request_handler) {
55   ProxyURLLoaderFactory::CreateProxy(web_contents_getter,
56                                      std::move(loader_receiver),
57                                      std::move(request_handler));
58 }
59 
DisableRequestHandlingForTesting()60 bool DisableRequestHandlingForTesting() {
61   static bool disabled([]() -> bool {
62     return base::CommandLine::ForCurrentProcess()->HasSwitch(
63         switches::kDisableRequestHandlingForTesting);
64   }());
65   return disabled;
66 }
67 
68 }  // namespace
69 
70 // Owns all of the ProxyURLLoaderFactorys for a given BrowserContext. Since
71 // these live on the IO thread this is done indirectly through the
72 // ResourceContext.
73 class ResourceContextData : public base::SupportsUserData::Data {
74  public:
75   ResourceContextData(const ResourceContextData&) = delete;
76   ResourceContextData& operator=(const ResourceContextData&) = delete;
77 
~ResourceContextData()78   ~ResourceContextData() override {}
79 
AddProxyOnUIThread(ProxyURLLoaderFactory * proxy,content::WebContents::Getter web_contents_getter)80   static void AddProxyOnUIThread(
81       ProxyURLLoaderFactory* proxy,
82       content::WebContents::Getter web_contents_getter) {
83     CEF_REQUIRE_UIT();
84 
85     content::WebContents* web_contents = web_contents_getter.Run();
86 
87     // Maybe the browser was destroyed while AddProxyOnUIThread was pending.
88     if (!web_contents) {
89       // Delete on the IO thread as expected by mojo bindings.
90       content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE,
91                                          proxy);
92       return;
93     }
94 
95     content::BrowserContext* browser_context =
96         web_contents->GetBrowserContext();
97     DCHECK(browser_context);
98 
99     content::ResourceContext* resource_context =
100         browser_context->GetResourceContext();
101     DCHECK(resource_context);
102 
103     CEF_POST_TASK(CEF_IOT, base::BindOnce(ResourceContextData::AddProxy,
104                                           base::Unretained(proxy),
105                                           base::Unretained(resource_context)));
106   }
107 
AddProxy(ProxyURLLoaderFactory * proxy,content::ResourceContext * resource_context)108   static void AddProxy(ProxyURLLoaderFactory* proxy,
109                        content::ResourceContext* resource_context) {
110     CEF_REQUIRE_IOT();
111 
112     // Maybe the proxy was destroyed while AddProxyOnUIThread was pending.
113     if (proxy->destroyed_) {
114       delete proxy;
115       return;
116     }
117 
118     auto* self = static_cast<ResourceContextData*>(
119         resource_context->GetUserData(kResourceContextUserDataKey));
120     if (!self) {
121       self = new ResourceContextData();
122       resource_context->SetUserData(kResourceContextUserDataKey,
123                                     base::WrapUnique(self));
124     }
125 
126     proxy->SetDisconnectCallback(base::BindOnce(
127         &ResourceContextData::RemoveProxy, self->weak_factory_.GetWeakPtr()));
128     self->proxies_.emplace(base::WrapUnique(proxy));
129   }
130 
131  private:
RemoveProxy(ProxyURLLoaderFactory * proxy)132   void RemoveProxy(ProxyURLLoaderFactory* proxy) {
133     CEF_REQUIRE_IOT();
134 
135     auto it = proxies_.find(proxy);
136     DCHECK(it != proxies_.end());
137     proxies_.erase(it);
138   }
139 
ResourceContextData()140   ResourceContextData() : weak_factory_(this) {}
141 
142   std::set<std::unique_ptr<ProxyURLLoaderFactory>, base::UniquePtrComparator>
143       proxies_;
144 
145   base::WeakPtrFactory<ResourceContextData> weak_factory_;
146 };
147 
148 // CORS preflight requests are handled in the network process, so we just need
149 // to continue all of the callbacks and then delete ourself.
150 class CorsPreflightRequest : public network::mojom::TrustedHeaderClient {
151  public:
CorsPreflightRequest(mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)152   explicit CorsPreflightRequest(
153       mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)
154       : weak_factory_(this) {
155     header_client_receiver_.Bind(std::move(receiver));
156 
157     header_client_receiver_.set_disconnect_handler(base::BindOnce(
158         &CorsPreflightRequest::OnDestroy, weak_factory_.GetWeakPtr()));
159   }
160 
161   CorsPreflightRequest(const CorsPreflightRequest&) = delete;
162   CorsPreflightRequest& operator=(const CorsPreflightRequest&) = delete;
163 
164   // mojom::TrustedHeaderClient methods:
OnBeforeSendHeaders(const net::HttpRequestHeaders & headers,OnBeforeSendHeadersCallback callback)165   void OnBeforeSendHeaders(const net::HttpRequestHeaders& headers,
166                            OnBeforeSendHeadersCallback callback) override {
167     std::move(callback).Run(net::OK, headers);
168   }
169 
OnHeadersReceived(const std::string & headers,const net::IPEndPoint & remote_endpoint,OnHeadersReceivedCallback callback)170   void OnHeadersReceived(const std::string& headers,
171                          const net::IPEndPoint& remote_endpoint,
172                          OnHeadersReceivedCallback callback) override {
173     std::move(callback).Run(net::OK, headers, /*redirect_url=*/GURL());
174     OnDestroy();
175   }
176 
177  private:
OnDestroy()178   void OnDestroy() { delete this; }
179 
180   mojo::Receiver<network::mojom::TrustedHeaderClient> header_client_receiver_{
181       this};
182 
183   base::WeakPtrFactory<CorsPreflightRequest> weak_factory_;
184 };
185 
186 //==============================
187 // InterceptedRequest
188 //=============================
189 
190 // Handles intercepted, in-progress requests/responses, so that they can be
191 // controlled and modified accordingly.
192 class InterceptedRequest : public network::mojom::URLLoader,
193                            public network::mojom::URLLoaderClient,
194                            public network::mojom::TrustedHeaderClient {
195  public:
196   InterceptedRequest(
197       ProxyURLLoaderFactory* factory,
198       int32_t id,
199       uint32_t options,
200       const network::ResourceRequest& request,
201       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
202       mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
203       mojo::PendingRemote<network::mojom::URLLoaderClient> client,
204       mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory);
205 
206   InterceptedRequest(const InterceptedRequest&) = delete;
207   InterceptedRequest& operator=(const InterceptedRequest&) = delete;
208 
209   ~InterceptedRequest() override;
210 
211   // Restart the request. This happens on initial start and after redirect.
212   void Restart();
213 
214   // Called from ProxyURLLoaderFactory::OnLoaderCreated.
215   void OnLoaderCreated(
216       mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver);
217 
218   // Called from InterceptDelegate::OnInputStreamOpenFailed.
219   void InputStreamFailed(bool restart_needed);
220 
221   // mojom::TrustedHeaderClient methods:
222   void OnBeforeSendHeaders(const net::HttpRequestHeaders& headers,
223                            OnBeforeSendHeadersCallback callback) override;
224   void OnHeadersReceived(const std::string& headers,
225                          const net::IPEndPoint& remote_endpoint,
226                          OnHeadersReceivedCallback callback) override;
227 
228   // mojom::URLLoaderClient methods:
229   void OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints) override;
230   void OnReceiveResponse(network::mojom::URLResponseHeadPtr head,
231                          mojo::ScopedDataPipeConsumerHandle body) override;
232   void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
233                          network::mojom::URLResponseHeadPtr head) override;
234   void OnUploadProgress(int64_t current_position,
235                         int64_t total_size,
236                         OnUploadProgressCallback callback) override;
237   void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override;
238   void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
239   void OnStartLoadingResponseBody(
240       mojo::ScopedDataPipeConsumerHandle body) override;
241   void OnComplete(const network::URLLoaderCompletionStatus& status) override;
242 
243   // mojom::URLLoader methods:
244   void FollowRedirect(
245       const std::vector<std::string>& removed_headers,
246       const net::HttpRequestHeaders& modified_headers,
247       const net::HttpRequestHeaders& modified_cors_exempt_headers,
248       const absl::optional<GURL>& new_url) override;
249   void SetPriority(net::RequestPriority priority,
250                    int32_t intra_priority_value) override;
251   void PauseReadingBodyFromNet() override;
252   void ResumeReadingBodyFromNet() override;
253 
id() const254   int32_t id() const { return id_; }
255 
256  private:
257   // Helpers for determining the request handler.
258   void BeforeRequestReceived(const GURL& original_url,
259                              bool intercept_request,
260                              bool intercept_only);
261   void InterceptResponseReceived(const GURL& original_url,
262                                  std::unique_ptr<ResourceResponse> response);
263   void ContinueAfterIntercept();
264   void ContinueAfterInterceptWithOverride(
265       std::unique_ptr<ResourceResponse> response);
266 
267   // Helpers for optionally overriding headers.
268   void HandleResponseOrRedirectHeaders(
269       absl::optional<net::RedirectInfo> redirect_info,
270       net::CompletionOnceCallback continuation);
271   void ContinueResponseOrRedirect(
272       net::CompletionOnceCallback continuation,
273       InterceptedRequestHandler::ResponseMode response_mode,
274       scoped_refptr<net::HttpResponseHeaders> override_headers,
275       const GURL& redirect_url);
276   void ContinueToHandleOverrideHeaders(int error_code);
277   net::RedirectInfo MakeRedirectResponseAndInfo(const GURL& new_location);
278 
279   // Helpers for redirect handling.
280   void ContinueToBeforeRedirect(const net::RedirectInfo& redirect_info,
281                                 int error_code);
282 
283   // Helpers for response handling.
284   void ContinueToResponseStarted(int error_code);
285 
286   void OnDestroy();
287 
288   void OnProcessRequestHeaders(const GURL& redirect_url,
289                                net::HttpRequestHeaders* modified_headers,
290                                std::vector<std::string>* removed_headers);
291 
292   // This is called when the original URLLoaderClient has a connection error.
293   void OnURLLoaderClientError();
294 
295   // This is called when the original URLLoader has a connection error.
296   void OnURLLoaderError(uint32_t custom_reason, const std::string& description);
297 
298   // Call OnComplete on |target_client_|. If |wait_for_loader_error| is true
299   // then this object will wait for |proxied_loader_receiver_| to have a
300   // connection error before destructing.
301   void CallOnComplete(const network::URLLoaderCompletionStatus& status,
302                       bool wait_for_loader_error);
303 
304   void SendErrorAndCompleteImmediately(int error_code);
305   void SendErrorStatusAndCompleteImmediately(
306       const network::URLLoaderCompletionStatus& status);
307 
308   void SendErrorCallback(int error_code, bool safebrowsing_hit);
309 
310   void OnUploadProgressACK();
311 
312   ProxyURLLoaderFactory* const factory_;
313   const int32_t id_;
314   const uint32_t options_;
315   bool input_stream_previously_failed_ = false;
316   bool request_was_redirected_ = false;
317   int redirect_limit_ = net::URLRequest::kMaxRedirects;
318 
319   // To avoid sending multiple OnReceivedError callbacks.
320   bool sent_error_callback_ = false;
321 
322   // When true, the loader will provide the option to intercept the request.
323   bool intercept_request_ = true;
324 
325   // When true, the loader will not proceed unless the intercept request
326   // callback provided a non-null response.
327   bool intercept_only_ = false;
328 
329   network::URLLoaderCompletionStatus status_;
330   bool got_loader_error_ = false;
331 
332   // Used for rate limiting OnUploadProgress callbacks.
333   bool waiting_for_upload_progress_ack_ = false;
334 
335   network::ResourceRequest request_;
336   network::mojom::URLResponseHeadPtr current_response_;
337   mojo::ScopedDataPipeConsumerHandle current_body_;
338   scoped_refptr<net::HttpResponseHeaders> current_headers_;
339   scoped_refptr<net::HttpResponseHeaders> override_headers_;
340   GURL original_url_;
341   GURL redirect_url_;
342   GURL header_client_redirect_url_;
343   const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
344 
345   mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_;
346   mojo::Remote<network::mojom::URLLoaderClient> target_client_;
347 
348   mojo::Receiver<network::mojom::URLLoaderClient> proxied_client_receiver_{
349       this};
350   mojo::Remote<network::mojom::URLLoader> target_loader_;
351   mojo::Remote<network::mojom::URLLoaderFactory> target_factory_;
352 
353   bool current_request_uses_header_client_ = false;
354   OnHeadersReceivedCallback on_headers_received_callback_;
355   mojo::Receiver<network::mojom::TrustedHeaderClient> header_client_receiver_{
356       this};
357 
358   StreamReaderURLLoader* stream_loader_ = nullptr;
359 
360   base::WeakPtrFactory<InterceptedRequest> weak_factory_;
361 };
362 
363 class InterceptDelegate : public StreamReaderURLLoader::Delegate {
364  public:
InterceptDelegate(std::unique_ptr<ResourceResponse> response,base::WeakPtr<InterceptedRequest> request)365   explicit InterceptDelegate(std::unique_ptr<ResourceResponse> response,
366                              base::WeakPtr<InterceptedRequest> request)
367       : response_(std::move(response)), request_(request) {}
368 
OpenInputStream(int32_t request_id,const network::ResourceRequest & request,OpenCallback callback)369   bool OpenInputStream(int32_t request_id,
370                        const network::ResourceRequest& request,
371                        OpenCallback callback) override {
372     return response_->OpenInputStream(request_id, request, std::move(callback));
373   }
374 
OnInputStreamOpenFailed(int32_t request_id,bool * restarted)375   void OnInputStreamOpenFailed(int32_t request_id, bool* restarted) override {
376     request_->InputStreamFailed(false /* restart_needed */);
377     *restarted = false;
378   }
379 
GetResponseHeaders(int32_t request_id,int * status_code,std::string * reason_phrase,std::string * mime_type,std::string * charset,int64_t * content_length,HeaderMap * extra_headers)380   void GetResponseHeaders(int32_t request_id,
381                           int* status_code,
382                           std::string* reason_phrase,
383                           std::string* mime_type,
384                           std::string* charset,
385                           int64_t* content_length,
386                           HeaderMap* extra_headers) override {
387     response_->GetResponseHeaders(request_id, status_code, reason_phrase,
388                                   mime_type, charset, content_length,
389                                   extra_headers);
390   }
391 
392  private:
393   std::unique_ptr<ResourceResponse> response_;
394   base::WeakPtr<InterceptedRequest> request_;
395 };
396 
InterceptedRequest(ProxyURLLoaderFactory * factory,int32_t id,uint32_t options,const network::ResourceRequest & request,const net::MutableNetworkTrafficAnnotationTag & traffic_annotation,mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,mojo::PendingRemote<network::mojom::URLLoaderClient> client,mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory)397 InterceptedRequest::InterceptedRequest(
398     ProxyURLLoaderFactory* factory,
399     int32_t id,
400     uint32_t options,
401     const network::ResourceRequest& request,
402     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
403     mojo::PendingReceiver<network::mojom::URLLoader> loader_receiver,
404     mojo::PendingRemote<network::mojom::URLLoaderClient> client,
405     mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory)
406     : factory_(factory),
407       id_(id),
408       options_(options),
409       request_(request),
410       traffic_annotation_(traffic_annotation),
411       proxied_loader_receiver_(this, std::move(loader_receiver)),
412       target_client_(std::move(client)),
413       target_factory_(std::move(target_factory)),
414       weak_factory_(this) {
415   status_ = network::URLLoaderCompletionStatus(net::OK);
416 
417   net::HttpRequestHeaders modified_headers;
418   std::vector<std::string> removed_headers;
419   OnProcessRequestHeaders(GURL() /* redirect_url */, &modified_headers,
420                           &removed_headers);
421 
422   // If there is a client error, clean up the request.
423   target_client_.set_disconnect_handler(base::BindOnce(
424       &InterceptedRequest::OnURLLoaderClientError, base::Unretained(this)));
425   proxied_loader_receiver_.set_disconnect_with_reason_handler(base::BindOnce(
426       &InterceptedRequest::OnURLLoaderError, base::Unretained(this)));
427 }
428 
~InterceptedRequest()429 InterceptedRequest::~InterceptedRequest() {
430   if (status_.error_code != net::OK)
431     SendErrorCallback(status_.error_code, false);
432   if (on_headers_received_callback_) {
433     std::move(on_headers_received_callback_)
434         .Run(net::ERR_ABORTED, absl::nullopt, GURL());
435   }
436 }
437 
Restart()438 void InterceptedRequest::Restart() {
439   stream_loader_ = nullptr;
440   if (proxied_client_receiver_.is_bound()) {
441     proxied_client_receiver_.reset();
442     target_loader_.reset();
443   }
444 
445   if (header_client_receiver_.is_bound())
446     std::ignore = header_client_receiver_.Unbind();
447 
448   current_request_uses_header_client_ =
449       factory_->url_loader_header_client_receiver_.is_bound();
450 
451   if (request_.request_initiator &&
452       network::cors::ShouldCheckCors(request_.url, request_.request_initiator,
453                                      request_.mode)) {
454     if (scheme::IsCorsEnabledScheme(request_.url.scheme())) {
455       // Add the Origin header for CORS-enabled scheme requests.
456       request_.headers.SetHeaderIfMissing(
457           net::HttpRequestHeaders::kOrigin,
458           request_.request_initiator->Serialize());
459     } else if (!HasCrossOriginWhitelistEntry(
460                    *request_.request_initiator,
461                    url::Origin::Create(request_.url))) {
462       // Fail requests if a CORS check is required and the scheme is not CORS
463       // enabled. This matches the error condition that would be generated by
464       // CorsURLLoader::StartRequest in the network process.
465       SendErrorStatusAndCompleteImmediately(
466           network::URLLoaderCompletionStatus(network::CorsErrorStatus(
467               network::mojom::CorsError::kCorsDisabledScheme)));
468       return;
469     }
470   }
471 
472   const GURL original_url = request_.url;
473 
474   factory_->request_handler_->OnBeforeRequest(
475       id_, &request_, request_was_redirected_,
476       base::BindOnce(&InterceptedRequest::BeforeRequestReceived,
477                      weak_factory_.GetWeakPtr(), original_url),
478       base::BindOnce(&InterceptedRequest::SendErrorAndCompleteImmediately,
479                      weak_factory_.GetWeakPtr()));
480 }
481 
OnLoaderCreated(mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)482 void InterceptedRequest::OnLoaderCreated(
483     mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
484   DCHECK(current_request_uses_header_client_);
485 
486   // Only called if we're using the default loader.
487   header_client_receiver_.Bind(std::move(receiver));
488 }
489 
InputStreamFailed(bool restart_needed)490 void InterceptedRequest::InputStreamFailed(bool restart_needed) {
491   DCHECK(!input_stream_previously_failed_);
492 
493   if (intercept_only_) {
494     // This can happen for unsupported schemes, when no proper
495     // response from the intercept handler is received, i.e.
496     // the provided input stream in response failed to load. In
497     // this case we send and error and stop loading.
498     SendErrorAndCompleteImmediately(net::ERR_UNKNOWN_URL_SCHEME);
499     return;
500   }
501 
502   if (!restart_needed)
503     return;
504 
505   input_stream_previously_failed_ = true;
506   Restart();
507 }
508 
509 // TrustedHeaderClient methods.
510 
OnBeforeSendHeaders(const net::HttpRequestHeaders & headers,OnBeforeSendHeadersCallback callback)511 void InterceptedRequest::OnBeforeSendHeaders(
512     const net::HttpRequestHeaders& headers,
513     OnBeforeSendHeadersCallback callback) {
514   if (!current_request_uses_header_client_) {
515     std::move(callback).Run(net::OK, absl::nullopt);
516     return;
517   }
518 
519   request_.headers = headers;
520   std::move(callback).Run(net::OK, absl::nullopt);
521 
522   // Resume handling of client messages after continuing from an async callback.
523   if (proxied_client_receiver_.is_bound())
524     proxied_client_receiver_.Resume();
525 }
526 
OnHeadersReceived(const std::string & headers,const net::IPEndPoint & remote_endpoint,OnHeadersReceivedCallback callback)527 void InterceptedRequest::OnHeadersReceived(
528     const std::string& headers,
529     const net::IPEndPoint& remote_endpoint,
530     OnHeadersReceivedCallback callback) {
531   if (!current_request_uses_header_client_) {
532     std::move(callback).Run(net::OK, absl::nullopt, GURL());
533     return;
534   }
535 
536   current_headers_ = base::MakeRefCounted<net::HttpResponseHeaders>(headers);
537   on_headers_received_callback_ = std::move(callback);
538 
539   absl::optional<net::RedirectInfo> redirect_info;
540   std::string location;
541   if (current_headers_->IsRedirect(&location)) {
542     const GURL new_url = request_.url.Resolve(location);
543     redirect_info =
544         MakeRedirectInfo(request_, current_headers_.get(), new_url, 0);
545   }
546 
547   HandleResponseOrRedirectHeaders(
548       redirect_info,
549       base::BindOnce(&InterceptedRequest::ContinueToHandleOverrideHeaders,
550                      weak_factory_.GetWeakPtr()));
551 }
552 
553 // URLLoaderClient methods.
554 
OnReceiveEarlyHints(network::mojom::EarlyHintsPtr early_hints)555 void InterceptedRequest::OnReceiveEarlyHints(
556     network::mojom::EarlyHintsPtr early_hints) {
557   target_client_->OnReceiveEarlyHints(std::move(early_hints));
558 }
559 
OnReceiveResponse(network::mojom::URLResponseHeadPtr head,mojo::ScopedDataPipeConsumerHandle body)560 void InterceptedRequest::OnReceiveResponse(
561     network::mojom::URLResponseHeadPtr head,
562     mojo::ScopedDataPipeConsumerHandle body) {
563   current_response_ = std::move(head);
564   current_body_ = std::move(body);
565 
566   if (current_request_uses_header_client_) {
567     // Use the headers we got from OnHeadersReceived as that'll contain
568     // Set-Cookie if it existed.
569     DCHECK(current_headers_);
570     current_response_->headers = current_headers_;
571     current_headers_ = nullptr;
572     ContinueToResponseStarted(net::OK);
573   } else {
574     HandleResponseOrRedirectHeaders(
575         absl::nullopt,
576         base::BindOnce(&InterceptedRequest::ContinueToResponseStarted,
577                        weak_factory_.GetWeakPtr()));
578   }
579 }
580 
OnReceiveRedirect(const net::RedirectInfo & redirect_info,network::mojom::URLResponseHeadPtr head)581 void InterceptedRequest::OnReceiveRedirect(
582     const net::RedirectInfo& redirect_info,
583     network::mojom::URLResponseHeadPtr head) {
584   bool needs_callback = false;
585 
586   current_response_ = std::move(head);
587   current_body_.reset();
588 
589   if (current_request_uses_header_client_) {
590     // Use the headers we got from OnHeadersReceived as that'll contain
591     // Set-Cookie if it existed. May be null for synthetic redirects.
592     if (current_headers_) {
593       current_response_->headers = current_headers_;
594       current_headers_ = nullptr;
595     }
596   } else {
597     needs_callback = true;
598   }
599 
600   if (--redirect_limit_ == 0) {
601     SendErrorAndCompleteImmediately(net::ERR_TOO_MANY_REDIRECTS);
602     return;
603   }
604 
605   net::RedirectInfo new_redirect_info;
606 
607   // When we redirect via ContinueToHandleOverrideHeaders the |redirect_info|
608   // value is sometimes nonsense (HTTP_OK). Also, we won't get another call to
609   // OnHeadersReceived for the new URL so we need to execute the callback here.
610   if (header_client_redirect_url_.is_valid() &&
611       redirect_info.status_code == net::HTTP_OK) {
612     DCHECK(current_request_uses_header_client_);
613     needs_callback = true;
614     new_redirect_info =
615         MakeRedirectResponseAndInfo(header_client_redirect_url_);
616   } else {
617     new_redirect_info = redirect_info;
618   }
619 
620   if (needs_callback) {
621     HandleResponseOrRedirectHeaders(
622         new_redirect_info,
623         base::BindOnce(&InterceptedRequest::ContinueToBeforeRedirect,
624                        weak_factory_.GetWeakPtr(), new_redirect_info));
625   } else {
626     ContinueToBeforeRedirect(new_redirect_info, net::OK);
627   }
628 }
629 
OnUploadProgress(int64_t current_position,int64_t total_size,OnUploadProgressCallback callback)630 void InterceptedRequest::OnUploadProgress(int64_t current_position,
631                                           int64_t total_size,
632                                           OnUploadProgressCallback callback) {
633   // Implement our own rate limiting for OnUploadProgress calls.
634   if (!waiting_for_upload_progress_ack_) {
635     waiting_for_upload_progress_ack_ = true;
636     target_client_->OnUploadProgress(
637         current_position, total_size,
638         base::BindOnce(&InterceptedRequest::OnUploadProgressACK,
639                        weak_factory_.GetWeakPtr()));
640   }
641 
642   // Always execute the callback immediately to avoid a race between
643   // URLLoaderClient_OnUploadProgress_ProxyToResponder::Run() (which would
644   // otherwise be blocked on the target client executing the callback) and
645   // CallOnComplete(). If CallOnComplete() is executed first the interface pipe
646   // will be closed and the callback destructor will generate an assertion like:
647   // "URLLoaderClient::OnUploadProgressCallback was destroyed without first
648   // either being run or its corresponding binding being closed. It is an error
649   // to drop response callbacks which still correspond to an open interface
650   // pipe."
651   std::move(callback).Run();
652 }
653 
OnReceiveCachedMetadata(mojo_base::BigBuffer data)654 void InterceptedRequest::OnReceiveCachedMetadata(mojo_base::BigBuffer data) {
655   target_client_->OnReceiveCachedMetadata(std::move(data));
656 }
657 
OnTransferSizeUpdated(int32_t transfer_size_diff)658 void InterceptedRequest::OnTransferSizeUpdated(int32_t transfer_size_diff) {
659   target_client_->OnTransferSizeUpdated(transfer_size_diff);
660 }
661 
OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body)662 void InterceptedRequest::OnStartLoadingResponseBody(
663     mojo::ScopedDataPipeConsumerHandle body) {
664   target_client_->OnStartLoadingResponseBody(
665       factory_->request_handler_->OnFilterResponseBody(id_, request_,
666                                                        std::move(body)));
667 }
668 
OnComplete(const network::URLLoaderCompletionStatus & status)669 void InterceptedRequest::OnComplete(
670     const network::URLLoaderCompletionStatus& status) {
671   // Only wait for the original loader to possibly have a custom error if the
672   // target loader exists and succeeded. If the target loader failed, then it
673   // was a race as to whether that error or the safe browsing error would be
674   // reported.
675   CallOnComplete(status, !stream_loader_ && status.error_code == net::OK);
676 }
677 
678 // URLLoader methods.
679 
FollowRedirect(const std::vector<std::string> & removed_headers_ext,const net::HttpRequestHeaders & modified_headers_ext,const net::HttpRequestHeaders & modified_cors_exempt_headers,const absl::optional<GURL> & new_url)680 void InterceptedRequest::FollowRedirect(
681     const std::vector<std::string>& removed_headers_ext,
682     const net::HttpRequestHeaders& modified_headers_ext,
683     const net::HttpRequestHeaders& modified_cors_exempt_headers,
684     const absl::optional<GURL>& new_url) {
685   std::vector<std::string> removed_headers = removed_headers_ext;
686   net::HttpRequestHeaders modified_headers = modified_headers_ext;
687   OnProcessRequestHeaders(new_url.value_or(GURL()), &modified_headers,
688                           &removed_headers);
689 
690   // If |OnURLLoaderClientError| was called then we're just waiting for the
691   // connection error handler of |proxied_loader_receiver_|. Don't restart the
692   // job since that'll create another URLLoader.
693   if (!target_client_)
694     return;
695 
696   // Normally we would call FollowRedirect on the target loader and it would
697   // begin loading the redirected request. However, the client might want to
698   // intercept that request so restart the job instead.
699   Restart();
700 }
701 
SetPriority(net::RequestPriority priority,int32_t intra_priority_value)702 void InterceptedRequest::SetPriority(net::RequestPriority priority,
703                                      int32_t intra_priority_value) {
704   if (target_loader_)
705     target_loader_->SetPriority(priority, intra_priority_value);
706 }
707 
PauseReadingBodyFromNet()708 void InterceptedRequest::PauseReadingBodyFromNet() {
709   if (target_loader_)
710     target_loader_->PauseReadingBodyFromNet();
711 }
712 
ResumeReadingBodyFromNet()713 void InterceptedRequest::ResumeReadingBodyFromNet() {
714   if (target_loader_)
715     target_loader_->ResumeReadingBodyFromNet();
716 }
717 
718 // Helper methods.
719 
BeforeRequestReceived(const GURL & original_url,bool intercept_request,bool intercept_only)720 void InterceptedRequest::BeforeRequestReceived(const GURL& original_url,
721                                                bool intercept_request,
722                                                bool intercept_only) {
723   intercept_request_ = intercept_request;
724   intercept_only_ = intercept_only;
725 
726   if (input_stream_previously_failed_ || !intercept_request_) {
727     // Equivalent to no interception.
728     InterceptResponseReceived(original_url, nullptr);
729   } else {
730     // TODO(network): Verify the case when WebContents::RenderFrameDeleted is
731     // called before network request is intercepted (i.e. if that's possible
732     // and whether it can result in any issues).
733     factory_->request_handler_->ShouldInterceptRequest(
734         id_, &request_,
735         base::BindOnce(&InterceptedRequest::InterceptResponseReceived,
736                        weak_factory_.GetWeakPtr(), original_url));
737   }
738 }
739 
InterceptResponseReceived(const GURL & original_url,std::unique_ptr<ResourceResponse> response)740 void InterceptedRequest::InterceptResponseReceived(
741     const GURL& original_url,
742     std::unique_ptr<ResourceResponse> response) {
743   if (request_.url != original_url) {
744     // A response object shouldn't be created if we're redirecting.
745     DCHECK(!response);
746 
747     // Perform the redirect.
748     current_response_ = network::mojom::URLResponseHead::New();
749     current_response_->request_start = base::TimeTicks::Now();
750     current_response_->response_start = base::TimeTicks::Now();
751     current_body_.reset();
752 
753     auto headers = MakeResponseHeaders(
754         net::HTTP_TEMPORARY_REDIRECT, std::string(), std::string(),
755         std::string(), -1, {}, false /* allow_existing_header_override */);
756     current_response_->headers = headers;
757 
758     current_response_->encoded_data_length = headers->raw_headers().length();
759     current_response_->content_length = current_response_->encoded_body_length =
760         0;
761 
762     std::string origin;
763     if (request_.headers.GetHeader(net::HttpRequestHeaders::kOrigin, &origin) &&
764         origin != url::Origin().Serialize()) {
765       // Allow redirects of cross-origin resource loads.
766       headers->AddHeader(network::cors::header_names::kAccessControlAllowOrigin,
767                          origin);
768     }
769 
770     if (request_.credentials_mode ==
771         network::mojom::CredentialsMode::kInclude) {
772       headers->AddHeader(
773           network::cors::header_names::kAccessControlAllowCredentials, "true");
774     }
775 
776     const net::RedirectInfo& redirect_info =
777         MakeRedirectInfo(request_, headers.get(), request_.url, 0);
778     HandleResponseOrRedirectHeaders(
779         redirect_info,
780         base::BindOnce(&InterceptedRequest::ContinueToBeforeRedirect,
781                        weak_factory_.GetWeakPtr(), redirect_info));
782     return;
783   }
784 
785   if (response) {
786     // Non-null response: make sure to use it as an override for the
787     // normal network data.
788     ContinueAfterInterceptWithOverride(std::move(response));
789   } else {
790     // Request was not intercepted/overridden. Proceed with loading
791     // from network, unless this is a special |intercept_only_| loader,
792     // which happens for external schemes (e.g. unsupported schemes).
793     if (intercept_only_) {
794       SendErrorAndCompleteImmediately(net::ERR_UNKNOWN_URL_SCHEME);
795       return;
796     }
797     ContinueAfterIntercept();
798   }
799 }
800 
ContinueAfterIntercept()801 void InterceptedRequest::ContinueAfterIntercept() {
802   if (!target_loader_ && target_factory_) {
803     // Even if this request does not use the header client, future redirects
804     // might, so we need to set the option on the loader.
805     uint32_t options = options_ | network::mojom::kURLLoadOptionUseHeaderClient;
806     target_factory_->CreateLoaderAndStart(
807         target_loader_.BindNewPipeAndPassReceiver(), id_, options, request_,
808         proxied_client_receiver_.BindNewPipeAndPassRemote(),
809         traffic_annotation_);
810   }
811 }
812 
ContinueAfterInterceptWithOverride(std::unique_ptr<ResourceResponse> response)813 void InterceptedRequest::ContinueAfterInterceptWithOverride(
814     std::unique_ptr<ResourceResponse> response) {
815   // StreamReaderURLLoader will synthesize TrustedHeaderClient callbacks to
816   // avoid having Set-Cookie headers stripped by the IPC layer.
817   current_request_uses_header_client_ = true;
818 
819   stream_loader_ = new StreamReaderURLLoader(
820       id_, request_, proxied_client_receiver_.BindNewPipeAndPassRemote(),
821       header_client_receiver_.BindNewPipeAndPassRemote(), traffic_annotation_,
822       std::make_unique<InterceptDelegate>(std::move(response),
823                                           weak_factory_.GetWeakPtr()));
824   stream_loader_->Start();
825 }
826 
HandleResponseOrRedirectHeaders(absl::optional<net::RedirectInfo> redirect_info,net::CompletionOnceCallback continuation)827 void InterceptedRequest::HandleResponseOrRedirectHeaders(
828     absl::optional<net::RedirectInfo> redirect_info,
829     net::CompletionOnceCallback continuation) {
830   override_headers_ = nullptr;
831   redirect_url_ = redirect_info.has_value() ? redirect_info->new_url : GURL();
832   original_url_ = request_.url;
833 
834   // |current_response_| may be nullptr when called from OnHeadersReceived.
835   auto headers =
836       current_response_ ? current_response_->headers : current_headers_;
837 
838   // Even though |head| is const we can get a non-const pointer to the headers
839   // and modifications we make are passed to the target client.
840   factory_->request_handler_->ProcessResponseHeaders(
841       id_, request_, redirect_url_, headers.get());
842 
843   // Pause handling of client messages before waiting on an async callback.
844   if (proxied_client_receiver_.is_bound())
845     proxied_client_receiver_.Pause();
846 
847   factory_->request_handler_->OnRequestResponse(
848       id_, &request_, headers.get(), redirect_info,
849       base::BindOnce(&InterceptedRequest::ContinueResponseOrRedirect,
850                      weak_factory_.GetWeakPtr(), std::move(continuation)));
851 }
852 
ContinueResponseOrRedirect(net::CompletionOnceCallback continuation,InterceptedRequestHandler::ResponseMode response_mode,scoped_refptr<net::HttpResponseHeaders> override_headers,const GURL & redirect_url)853 void InterceptedRequest::ContinueResponseOrRedirect(
854     net::CompletionOnceCallback continuation,
855     InterceptedRequestHandler::ResponseMode response_mode,
856     scoped_refptr<net::HttpResponseHeaders> override_headers,
857     const GURL& redirect_url) {
858   if (response_mode == InterceptedRequestHandler::ResponseMode::CANCEL) {
859     std::move(continuation).Run(net::ERR_ABORTED);
860     return;
861   } else if (response_mode ==
862              InterceptedRequestHandler::ResponseMode::RESTART) {
863     Restart();
864     return;
865   }
866 
867   override_headers_ = override_headers;
868   if (override_headers_) {
869     // Make sure to update current_response_, since when OnReceiveResponse
870     // is called we will not use its headers as it might be missing the
871     // Set-Cookie line (which gets stripped by the IPC layer).
872     current_response_->headers = override_headers_;
873   }
874   redirect_url_ = redirect_url;
875 
876   std::move(continuation).Run(net::OK);
877 }
878 
ContinueToHandleOverrideHeaders(int error_code)879 void InterceptedRequest::ContinueToHandleOverrideHeaders(int error_code) {
880   if (error_code != net::OK) {
881     SendErrorAndCompleteImmediately(error_code);
882     return;
883   }
884 
885   DCHECK(on_headers_received_callback_);
886   absl::optional<std::string> headers;
887   if (override_headers_)
888     headers = override_headers_->raw_headers();
889   header_client_redirect_url_ = redirect_url_;
890   std::move(on_headers_received_callback_).Run(net::OK, headers, redirect_url_);
891 
892   override_headers_ = nullptr;
893   redirect_url_ = GURL();
894 
895   // Resume handling of client messages after continuing from an async callback.
896   if (proxied_client_receiver_.is_bound())
897     proxied_client_receiver_.Resume();
898 }
899 
MakeRedirectResponseAndInfo(const GURL & new_location)900 net::RedirectInfo InterceptedRequest::MakeRedirectResponseAndInfo(
901     const GURL& new_location) {
902   // Clear the Content-Type values.
903   current_response_->mime_type = current_response_->charset = std::string();
904   current_response_->headers->RemoveHeader(
905       net::HttpRequestHeaders::kContentType);
906 
907   // Clear the Content-Length values.
908   current_response_->content_length = current_response_->encoded_body_length =
909       0;
910   current_response_->headers->RemoveHeader(
911       net::HttpRequestHeaders::kContentLength);
912 
913   current_response_->encoded_data_length =
914       current_response_->headers->raw_headers().size();
915 
916   const net::RedirectInfo& redirect_info = MakeRedirectInfo(
917       request_, current_response_->headers.get(), new_location, 0);
918   current_response_->headers->ReplaceStatusLine(
919       MakeStatusLine(redirect_info.status_code, std::string(), true));
920 
921   return redirect_info;
922 }
923 
ContinueToBeforeRedirect(const net::RedirectInfo & redirect_info,int error_code)924 void InterceptedRequest::ContinueToBeforeRedirect(
925     const net::RedirectInfo& redirect_info,
926     int error_code) {
927   if (error_code != net::OK) {
928     SendErrorAndCompleteImmediately(error_code);
929     return;
930   }
931 
932   request_was_redirected_ = true;
933 
934   if (header_client_redirect_url_.is_valid())
935     header_client_redirect_url_ = GURL();
936 
937   const GURL redirect_url = redirect_url_;
938   override_headers_ = nullptr;
939   redirect_url_ = GURL();
940 
941   // Resume handling of client messages after continuing from an async callback.
942   if (proxied_client_receiver_.is_bound())
943     proxied_client_receiver_.Resume();
944 
945   const auto original_url = request_.url;
946   const auto original_method = request_.method;
947 
948   net::RedirectInfo new_redirect_info = redirect_info;
949   if (redirect_url.is_valid()) {
950     new_redirect_info.new_url = redirect_url;
951     new_redirect_info.new_site_for_cookies =
952         net::SiteForCookies::FromUrl(redirect_url);
953   }
954 
955   target_client_->OnReceiveRedirect(new_redirect_info,
956                                     std::move(current_response_));
957 
958   request_.url = new_redirect_info.new_url;
959   request_.method = new_redirect_info.new_method;
960   request_.site_for_cookies = new_redirect_info.new_site_for_cookies;
961   request_.referrer = GURL(new_redirect_info.new_referrer);
962   request_.referrer_policy = new_redirect_info.new_referrer_policy;
963 
964   if (request_.trusted_params) {
965     request_.trusted_params->isolation_info =
966         request_.trusted_params->isolation_info.CreateForRedirect(
967             url::Origin::Create(request_.url));
968   }
969 
970   // Remove existing Cookie headers. They may be re-added after Restart().
971   const std::vector<std::string> remove_headers{
972       net::HttpRequestHeaders::kCookie};
973 
974   // Use common logic for sanitizing request headers including Origin and
975   // Content-*.
976   bool should_clear_upload;
977   net::RedirectUtil::UpdateHttpRequest(original_url, original_method,
978                                        new_redirect_info,
979                                        absl::make_optional(remove_headers),
980                                        /*modified_headers=*/absl::nullopt,
981                                        &request_.headers, &should_clear_upload);
982 
983   if (should_clear_upload) {
984     request_.request_body = nullptr;
985   }
986 }
987 
ContinueToResponseStarted(int error_code)988 void InterceptedRequest::ContinueToResponseStarted(int error_code) {
989   if (error_code != net::OK) {
990     SendErrorAndCompleteImmediately(error_code);
991     return;
992   }
993 
994   const GURL redirect_url = redirect_url_;
995   override_headers_ = nullptr;
996   redirect_url_ = GURL();
997 
998   scoped_refptr<net::HttpResponseHeaders> headers =
999       current_response_ ? current_response_->headers : nullptr;
1000 
1001   std::string location;
1002   const bool is_redirect =
1003       redirect_url.is_valid() || (headers && headers->IsRedirect(&location));
1004   if (stream_loader_ && is_redirect) {
1005     // Redirecting from OnReceiveResponse generally isn't supported by the
1006     // NetworkService, so we can only support it when using a custom loader.
1007     // TODO(network): Remove this special case.
1008     const GURL new_location = redirect_url.is_valid()
1009                                   ? redirect_url
1010                                   : original_url_.Resolve(location);
1011     const net::RedirectInfo& redirect_info =
1012         MakeRedirectResponseAndInfo(new_location);
1013 
1014     HandleResponseOrRedirectHeaders(
1015         redirect_info,
1016         base::BindOnce(&InterceptedRequest::ContinueToBeforeRedirect,
1017                        weak_factory_.GetWeakPtr(), redirect_info));
1018   } else {
1019     LOG_IF(WARNING, is_redirect) << "Redirect at this time is not supported by "
1020                                     "the default network loader.";
1021 
1022     // CORS check for requests that are handled by the client. Requests handled
1023     // by the network process will be checked there.
1024     if (stream_loader_ && !is_redirect && request_.request_initiator &&
1025         network::cors::ShouldCheckCors(request_.url, request_.request_initiator,
1026                                        request_.mode)) {
1027       const auto error_status = network::cors::CheckAccess(
1028           request_.url,
1029           GetHeaderString(
1030               headers.get(),
1031               network::cors::header_names::kAccessControlAllowOrigin),
1032           GetHeaderString(
1033               headers.get(),
1034               network::cors::header_names::kAccessControlAllowCredentials),
1035           request_.credentials_mode, *request_.request_initiator);
1036       if (error_status &&
1037           !HasCrossOriginWhitelistEntry(*request_.request_initiator,
1038                                         url::Origin::Create(request_.url))) {
1039         SendErrorStatusAndCompleteImmediately(
1040             network::URLLoaderCompletionStatus(*error_status));
1041         return;
1042       }
1043     }
1044 
1045     // Resume handling of client messages after continuing from an async
1046     // callback.
1047     if (proxied_client_receiver_.is_bound())
1048       proxied_client_receiver_.Resume();
1049 
1050     target_client_->OnReceiveResponse(std::move(current_response_),
1051                                       std::move(current_body_));
1052   }
1053 
1054   if (stream_loader_)
1055     stream_loader_->ContinueResponse(is_redirect);
1056 }
1057 
OnDestroy()1058 void InterceptedRequest::OnDestroy() {
1059   // We don't want any callbacks after this point.
1060   weak_factory_.InvalidateWeakPtrs();
1061 
1062   factory_->request_handler_->OnRequestComplete(id_, request_, status_);
1063 
1064   // Destroys |this|.
1065   factory_->RemoveRequest(this);
1066 }
1067 
OnProcessRequestHeaders(const GURL & redirect_url,net::HttpRequestHeaders * modified_headers,std::vector<std::string> * removed_headers)1068 void InterceptedRequest::OnProcessRequestHeaders(
1069     const GURL& redirect_url,
1070     net::HttpRequestHeaders* modified_headers,
1071     std::vector<std::string>* removed_headers) {
1072   factory_->request_handler_->ProcessRequestHeaders(
1073       id_, request_, redirect_url, modified_headers, removed_headers);
1074 
1075   if (!modified_headers->IsEmpty() || !removed_headers->empty()) {
1076     request_.headers.MergeFrom(*modified_headers);
1077     for (const std::string& name : *removed_headers)
1078       request_.headers.RemoveHeader(name);
1079   }
1080 }
1081 
OnURLLoaderClientError()1082 void InterceptedRequest::OnURLLoaderClientError() {
1083   // We set |wait_for_loader_error| to true because if the loader did have a
1084   // custom_reason error then the client would be reset as well and it would be
1085   // a race as to which connection error we saw first.
1086   CallOnComplete(network::URLLoaderCompletionStatus(net::ERR_ABORTED),
1087                  true /* wait_for_loader_error */);
1088 }
1089 
OnURLLoaderError(uint32_t custom_reason,const std::string & description)1090 void InterceptedRequest::OnURLLoaderError(uint32_t custom_reason,
1091                                           const std::string& description) {
1092   if (custom_reason == network::mojom::URLLoader::kClientDisconnectReason)
1093     SendErrorCallback(safe_browsing::kNetErrorCodeForSafeBrowsing, true);
1094 
1095   got_loader_error_ = true;
1096 
1097   // If CallOnComplete was already called, then this object is ready to be
1098   // deleted.
1099   if (!target_client_)
1100     OnDestroy();
1101 }
1102 
CallOnComplete(const network::URLLoaderCompletionStatus & status,bool wait_for_loader_error)1103 void InterceptedRequest::CallOnComplete(
1104     const network::URLLoaderCompletionStatus& status,
1105     bool wait_for_loader_error) {
1106   status_ = status;
1107 
1108   if (target_client_)
1109     target_client_->OnComplete(status);
1110 
1111   if (proxied_loader_receiver_.is_bound() &&
1112       (wait_for_loader_error && !got_loader_error_)) {
1113     // Don't delete |this| yet, in case the |proxied_loader_receiver_|'s
1114     // error_handler is called with a reason to indicate an error which we want
1115     // to send to the client bridge. Also reset |target_client_| so we don't
1116     // get its error_handler called and then delete |this|.
1117     target_client_.reset();
1118 
1119     // Since the original client is gone no need to continue loading the
1120     // request.
1121     proxied_client_receiver_.reset();
1122     header_client_receiver_.reset();
1123     target_loader_.reset();
1124 
1125     // In case there are pending checks as to whether this request should be
1126     // intercepted, we don't want that causing |target_client_| to be used
1127     // later.
1128     weak_factory_.InvalidateWeakPtrs();
1129   } else {
1130     OnDestroy();
1131   }
1132 }
1133 
SendErrorAndCompleteImmediately(int error_code)1134 void InterceptedRequest::SendErrorAndCompleteImmediately(int error_code) {
1135   SendErrorStatusAndCompleteImmediately(
1136       network::URLLoaderCompletionStatus(error_code));
1137 }
1138 
SendErrorStatusAndCompleteImmediately(const network::URLLoaderCompletionStatus & status)1139 void InterceptedRequest::SendErrorStatusAndCompleteImmediately(
1140     const network::URLLoaderCompletionStatus& status) {
1141   status_ = status;
1142   SendErrorCallback(status_.error_code, false);
1143   target_client_->OnComplete(status_);
1144   OnDestroy();
1145 }
1146 
SendErrorCallback(int error_code,bool safebrowsing_hit)1147 void InterceptedRequest::SendErrorCallback(int error_code,
1148                                            bool safebrowsing_hit) {
1149   // Ensure we only send one error callback, e.g. to avoid sending two if
1150   // there's both a networking error and safe browsing blocked the request.
1151   if (sent_error_callback_)
1152     return;
1153 
1154   sent_error_callback_ = true;
1155   factory_->request_handler_->OnRequestError(id_, request_, error_code,
1156                                              safebrowsing_hit);
1157 }
1158 
OnUploadProgressACK()1159 void InterceptedRequest::OnUploadProgressACK() {
1160   DCHECK(waiting_for_upload_progress_ack_);
1161   waiting_for_upload_progress_ack_ = false;
1162 }
1163 
1164 //==============================
1165 // InterceptedRequestHandler
1166 //==============================
1167 
InterceptedRequestHandler()1168 InterceptedRequestHandler::InterceptedRequestHandler() {}
~InterceptedRequestHandler()1169 InterceptedRequestHandler::~InterceptedRequestHandler() {}
1170 
OnBeforeRequest(int32_t request_id,network::ResourceRequest * request,bool request_was_redirected,OnBeforeRequestResultCallback callback,CancelRequestCallback cancel_callback)1171 void InterceptedRequestHandler::OnBeforeRequest(
1172     int32_t request_id,
1173     network::ResourceRequest* request,
1174     bool request_was_redirected,
1175     OnBeforeRequestResultCallback callback,
1176     CancelRequestCallback cancel_callback) {
1177   std::move(callback).Run(false, false);
1178 }
1179 
ShouldInterceptRequest(int32_t request_id,network::ResourceRequest * request,ShouldInterceptRequestResultCallback callback)1180 void InterceptedRequestHandler::ShouldInterceptRequest(
1181     int32_t request_id,
1182     network::ResourceRequest* request,
1183     ShouldInterceptRequestResultCallback callback) {
1184   std::move(callback).Run(nullptr);
1185 }
1186 
OnRequestResponse(int32_t request_id,network::ResourceRequest * request,net::HttpResponseHeaders * headers,absl::optional<net::RedirectInfo> redirect_info,OnRequestResponseResultCallback callback)1187 void InterceptedRequestHandler::OnRequestResponse(
1188     int32_t request_id,
1189     network::ResourceRequest* request,
1190     net::HttpResponseHeaders* headers,
1191     absl::optional<net::RedirectInfo> redirect_info,
1192     OnRequestResponseResultCallback callback) {
1193   std::move(callback).Run(
1194       ResponseMode::CONTINUE, nullptr,
1195       redirect_info.has_value() ? redirect_info->new_url : GURL());
1196 }
1197 
1198 mojo::ScopedDataPipeConsumerHandle
OnFilterResponseBody(int32_t request_id,const network::ResourceRequest & request,mojo::ScopedDataPipeConsumerHandle body)1199 InterceptedRequestHandler::OnFilterResponseBody(
1200     int32_t request_id,
1201     const network::ResourceRequest& request,
1202     mojo::ScopedDataPipeConsumerHandle body) {
1203   return body;
1204 }
1205 
1206 //==============================
1207 // ProxyURLLoaderFactory
1208 //==============================
1209 
ProxyURLLoaderFactory(mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,network::mojom::URLLoaderFactoryPtrInfo target_factory_info,mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient> header_client_receiver,std::unique_ptr<InterceptedRequestHandler> request_handler)1210 ProxyURLLoaderFactory::ProxyURLLoaderFactory(
1211     mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,
1212     network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
1213     mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
1214         header_client_receiver,
1215     std::unique_ptr<InterceptedRequestHandler> request_handler)
1216     : request_handler_(std::move(request_handler)), weak_factory_(this) {
1217   CEF_REQUIRE_IOT();
1218   DCHECK(request_handler_);
1219 
1220   // Actual creation of the factory.
1221   if (target_factory_info) {
1222     target_factory_.Bind(std::move(target_factory_info));
1223     target_factory_.set_disconnect_handler(base::BindOnce(
1224         &ProxyURLLoaderFactory::OnTargetFactoryError, base::Unretained(this)));
1225   }
1226   proxy_receivers_.Add(this, std::move(factory_receiver));
1227   proxy_receivers_.set_disconnect_handler(base::BindRepeating(
1228       &ProxyURLLoaderFactory::OnProxyBindingError, base::Unretained(this)));
1229 
1230   if (header_client_receiver)
1231     url_loader_header_client_receiver_.Bind(std::move(header_client_receiver));
1232 }
1233 
~ProxyURLLoaderFactory()1234 ProxyURLLoaderFactory::~ProxyURLLoaderFactory() {
1235   CEF_REQUIRE_IOT();
1236 }
1237 
1238 // static
CreateOnIOThread(mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,network::mojom::URLLoaderFactoryPtrInfo target_factory_info,mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient> header_client_receiver,content::ResourceContext * resource_context,std::unique_ptr<InterceptedRequestHandler> request_handler)1239 void ProxyURLLoaderFactory::CreateOnIOThread(
1240     mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory_receiver,
1241     network::mojom::URLLoaderFactoryPtrInfo target_factory_info,
1242     mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
1243         header_client_receiver,
1244     content::ResourceContext* resource_context,
1245     std::unique_ptr<InterceptedRequestHandler> request_handler) {
1246   CEF_REQUIRE_IOT();
1247   auto proxy = new ProxyURLLoaderFactory(
1248       std::move(factory_receiver), std::move(target_factory_info),
1249       std::move(header_client_receiver), std::move(request_handler));
1250   ResourceContextData::AddProxy(proxy, resource_context);
1251 }
1252 
SetDisconnectCallback(DisconnectCallback on_disconnect)1253 void ProxyURLLoaderFactory::SetDisconnectCallback(
1254     DisconnectCallback on_disconnect) {
1255   CEF_REQUIRE_IOT();
1256   DCHECK(!destroyed_);
1257   DCHECK(!on_disconnect_);
1258   on_disconnect_ = std::move(on_disconnect);
1259 }
1260 
1261 // static
CreateProxy(content::BrowserContext * browser_context,mojo::PendingReceiver<network::mojom::URLLoaderFactory> * factory_receiver,mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> * header_client,std::unique_ptr<InterceptedRequestHandler> request_handler)1262 void ProxyURLLoaderFactory::CreateProxy(
1263     content::BrowserContext* browser_context,
1264     mojo::PendingReceiver<network::mojom::URLLoaderFactory>* factory_receiver,
1265     mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient>*
1266         header_client,
1267     std::unique_ptr<InterceptedRequestHandler> request_handler) {
1268   CEF_REQUIRE_UIT();
1269   DCHECK(request_handler);
1270 
1271   auto proxied_receiver = std::move(*factory_receiver);
1272   network::mojom::URLLoaderFactoryPtrInfo target_factory_info;
1273   *factory_receiver = mojo::MakeRequest(&target_factory_info);
1274 
1275   mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>
1276       header_client_receiver;
1277   if (header_client)
1278     header_client_receiver = header_client->InitWithNewPipeAndPassReceiver();
1279 
1280   content::ResourceContext* resource_context =
1281       browser_context->GetResourceContext();
1282   DCHECK(resource_context);
1283 
1284   CEF_POST_TASK(
1285       CEF_IOT,
1286       base::BindOnce(
1287           &ProxyURLLoaderFactory::CreateOnIOThread, std::move(proxied_receiver),
1288           std::move(target_factory_info), std::move(header_client_receiver),
1289           base::Unretained(resource_context), std::move(request_handler)));
1290 }
1291 
1292 // static
CreateProxy(content::WebContents::Getter web_contents_getter,mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,std::unique_ptr<InterceptedRequestHandler> request_handler)1293 void ProxyURLLoaderFactory::CreateProxy(
1294     content::WebContents::Getter web_contents_getter,
1295     mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
1296     std::unique_ptr<InterceptedRequestHandler> request_handler) {
1297   DCHECK(request_handler);
1298 
1299   if (!CEF_CURRENTLY_ON_IOT()) {
1300     CEF_POST_TASK(
1301         CEF_IOT,
1302         base::BindOnce(CreateProxyHelper, web_contents_getter,
1303                        std::move(loader_receiver), std::move(request_handler)));
1304     return;
1305   }
1306 
1307   auto proxy = new ProxyURLLoaderFactory(
1308       std::move(loader_receiver), nullptr,
1309       mojo::PendingReceiver<network::mojom::TrustedURLLoaderHeaderClient>(),
1310       std::move(request_handler));
1311   CEF_POST_TASK(CEF_UIT,
1312                 base::BindOnce(ResourceContextData::AddProxyOnUIThread,
1313                                base::Unretained(proxy), web_contents_getter));
1314 }
1315 
CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> receiver,int32_t request_id,uint32_t options,const network::ResourceRequest & request,mojo::PendingRemote<network::mojom::URLLoaderClient> client,const net::MutableNetworkTrafficAnnotationTag & traffic_annotation)1316 void ProxyURLLoaderFactory::CreateLoaderAndStart(
1317     mojo::PendingReceiver<network::mojom::URLLoader> receiver,
1318     int32_t request_id,
1319     uint32_t options,
1320     const network::ResourceRequest& request,
1321     mojo::PendingRemote<network::mojom::URLLoaderClient> client,
1322     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
1323   CEF_REQUIRE_IOT();
1324   if (!CONTEXT_STATE_VALID()) {
1325     // Don't start a request while we're shutting down.
1326     return;
1327   }
1328 
1329   if (DisableRequestHandlingForTesting() && request.url.SchemeIsHTTPOrHTTPS()) {
1330     // This is the so-called pass-through, no-op option.
1331     if (target_factory_) {
1332       target_factory_->CreateLoaderAndStart(std::move(receiver), request_id,
1333                                             options, request, std::move(client),
1334                                             traffic_annotation);
1335     }
1336     return;
1337   }
1338 
1339   mojo::PendingRemote<network::mojom::URLLoaderFactory> target_factory_clone;
1340   if (target_factory_) {
1341     target_factory_->Clone(
1342         target_factory_clone.InitWithNewPipeAndPassReceiver());
1343   }
1344 
1345   InterceptedRequest* req = new InterceptedRequest(
1346       this, request_id, options, request, traffic_annotation,
1347       std::move(receiver), std::move(client), std::move(target_factory_clone));
1348   requests_.insert(std::make_pair(request_id, base::WrapUnique(req)));
1349   req->Restart();
1350 }
1351 
Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory)1352 void ProxyURLLoaderFactory::Clone(
1353     mojo::PendingReceiver<network::mojom::URLLoaderFactory> factory) {
1354   CEF_REQUIRE_IOT();
1355   proxy_receivers_.Add(this, std::move(factory));
1356 }
1357 
OnLoaderCreated(int32_t request_id,mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)1358 void ProxyURLLoaderFactory::OnLoaderCreated(
1359     int32_t request_id,
1360     mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
1361   CEF_REQUIRE_IOT();
1362   auto request_it = requests_.find(request_id);
1363   if (request_it != requests_.end())
1364     request_it->second->OnLoaderCreated(std::move(receiver));
1365 }
1366 
OnLoaderForCorsPreflightCreated(const network::ResourceRequest & request,mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver)1367 void ProxyURLLoaderFactory::OnLoaderForCorsPreflightCreated(
1368     const network::ResourceRequest& request,
1369     mojo::PendingReceiver<network::mojom::TrustedHeaderClient> receiver) {
1370   CEF_REQUIRE_IOT();
1371   new CorsPreflightRequest(std::move(receiver));
1372 }
1373 
OnTargetFactoryError()1374 void ProxyURLLoaderFactory::OnTargetFactoryError() {
1375   // Stop calls to CreateLoaderAndStart() when |target_factory_| is invalid.
1376   target_factory_.reset();
1377   proxy_receivers_.Clear();
1378 
1379   MaybeDestroySelf();
1380 }
1381 
OnProxyBindingError()1382 void ProxyURLLoaderFactory::OnProxyBindingError() {
1383   if (proxy_receivers_.empty())
1384     target_factory_.reset();
1385 
1386   MaybeDestroySelf();
1387 }
1388 
RemoveRequest(InterceptedRequest * request)1389 void ProxyURLLoaderFactory::RemoveRequest(InterceptedRequest* request) {
1390   auto it = requests_.find(request->id());
1391   DCHECK(it != requests_.end());
1392   requests_.erase(it);
1393 
1394   MaybeDestroySelf();
1395 }
1396 
MaybeDestroySelf()1397 void ProxyURLLoaderFactory::MaybeDestroySelf() {
1398   // Even if all URLLoaderFactory pipes connected to this object have been
1399   // closed it has to stay alive until all active requests have completed.
1400   if (target_factory_.is_bound() || !requests_.empty())
1401     return;
1402 
1403   destroyed_ = true;
1404 
1405   // In some cases we may be destroyed before SetDisconnectCallback is called.
1406   if (on_disconnect_) {
1407     // Deletes |this|.
1408     std::move(on_disconnect_).Run(this);
1409   }
1410 }
1411 
1412 }  // namespace net_service
1413