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