• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015 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 "tests/cefclient/browser/urlrequest_test.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "include/base/cef_callback.h"
11 #include "include/base/cef_logging.h"
12 #include "include/cef_urlrequest.h"
13 #include "include/wrapper/cef_helpers.h"
14 #include "tests/cefclient/browser/test_runner.h"
15 
16 namespace client {
17 namespace urlrequest_test {
18 
19 namespace {
20 
21 const char kTestUrlPath[] = "/urlrequest";
22 const char kTestMessageName[] = "URLRequestTest";
23 
24 // Implementation of CefURLRequestClient that stores response information. Only
25 // accessed on the UI thread.
26 class RequestClient : public CefURLRequestClient {
27  public:
28   // Callback to be executed on request completion.
29   using Callback =
30       base::OnceCallback<void(CefURLRequest::ErrorCode /*error_code*/,
31                               const std::string& /*download_data*/)>;
32 
RequestClient(Callback callback)33   explicit RequestClient(Callback callback) : callback_(std::move(callback)) {
34     CEF_REQUIRE_UI_THREAD();
35     DCHECK(!callback_.is_null());
36   }
37 
Detach()38   void Detach() {
39     CEF_REQUIRE_UI_THREAD();
40     if (!callback_.is_null())
41       callback_.Reset();
42   }
43 
OnRequestComplete(CefRefPtr<CefURLRequest> request)44   void OnRequestComplete(CefRefPtr<CefURLRequest> request) override {
45     CEF_REQUIRE_UI_THREAD();
46     if (!callback_.is_null()) {
47       std::move(callback_).Run(request->GetRequestError(), download_data_);
48     }
49   }
50 
OnUploadProgress(CefRefPtr<CefURLRequest> request,int64 current,int64 total)51   void OnUploadProgress(CefRefPtr<CefURLRequest> request,
52                         int64 current,
53                         int64 total) override {}
54 
OnDownloadProgress(CefRefPtr<CefURLRequest> request,int64 current,int64 total)55   void OnDownloadProgress(CefRefPtr<CefURLRequest> request,
56                           int64 current,
57                           int64 total) override {}
58 
OnDownloadData(CefRefPtr<CefURLRequest> request,const void * data,size_t data_length)59   void OnDownloadData(CefRefPtr<CefURLRequest> request,
60                       const void* data,
61                       size_t data_length) override {
62     CEF_REQUIRE_UI_THREAD();
63     download_data_ += std::string(static_cast<const char*>(data), data_length);
64   }
65 
GetAuthCredentials(bool isProxy,const CefString & host,int port,const CefString & realm,const CefString & scheme,CefRefPtr<CefAuthCallback> callback)66   bool GetAuthCredentials(bool isProxy,
67                           const CefString& host,
68                           int port,
69                           const CefString& realm,
70                           const CefString& scheme,
71                           CefRefPtr<CefAuthCallback> callback) override {
72     return false;
73   }
74 
75  private:
76   Callback callback_;
77   std::string download_data_;
78 
79   IMPLEMENT_REFCOUNTING(RequestClient);
80   DISALLOW_COPY_AND_ASSIGN(RequestClient);
81 };
82 
83 // Handle messages in the browser process. Only accessed on the UI thread.
84 class Handler : public CefMessageRouterBrowserSide::Handler {
85  public:
Handler()86   Handler() { CEF_REQUIRE_UI_THREAD(); }
87 
~Handler()88   ~Handler() { CancelPendingRequest(); }
89 
90   // Called due to cefQuery execution in urlrequest.html.
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)91   bool OnQuery(CefRefPtr<CefBrowser> browser,
92                CefRefPtr<CefFrame> frame,
93                int64 query_id,
94                const CefString& request,
95                bool persistent,
96                CefRefPtr<Callback> callback) override {
97     CEF_REQUIRE_UI_THREAD();
98 
99     // Only handle messages from the test URL.
100     const std::string& url = frame->GetURL();
101     if (!test_runner::IsTestURL(url, kTestUrlPath))
102       return false;
103 
104     const std::string& message_name = request;
105     if (message_name.find(kTestMessageName) == 0) {
106       const std::string& load_url =
107           message_name.substr(sizeof(kTestMessageName));
108 
109       CancelPendingRequest();
110 
111       DCHECK(!callback_.get());
112       DCHECK(!urlrequest_.get());
113 
114       callback_ = callback;
115 
116       // Create a CefRequest for the specified URL.
117       CefRefPtr<CefRequest> cef_request = CefRequest::Create();
118       cef_request->SetURL(load_url);
119       cef_request->SetMethod("GET");
120 
121       // Callback to be executed on request completion.
122       // It's safe to use base::Unretained() here because there is only one
123       // RequestClient pending at any given time and we explicitly detach the
124       // callback in the Handler destructor.
125       auto request_callback =
126           base::BindOnce(&Handler::OnRequestComplete, base::Unretained(this));
127 
128       // Create and start a new CefURLRequest associated with the frame, so
129       // that it shares authentication with ClientHandler::GetAuthCredentials.
130       urlrequest_ = frame->CreateURLRequest(
131           cef_request, new RequestClient(std::move(request_callback)));
132 
133       return true;
134     }
135 
136     return false;
137   }
138 
139  private:
140   // Cancel the currently pending URL request, if any.
CancelPendingRequest()141   void CancelPendingRequest() {
142     CEF_REQUIRE_UI_THREAD();
143 
144     if (urlrequest_.get()) {
145       // Don't execute the callback when we explicitly cancel the request.
146       static_cast<RequestClient*>(urlrequest_->GetClient().get())->Detach();
147 
148       urlrequest_->Cancel();
149       urlrequest_ = nullptr;
150     }
151 
152     if (callback_.get()) {
153       // Must always execute |callback_| before deleting it.
154       callback_->Failure(ERR_ABORTED, test_runner::GetErrorString(ERR_ABORTED));
155       callback_ = nullptr;
156     }
157   }
158 
OnRequestComplete(CefURLRequest::ErrorCode error_code,const std::string & download_data)159   void OnRequestComplete(CefURLRequest::ErrorCode error_code,
160                          const std::string& download_data) {
161     CEF_REQUIRE_UI_THREAD();
162 
163     if (error_code == ERR_NONE)
164       callback_->Success(download_data);
165     else
166       callback_->Failure(error_code, test_runner::GetErrorString(error_code));
167 
168     callback_ = nullptr;
169     urlrequest_ = nullptr;
170   }
171 
172   CefRefPtr<Callback> callback_;
173   CefRefPtr<CefURLRequest> urlrequest_;
174 
175   DISALLOW_COPY_AND_ASSIGN(Handler);
176 };
177 
178 }  // namespace
179 
CreateMessageHandlers(test_runner::MessageHandlerSet & handlers)180 void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) {
181   handlers.insert(new Handler());
182 }
183 
184 }  // namespace urlrequest_test
185 }  // namespace client
186