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