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