• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "libcef/browser/net_service/resource_handler_wrapper.h"
6 
7 #include "libcef/browser/net_service/proxy_url_loader_factory.h"
8 #include "libcef/browser/thread_util.h"
9 #include "libcef/common/net_service/net_service_util.h"
10 #include "libcef/common/request_impl.h"
11 
12 #include "base/strings/string_number_conversions.h"
13 #include "net/http/http_status_code.h"
14 
15 namespace net_service {
16 
17 namespace {
18 
19 class SkipCallbackWrapper : public CefResourceSkipCallback {
20  public:
SkipCallbackWrapper(InputStream::SkipCallback callback)21   explicit SkipCallbackWrapper(InputStream::SkipCallback callback)
22       : callback_(std::move(callback)),
23         work_thread_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
24 
25   SkipCallbackWrapper(const SkipCallbackWrapper&) = delete;
26   SkipCallbackWrapper& operator=(const SkipCallbackWrapper&) = delete;
27 
~SkipCallbackWrapper()28   ~SkipCallbackWrapper() override {
29     if (!callback_.is_null()) {
30       // Make sure it executes on the correct thread.
31       work_thread_task_runner_->PostTask(
32           FROM_HERE, base::BindOnce(std::move(callback_), net::ERR_FAILED));
33     }
34   }
35 
Continue(int64 bytes_skipped)36   void Continue(int64 bytes_skipped) override {
37     if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
38       work_thread_task_runner_->PostTask(
39           FROM_HERE,
40           base::BindOnce(&SkipCallbackWrapper::Continue, this, bytes_skipped));
41       return;
42     }
43     if (!callback_.is_null()) {
44       std::move(callback_).Run(bytes_skipped);
45     }
46   }
47 
Disconnect()48   void Disconnect() { callback_.Reset(); }
49 
50  private:
51   InputStream::SkipCallback callback_;
52 
53   scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
54 
55   IMPLEMENT_REFCOUNTING(SkipCallbackWrapper);
56 };
57 
58 class ReadCallbackWrapper : public CefResourceReadCallback {
59  public:
ReadCallbackWrapper(InputStream::ReadCallback callback)60   explicit ReadCallbackWrapper(InputStream::ReadCallback callback)
61       : callback_(std::move(callback)),
62         work_thread_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
63 
64   ReadCallbackWrapper(const ReadCallbackWrapper&) = delete;
65   ReadCallbackWrapper& operator=(const ReadCallbackWrapper&) = delete;
66 
~ReadCallbackWrapper()67   ~ReadCallbackWrapper() override {
68     if (!callback_.is_null()) {
69       // Make sure it executes on the correct thread.
70       work_thread_task_runner_->PostTask(
71           FROM_HERE, base::BindOnce(std::move(callback_), net::ERR_FAILED));
72     }
73   }
74 
Continue(int bytes_read)75   void Continue(int bytes_read) override {
76     if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
77       work_thread_task_runner_->PostTask(
78           FROM_HERE,
79           base::BindOnce(&ReadCallbackWrapper::Continue, this, bytes_read));
80       return;
81     }
82     if (!callback_.is_null()) {
83       std::move(callback_).Run(bytes_read);
84     }
85   }
86 
Disconnect()87   void Disconnect() { callback_.Reset(); }
88 
89  private:
90   InputStream::ReadCallback callback_;
91 
92   scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
93 
94   IMPLEMENT_REFCOUNTING(ReadCallbackWrapper);
95 };
96 
97 // Helper for accessing a CefResourceHandler without creating reference loops.
98 class HandlerProvider : public base::RefCountedThreadSafe<HandlerProvider> {
99  public:
HandlerProvider(CefRefPtr<CefResourceHandler> handler)100   explicit HandlerProvider(CefRefPtr<CefResourceHandler> handler)
101       : handler_(handler) {
102     DCHECK(handler_);
103   }
~HandlerProvider()104   virtual ~HandlerProvider() {
105     // Detach should have been called.
106     DCHECK(!handler_);
107   }
108 
handler() const109   CefRefPtr<CefResourceHandler> handler() const {
110     base::AutoLock lock_scope(lock_);
111     return handler_;
112   }
113 
Detach()114   void Detach() {
115     base::AutoLock lock_scope(lock_);
116     if (!handler_)
117       return;
118 
119     // Execute on the expected thread.
120     CEF_POST_TASK(CEF_IOT,
121                   base::BindOnce(&CefResourceHandler::Cancel, handler_));
122 
123     handler_ = nullptr;
124   }
125 
126  private:
127   mutable base::Lock lock_;
128   CefRefPtr<CefResourceHandler> handler_;
129 };
130 
131 class ReadResponseCallbackWrapper : public CefCallback {
132  public:
133   ReadResponseCallbackWrapper(const ReadResponseCallbackWrapper&) = delete;
134   ReadResponseCallbackWrapper& operator=(const ReadResponseCallbackWrapper&) =
135       delete;
136 
~ReadResponseCallbackWrapper()137   ~ReadResponseCallbackWrapper() override {
138     if (callback_) {
139       // This will post to the correct thread if necessary.
140       callback_->Continue(net::ERR_FAILED);
141     }
142   }
143 
Continue()144   void Continue() override {
145     CEF_POST_TASK(CEF_IOT,
146                   base::BindOnce(&ReadResponseCallbackWrapper::DoRead, this));
147   }
148 
Cancel()149   void Cancel() override {
150     CEF_POST_TASK(CEF_IOT,
151                   base::BindOnce(&ReadResponseCallbackWrapper::DoCancel, this));
152   }
153 
ReadResponse(scoped_refptr<HandlerProvider> handler_provider,net::IOBuffer * dest,int length,CefRefPtr<ReadCallbackWrapper> callback)154   static void ReadResponse(scoped_refptr<HandlerProvider> handler_provider,
155                            net::IOBuffer* dest,
156                            int length,
157                            CefRefPtr<ReadCallbackWrapper> callback) {
158     CEF_POST_TASK(
159         CEF_IOT,
160         base::BindOnce(ReadResponseCallbackWrapper::ReadResponseOnIOThread,
161                        handler_provider, base::Unretained(dest), length,
162                        callback));
163   }
164 
165  private:
ReadResponseCallbackWrapper(scoped_refptr<HandlerProvider> handler_provider,net::IOBuffer * dest,int length,CefRefPtr<ReadCallbackWrapper> callback)166   ReadResponseCallbackWrapper(scoped_refptr<HandlerProvider> handler_provider,
167                               net::IOBuffer* dest,
168                               int length,
169                               CefRefPtr<ReadCallbackWrapper> callback)
170       : handler_provider_(handler_provider),
171         dest_(dest),
172         length_(length),
173         callback_(callback) {}
174 
ReadResponseOnIOThread(scoped_refptr<HandlerProvider> handler_provider,net::IOBuffer * dest,int length,CefRefPtr<ReadCallbackWrapper> callback)175   static void ReadResponseOnIOThread(
176       scoped_refptr<HandlerProvider> handler_provider,
177       net::IOBuffer* dest,
178       int length,
179       CefRefPtr<ReadCallbackWrapper> callback) {
180     CEF_REQUIRE_IOT();
181     CefRefPtr<ReadResponseCallbackWrapper> callbackWrapper =
182         new ReadResponseCallbackWrapper(handler_provider, dest, length,
183                                         callback);
184     callbackWrapper->DoRead();
185   }
186 
DoRead()187   void DoRead() {
188     CEF_REQUIRE_IOT();
189     if (!callback_)
190       return;
191 
192     auto handler = handler_provider_->handler();
193     if (!handler) {
194       DoCancel();
195       return;
196     }
197 
198     int bytes_read = 0;
199     bool result =
200         handler->ReadResponse(dest_->data(), length_, bytes_read, this);
201     if (result) {
202       if (bytes_read > 0) {
203         // Continue immediately.
204         callback_->Continue(bytes_read);
205         callback_ = nullptr;
206       }
207       return;
208     }
209 
210     // Signal response completion immediately.
211     callback_->Continue(0);
212     callback_ = nullptr;
213   }
214 
DoCancel()215   void DoCancel() {
216     CEF_REQUIRE_IOT();
217     if (callback_) {
218       callback_->Continue(net::ERR_FAILED);
219       callback_ = nullptr;
220     }
221   }
222 
223   scoped_refptr<HandlerProvider> handler_provider_;
224   net::IOBuffer* const dest_;
225   int length_;
226   CefRefPtr<ReadCallbackWrapper> callback_;
227 
228   IMPLEMENT_REFCOUNTING(ReadResponseCallbackWrapper);
229 };
230 
231 class InputStreamWrapper : public InputStream {
232  public:
InputStreamWrapper(scoped_refptr<HandlerProvider> handler_provider)233   explicit InputStreamWrapper(scoped_refptr<HandlerProvider> handler_provider)
234       : handler_provider_(handler_provider) {}
235 
236   InputStreamWrapper(const InputStreamWrapper&) = delete;
237   InputStreamWrapper& operator=(const InputStreamWrapper&) = delete;
238 
~InputStreamWrapper()239   ~InputStreamWrapper() override { Cancel(); }
240 
241   // InputStream methods:
Skip(int64_t n,int64_t * bytes_skipped,SkipCallback callback)242   bool Skip(int64_t n, int64_t* bytes_skipped, SkipCallback callback) override {
243     auto handler = handler_provider_->handler();
244     if (!handler) {
245       // Cancel immediately.
246       *bytes_skipped = net::ERR_FAILED;
247       return false;
248     }
249 
250     CefRefPtr<SkipCallbackWrapper> callbackWrapper =
251         new SkipCallbackWrapper(std::move(callback));
252     bool result = handler->Skip(n, *bytes_skipped, callbackWrapper.get());
253     if (result) {
254       if (*bytes_skipped > 0) {
255         // Continue immediately.
256         callbackWrapper->Disconnect();
257       }
258       return true;
259     }
260 
261     // Cancel immediately.
262     return false;
263   }
264 
Read(net::IOBuffer * dest,int length,int * bytes_read,ReadCallback callback)265   bool Read(net::IOBuffer* dest,
266             int length,
267             int* bytes_read,
268             ReadCallback callback) override {
269     auto handler = handler_provider_->handler();
270     if (!handler) {
271       // Cancel immediately.
272       *bytes_read = net::ERR_FAILED;
273       return false;
274     }
275 
276     CefRefPtr<ReadCallbackWrapper> callbackWrapper =
277         new ReadCallbackWrapper(std::move(callback));
278     bool result =
279         handler->Read(dest->data(), length, *bytes_read, callbackWrapper.get());
280     if (result) {
281       if (*bytes_read > 0) {
282         // Continue immediately.
283         callbackWrapper->Disconnect();
284       }
285       return true;
286     }
287 
288     if (*bytes_read == -1) {
289       // Call ReadResponse on the IO thread.
290       ReadResponseCallbackWrapper::ReadResponse(handler_provider_, dest, length,
291                                                 callbackWrapper);
292       *bytes_read = 0;
293       return true;
294     }
295 
296     // Complete or cancel immediately.
297     return false;
298   }
299 
Cancel()300   void Cancel() {
301     // Triggers a call to Cancel on the handler.
302     handler_provider_->Detach();
303   }
304 
305  private:
306   scoped_refptr<HandlerProvider> handler_provider_;
307 };
308 
309 class OpenCallbackWrapper : public CefCallback {
310  public:
OpenCallbackWrapper(ResourceResponse::OpenCallback callback,std::unique_ptr<InputStreamWrapper> stream)311   OpenCallbackWrapper(ResourceResponse::OpenCallback callback,
312                       std::unique_ptr<InputStreamWrapper> stream)
313       : callback_(std::move(callback)),
314         stream_(std::move(stream)),
315         work_thread_task_runner_(base::SequencedTaskRunnerHandle::Get()) {}
316 
317   OpenCallbackWrapper(const OpenCallbackWrapper&) = delete;
318   OpenCallbackWrapper& operator=(const OpenCallbackWrapper&) = delete;
319 
~OpenCallbackWrapper()320   ~OpenCallbackWrapper() override {
321     if (!callback_.is_null()) {
322       // Make sure it executes on the correct thread.
323       work_thread_task_runner_->PostTask(
324           FROM_HERE,
325           base::BindOnce(&OpenCallbackWrapper::Execute, std::move(callback_),
326                          std::move(stream_), false));
327     }
328   }
329 
Continue()330   void Continue() override {
331     if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
332       work_thread_task_runner_->PostTask(
333           FROM_HERE, base::BindOnce(&OpenCallbackWrapper::Continue, this));
334       return;
335     }
336     if (!callback_.is_null()) {
337       Execute(std::move(callback_), std::move(stream_), true);
338     }
339   }
340 
Cancel()341   void Cancel() override {
342     if (!work_thread_task_runner_->RunsTasksInCurrentSequence()) {
343       work_thread_task_runner_->PostTask(
344           FROM_HERE, base::BindOnce(&OpenCallbackWrapper::Cancel, this));
345       return;
346     }
347     if (!callback_.is_null()) {
348       Execute(std::move(callback_), std::move(stream_), false);
349     }
350   }
351 
352  private:
Execute(ResourceResponse::OpenCallback callback,std::unique_ptr<InputStreamWrapper> stream,bool cont)353   static void Execute(ResourceResponse::OpenCallback callback,
354                       std::unique_ptr<InputStreamWrapper> stream,
355                       bool cont) {
356     std::move(callback).Run(cont ? std::move(stream) : nullptr);
357   }
358 
359   ResourceResponse::OpenCallback callback_;
360   std::unique_ptr<InputStreamWrapper> stream_;
361 
362   scoped_refptr<base::SequencedTaskRunner> work_thread_task_runner_;
363 
364   IMPLEMENT_REFCOUNTING(OpenCallbackWrapper);
365 };
366 
CallProcessRequestOnIOThread(scoped_refptr<HandlerProvider> handler_provider,CefRefPtr<CefRequestImpl> request,CefRefPtr<OpenCallbackWrapper> callbackWrapper)367 void CallProcessRequestOnIOThread(
368     scoped_refptr<HandlerProvider> handler_provider,
369     CefRefPtr<CefRequestImpl> request,
370     CefRefPtr<OpenCallbackWrapper> callbackWrapper) {
371   CEF_REQUIRE_IOT();
372   auto handler = handler_provider->handler();
373   if (!handler) {
374     callbackWrapper->Cancel();
375     return;
376   }
377 
378   if (!handler->ProcessRequest(request.get(), callbackWrapper.get())) {
379     callbackWrapper->Cancel();
380   }
381 }
382 
383 class ResourceResponseWrapper : public ResourceResponse {
384  public:
ResourceResponseWrapper(const int32_t request_id,CefRefPtr<CefResourceHandler> handler)385   ResourceResponseWrapper(const int32_t request_id,
386                           CefRefPtr<CefResourceHandler> handler)
387       : request_id_(request_id),
388         handler_provider_(new HandlerProvider(handler)) {}
389 
390   ResourceResponseWrapper(const ResourceResponseWrapper&) = delete;
391   ResourceResponseWrapper& operator=(const ResourceResponseWrapper&) = delete;
392 
~ResourceResponseWrapper()393   ~ResourceResponseWrapper() override {
394     // Triggers a call to Cancel on the handler.
395     handler_provider_->Detach();
396   }
397 
398   // ResourceResponse methods:
OpenInputStream(int32_t request_id,const network::ResourceRequest & request,OpenCallback callback)399   bool OpenInputStream(int32_t request_id,
400                        const network::ResourceRequest& request,
401                        OpenCallback callback) override {
402     DCHECK_EQ(request_id, request_id_);
403 
404     auto handler = handler_provider_->handler();
405     if (!handler) {
406       // Cancel immediately.
407       return false;
408     }
409 
410     // May be recreated on redirect.
411     request_ = new CefRequestImpl();
412     request_->Set(&request, request_id);
413     request_->SetReadOnly(true);
414 
415     CefRefPtr<OpenCallbackWrapper> callbackWrapper = new OpenCallbackWrapper(
416         std::move(callback),
417         std::make_unique<InputStreamWrapper>(handler_provider_));
418     bool handle_request = false;
419     bool result =
420         handler->Open(request_.get(), handle_request, callbackWrapper.get());
421     if (result) {
422       if (handle_request) {
423         // Continue immediately.
424         callbackWrapper->Continue();
425       }
426       return true;
427     }
428 
429     if (handle_request) {
430       // Cancel immediately.
431       callbackWrapper->Cancel();
432       return true;
433     }
434 
435     // Call ProcessRequest on the IO thread.
436     CEF_POST_TASK(
437         CEF_IOT, base::BindOnce(CallProcessRequestOnIOThread, handler_provider_,
438                                 request_, callbackWrapper));
439     return true;
440   }
441 
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)442   void GetResponseHeaders(int32_t request_id,
443                           int* status_code,
444                           std::string* reason_phrase,
445                           std::string* mime_type,
446                           std::string* charset,
447                           int64_t* content_length,
448                           HeaderMap* extra_headers) override {
449     DCHECK_EQ(request_id, request_id_);
450     CEF_REQUIRE_IOT();
451 
452     auto handler = handler_provider_->handler();
453     if (!handler) {
454       // Cancel immediately.
455       *status_code = net::ERR_FAILED;
456       return;
457     }
458 
459     CefRefPtr<CefResponse> response = CefResponse::Create();
460     int64_t response_length = -1;
461     CefString redirect_url;
462     handler->GetResponseHeaders(response, response_length, redirect_url);
463 
464     const auto error_code = response->GetError();
465     if (error_code != ERR_NONE) {
466       // Early exit if the handler reported an error.
467       *status_code = error_code;
468       return;
469     }
470 
471     if (!redirect_url.empty()) {
472       // Perform a redirect.
473       *status_code = net::HTTP_TEMPORARY_REDIRECT;
474       *reason_phrase = std::string();
475       extra_headers->insert(
476           std::make_pair(kHTTPLocationHeaderName, redirect_url));
477     } else {
478       *status_code = response->GetStatus();
479       *reason_phrase = response->GetStatusText();
480     }
481 
482     if (reason_phrase->empty() && *status_code > 0) {
483       *reason_phrase = net::GetHttpReasonPhrase(
484           static_cast<net::HttpStatusCode>(*status_code));
485     }
486 
487     *mime_type = response->GetMimeType();
488     *charset = response->GetCharset();
489 
490     // A |content_length| value may already be specified if the request included
491     // a Range header.
492     if (response_length >= 0 && *content_length == -1)
493       *content_length = response_length;
494 
495     CefResponse::HeaderMap headerMap;
496     response->GetHeaderMap(headerMap);
497     for (const auto& value : headerMap) {
498       extra_headers->insert(std::make_pair(value.first, value.second));
499     }
500   }
501 
502  private:
503   const int32_t request_id_;
504 
505   CefRefPtr<CefRequestImpl> request_;
506   scoped_refptr<HandlerProvider> handler_provider_;
507 };
508 
509 }  // namespace
510 
CreateResourceResponse(int32_t request_id,CefRefPtr<CefResourceHandler> handler)511 std::unique_ptr<ResourceResponse> CreateResourceResponse(
512     int32_t request_id,
513     CefRefPtr<CefResourceHandler> handler) {
514   return std::make_unique<ResourceResponseWrapper>(request_id, handler);
515 }
516 
517 }  // namespace net_service
518