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