// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include "tests/cefclient/browser/urlrequest_test.h" #include #include "include/base/cef_bind.h" #include "include/base/cef_callback.h" #include "include/base/cef_logging.h" #include "include/cef_urlrequest.h" #include "include/wrapper/cef_helpers.h" namespace client { namespace urlrequest_test { namespace { const char kTestUrl[] = "http://tests/urlrequest"; const char kTestMessageName[] = "URLRequestTest"; // Implementation of CefURLRequestClient that stores response information. Only // accessed on the UI thread. class RequestClient : public CefURLRequestClient { public: // Callback to be executed on request completion. typedef base::Callback Callback; explicit RequestClient(const Callback& callback) : callback_(callback) { CEF_REQUIRE_UI_THREAD(); DCHECK(!callback_.is_null()); } void Detach() { CEF_REQUIRE_UI_THREAD(); if (!callback_.is_null()) callback_.Reset(); } void OnRequestComplete(CefRefPtr request) OVERRIDE { CEF_REQUIRE_UI_THREAD(); if (!callback_.is_null()) { callback_.Run(request->GetRequestError(), download_data_); callback_.Reset(); } } void OnUploadProgress(CefRefPtr request, int64 current, int64 total) OVERRIDE {} void OnDownloadProgress(CefRefPtr request, int64 current, int64 total) OVERRIDE {} void OnDownloadData(CefRefPtr request, const void* data, size_t data_length) OVERRIDE { CEF_REQUIRE_UI_THREAD(); download_data_ += std::string(static_cast(data), data_length); } bool GetAuthCredentials(bool isProxy, const CefString& host, int port, const CefString& realm, const CefString& scheme, CefRefPtr callback) OVERRIDE { return false; } private: Callback callback_; std::string download_data_; IMPLEMENT_REFCOUNTING(RequestClient); DISALLOW_COPY_AND_ASSIGN(RequestClient); }; // Handle messages in the browser process. Only accessed on the UI thread. class Handler : public CefMessageRouterBrowserSide::Handler { public: Handler() { CEF_REQUIRE_UI_THREAD(); } ~Handler() { CancelPendingRequest(); } // Called due to cefQuery execution in urlrequest.html. bool OnQuery(CefRefPtr browser, CefRefPtr frame, int64 query_id, const CefString& request, bool persistent, CefRefPtr callback) OVERRIDE { CEF_REQUIRE_UI_THREAD(); // Only handle messages from the test URL. std::string url = frame->GetURL(); if (url.find(kTestUrl) != 0) return false; const std::string& message_name = request; if (message_name.find(kTestMessageName) == 0) { url = message_name.substr(sizeof(kTestMessageName)); CancelPendingRequest(); DCHECK(!callback_.get()); DCHECK(!urlrequest_.get()); callback_ = callback; // Create a CefRequest for the specified URL. CefRefPtr cef_request = CefRequest::Create(); cef_request->SetURL(url); cef_request->SetMethod("GET"); // Callback to be executed on request completion. // It's safe to use base::Unretained() here because there is only one // RequestClient pending at any given time and we explicitly detach the // callback in the Handler destructor. const RequestClient::Callback& request_callback = base::Bind(&Handler::OnRequestComplete, base::Unretained(this)); // Create and start the new CefURLRequest. urlrequest_ = CefURLRequest::Create( cef_request, new RequestClient(request_callback), NULL); return true; } return false; } private: // Cancel the currently pending URL request, if any. void CancelPendingRequest() { CEF_REQUIRE_UI_THREAD(); if (urlrequest_.get()) { // Don't execute the callback when we explicitly cancel the request. static_cast(urlrequest_->GetClient().get())->Detach(); urlrequest_->Cancel(); urlrequest_ = NULL; } if (callback_.get()) { // Must always execute |callback_| before deleting it. callback_->Failure(ERR_ABORTED, test_runner::GetErrorString(ERR_ABORTED)); callback_ = NULL; } } void OnRequestComplete(CefURLRequest::ErrorCode error_code, const std::string& download_data) { CEF_REQUIRE_UI_THREAD(); if (error_code == ERR_NONE) callback_->Success(download_data); else callback_->Failure(error_code, test_runner::GetErrorString(error_code)); callback_ = NULL; urlrequest_ = NULL; } CefRefPtr callback_; CefRefPtr urlrequest_; DISALLOW_COPY_AND_ASSIGN(Handler); }; } // namespace void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) { handlers.insert(new Handler()); } } // namespace urlrequest_test } // namespace client