• 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/browser_urlrequest_impl.h"
7 
8 #include <string>
9 #include <utility>
10 
11 #include "libcef/browser/browser_context.h"
12 #include "libcef/browser/frame_host_impl.h"
13 #include "libcef/browser/net_service/url_loader_factory_getter.h"
14 #include "libcef/browser/request_context_impl.h"
15 #include "libcef/browser/thread_util.h"
16 #include "libcef/common/net_service/net_service_util.h"
17 #include "libcef/common/request_impl.h"
18 #include "libcef/common/response_impl.h"
19 #include "libcef/common/task_runner_impl.h"
20 
21 #include "base/lazy_instance.h"
22 #include "base/logging.h"
23 #include "base/memory/weak_ptr.h"
24 #include "base/strings/string_util.h"
25 #include "content/browser/renderer_host/render_frame_host_impl.h"
26 #include "content/browser/storage_partition_impl.h"
27 #include "content/public/browser/browser_context.h"
28 #include "content/public/browser/global_request_id.h"
29 #include "content/public/browser/render_frame_host.h"
30 #include "net/base/mime_util.h"
31 #include "net/base/net_errors.h"
32 #include "net/http/http_response_headers.h"
33 #include "services/network/public/cpp/shared_url_loader_factory.h"
34 #include "services/network/public/cpp/simple_url_loader.h"
35 #include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
36 #include "third_party/blink/public/mojom/loader/resource_load_info.mojom.h"
37 
38 namespace {
39 
40 const int32_t kInitialRequestID = -2;
41 
42 // Request ID for requests initiated by CefBrowserURLRequest. request_ids
43 // generated by child processes are counted up from 0, while browser
44 // created requests start at -2 and go down from there. (We need to start at -2
45 // because -1 is used as a special value all over the resource_dispatcher_host
46 // for uninitialized variables.) The resource_dispatcher_host code path is not
47 // used when NetworkService is enabled so it's safe to repurpose the -2 and
48 // below range here.
49 // This method is only called on the UI thread.
MakeRequestID()50 int32_t MakeRequestID() {
51   static int32_t request_id = kInitialRequestID;
52   return --request_id;
53 }
54 
IsValidRequestID(int32_t request_id)55 bool IsValidRequestID(int32_t request_id) {
56   return request_id < kInitialRequestID;
57 }
58 
59 // Manages the mapping of request IDs to request objects.
60 class RequestManager {
61  public:
RequestManager()62   RequestManager() {}
63 
64   RequestManager(const RequestManager&) = delete;
65   RequestManager& operator=(const RequestManager&) = delete;
66 
~RequestManager()67   ~RequestManager() { DCHECK(map_.empty()); }
68 
Add(int32_t request_id,CefRefPtr<CefBrowserURLRequest> request,CefRefPtr<CefURLRequestClient> client)69   void Add(int32_t request_id,
70            CefRefPtr<CefBrowserURLRequest> request,
71            CefRefPtr<CefURLRequestClient> client) {
72     DCHECK_LE(request_id, kInitialRequestID);
73 
74     base::AutoLock lock_scope(lock_);
75     DCHECK(map_.find(request_id) == map_.end());
76     map_.insert(std::make_pair(request_id, std::make_pair(request, client)));
77   }
78 
Remove(int32_t request_id)79   void Remove(int32_t request_id) {
80     if (request_id > kInitialRequestID)
81       return;
82 
83     base::AutoLock lock_scope(lock_);
84     RequestMap::iterator it = map_.find(request_id);
85     DCHECK(it != map_.end());
86     map_.erase(it);
87   }
88 
Get(int32_t request_id)89   absl::optional<CefBrowserURLRequest::RequestInfo> Get(int32_t request_id) {
90     if (request_id > kInitialRequestID)
91       return absl::nullopt;
92 
93     base::AutoLock lock_scope(lock_);
94     RequestMap::const_iterator it = map_.find(request_id);
95     if (it != map_.end()) {
96       return it->second;
97     }
98     return absl::nullopt;
99   }
100 
101  private:
102   base::Lock lock_;
103 
104   using RequestMap = std::map<int32_t, CefBrowserURLRequest::RequestInfo>;
105   RequestMap map_;
106 };
107 
108 #if DCHECK_IS_ON()
109 // Because of DCHECK()s in the object destructor.
110 base::LazyInstance<RequestManager>::DestructorAtExit g_manager =
111     LAZY_INSTANCE_INITIALIZER;
112 #else
113 base::LazyInstance<RequestManager>::Leaky g_manager = LAZY_INSTANCE_INITIALIZER;
114 #endif
115 
116 }  // namespace
117 
118 // CefBrowserURLRequest::Context ----------------------------------------------
119 
120 class CefBrowserURLRequest::Context
121     : public network::SimpleURLLoaderStreamConsumer {
122  public:
Context(CefRefPtr<CefBrowserURLRequest> url_request,CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefURLRequestClient> client,CefRefPtr<CefRequestContext> request_context)123   Context(CefRefPtr<CefBrowserURLRequest> url_request,
124           CefRefPtr<CefFrame> frame,
125           CefRefPtr<CefRequest> request,
126           CefRefPtr<CefURLRequestClient> client,
127           CefRefPtr<CefRequestContext> request_context)
128       : url_request_(url_request),
129         frame_(frame),
130         request_(static_cast<CefRequestImpl*>(request.get())),
131         client_(client),
132         request_context_(request_context),
133         task_runner_(CefTaskRunnerImpl::GetCurrentTaskRunner()),
134         response_(new CefResponseImpl()),
135         weak_ptr_factory_(this) {
136     // Mark the request/response objects as read-only.
137     request_->SetReadOnly(true);
138     response_->SetReadOnly(true);
139   }
140   ~Context() override = default;
141 
Start()142   bool Start() {
143     DCHECK(CalledOnValidThread());
144 
145     const GURL& url = GURL(request_->GetURL().ToString());
146     if (!url.is_valid())
147       return false;
148 
149     if (!request_context_) {
150       request_context_ = CefRequestContext::GetGlobalContext();
151     }
152 
153     auto request_context_impl =
154         static_cast<CefRequestContextImpl*>(request_context_.get());
155 
156     // Wait for the browser context to be initialized before continuing.
157     request_context_impl->ExecuteWhenBrowserContextInitialized(base::BindOnce(
158         &CefBrowserURLRequest::Context::GetURLLoaderFactoryGetterOnUIThread,
159         frame_, request_context_, weak_ptr_factory_.GetWeakPtr(),
160         task_runner_));
161 
162     return true;
163   }
164 
Cancel()165   void Cancel() {
166     DCHECK(CalledOnValidThread());
167 
168     // The request may already be complete or canceled.
169     if (!url_request_)
170       return;
171 
172     DCHECK_EQ(status_, UR_IO_PENDING);
173     status_ = UR_CANCELED;
174 
175     response_->SetReadOnly(false);
176     response_->SetError(ERR_ABORTED);
177     response_->SetReadOnly(true);
178 
179     cleanup_immediately_ = true;
180     OnComplete(false);
181   }
182 
request() const183   CefRefPtr<CefRequest> request() const { return request_.get(); }
client() const184   CefRefPtr<CefURLRequestClient> client() const { return client_; }
status() const185   CefURLRequest::Status status() const { return status_; }
response() const186   CefRefPtr<CefResponse> response() const { return response_.get(); }
response_was_cached() const187   bool response_was_cached() const { return response_was_cached_; }
188 
CalledOnValidThread()189   inline bool CalledOnValidThread() {
190     return task_runner_->RunsTasksInCurrentSequence();
191   }
192 
193  private:
GetURLLoaderFactoryGetterOnUIThread(CefRefPtr<CefFrame> frame,CefRefPtr<CefRequestContext> request_context,base::WeakPtr<CefBrowserURLRequest::Context> self,scoped_refptr<base::SequencedTaskRunner> task_runner)194   static void GetURLLoaderFactoryGetterOnUIThread(
195       CefRefPtr<CefFrame> frame,
196       CefRefPtr<CefRequestContext> request_context,
197       base::WeakPtr<CefBrowserURLRequest::Context> self,
198       scoped_refptr<base::SequencedTaskRunner> task_runner) {
199     CEF_REQUIRE_UIT();
200 
201     // Get or create the request context and browser context.
202     CefRefPtr<CefRequestContextImpl> request_context_impl =
203         CefRequestContextImpl::GetOrCreateForRequestContext(request_context);
204     CHECK(request_context_impl);
205     CefBrowserContext* cef_browser_context =
206         request_context_impl->GetBrowserContext();
207     CHECK(cef_browser_context);
208     auto browser_context = cef_browser_context->AsBrowserContext();
209     CHECK(browser_context);
210 
211     scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter;
212 
213     // Used to route authentication and certificate callbacks through the
214     // associated StoragePartition instance.
215     mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
216         url_loader_network_observer;
217 
218     if (frame) {
219       // The request will be associated with this frame/browser if it's valid,
220       // otherwise the request will be canceled.
221       content::RenderFrameHost* rfh =
222           static_cast<CefFrameHostImpl*>(frame.get())->GetRenderFrameHost();
223       if (rfh) {
224         loader_factory_getter =
225             net_service::URLLoaderFactoryGetter::Create(rfh, browser_context);
226         url_loader_network_observer =
227             static_cast<content::RenderFrameHostImpl*>(rfh)
228                 ->CreateURLLoaderNetworkObserver();
229       }
230     } else {
231       loader_factory_getter =
232           net_service::URLLoaderFactoryGetter::Create(nullptr, browser_context);
233       url_loader_network_observer =
234           static_cast<content::StoragePartitionImpl*>(
235               browser_context->GetDefaultStoragePartition())
236               ->CreateAuthCertObserverForServiceWorker();
237     }
238 
239     task_runner->PostTask(
240         FROM_HERE,
241         base::BindOnce(
242             &CefBrowserURLRequest::Context::ContinueOnOriginatingThread, self,
243             MakeRequestID(), loader_factory_getter,
244             std::move(url_loader_network_observer)));
245   }
246 
ContinueOnOriginatingThread(int32_t request_id,scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter,mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver> url_loader_network_observer)247   void ContinueOnOriginatingThread(
248       int32_t request_id,
249       scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter,
250       mojo::PendingRemote<network::mojom::URLLoaderNetworkServiceObserver>
251           url_loader_network_observer) {
252     DCHECK(CalledOnValidThread());
253 
254     // The request may have been canceled.
255     if (!url_request_)
256       return;
257 
258     if (!loader_factory_getter) {
259       // Cancel the request immediately.
260       Cancel();
261       return;
262     }
263 
264     DCHECK_EQ(status_, UR_IO_PENDING);
265 
266     loader_factory_getter_ = loader_factory_getter;
267 
268     const int request_flags = request_->GetFlags();
269 
270     // Create the URLLoaderFactory and bind to this thread.
271     auto loader_factory = loader_factory_getter_->GetURLLoaderFactory();
272 
273     auto resource_request = std::make_unique<network::ResourceRequest>();
274     static_cast<CefRequestImpl*>(request_.get())
275         ->Get(resource_request.get(), false);
276 
277     // Behave the same as a subresource load.
278     resource_request->resource_type =
279         static_cast<int>(blink::mojom::ResourceType::kSubResource);
280 
281     // Set the origin to match the request.
282     const GURL& url = GURL(request_->GetURL().ToString());
283     resource_request->request_initiator = url::Origin::Create(url);
284 
285     if (request_flags & UR_FLAG_ALLOW_STORED_CREDENTIALS) {
286       // Include SameSite cookies.
287       resource_request->site_for_cookies =
288           net::SiteForCookies::FromOrigin(*resource_request->request_initiator);
289     }
290 
291     if (url_loader_network_observer) {
292       resource_request->trusted_params =
293           network::ResourceRequest::TrustedParams();
294       resource_request->trusted_params->url_loader_network_observer =
295           std::move(url_loader_network_observer);
296     }
297 
298     // SimpleURLLoader is picky about the body contents. Try to populate them
299     // correctly below.
300     auto request_body = resource_request->request_body;
301     resource_request->request_body = nullptr;
302 
303     std::string content_type;
304     std::string method = resource_request->method;
305     if (request_body) {
306       if (method == "GET" || method == "HEAD") {
307         // Fix the method value to allow a request body.
308         method = "POST";
309         resource_request->method = method;
310 
311         request_->SetReadOnly(false);
312         request_->SetMethod(method);
313         request_->SetReadOnly(true);
314       }
315       resource_request->headers.GetHeader(net::HttpRequestHeaders::kContentType,
316                                           &content_type);
317     }
318 
319     loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
320                                                MISSING_TRAFFIC_ANNOTATION);
321 
322     // Associate the request with |request_id|.
323     request_id_ = request_id;
324     loader_->SetRequestID(request_id);
325     g_manager.Get().Add(request_id, url_request_, client_);
326 
327     if (request_body) {
328       if (request_body->elements()->size() == 1) {
329         const auto& element = (*request_body->elements())[0];
330         if (element.type() == network::DataElement::Tag::kFile) {
331           const auto& file_element = element.As<network::DataElementFile>();
332           if (content_type.empty()) {
333             const auto& extension = file_element.path().Extension();
334             if (!extension.empty()) {
335               // Requests should not block on the disk! On POSIX this goes to
336               // disk. http://code.google.com/p/chromium/issues/detail?id=59849
337               base::ThreadRestrictions::ScopedAllowIO allow_io;
338               // Also remove the leading period.
339               net::GetMimeTypeFromExtension(extension.substr(1), &content_type);
340             }
341           }
342           loader_->AttachFileForUpload(file_element.path(), content_type);
343         } else if (element.type() == network::DataElement::Tag::kBytes) {
344           const auto& bytes_element = element.As<network::DataElementBytes>();
345           const auto& bytes = bytes_element.bytes();
346           if (content_type.empty()) {
347             content_type = net_service::kContentTypeApplicationFormURLEncoded;
348           }
349           loader_->AttachStringForUpload(
350               std::string(bytes_element.AsStringPiece()), content_type);
351 
352           if (request_flags & UR_FLAG_REPORT_UPLOAD_PROGRESS) {
353             // Report the expected upload data size.
354             upload_data_size_ = bytes.size();
355           }
356         } else {
357           NOTIMPLEMENTED() << "Unsupported element type: "
358                            << static_cast<int>(element.type());
359         }
360       } else if (request_body->elements()->size() > 1) {
361         NOTIMPLEMENTED() << "Multi-part form data is not supported";
362       }
363     }
364 
365     // Allow delivery of non-2xx response bodies.
366     loader_->SetAllowHttpErrorResults(true);
367 
368     if (!(request_flags & UR_FLAG_NO_RETRY_ON_5XX)) {
369       // Allow 2 retries on 5xx response or network change.
370       // TODO(network): Consider exposing configuration of max retries and/or
371       // RETRY_ON_NETWORK_CHANGE as a separate flag.
372       loader_->SetRetryOptions(
373           2, network::SimpleURLLoader::RETRY_ON_5XX |
374                  network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
375     }
376 
377     if (request_flags & UR_FLAG_STOP_ON_REDIRECT) {
378       // The request will be canceled in OnRedirect.
379       loader_->SetOnRedirectCallback(
380           base::BindRepeating(&CefBrowserURLRequest::Context::OnRedirect,
381                               weak_ptr_factory_.GetWeakPtr()));
382     }
383 
384     if (request_flags & UR_FLAG_REPORT_UPLOAD_PROGRESS) {
385       loader_->SetOnUploadProgressCallback(
386           base::BindRepeating(&CefBrowserURLRequest::Context::OnUploadProgress,
387                               weak_ptr_factory_.GetWeakPtr()));
388     }
389 
390     if ((request_flags & UR_FLAG_NO_DOWNLOAD_DATA) || method == "HEAD") {
391       loader_->DownloadHeadersOnly(
392           loader_factory.get(),
393           base::BindOnce(&CefBrowserURLRequest::Context::OnHeadersOnly,
394                          weak_ptr_factory_.GetWeakPtr()));
395     } else {
396       loader_->SetOnResponseStartedCallback(
397           base::BindOnce(&CefBrowserURLRequest::Context::OnResponseStarted,
398                          weak_ptr_factory_.GetWeakPtr()));
399       loader_->SetOnDownloadProgressCallback(base::BindRepeating(
400           &CefBrowserURLRequest::Context::OnDownloadProgress,
401           weak_ptr_factory_.GetWeakPtr()));
402 
403       loader_->DownloadAsStream(loader_factory.get(), this);
404     }
405   }
406 
OnHeadersOnly(scoped_refptr<net::HttpResponseHeaders> headers)407   void OnHeadersOnly(scoped_refptr<net::HttpResponseHeaders> headers) {
408     DCHECK(CalledOnValidThread());
409     DCHECK_EQ(status_, UR_IO_PENDING);
410 
411     cleanup_immediately_ = true;
412 
413     if (headers) {
414       response_->SetReadOnly(false);
415       response_->SetResponseHeaders(*headers);
416       response_->SetReadOnly(true);
417 
418       // Match the previous behavior of sending download progress notifications
419       // for UR_FLAG_NO_DOWNLOAD_DATA requests but not HEAD requests.
420       if (request_->GetMethod().ToString() != "HEAD") {
421         download_data_size_ = headers->GetContentLength();
422         OnDownloadProgress(0);
423       }
424 
425       OnComplete(true);
426     } else {
427       OnComplete(false);
428     }
429   }
430 
OnRedirect(const net::RedirectInfo & redirect_info,const network::mojom::URLResponseHead & response_head,std::vector<std::string> * removed_headers)431   void OnRedirect(const net::RedirectInfo& redirect_info,
432                   const network::mojom::URLResponseHead& response_head,
433                   std::vector<std::string>* removed_headers) {
434     DCHECK(CalledOnValidThread());
435     DCHECK_EQ(status_, UR_IO_PENDING);
436 
437     // This method is only called if we intend to stop on redirects.
438     DCHECK(request_->GetFlags() | UR_FLAG_STOP_ON_REDIRECT);
439 
440     response_->SetReadOnly(false);
441     response_->SetURL(redirect_info.new_url.spec());
442     response_->SetResponseHeaders(*response_head.headers);
443     response_->SetReadOnly(true);
444 
445     Cancel();
446   }
447 
OnResponseStarted(const GURL & final_url,const network::mojom::URLResponseHead & response_head)448   void OnResponseStarted(const GURL& final_url,
449                          const network::mojom::URLResponseHead& response_head) {
450     DCHECK(CalledOnValidThread());
451     DCHECK_EQ(status_, UR_IO_PENDING);
452 
453     response_->SetReadOnly(false);
454     response_->SetURL(final_url.spec());
455     response_->SetResponseHeaders(*response_head.headers);
456     response_->SetReadOnly(true);
457 
458     download_data_size_ = response_head.content_length;
459   }
460 
OnUploadProgress(uint64_t position,uint64_t total)461   void OnUploadProgress(uint64_t position, uint64_t total) {
462     DCHECK(CalledOnValidThread());
463     DCHECK_EQ(status_, UR_IO_PENDING);
464 
465     upload_data_size_ = total;
466     if (position == total)
467       got_upload_progress_complete_ = true;
468 
469     client_->OnUploadProgress(url_request_.get(), position, total);
470   }
471 
OnDownloadProgress(uint64_t current)472   void OnDownloadProgress(uint64_t current) {
473     DCHECK(CalledOnValidThread());
474     DCHECK_EQ(status_, UR_IO_PENDING);
475 
476     if (response_->GetStatus() == 0) {
477       // With failed requests this callback may arrive without a proceeding
478       // OnHeadersOnly or OnResponseStarted.
479       return;
480     }
481 
482     NotifyUploadProgressIfNecessary();
483 
484     client_->OnDownloadProgress(url_request_.get(), current,
485                                 download_data_size_);
486   }
487 
NotifyUploadProgressIfNecessary()488   void NotifyUploadProgressIfNecessary() {
489     if (!got_upload_progress_complete_ && upload_data_size_ > 0) {
490       // URLLoader sends upload notifications using a timer and will not send
491       // a notification if the request completes too quickly. We therefore
492       // send the notification here if necessary.
493       client_->OnUploadProgress(url_request_.get(), upload_data_size_,
494                                 upload_data_size_);
495       got_upload_progress_complete_ = true;
496     }
497   }
498 
499   // SimpleURLLoaderStreamConsumer methods:
OnDataReceived(base::StringPiece string_piece,base::OnceClosure resume)500   void OnDataReceived(base::StringPiece string_piece,
501                       base::OnceClosure resume) override {
502     DCHECK(CalledOnValidThread());
503     DCHECK_EQ(status_, UR_IO_PENDING);
504 
505     client_->OnDownloadData(url_request_.get(), string_piece.data(),
506                             string_piece.length());
507     std::move(resume).Run();
508   }
509 
OnComplete(bool success)510   void OnComplete(bool success) override {
511     DCHECK(CalledOnValidThread());
512 
513     // The request may already be complete or canceled.
514     if (!url_request_)
515       return;
516 
517     // Status will be UR_IO_PENDING if we're called when the request is complete
518     // (via SimpleURLLoaderStreamConsumer or OnHeadersOnly). We can only call
519     // these SimpleURLLoader methods if the request is complete.
520     if (status_ == UR_IO_PENDING) {
521       status_ = success ? UR_SUCCESS : UR_FAILED;
522 
523       response_->SetReadOnly(false);
524       response_->SetURL(loader_->GetFinalURL().spec());
525       response_->SetError(static_cast<cef_errorcode_t>(loader_->NetError()));
526       response_->SetReadOnly(true);
527 
528       response_was_cached_ = loader_->LoadedFromCache();
529     }
530 
531     if (success)
532       NotifyUploadProgressIfNecessary();
533 
534     client_->OnRequestComplete(url_request_.get());
535 
536     // When called via SimpleURLLoaderStreamConsumer we need to cleanup
537     // asynchronously. If the load is still pending this will also cancel it.
538     Cleanup();
539   }
540 
OnRetry(base::OnceClosure start_retry)541   void OnRetry(base::OnceClosure start_retry) override {
542     DCHECK(CalledOnValidThread());
543     DCHECK_EQ(status_, UR_IO_PENDING);
544     std::move(start_retry).Run();
545   }
546 
Cleanup()547   void Cleanup() {
548     DCHECK(CalledOnValidThread());
549     DCHECK(url_request_);
550 
551     g_manager.Get().Remove(request_id_);
552 
553     client_ = nullptr;
554     request_context_ = nullptr;
555 
556     // We may be canceled before the loader is created.
557     if (loader_) {
558       // Must delete the loader before the factory.
559       if (cleanup_immediately_) {
560         // Most SimpleURLLoader callbacks let us delete the URLLoader objects
561         // immediately.
562         loader_.reset();
563         loader_factory_getter_ = nullptr;
564       } else {
565         // Delete the URLLoader objects asynchronously on the correct thread.
566         task_runner_->DeleteSoon(FROM_HERE, std::move(loader_));
567         task_runner_->ReleaseSoon(FROM_HERE, std::move(loader_factory_getter_));
568       }
569     }
570 
571     // We may be holding the last reference to |url_request_|, destruction of
572     // which will delete |this|. Use a local variable to keep |url_request_|
573     // alive until this method returns.
574     auto url_request = url_request_;
575     url_request_ = nullptr;
576   }
577 
578   // Members only accessed on the initialization thread.
579   CefRefPtr<CefBrowserURLRequest> url_request_;
580   CefRefPtr<CefFrame> frame_;
581   CefRefPtr<CefRequestImpl> request_;
582   CefRefPtr<CefURLRequestClient> client_;
583   CefRefPtr<CefRequestContext> request_context_;
584   scoped_refptr<base::SequencedTaskRunner> task_runner_;
585 
586   scoped_refptr<net_service::URLLoaderFactoryGetter> loader_factory_getter_;
587   std::unique_ptr<network::SimpleURLLoader> loader_;
588 
589   int32_t request_id_ = 0;
590 
591   CefURLRequest::Status status_ = UR_IO_PENDING;
592   CefRefPtr<CefResponseImpl> response_;
593   bool response_was_cached_ = false;
594   int64 upload_data_size_ = 0;
595   int64 download_data_size_ = -1;
596   bool got_upload_progress_complete_ = false;
597   bool cleanup_immediately_ = false;
598 
599   // Must be the last member.
600   base::WeakPtrFactory<CefBrowserURLRequest::Context> weak_ptr_factory_;
601 };
602 
603 // CefBrowserURLRequest -------------------------------------------------------
604 
605 // static
606 absl::optional<CefBrowserURLRequest::RequestInfo>
FromRequestID(int32_t request_id)607 CefBrowserURLRequest::FromRequestID(int32_t request_id) {
608   if (IsValidRequestID(request_id)) {
609     return g_manager.Get().Get(request_id);
610   }
611   return absl::nullopt;
612 }
613 
614 // static
615 absl::optional<CefBrowserURLRequest::RequestInfo>
FromRequestID(const content::GlobalRequestID & request_id)616 CefBrowserURLRequest::FromRequestID(
617     const content::GlobalRequestID& request_id) {
618   return FromRequestID(request_id.request_id);
619 }
620 
CefBrowserURLRequest(CefRefPtr<CefFrame> frame,CefRefPtr<CefRequest> request,CefRefPtr<CefURLRequestClient> client,CefRefPtr<CefRequestContext> request_context)621 CefBrowserURLRequest::CefBrowserURLRequest(
622     CefRefPtr<CefFrame> frame,
623     CefRefPtr<CefRequest> request,
624     CefRefPtr<CefURLRequestClient> client,
625     CefRefPtr<CefRequestContext> request_context) {
626   context_.reset(new Context(this, frame, request, client, request_context));
627 }
628 
~CefBrowserURLRequest()629 CefBrowserURLRequest::~CefBrowserURLRequest() {}
630 
Start()631 bool CefBrowserURLRequest::Start() {
632   if (!VerifyContext())
633     return false;
634   return context_->Start();
635 }
636 
GetRequest()637 CefRefPtr<CefRequest> CefBrowserURLRequest::GetRequest() {
638   if (!VerifyContext())
639     return nullptr;
640   return context_->request();
641 }
642 
GetClient()643 CefRefPtr<CefURLRequestClient> CefBrowserURLRequest::GetClient() {
644   if (!VerifyContext())
645     return nullptr;
646   return context_->client();
647 }
648 
GetRequestStatus()649 CefURLRequest::Status CefBrowserURLRequest::GetRequestStatus() {
650   if (!VerifyContext())
651     return UR_UNKNOWN;
652   return context_->status();
653 }
654 
GetRequestError()655 CefURLRequest::ErrorCode CefBrowserURLRequest::GetRequestError() {
656   if (!VerifyContext())
657     return ERR_NONE;
658   return context_->response()->GetError();
659 }
660 
GetResponse()661 CefRefPtr<CefResponse> CefBrowserURLRequest::GetResponse() {
662   if (!VerifyContext())
663     return nullptr;
664   return context_->response();
665 }
666 
ResponseWasCached()667 bool CefBrowserURLRequest::ResponseWasCached() {
668   if (!VerifyContext())
669     return false;
670   return context_->response_was_cached();
671 }
672 
Cancel()673 void CefBrowserURLRequest::Cancel() {
674   if (!VerifyContext())
675     return;
676   return context_->Cancel();
677 }
678 
VerifyContext()679 bool CefBrowserURLRequest::VerifyContext() {
680   if (!context_->CalledOnValidThread()) {
681     NOTREACHED() << "called on invalid thread";
682     return false;
683   }
684 
685   return true;
686 }
687