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