diff --git a/include/wrapper/cef_stream_resource_handler.h b/include/wrapper/cef_stream_resource_handler.h index 8e549ddf2..130e20b88 100644 --- a/include/wrapper/cef_stream_resource_handler.h +++ b/include/wrapper/cef_stream_resource_handler.h @@ -37,14 +37,10 @@ #define CEF_INCLUDE_WRAPPER_CEF_STREAM_RESOURCE_HANDLER_H_ #pragma once -#include "include/base/cef_logging.h" #include "include/base/cef_macros.h" -#include "include/base/cef_scoped_ptr.h" -#include "include/cef_base.h" #include "include/cef_resource_handler.h" #include "include/cef_response.h" - -class CefStreamReader; +#include "include/cef_stream.h" /// // Implementation of the CefResourceHandler class for reading from a CefStream. @@ -65,37 +61,25 @@ class CefStreamResourceHandler : public CefResourceHandler { CefResponse::HeaderMap header_map, CefRefPtr stream); - virtual ~CefStreamResourceHandler(); - // CefResourceHandler methods. - virtual bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) OVERRIDE; - virtual void GetResponseHeaders(CefRefPtr response, - int64& response_length, - CefString& redirectUrl) OVERRIDE; - virtual bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) OVERRIDE; - virtual void Cancel() OVERRIDE; + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) OVERRIDE; + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) OVERRIDE; + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) OVERRIDE; + void Cancel() OVERRIDE; private: - void ReadOnFileThread(int bytes_to_read, CefRefPtr callback); - const int status_code_; const CefString status_text_; const CefString mime_type_; const CefResponse::HeaderMap header_map_; const CefRefPtr stream_; - bool read_on_file_thread_; - - class Buffer; - scoped_ptr buffer_; -#if DCHECK_IS_ON() - // Used in debug builds to verify that |buffer_| isn't being accessed on - // multiple threads at the same time. - bool buffer_owned_by_file_thread_; -#endif IMPLEMENT_REFCOUNTING(CefStreamResourceHandler); DISALLOW_COPY_AND_ASSIGN(CefStreamResourceHandler); diff --git a/libcef/browser/net/internal_scheme_handler.cc b/libcef/browser/net/internal_scheme_handler.cc index 43363f318..2ee0ec3b6 100644 --- a/libcef/browser/net/internal_scheme_handler.cc +++ b/libcef/browser/net/internal_scheme_handler.cc @@ -52,9 +52,11 @@ class RedirectHandler : public CefResourceHandler { public: explicit RedirectHandler(const GURL& url) : url_(url) {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { - callback->Continue(); + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + // Continue immediately. + handle_request = true; return true; } @@ -65,10 +67,11 @@ class RedirectHandler : public CefResourceHandler { redirectUrl = url_.spec(); } - bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + NOTREACHED(); return false; } @@ -78,6 +81,7 @@ class RedirectHandler : public CefResourceHandler { GURL url_; IMPLEMENT_REFCOUNTING(RedirectHandler); + DISALLOW_COPY_AND_ASSIGN(RedirectHandler); }; class InternalHandler : public CefResourceHandler { @@ -87,9 +91,11 @@ class InternalHandler : public CefResourceHandler { int size) : mime_type_(mime_type), reader_(reader), size_(size) {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { - callback->Continue(); + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + // Continue immediately. + handle_request = true; return true; } @@ -102,11 +108,21 @@ class InternalHandler : public CefResourceHandler { response->SetStatus(200); } - bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { - bytes_read = reader_->Read(data_out, 1, bytes_to_read); + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + // Read until the buffer is full or until Read() returns 0 to indicate no + // more data. + bytes_read = 0; + int read = 0; + do { + read = static_cast( + reader_->Read(static_cast(data_out) + bytes_read, 1, + bytes_to_read - bytes_read)); + bytes_read += read; + } while (read != 0 && bytes_read < bytes_to_read); + return (bytes_read > 0); } @@ -118,6 +134,7 @@ class InternalHandler : public CefResourceHandler { int size_; IMPLEMENT_REFCOUNTING(InternalHandler); + DISALLOW_COPY_AND_ASSIGN(InternalHandler); }; class InternalHandlerFactory : public CefSchemeHandlerFactory { @@ -170,6 +187,7 @@ class InternalHandlerFactory : public CefSchemeHandlerFactory { std::unique_ptr delegate_; IMPLEMENT_REFCOUNTING(InternalHandlerFactory); + DISALLOW_COPY_AND_ASSIGN(InternalHandlerFactory); }; } // namespace diff --git a/libcef_dll/wrapper/cef_stream_resource_handler.cc b/libcef_dll/wrapper/cef_stream_resource_handler.cc index 0362c705e..ad5a34faf 100644 --- a/libcef_dll/wrapper/cef_stream_resource_handler.cc +++ b/libcef_dll/wrapper/cef_stream_resource_handler.cc @@ -6,84 +6,19 @@ #include -#include "include/base/cef_bind.h" #include "include/base/cef_logging.h" -#include "include/base/cef_macros.h" -#include "include/cef_callback.h" -#include "include/cef_request.h" -#include "include/cef_stream.h" -#include "include/wrapper/cef_closure_task.h" +#include "include/cef_task.h" #include "include/wrapper/cef_helpers.h" -// Class that represents a readable/writable character buffer. -class CefStreamResourceHandler::Buffer { - public: - Buffer() : size_(0), bytes_requested_(0), bytes_written_(0), bytes_read_(0) {} - - void Reset(int new_size) { - if (size_ < new_size) { - size_ = new_size; - buffer_.reset(new char[size_]); - DCHECK(buffer_); - } - bytes_requested_ = new_size; - bytes_written_ = 0; - bytes_read_ = 0; - } - - bool IsEmpty() const { return (bytes_written_ == 0); } - - bool CanRead() const { return (bytes_read_ < bytes_written_); } - - int WriteTo(void* data_out, int bytes_to_read) { - const int write_size = - std::min(bytes_to_read, bytes_written_ - bytes_read_); - if (write_size > 0) { - memcpy(data_out, buffer_.get() + bytes_read_, write_size); - bytes_read_ += write_size; - } - return write_size; - } - - int ReadFrom(CefRefPtr reader) { - // Read until the buffer is full or until Read() returns 0 to indicate no - // more data. - int bytes_read; - do { - bytes_read = - static_cast(reader->Read(buffer_.get() + bytes_written_, 1, - bytes_requested_ - bytes_written_)); - bytes_written_ += bytes_read; - } while (bytes_read != 0 && bytes_written_ < bytes_requested_); - - return bytes_written_; - } - - private: - scoped_ptr buffer_; - int size_; - int bytes_requested_; - int bytes_written_; - int bytes_read_; - - DISALLOW_COPY_AND_ASSIGN(Buffer); -}; - CefStreamResourceHandler::CefStreamResourceHandler( const CefString& mime_type, CefRefPtr stream) : status_code_(200), status_text_("OK"), mime_type_(mime_type), - stream_(stream) -#if DCHECK_IS_ON() - , - buffer_owned_by_file_thread_(false) -#endif -{ + stream_(stream) { DCHECK(!mime_type_.empty()); DCHECK(stream_.get()); - read_on_file_thread_ = stream_->MayBlock(); } CefStreamResourceHandler::CefStreamResourceHandler( @@ -96,22 +31,18 @@ CefStreamResourceHandler::CefStreamResourceHandler( status_text_(status_text), mime_type_(mime_type), header_map_(header_map), - stream_(stream) -#if DCHECK_IS_ON() - , - buffer_owned_by_file_thread_(false) -#endif -{ + stream_(stream) { DCHECK(!mime_type_.empty()); DCHECK(stream_.get()); - read_on_file_thread_ = stream_->MayBlock(); } -CefStreamResourceHandler::~CefStreamResourceHandler() {} +bool CefStreamResourceHandler::Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) { + DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO)); -bool CefStreamResourceHandler::ProcessRequest(CefRefPtr request, - CefRefPtr callback) { - callback->Continue(); + // Continue the request immediately. + handle_request = true; return true; } @@ -119,6 +50,8 @@ void CefStreamResourceHandler::GetResponseHeaders( CefRefPtr response, int64& response_length, CefString& redirectUrl) { + CEF_REQUIRE_IO_THREAD(); + response->SetStatus(status_code_); response->SetStatusText(status_text_); response->SetMimeType(mime_type_); @@ -129,70 +62,26 @@ void CefStreamResourceHandler::GetResponseHeaders( response_length = -1; } -bool CefStreamResourceHandler::ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) { +bool CefStreamResourceHandler::Read( + void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) { + DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO)); DCHECK_GT(bytes_to_read, 0); - if (read_on_file_thread_) { -#if DCHECK_IS_ON() - DCHECK(!buffer_owned_by_file_thread_); -#endif - if (buffer_ && (buffer_->CanRead() || buffer_->IsEmpty())) { - if (buffer_->CanRead()) { - // Provide data from the buffer. - bytes_read = buffer_->WriteTo(data_out, bytes_to_read); - return (bytes_read > 0); - } else { - // End of the steam. - bytes_read = 0; - return false; - } - } else { - // Perform another read on the file thread. - bytes_read = 0; -#if DCHECK_IS_ON() - buffer_owned_by_file_thread_ = true; -#endif - CefPostTask(TID_FILE, - base::Bind(&CefStreamResourceHandler::ReadOnFileThread, this, - bytes_to_read, callback)); - return true; - } - } else { - // Read until the buffer is full or until Read() returns 0 to indicate no - // more data. - bytes_read = 0; - int read = 0; - do { - read = static_cast( - stream_->Read(static_cast(data_out) + bytes_read, 1, - bytes_to_read - bytes_read)); - bytes_read += read; - } while (read != 0 && bytes_read < bytes_to_read); + // Read until the buffer is full or until Read() returns 0 to indicate no + // more data. + bytes_read = 0; + int read = 0; + do { + read = static_cast( + stream_->Read(static_cast(data_out) + bytes_read, 1, + bytes_to_read - bytes_read)); + bytes_read += read; + } while (read != 0 && bytes_read < bytes_to_read); - return (bytes_read > 0); - } + return (bytes_read > 0); } void CefStreamResourceHandler::Cancel() {} - -void CefStreamResourceHandler::ReadOnFileThread( - int bytes_to_read, - CefRefPtr callback) { - CEF_REQUIRE_FILE_THREAD(); -#if DCHECK_IS_ON() - DCHECK(buffer_owned_by_file_thread_); -#endif - - if (!buffer_) - buffer_.reset(new Buffer()); - buffer_->Reset(bytes_to_read); - buffer_->ReadFrom(stream_); - -#if DCHECK_IS_ON() - buffer_owned_by_file_thread_ = false; -#endif - callback->Continue(); -} diff --git a/tests/cefclient/browser/scheme_test.cc b/tests/cefclient/browser/scheme_test.cc index 4aab1e5e4..1e9dd12f9 100644 --- a/tests/cefclient/browser/scheme_test.cc +++ b/tests/cefclient/browser/scheme_test.cc @@ -28,9 +28,13 @@ class ClientSchemeHandler : public CefResourceHandler { public: ClientSchemeHandler() : offset_(0) {} - virtual bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) OVERRIDE { - CEF_REQUIRE_IO_THREAD(); + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) OVERRIDE { + DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO)); + + // The request will be continued or canceled based on the return value. + handle_request = true; bool handled = false; @@ -70,18 +74,12 @@ class ClientSchemeHandler : public CefResourceHandler { } } - if (handled) { - // Indicate the headers are available. - callback->Continue(); - return true; - } - - return false; + return handled; } - virtual void GetResponseHeaders(CefRefPtr response, - int64& response_length, - CefString& redirectUrl) OVERRIDE { + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) OVERRIDE { CEF_REQUIRE_IO_THREAD(); DCHECK(!data_.empty()); @@ -93,13 +91,13 @@ class ClientSchemeHandler : public CefResourceHandler { response_length = data_.length(); } - virtual void Cancel() OVERRIDE { CEF_REQUIRE_IO_THREAD(); } + void Cancel() OVERRIDE { CEF_REQUIRE_IO_THREAD(); } - virtual bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) OVERRIDE { - CEF_REQUIRE_IO_THREAD(); + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) OVERRIDE { + DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO)); bool has_data = false; bytes_read = 0; @@ -124,22 +122,25 @@ class ClientSchemeHandler : public CefResourceHandler { size_t offset_; IMPLEMENT_REFCOUNTING(ClientSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler); }; // Implementation of the factory for for creating schema handlers. class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory { public: + ClientSchemeHandlerFactory() {} + // Return a new scheme handler instance to handle the request. - virtual CefRefPtr Create( - CefRefPtr browser, - CefRefPtr frame, - const CefString& scheme_name, - CefRefPtr request) OVERRIDE { + CefRefPtr Create(CefRefPtr browser, + CefRefPtr frame, + const CefString& scheme_name, + CefRefPtr request) OVERRIDE { CEF_REQUIRE_IO_THREAD(); return new ClientSchemeHandler(); } IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory); + DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory); }; } // namespace diff --git a/tests/ceftests/cookie_unittest.cc b/tests/ceftests/cookie_unittest.cc index d7a425ae0..57f33e6a1 100644 --- a/tests/ceftests/cookie_unittest.cc +++ b/tests/ceftests/cookie_unittest.cc @@ -709,8 +709,11 @@ class CookieTestSchemeHandler : public TestHandler { explicit SchemeHandler(CookieTestSchemeHandler* handler) : handler_(handler), offset_(0) {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + std::string url = request->GetURL(); if (url == handler_->url1_) { content_ = "COOKIE TEST1"; @@ -731,7 +734,9 @@ class CookieTestSchemeHandler : public TestHandler { if (it != headerMap.end() && it->second == "name2=value2") handler_->got_process_request_cookie_.yes(); } - callback->Continue(); + + // Continue immediately. + handle_request = true; return true; } @@ -751,10 +756,12 @@ class CookieTestSchemeHandler : public TestHandler { } } - bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + bool has_data = false; bytes_read = 0; @@ -781,6 +788,7 @@ class CookieTestSchemeHandler : public TestHandler { std::string cookie_; IMPLEMENT_REFCOUNTING(SchemeHandler); + DISALLOW_COPY_AND_ASSIGN(SchemeHandler); }; class SchemeHandlerFactory : public CefSchemeHandlerFactory { @@ -810,6 +818,7 @@ class CookieTestSchemeHandler : public TestHandler { CookieTestSchemeHandler* handler_; IMPLEMENT_REFCOUNTING(SchemeHandlerFactory); + DISALLOW_COPY_AND_ASSIGN(SchemeHandlerFactory); }; CookieTestSchemeHandler(const std::string& scheme, @@ -1106,9 +1115,10 @@ class CookieAccessSchemeHandler : public CefResourceHandler { explicit CookieAccessSchemeHandler(CookieAccessData* data) : data_(data), offset_(0) {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { - EXPECT_IO_THREAD(); + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); CefRequest::HeaderMap headerMap; request->GetHeaderMap(headerMap); @@ -1116,7 +1126,7 @@ class CookieAccessSchemeHandler : public CefResourceHandler { TestCookieString(cookie_str, data_->cookie_js_ct_, data_->cookie_net_ct_); // Continue immediately. - callback->Continue(); + handle_request = true; return true; } @@ -1136,11 +1146,11 @@ class CookieAccessSchemeHandler : public CefResourceHandler { response_length = data_->response_data.length(); } - bool ReadResponse(void* response_data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { - EXPECT_IO_THREAD(); + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); bool has_data = false; bytes_read = 0; @@ -1149,8 +1159,7 @@ class CookieAccessSchemeHandler : public CefResourceHandler { if (offset_ < size) { int transfer_size = std::min(bytes_to_read, static_cast(size - offset_)); - memcpy(response_data_out, data_->response_data.c_str() + offset_, - transfer_size); + memcpy(data_out, data_->response_data.c_str() + offset_, transfer_size); offset_ += transfer_size; bytes_read = transfer_size; @@ -1185,6 +1194,7 @@ class CookieAccessSchemeHandler : public CefResourceHandler { size_t offset_; IMPLEMENT_REFCOUNTING(CookieAccessSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(CookieAccessSchemeHandler); }; class CookieAccessSchemeHandlerFactory : public CefSchemeHandlerFactory, diff --git a/tests/ceftests/download_unittest.cc b/tests/ceftests/download_unittest.cc index 5796fc0f2..6408f6fe3 100644 --- a/tests/ceftests/download_unittest.cc +++ b/tests/ceftests/download_unittest.cc @@ -22,7 +22,7 @@ const char kTestContentDisposition[] = const char kTestMimeType[] = "text/plain"; const char kTestContent[] = "Download test text"; -typedef base::Callback /*callback*/)> DelayCallback; +typedef base::Callback DelayCallback; class DownloadSchemeHandler : public CefResourceHandler { public: @@ -33,8 +33,11 @@ class DownloadSchemeHandler : public CefResourceHandler { should_delay_(false), offset_(0) {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + std::string url = request->GetURL(); if (url == kTestDownloadUrl) { got_download_request_->yes(); @@ -44,10 +47,14 @@ class DownloadSchemeHandler : public CefResourceHandler { should_delay_ = true; } else { EXPECT_TRUE(false); // Not reached. + + // Cancel immediately. + handle_request = true; return false; } - callback->Continue(); + // Continue immediately. + handle_request = true; return true; } @@ -68,19 +75,37 @@ class DownloadSchemeHandler : public CefResourceHandler { } } - bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + bytes_read = 0; if (should_delay_ && !delay_callback_.is_null()) { // Delay the download response a single time. - delay_callback_.Run(callback); + delay_callback_.Run(base::Bind(&DownloadSchemeHandler::ContinueRead, this, + data_out, bytes_to_read, callback)); delay_callback_.Reset(); return true; } + return DoRead(data_out, bytes_to_read, bytes_read); + } + + void Cancel() override {} + + private: + void ContinueRead(void* data_out, + int bytes_to_read, + CefRefPtr callback) { + int bytes_read = 0; + DoRead(data_out, bytes_to_read, bytes_read); + callback->Continue(bytes_read); + } + + bool DoRead(void* data_out, int bytes_to_read, int& bytes_read) { bool has_data = false; size_t size = content_.size(); if (offset_ < size) { @@ -96,9 +121,6 @@ class DownloadSchemeHandler : public CefResourceHandler { return has_data; } - void Cancel() override {} - - private: DelayCallback delay_callback_; TrackCallback* got_download_request_; bool should_delay_; @@ -106,8 +128,10 @@ class DownloadSchemeHandler : public CefResourceHandler { std::string mime_type_; std::string content_disposition_; size_t offset_; + CefRefPtr read_callback_; IMPLEMENT_REFCOUNTING(DownloadSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(DownloadSchemeHandler); }; class DownloadSchemeHandlerFactory : public CefSchemeHandlerFactory { @@ -129,6 +153,7 @@ class DownloadSchemeHandlerFactory : public CefSchemeHandlerFactory { TrackCallback* got_download_request_; IMPLEMENT_REFCOUNTING(DownloadSchemeHandlerFactory); + DISALLOW_COPY_AND_ASSIGN(DownloadSchemeHandlerFactory); }; class DownloadTestHandler : public TestHandler { @@ -239,7 +264,7 @@ class DownloadTestHandler : public TestHandler { } // Callback from the scheme handler when the download request is delayed. - void OnDelayCallback(CefRefPtr callback) { + void OnDelayCallback(const base::Closure& callback) { if (!CefCurrentlyOn(TID_UI)) { CefPostTask(TID_UI, base::Bind(&DownloadTestHandler::OnDelayCallback, this, callback)); @@ -261,8 +286,9 @@ class DownloadTestHandler : public TestHandler { void ContinueNavigatedIfReady() { EXPECT_EQ(test_mode_, NAVIGATED); if (got_delay_callback_ && got_nav_load_) { - delay_callback_->Continue(); - delay_callback_ = nullptr; + EXPECT_FALSE(delay_callback_.is_null()); + delay_callback_.Run(); + delay_callback_.Reset(); } } @@ -462,7 +488,7 @@ class DownloadTestHandler : public TestHandler { CefRefPtr request_context_; // Used with NAVIGATED and PENDING test modes. - CefRefPtr delay_callback_; + base::Closure delay_callback_; // Used with PENDING test mode. CefRefPtr download_item_callback_; diff --git a/tests/ceftests/navigation_unittest.cc b/tests/ceftests/navigation_unittest.cc index 36f9b371f..1a09c0c8f 100644 --- a/tests/ceftests/navigation_unittest.cc +++ b/tests/ceftests/navigation_unittest.cc @@ -688,9 +688,10 @@ class RedirectSchemeHandler : public CefResourceHandler { public: RedirectSchemeHandler() : offset_(0), status_(0) {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { - EXPECT_TRUE(CefCurrentlyOn(TID_IO)); + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); std::string url = request->GetURL(); if (url == kRNav1) { @@ -711,13 +712,16 @@ class RedirectSchemeHandler : public CefResourceHandler { content_ = "Nav4"; } + handle_request = true; + if (status_ != 0) { - callback->Continue(); + // Continue request. return true; - } else { - g_got_invalid_request = true; - return false; } + + // Cancel request. + g_got_invalid_request = true; + return false; } void GetResponseHeaders(CefRefPtr response, @@ -748,11 +752,14 @@ class RedirectSchemeHandler : public CefResourceHandler { void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); } - bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { - EXPECT_TRUE(CefCurrentlyOn(TID_IO)); + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + bytes_read = 0; + bool has_data = false; size_t size = content_.size(); if (offset_ < size) { @@ -762,10 +769,10 @@ class RedirectSchemeHandler : public CefResourceHandler { offset_ += transfer_size; bytes_read = transfer_size; - return true; + has_data = true; } - return false; + return has_data; } protected: @@ -775,6 +782,7 @@ class RedirectSchemeHandler : public CefResourceHandler { std::string location_; IMPLEMENT_REFCOUNTING(RedirectSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandler); }; class RedirectSchemeHandlerFactory : public CefSchemeHandlerFactory { @@ -795,6 +803,7 @@ class RedirectSchemeHandlerFactory : public CefSchemeHandlerFactory { } IMPLEMENT_REFCOUNTING(RedirectSchemeHandlerFactory); + DISALLOW_COPY_AND_ASSIGN(RedirectSchemeHandlerFactory); }; class RedirectTestHandler : public TestHandler { @@ -2843,9 +2852,13 @@ class UnstartedSchemeHandler : public CefResourceHandler { public: UnstartedSchemeHandler() {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { - callback->Continue(); + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + // Continue immediately. + handle_request = true; return true; } @@ -2859,10 +2872,12 @@ class UnstartedSchemeHandler : public CefResourceHandler { void Cancel() override { callback_ = nullptr; } - bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + callback_ = callback; // Pretend that we'll provide the data later. @@ -2871,9 +2886,10 @@ class UnstartedSchemeHandler : public CefResourceHandler { } protected: - CefRefPtr callback_; + CefRefPtr callback_; IMPLEMENT_REFCOUNTING(UnstartedSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(UnstartedSchemeHandler); }; // Browser side. @@ -3055,9 +3071,13 @@ class StalledSchemeHandler : public CefResourceHandler { public: StalledSchemeHandler() : offset_(0), write_size_(0) {} - bool ProcessRequest(CefRefPtr request, - CefRefPtr callback) override { - callback->Continue(); + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + // Continue immediately. + handle_request = true; return true; } @@ -3074,18 +3094,23 @@ class StalledSchemeHandler : public CefResourceHandler { void Cancel() override { callback_ = nullptr; } - bool ReadResponse(void* data_out, - int bytes_to_read, - int& bytes_read, - CefRefPtr callback) override { + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + bytes_read = 0; + size_t size = content_.size(); if (offset_ >= write_size_) { // Now stall. - bytes_read = 0; callback_ = callback; return true; } + bool has_data = false; + if (offset_ < size) { // Write up to |write_size_| bytes. int transfer_size = @@ -3095,19 +3120,20 @@ class StalledSchemeHandler : public CefResourceHandler { offset_ += transfer_size; bytes_read = transfer_size; - return true; + has_data = true; } - return false; + return has_data; } protected: std::string content_; size_t offset_; size_t write_size_; - CefRefPtr callback_; + CefRefPtr callback_; IMPLEMENT_REFCOUNTING(StalledSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(StalledSchemeHandler); }; // Browser side. diff --git a/tests/ceftests/resource_request_handler_unittest.cc b/tests/ceftests/resource_request_handler_unittest.cc index ceba5904e..9f21bde17 100644 --- a/tests/ceftests/resource_request_handler_unittest.cc +++ b/tests/ceftests/resource_request_handler_unittest.cc @@ -22,6 +22,7 @@ namespace { // Normal stream resource handler implementation that additionally verifies // calls to Cancel. +// This also tests the CefStreamResourceHandler implementation. class NormalResourceHandler : public CefStreamResourceHandler { public: NormalResourceHandler(int status_code, @@ -50,27 +51,186 @@ class NormalResourceHandler : public CefStreamResourceHandler { private: const base::Closure destroy_callback_; int cancel_ct_ = 0; +}; - DISALLOW_COPY_AND_ASSIGN(NormalResourceHandler); +// Normal stream resource handler implementation that additionally continues +// using the callback object and verifies calls to Cancel. +class CallbackResourceHandler : public CefResourceHandler { + public: + enum Mode { + DELAYED_OPEN, + DELAYED_READ, + IMMEDIATE_OPEN, + IMMEDIATE_READ, + DELAYED_ALL, + IMMEDIATE_ALL, + }; + + bool IsDelayedOpen() const { + return mode_ == DELAYED_OPEN || mode_ == DELAYED_ALL; + } + + bool IsDelayedRead() const { + return mode_ == DELAYED_READ || mode_ == DELAYED_ALL; + } + + bool IsImmediateOpen() const { + return mode_ == IMMEDIATE_OPEN || mode_ == IMMEDIATE_ALL; + } + + bool IsImmediateRead() const { + return mode_ == IMMEDIATE_READ || mode_ == IMMEDIATE_ALL; + } + + CallbackResourceHandler(Mode mode, + int status_code, + const CefString& status_text, + const CefString& mime_type, + CefResponse::HeaderMap header_map, + CefRefPtr stream, + const base::Closure& destroy_callback) + : mode_(mode), + status_code_(status_code), + status_text_(status_text), + mime_type_(mime_type), + header_map_(header_map), + stream_(stream), + destroy_callback_(destroy_callback) { + DCHECK(!mime_type_.empty()); + DCHECK(stream_.get()); + } + + ~CallbackResourceHandler() override { + EXPECT_EQ(1, cancel_ct_); + destroy_callback_.Run(); + } + + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + if (IsDelayedOpen()) { + // Continue the request asynchronously by executing the callback. + CefPostTask(TID_FILE_USER_VISIBLE, + base::Bind(&CefCallback::Continue, callback)); + handle_request = false; + return true; + } else if (IsImmediateOpen()) { + // Continue the request immediately be executing the callback. + callback->Continue(); + handle_request = false; + return true; + } + + // Continue the request immediately in the default manner. + handle_request = true; + return true; + } + + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) override { + response->SetStatus(status_code_); + response->SetStatusText(status_text_); + response->SetMimeType(mime_type_); + + if (!header_map_.empty()) + response->SetHeaderMap(header_map_); + + response_length = -1; + } + + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + EXPECT_GT(bytes_to_read, 0); + + bytes_read = 0; + + if (IsDelayedRead()) { + // Continue the request asynchronously by executing the callback. + CefPostTask(TID_FILE_USER_VISIBLE, + base::Bind(&CallbackResourceHandler::ContinueRead, this, + data_out, bytes_to_read, callback)); + return true; + } else if (IsImmediateRead()) { + // Continue the request immediately be executing the callback. + ContinueRead(data_out, bytes_to_read, callback); + return true; + } + + // Continue the request immediately in the default manner. + return DoRead(data_out, bytes_to_read, bytes_read); + } + + void Cancel() override { + EXPECT_IO_THREAD(); + cancel_ct_++; + } + + private: + void ContinueRead(void* data_out, + int bytes_to_read, + CefRefPtr callback) { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + int bytes_read = 0; + DoRead(data_out, bytes_to_read, bytes_read); + callback->Continue(bytes_read); + } + + bool DoRead(void* data_out, int bytes_to_read, int& bytes_read) { + DCHECK_GT(bytes_to_read, 0); + + // Read until the buffer is full or until Read() returns 0 to indicate no + // more data. + bytes_read = 0; + int read = 0; + do { + read = static_cast( + stream_->Read(static_cast(data_out) + bytes_read, 1, + bytes_to_read - bytes_read)); + bytes_read += read; + } while (read != 0 && bytes_read < bytes_to_read); + + return (bytes_read > 0); + } + + const Mode mode_; + + const int status_code_; + const CefString status_text_; + const CefString mime_type_; + const CefResponse::HeaderMap header_map_; + const CefRefPtr stream_; + + const base::Closure destroy_callback_; + int cancel_ct_ = 0; + + IMPLEMENT_REFCOUNTING(CallbackResourceHandler); + DISALLOW_COPY_AND_ASSIGN(CallbackResourceHandler); }; // Resource handler implementation that never completes. Used to test // destruction handling behavior for in-progress requests. -class IncompleteResourceHandler : public CefResourceHandler { +class IncompleteResourceHandlerOld : public CefResourceHandler { public: enum TestMode { BLOCK_PROCESS_REQUEST, BLOCK_READ_RESPONSE, }; - IncompleteResourceHandler(TestMode test_mode, - const std::string& mime_type, - const base::Closure& destroy_callback) + IncompleteResourceHandlerOld(TestMode test_mode, + const std::string& mime_type, + const base::Closure& destroy_callback) : test_mode_(test_mode), mime_type_(mime_type), destroy_callback_(destroy_callback) {} - ~IncompleteResourceHandler() override { + ~IncompleteResourceHandlerOld() override { EXPECT_EQ(1, process_request_ct_); EXPECT_EQ(1, cancel_ct_); @@ -147,6 +307,119 @@ class IncompleteResourceHandler : public CefResourceHandler { CefRefPtr incomplete_callback_; + IMPLEMENT_REFCOUNTING(IncompleteResourceHandlerOld); + DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandlerOld); +}; + +class IncompleteResourceHandler : public CefResourceHandler { + public: + enum TestMode { + BLOCK_OPEN, + BLOCK_READ, + }; + + IncompleteResourceHandler(TestMode test_mode, + const std::string& mime_type, + const base::Closure& destroy_callback) + : test_mode_(test_mode), + mime_type_(mime_type), + destroy_callback_(destroy_callback) {} + + ~IncompleteResourceHandler() override { + EXPECT_EQ(1, open_ct_); + + EXPECT_EQ(1, cancel_ct_); + + if (test_mode_ == BLOCK_READ) { + EXPECT_EQ(1, get_response_headers_ct_); + EXPECT_EQ(1, read_ct_); + } else { + EXPECT_EQ(0, get_response_headers_ct_); + EXPECT_EQ(0, read_ct_); + } + + destroy_callback_.Run(); + } + + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + open_ct_++; + + if (test_mode_ == BLOCK_OPEN) { + // Never release or execute this callback. + incomplete_open_callback_ = callback; + } else { + // Continue immediately. + handle_request = true; + } + return true; + } + + bool ProcessRequest(CefRefPtr request, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + return false; + } + + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) override { + EXPECT_IO_THREAD(); + EXPECT_EQ(test_mode_, BLOCK_READ); + + get_response_headers_ct_++; + + response->SetStatus(200); + response->SetStatusText("OK"); + response->SetMimeType(mime_type_); + response_length = 100; + } + + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + EXPECT_EQ(test_mode_, BLOCK_READ); + + read_ct_++; + + // Never release or execute this callback. + incomplete_read_callback_ = callback; + bytes_read = 0; + return true; + } + + bool ReadResponse(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + bytes_read = -2; + return false; + } + + void Cancel() override { + EXPECT_IO_THREAD(); + cancel_ct_++; + } + + private: + const TestMode test_mode_; + const std::string mime_type_; + const base::Closure destroy_callback_; + + int open_ct_ = 0; + int get_response_headers_ct_ = 0; + int read_ct_ = 0; + int cancel_ct_ = 0; + + CefRefPtr incomplete_open_callback_; + CefRefPtr incomplete_read_callback_; + IMPLEMENT_REFCOUNTING(IncompleteResourceHandler); DISALLOW_COPY_AND_ASSIGN(IncompleteResourceHandler); }; @@ -175,11 +448,23 @@ class BasicResponseTest : public TestHandler { // Redirect the request (change the URL) in OnBeforeResourceLoad. REDIRECT_BEFORE_RESOURCE_LOAD, + // Return a CefResourceHandler from GetResourceHandler that continues + // immediately by using the callback object instead of the return value. + IMMEDIATE_REQUEST_HANDLER_OPEN, + IMMEDIATE_REQUEST_HANDLER_READ, + IMMEDIATE_REQUEST_HANDLER_ALL, + + // Return a CefResourceHandler from GetResourceHandler that continues with + // a delay by using the callback object. + DELAYED_REQUEST_HANDLER_OPEN, + DELAYED_REQUEST_HANDLER_READ, + DELAYED_REQUEST_HANDLER_ALL, + // Return a CefResourceHandler from GetResourceHandler that never completes, // then close the browser to verify destruction handling of in-progress // requests. - INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST, - INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE, + INCOMPLETE_REQUEST_HANDLER_OPEN, + INCOMPLETE_REQUEST_HANDLER_READ, // Redirect the request using a CefResourceHandler returned from // GetResourceHandler. @@ -552,24 +837,7 @@ class BasicResponseTest : public TestHandler { } void DestroyTest() override { - if (mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD) { - EXPECT_EQ(1, on_before_browse_ct_); - EXPECT_EQ(1, get_resource_request_handler_ct_); - EXPECT_EQ(1, get_cookie_access_filter_ct_); - EXPECT_EQ(1, on_before_resource_load_ct_); - EXPECT_EQ(1, get_resource_handler_ct_); - EXPECT_EQ(0, on_resource_redirect_ct_); - - // Unhandled requests won't see a call to GetResourceResponseFilter - // or OnResourceResponse. - if (unhandled_) { - EXPECT_EQ(0, get_resource_response_filter_ct_); - EXPECT_EQ(0, on_resource_response_ct_); - } else { - EXPECT_EQ(1, get_resource_response_filter_ct_); - EXPECT_EQ(1, on_resource_response_ct_); - } - } else if (mode_ == RESTART_RESOURCE_RESPONSE) { + if (mode_ == RESTART_RESOURCE_RESPONSE) { EXPECT_EQ(1, on_before_browse_ct_); EXPECT_EQ(2, get_resource_request_handler_ct_); EXPECT_EQ(2, get_cookie_access_filter_ct_); @@ -586,6 +854,23 @@ class BasicResponseTest : public TestHandler { EXPECT_EQ(1, get_resource_response_filter_ct_); EXPECT_EQ(2, on_resource_response_ct_); } + } else if (IsLoad()) { + EXPECT_EQ(1, on_before_browse_ct_); + EXPECT_EQ(1, get_resource_request_handler_ct_); + EXPECT_EQ(1, get_cookie_access_filter_ct_); + EXPECT_EQ(1, on_before_resource_load_ct_); + EXPECT_EQ(1, get_resource_handler_ct_); + EXPECT_EQ(0, on_resource_redirect_ct_); + + // Unhandled requests won't see a call to GetResourceResponseFilter + // or OnResourceResponse. + if (unhandled_) { + EXPECT_EQ(0, get_resource_response_filter_ct_); + EXPECT_EQ(0, on_resource_response_ct_); + } else { + EXPECT_EQ(1, get_resource_response_filter_ct_); + EXPECT_EQ(1, on_resource_response_ct_); + } } else if (IsRedirect()) { EXPECT_EQ(2, on_before_browse_ct_); EXPECT_EQ(2, get_resource_request_handler_ct_); @@ -634,7 +919,7 @@ class BasicResponseTest : public TestHandler { EXPECT_EQ(0, on_resource_redirect_ct_); - if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE) { + if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) { EXPECT_EQ(1, get_resource_response_filter_ct_); EXPECT_EQ(1, on_resource_response_ct_); } else { @@ -739,46 +1024,96 @@ class BasicResponseTest : public TestHandler { return base::Bind(&BasicResponseTest::MaybeDestroyTest, this, true); } - CefRefPtr GetOKResource() { - const std::string& body = GetResponseBody(); + bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) { + switch (mode_) { + case IMMEDIATE_REQUEST_HANDLER_OPEN: + mode = CallbackResourceHandler::IMMEDIATE_OPEN; + return true; + case IMMEDIATE_REQUEST_HANDLER_READ: + mode = CallbackResourceHandler::IMMEDIATE_READ; + return true; + case IMMEDIATE_REQUEST_HANDLER_ALL: + mode = CallbackResourceHandler::IMMEDIATE_ALL; + return true; + case DELAYED_REQUEST_HANDLER_OPEN: + mode = CallbackResourceHandler::DELAYED_OPEN; + return true; + case DELAYED_REQUEST_HANDLER_READ: + mode = CallbackResourceHandler::DELAYED_READ; + return true; + case DELAYED_REQUEST_HANDLER_ALL: + mode = CallbackResourceHandler::DELAYED_ALL; + return true; + default: + break; + } + return false; + } + + CefRefPtr GetResource(int status_code, + const CefString& status_text, + const CefString& mime_type, + CefResponse::HeaderMap header_map, + const std::string& body) { CefRefPtr stream = CefStreamReader::CreateForData( const_cast(body.c_str()), body.size()); - return new NormalResourceHandler(200, "OK", "text/html", - CefResponse::HeaderMap(), stream, + CallbackResourceHandler::Mode handler_mode; + if (GetCallbackResourceHandlerMode(handler_mode)) { + return new CallbackResourceHandler(handler_mode, status_code, status_text, + mime_type, header_map, stream, + GetResourceDestroyCallback()); + } + + return new NormalResourceHandler(status_code, status_text, mime_type, + header_map, stream, GetResourceDestroyCallback()); } + CefRefPtr GetOKResource() { + return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(), + GetResponseBody()); + } + CefRefPtr GetRedirectResource( const std::string& redirect_url) { - const std::string& body = GetRedirectBody(); - CefRefPtr stream = CefStreamReader::CreateForData( - const_cast(body.c_str()), body.size()); - CefResponse::HeaderMap headerMap; headerMap.insert(std::make_pair("Location", redirect_url)); - return new NormalResourceHandler(307, "Temporary Redirect", "text/html", - headerMap, stream, - GetResourceDestroyCallback()); + return GetResource(307, "Temporary Redirect", "text/html", headerMap, + GetRedirectBody()); } CefRefPtr GetIncompleteResource() { + if (TestOldResourceAPI()) { + return new IncompleteResourceHandlerOld( + mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN + ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST + : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE, + "text/html", GetResourceDestroyCallback()); + } + return new IncompleteResourceHandler( - mode_ == INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST - ? IncompleteResourceHandler::BLOCK_PROCESS_REQUEST - : IncompleteResourceHandler::BLOCK_READ_RESPONSE, + mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN + ? IncompleteResourceHandler::BLOCK_OPEN + : IncompleteResourceHandler::BLOCK_READ, "text/html", GetResourceDestroyCallback()); } bool IsLoad() const { return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD || - mode_ == RESTART_RESOURCE_RESPONSE; + mode_ == RESTART_RESOURCE_RESPONSE || + mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN || + mode_ == IMMEDIATE_REQUEST_HANDLER_READ || + mode_ == IMMEDIATE_REQUEST_HANDLER_ALL || + mode_ == DELAYED_REQUEST_HANDLER_OPEN || + mode_ == DELAYED_REQUEST_HANDLER_READ || + mode_ == DELAYED_REQUEST_HANDLER_ALL; } bool IsIncompleteRequestHandler() const { - return mode_ == INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST || - mode_ == INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE; + return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN || + mode_ == INCOMPLETE_REQUEST_HANDLER_READ; } bool IsIncomplete() const { @@ -916,7 +1251,7 @@ class BasicResponseTest : public TestHandler { // response. const bool incomplete_unhandled = (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD || - mode_ == INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST || + mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN || (IsAborted() && !custom_scheme_)); if ((unhandled_ && !override_unhandled) || incomplete_unhandled) { @@ -932,7 +1267,7 @@ class BasicResponseTest : public TestHandler { EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback; EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback; } else { - if ((mode_ == INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE || IsAborted()) && + if ((mode_ == INCOMPLETE_REQUEST_HANDLER_READ || IsAborted()) && callback == kOnResourceLoadComplete) { // We got a response, but we also got aborted. EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback; @@ -1059,13 +1394,25 @@ class BasicResponseTest : public TestHandler { unhandled) // Tests only supported in handled mode. -#define BASIC_TEST_HANDLED_MODES(name, custom) \ - BASIC_TEST(name##IncompleteBeforeResourceLoad, \ - INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false) \ - BASIC_TEST(name##IncompleteRequestHandlerProcessRequest, \ - INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST, custom, false) \ - BASIC_TEST(name##IncompleteRequestHandlerReadResponse, \ - INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE, custom, false) +#define BASIC_TEST_HANDLED_MODES(name, custom) \ + BASIC_TEST(name##ImmediateRequestHandlerOpen, \ + IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false) \ + BASIC_TEST(name##ImmediateRequestHandlerRead, \ + IMMEDIATE_REQUEST_HANDLER_READ, custom, false) \ + BASIC_TEST(name##ImmediateRequestHandlerAll, IMMEDIATE_REQUEST_HANDLER_ALL, \ + custom, false) \ + BASIC_TEST(name##DelayedRequestHandlerOpen, DELAYED_REQUEST_HANDLER_OPEN, \ + custom, false) \ + BASIC_TEST(name##DelayedRequestHandlerRead, DELAYED_REQUEST_HANDLER_READ, \ + custom, false) \ + BASIC_TEST(name##DelayedRequestHandlerAll, DELAYED_REQUEST_HANDLER_ALL, \ + custom, false) \ + BASIC_TEST(name##IncompleteBeforeResourceLoad, \ + INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false) \ + BASIC_TEST(name##IncompleteRequestHandlerOpen, \ + INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false) \ + BASIC_TEST(name##IncompleteRequestHandlerRead, \ + INCOMPLETE_REQUEST_HANDLER_READ, custom, false) BASIC_TEST_ALL_MODES(StandardHandled, false, false) BASIC_TEST_ALL_MODES(StandardUnhandled, false, true) @@ -1095,11 +1442,23 @@ class SubresourceResponseTest : public RoutingTestHandler { // Redirect the request (change the URL) in OnBeforeResourceLoad. REDIRECT_BEFORE_RESOURCE_LOAD, + // Return a CefResourceHandler from GetResourceHandler that continues + // immediately by using the callback object instead of the return value. + IMMEDIATE_REQUEST_HANDLER_OPEN, + IMMEDIATE_REQUEST_HANDLER_READ, + IMMEDIATE_REQUEST_HANDLER_ALL, + + // Return a CefResourceHandler from GetResourceHandler that continues with + // a delay by using the callback object. + DELAYED_REQUEST_HANDLER_OPEN, + DELAYED_REQUEST_HANDLER_READ, + DELAYED_REQUEST_HANDLER_ALL, + // Return a CefResourceHandler from GetResourceHandler that never completes, // then close the browser to verify destruction handling of in-progress // requests. - INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST, - INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE, + INCOMPLETE_REQUEST_HANDLER_OPEN, + INCOMPLETE_REQUEST_HANDLER_READ, // Redirect the request using a CefResourceHandler returned from // GetResourceHandler. @@ -1581,22 +1940,7 @@ class SubresourceResponseTest : public RoutingTestHandler { EXPECT_EQ(1, on_before_browse_ct_); } - if (mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD) { - EXPECT_EQ(1, get_resource_request_handler_ct_); - EXPECT_EQ(1, get_cookie_access_filter_ct_); - EXPECT_EQ(1, on_before_resource_load_ct_); - EXPECT_EQ(1, get_resource_handler_ct_); - EXPECT_EQ(0, on_resource_redirect_ct_); - // Unhandled requests won't see a call to GetResourceResponseFilter or - // OnResourceResponse. - if (unhandled_) { - EXPECT_EQ(0, get_resource_response_filter_ct_); - EXPECT_EQ(0, on_resource_response_ct_); - } else { - EXPECT_EQ(1, get_resource_response_filter_ct_); - EXPECT_EQ(1, on_resource_response_ct_); - } - } else if (mode_ == RESTART_RESOURCE_RESPONSE) { + if (mode_ == RESTART_RESOURCE_RESPONSE) { EXPECT_EQ(2, get_resource_request_handler_ct_); EXPECT_EQ(2, get_cookie_access_filter_ct_); EXPECT_EQ(2, on_before_resource_load_ct_); @@ -1612,6 +1956,21 @@ class SubresourceResponseTest : public RoutingTestHandler { EXPECT_EQ(1, get_resource_response_filter_ct_); EXPECT_EQ(2, on_resource_response_ct_); } + } else if (IsLoad()) { + EXPECT_EQ(1, get_resource_request_handler_ct_); + EXPECT_EQ(1, get_cookie_access_filter_ct_); + EXPECT_EQ(1, on_before_resource_load_ct_); + EXPECT_EQ(1, get_resource_handler_ct_); + EXPECT_EQ(0, on_resource_redirect_ct_); + // Unhandled requests won't see a call to GetResourceResponseFilter or + // OnResourceResponse. + if (unhandled_) { + EXPECT_EQ(0, get_resource_response_filter_ct_); + EXPECT_EQ(0, on_resource_response_ct_); + } else { + EXPECT_EQ(1, get_resource_response_filter_ct_); + EXPECT_EQ(1, on_resource_response_ct_); + } } else if (IsRedirect()) { EXPECT_EQ(2, get_resource_request_handler_ct_); EXPECT_EQ(2, get_cookie_access_filter_ct_); @@ -1655,7 +2014,7 @@ class SubresourceResponseTest : public RoutingTestHandler { EXPECT_EQ(0, on_resource_redirect_ct_); - if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE) { + if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ) { EXPECT_EQ(1, get_resource_response_filter_ct_); EXPECT_EQ(1, on_resource_response_ct_); } else { @@ -1812,66 +2171,106 @@ class SubresourceResponseTest : public RoutingTestHandler { return base::Bind(&SubresourceResponseTest::MaybeDestroyTest, this, true); } - CefRefPtr GetMainResource() { - const std::string& body = GetMainResponseBody(); + bool GetCallbackResourceHandlerMode(CallbackResourceHandler::Mode& mode) { + switch (mode_) { + case IMMEDIATE_REQUEST_HANDLER_OPEN: + mode = CallbackResourceHandler::IMMEDIATE_OPEN; + return true; + case IMMEDIATE_REQUEST_HANDLER_READ: + mode = CallbackResourceHandler::IMMEDIATE_READ; + return true; + case IMMEDIATE_REQUEST_HANDLER_ALL: + mode = CallbackResourceHandler::IMMEDIATE_ALL; + return true; + case DELAYED_REQUEST_HANDLER_OPEN: + mode = CallbackResourceHandler::DELAYED_OPEN; + return true; + case DELAYED_REQUEST_HANDLER_READ: + mode = CallbackResourceHandler::DELAYED_READ; + return true; + case DELAYED_REQUEST_HANDLER_ALL: + mode = CallbackResourceHandler::DELAYED_ALL; + return true; + default: + break; + } + return false; + } + + CefRefPtr GetResource(int status_code, + const CefString& status_text, + const CefString& mime_type, + CefResponse::HeaderMap header_map, + const std::string& body) { CefRefPtr stream = CefStreamReader::CreateForData( const_cast(body.c_str()), body.size()); - return new NormalResourceHandler(200, "OK", "text/html", - CefResponse::HeaderMap(), stream, + CallbackResourceHandler::Mode handler_mode; + if (GetCallbackResourceHandlerMode(handler_mode)) { + return new CallbackResourceHandler(handler_mode, status_code, status_text, + mime_type, header_map, stream, + GetResourceDestroyCallback()); + } + + return new NormalResourceHandler(status_code, status_text, mime_type, + header_map, stream, GetResourceDestroyCallback()); } + CefRefPtr GetMainResource() { + return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(), + GetMainResponseBody()); + } + CefRefPtr GetSubResource() { - const std::string& body = GetSubResponseBody(); - CefRefPtr stream = CefStreamReader::CreateForData( - const_cast(body.c_str()), body.size()); - - return new NormalResourceHandler(200, "OK", "text/html", - CefResponse::HeaderMap(), stream, - GetResourceDestroyCallback()); + return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(), + GetSubResponseBody()); } CefRefPtr GetOKResource() { - const std::string& body = GetResponseBody(); - CefRefPtr stream = CefStreamReader::CreateForData( - const_cast(body.c_str()), body.size()); - - return new NormalResourceHandler(200, "OK", "text/javascript", - CefResponse::HeaderMap(), stream, - GetResourceDestroyCallback()); + return GetResource(200, "OK", "text/javascript", CefResponse::HeaderMap(), + GetResponseBody()); } CefRefPtr GetRedirectResource( const std::string& redirect_url) { - const std::string& body = GetRedirectBody(); - CefRefPtr stream = CefStreamReader::CreateForData( - const_cast(body.c_str()), body.size()); - CefResponse::HeaderMap headerMap; headerMap.insert(std::make_pair("Location", redirect_url)); - return new NormalResourceHandler(307, "Temporary Redirect", - "text/javascript", headerMap, stream, - GetResourceDestroyCallback()); + return GetResource(307, "Temporary Redirect", "text/javascript", headerMap, + GetRedirectBody()); } CefRefPtr GetIncompleteResource() { + if (TestOldResourceAPI()) { + return new IncompleteResourceHandlerOld( + mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN + ? IncompleteResourceHandlerOld::BLOCK_PROCESS_REQUEST + : IncompleteResourceHandlerOld::BLOCK_READ_RESPONSE, + "text/javascript", GetResourceDestroyCallback()); + } + return new IncompleteResourceHandler( - mode_ == INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST - ? IncompleteResourceHandler::BLOCK_PROCESS_REQUEST - : IncompleteResourceHandler::BLOCK_READ_RESPONSE, + mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN + ? IncompleteResourceHandler::BLOCK_OPEN + : IncompleteResourceHandler::BLOCK_READ, "text/javascript", GetResourceDestroyCallback()); } bool IsLoad() const { return mode_ == LOAD || mode_ == MODIFY_BEFORE_RESOURCE_LOAD || - mode_ == RESTART_RESOURCE_RESPONSE; + mode_ == RESTART_RESOURCE_RESPONSE || + mode_ == IMMEDIATE_REQUEST_HANDLER_OPEN || + mode_ == IMMEDIATE_REQUEST_HANDLER_READ || + mode_ == IMMEDIATE_REQUEST_HANDLER_ALL || + mode_ == DELAYED_REQUEST_HANDLER_OPEN || + mode_ == DELAYED_REQUEST_HANDLER_READ || + mode_ == DELAYED_REQUEST_HANDLER_ALL; } bool IsIncompleteRequestHandler() const { - return mode_ == INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST || - mode_ == INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE; + return mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN || + mode_ == INCOMPLETE_REQUEST_HANDLER_READ; } bool IsIncomplete() const { @@ -2010,7 +2409,7 @@ class SubresourceResponseTest : public RoutingTestHandler { // response. const bool incomplete_unhandled = (mode_ == INCOMPLETE_BEFORE_RESOURCE_LOAD || - mode_ == INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST); + mode_ == INCOMPLETE_REQUEST_HANDLER_OPEN); if ((unhandled_ && !override_unhandled) || incomplete_unhandled) { if (incomplete_unhandled) { @@ -2025,7 +2424,7 @@ class SubresourceResponseTest : public RoutingTestHandler { EXPECT_STREQ("", response->GetMimeType().ToString().c_str()) << callback; EXPECT_STREQ("", response->GetCharset().ToString().c_str()) << callback; } else { - if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE && + if (mode_ == INCOMPLETE_REQUEST_HANDLER_READ && callback == kOnResourceLoadComplete) { // We got a response, but we also got aborted. EXPECT_EQ(ERR_ABORTED, response->GetError()) << callback; @@ -2156,15 +2555,25 @@ class SubresourceResponseTest : public RoutingTestHandler { custom, unhandled, subframe) // Tests only supported in handled mode. -#define SUBRESOURCE_TEST_HANDLED_MODES(name, custom, subframe) \ - SUBRESOURCE_TEST(name##IncompleteBeforeResourceLoad, \ - INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false, subframe) \ - SUBRESOURCE_TEST(name##IncompleteRequestHandlerProcessRequest, \ - INCOMPLETE_REQUEST_HANDLER_PROCESS_REQUEST, custom, false, \ - subframe) \ - SUBRESOURCE_TEST(name##IncompleteRequestHandlerReadResponse, \ - INCOMPLETE_REQUEST_HANDLER_READ_RESPONSE, custom, false, \ - subframe) +#define SUBRESOURCE_TEST_HANDLED_MODES(name, custom, subframe) \ + SUBRESOURCE_TEST(name##ImmediateRequestHandlerOpen, \ + IMMEDIATE_REQUEST_HANDLER_OPEN, custom, false, subframe) \ + SUBRESOURCE_TEST(name##ImmediateRequestHandlerRead, \ + IMMEDIATE_REQUEST_HANDLER_READ, custom, false, subframe) \ + SUBRESOURCE_TEST(name##ImmediateRequestHandlerAll, \ + IMMEDIATE_REQUEST_HANDLER_ALL, custom, false, subframe) \ + SUBRESOURCE_TEST(name##DelayedRequestHandlerOpen, \ + DELAYED_REQUEST_HANDLER_OPEN, custom, false, subframe) \ + SUBRESOURCE_TEST(name##DelayedRequestHandlerRead, \ + DELAYED_REQUEST_HANDLER_READ, custom, false, subframe) \ + SUBRESOURCE_TEST(name##DelayedRequestHandlerAll, \ + DELAYED_REQUEST_HANDLER_ALL, custom, false, subframe) \ + SUBRESOURCE_TEST(name##IncompleteBeforeResourceLoad, \ + INCOMPLETE_BEFORE_RESOURCE_LOAD, custom, false, subframe) \ + SUBRESOURCE_TEST(name##IncompleteRequestHandlerOpen, \ + INCOMPLETE_REQUEST_HANDLER_OPEN, custom, false, subframe) \ + SUBRESOURCE_TEST(name##IncompleteRequestHandlerRead, \ + INCOMPLETE_REQUEST_HANDLER_READ, custom, false, subframe) SUBRESOURCE_TEST_ALL_MODES(StandardHandledMainFrame, false, false, false) SUBRESOURCE_TEST_ALL_MODES(StandardUnhandledMainFrame, false, true, false) diff --git a/tests/ceftests/scheme_handler_unittest.cc b/tests/ceftests/scheme_handler_unittest.cc index 0f0029cca..d14df44fa 100644 --- a/tests/ceftests/scheme_handler_unittest.cc +++ b/tests/ceftests/scheme_handler_unittest.cc @@ -212,9 +212,9 @@ class TestSchemeHandler : public TestHandler { IMPLEMENT_REFCOUNTING(TestSchemeHandler); }; -class ClientSchemeHandler : public CefResourceHandler { +class ClientSchemeHandlerOld : public CefResourceHandler { public: - explicit ClientSchemeHandler(TestResults* tr) + explicit ClientSchemeHandlerOld(TestResults* tr) : test_results_(tr), offset_(0), is_sub_(false), has_delayed_(false) {} bool ProcessRequest(CefRefPtr request, @@ -329,10 +329,11 @@ class ClientSchemeHandler : public CefResourceHandler { if (test_results_->delay > 0) { if (!has_delayed_) { // Continue after a delay. - CefPostDelayedTask(TID_IO, - base::Bind(&ClientSchemeHandler::ContinueAfterDelay, - this, callback), - test_results_->delay); + CefPostDelayedTask( + TID_IO, + base::Bind(&ClientSchemeHandlerOld::ContinueAfterDelay, this, + callback), + test_results_->delay); bytes_read = 0; return true; } @@ -378,7 +379,206 @@ class ClientSchemeHandler : public CefResourceHandler { bool is_sub_; bool has_delayed_; + IMPLEMENT_REFCOUNTING(ClientSchemeHandlerOld); + DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerOld); +}; + +class ClientSchemeHandler : public CefResourceHandler { + public: + explicit ClientSchemeHandler(TestResults* tr) + : test_results_(tr), offset_(0), is_sub_(false), has_delayed_(false) {} + + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + bool handled = false; + + std::string url = request->GetURL(); + is_sub_ = + (!test_results_->sub_url.empty() && test_results_->sub_url == url); + + if (is_sub_) { + test_results_->got_sub_request.yes(); + + if (!test_results_->sub_html.empty()) + handled = true; + } else { + EXPECT_EQ(url, test_results_->url); + + test_results_->got_request.yes(); + + if (!test_results_->html.empty()) + handled = true; + } + + std::string accept_language; + CefRequest::HeaderMap headerMap; + CefRequest::HeaderMap::iterator headerIter; + request->GetHeaderMap(headerMap); + headerIter = headerMap.find("Accept-Language"); + if (headerIter != headerMap.end()) + accept_language = headerIter->second; + EXPECT_TRUE(!accept_language.empty()); + + if (!test_results_->accept_language.empty()) { + // Value from CefBrowserSettings.accept_language set in + // PopulateBrowserSettings(). + EXPECT_STREQ(test_results_->accept_language.data(), + accept_language.data()); + } else { + // CEF_SETTINGS_ACCEPT_LANGUAGE value from + // CefSettings.accept_language_list set in CefTestSuite::GetSettings() + // and expanded internally by ComputeAcceptLanguageFromPref. + EXPECT_STREQ("en-GB,en;q=0.9", accept_language.data()); + } + + // Continue or cancel the request immediately based on the return value. + handle_request = true; + + if (handled) { + if (test_results_->delay > 0) { + // Continue after the delay. + handle_request = false; + CefPostDelayedTask(TID_FILE_USER_BLOCKING, + base::Bind(&CefCallback::Continue, callback.get()), + test_results_->delay); + } + return true; + } else if (test_results_->response_error_code != ERR_NONE) { + // Propagate the error code. + return true; + } + + // Response was canceled. + if (g_current_handler) + g_current_handler->DestroyTest(); + return false; + } + + bool ProcessRequest(CefRefPtr request, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + return false; + } + + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) override { + if (is_sub_) { + response->SetStatus(test_results_->sub_status_code); + + if (!test_results_->sub_allow_origin.empty()) { + // Set the Access-Control-Allow-Origin header to allow cross-domain + // scripting. + CefResponse::HeaderMap headers; + headers.insert(std::make_pair("Access-Control-Allow-Origin", + test_results_->sub_allow_origin)); + response->SetHeaderMap(headers); + } + + if (!test_results_->sub_html.empty()) { + response->SetMimeType("text/html"); + response_length = test_results_->sub_html.size(); + } + } else if (!test_results_->redirect_url.empty()) { + redirectUrl = test_results_->redirect_url; + } else if (test_results_->response_error_code != ERR_NONE) { + response->SetError(test_results_->response_error_code); + } else { + response->SetStatus(test_results_->status_code); + + if (!test_results_->html.empty()) { + response->SetMimeType("text/html"); + response_length = test_results_->html.size(); + } + } + } + + void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); } + + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + if (test_results_->delay > 0) { + if (!has_delayed_) { + // Continue after a delay. + CefPostDelayedTask(TID_FILE_USER_BLOCKING, + base::Bind(&ClientSchemeHandler::ContinueAfterDelay, + this, data_out, bytes_to_read, callback), + test_results_->delay); + bytes_read = 0; + return true; + } + + has_delayed_ = false; + } + + return GetData(data_out, bytes_to_read, bytes_read); + } + + bool ReadResponse(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + bytes_read = -2; + return false; + } + + private: + void ContinueAfterDelay(void* data_out, + int bytes_to_read, + CefRefPtr callback) { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + has_delayed_ = true; + + int bytes_read = 0; + GetData(data_out, bytes_to_read, bytes_read); + callback->Continue(bytes_read); + } + + bool GetData(void* data_out, int bytes_to_read, int& bytes_read) { + std::string* data; + + if (is_sub_) { + test_results_->got_sub_read.yes(); + data = &test_results_->sub_html; + } else { + test_results_->got_read.yes(); + data = &test_results_->html; + } + + // Default to response complete. + bool has_data = false; + bytes_read = 0; + + size_t size = data->size(); + if (offset_ < size) { + int transfer_size = + std::min(bytes_to_read, static_cast(size - offset_)); + memcpy(data_out, data->c_str() + offset_, transfer_size); + offset_ += transfer_size; + + bytes_read = transfer_size; + has_data = true; + } + + return has_data; + } + + TestResults* test_results_; + size_t offset_; + bool is_sub_; + bool has_delayed_; + IMPLEMENT_REFCOUNTING(ClientSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandler); }; class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory { @@ -390,12 +590,16 @@ class ClientSchemeHandlerFactory : public CefSchemeHandlerFactory { const CefString& scheme_name, CefRefPtr request) override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); + if (TestOldResourceAPI()) { + return new ClientSchemeHandlerOld(test_results_); + } return new ClientSchemeHandler(test_results_); } TestResults* test_results_; IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory); + DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory); }; // Global test results object. diff --git a/tests/ceftests/test_util.cc b/tests/ceftests/test_util.cc index 288c7cb7e..d8e6c9dfa 100644 --- a/tests/ceftests/test_util.cc +++ b/tests/ceftests/test_util.cc @@ -3,6 +3,7 @@ // can be found in the LICENSE file. #include "tests/ceftests/test_util.h" +#include "include/cef_command_line.h" #include "include/cef_request_context_handler.h" #include "tests/gtest/include/gtest/gtest.h" @@ -266,6 +267,16 @@ void TestStringVectorEqual(const std::vector& val1, EXPECT_STREQ(val1[i].ToString().c_str(), val2[i].ToString().c_str()); } +bool TestOldResourceAPI() { + static int state = -1; + if (state == -1) { + CefRefPtr command_line = + CefCommandLine::GetGlobalCommandLine(); + state = command_line->HasSwitch("test-old-resource-api") ? 1 : 0; + } + return state ? true : false; +} + CefRefPtr CreateTestRequestContext( TestRequestContextMode mode, const std::string& cache_path) { diff --git a/tests/ceftests/test_util.h b/tests/ceftests/test_util.h index 675182e2b..7f0fe4a5a 100644 --- a/tests/ceftests/test_util.h +++ b/tests/ceftests/test_util.h @@ -78,6 +78,9 @@ inline bool IsTestRequestContextModeCustom(TestRequestContextMode mode) { mode == TEST_RC_MODE_CUSTOM_WITH_HANDLER; } +// Returns true if the old CefResourceHandler API should be tested. +bool TestOldResourceAPI(); + // Return a RequestContext object matching the specified |mode|. // |cache_path| may be specified for CUSTOM modes. // Use the RC_TEST_GROUP_BASE macro to test all valid combinations. diff --git a/tests/ceftests/urlrequest_unittest.cc b/tests/ceftests/urlrequest_unittest.cc index ec65f9990..bb528b84c 100644 --- a/tests/ceftests/urlrequest_unittest.cc +++ b/tests/ceftests/urlrequest_unittest.cc @@ -546,13 +546,13 @@ bool IsAuthorized(CefRefPtr request, // SCHEME HANDLER BACKEND // Serves request responses. -class RequestSchemeHandler : public CefResourceHandler { +class RequestSchemeHandlerOld : public CefResourceHandler { public: - RequestSchemeHandler(RequestRunSettings* settings, - const base::Closure& destroy_callback) + RequestSchemeHandlerOld(RequestRunSettings* settings, + const base::Closure& destroy_callback) : settings_(settings), destroy_callback_(destroy_callback) {} - ~RequestSchemeHandler() override { + ~RequestSchemeHandlerOld() override { EXPECT_EQ(1, cancel_ct_); destroy_callback_.Run(); } @@ -580,7 +580,7 @@ class RequestSchemeHandler : public CefResourceHandler { response_length = response_data_.length(); } - bool ReadResponse(void* response_data_out, + bool ReadResponse(void* data_out, int bytes_to_read, int& bytes_read, CefRefPtr callback) override { @@ -593,8 +593,7 @@ class RequestSchemeHandler : public CefResourceHandler { if (offset_ < size) { int transfer_size = std::min(bytes_to_read, static_cast(size - offset_)); - memcpy(response_data_out, response_data_.c_str() + offset_, - transfer_size); + memcpy(data_out, response_data_.c_str() + offset_, transfer_size); offset_ += transfer_size; bytes_read = transfer_size; @@ -609,6 +608,99 @@ class RequestSchemeHandler : public CefResourceHandler { cancel_ct_++; } + private: + // |settings_| is not owned by this object. + RequestRunSettings* settings_; + base::Closure destroy_callback_; + + std::string response_data_; + size_t offset_ = 0; + + int cancel_ct_ = 0; + + IMPLEMENT_REFCOUNTING(RequestSchemeHandlerOld); + DISALLOW_COPY_AND_ASSIGN(RequestSchemeHandlerOld); +}; + +class RequestSchemeHandler : public CefResourceHandler { + public: + RequestSchemeHandler(RequestRunSettings* settings, + const base::Closure& destroy_callback) + : settings_(settings), destroy_callback_(destroy_callback) {} + + ~RequestSchemeHandler() override { + EXPECT_EQ(1, cancel_ct_); + destroy_callback_.Run(); + } + + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + VerifyNormalRequest(settings_, request, false); + + // HEAD requests are identical to GET requests except no response data is + // sent. + if (request->GetMethod() != "HEAD") + response_data_ = settings_->response_data; + + // Continue immediately. + handle_request = true; + return true; + } + + bool ProcessRequest(CefRefPtr request, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + return false; + } + + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) override { + EXPECT_IO_THREAD(); + GetNormalResponse(settings_, response); + response_length = response_data_.length(); + } + + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + // Default to response complete. + bool has_data = false; + bytes_read = 0; + + size_t size = response_data_.length(); + if (offset_ < size) { + int transfer_size = + std::min(bytes_to_read, static_cast(size - offset_)); + memcpy(data_out, response_data_.c_str() + offset_, transfer_size); + offset_ += transfer_size; + + bytes_read = transfer_size; + has_data = true; + } + + return has_data; + } + + bool ReadResponse(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + bytes_read = -2; + return false; + } + + void Cancel() override { + EXPECT_IO_THREAD(); + cancel_ct_++; + } + private: // |settings_| is not owned by this object. RequestRunSettings* settings_; @@ -620,19 +712,20 @@ class RequestSchemeHandler : public CefResourceHandler { int cancel_ct_ = 0; IMPLEMENT_REFCOUNTING(RequestSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(RequestSchemeHandler); }; // Serves redirect request responses. -class RequestRedirectSchemeHandler : public CefResourceHandler { +class RequestRedirectSchemeHandlerOld : public CefResourceHandler { public: - RequestRedirectSchemeHandler(CefRefPtr request, - CefRefPtr response, - const base::Closure& destroy_callback) + RequestRedirectSchemeHandlerOld(CefRefPtr request, + CefRefPtr response, + const base::Closure& destroy_callback) : request_(request), response_(response), destroy_callback_(destroy_callback) {} - ~RequestRedirectSchemeHandler() override { + ~RequestRedirectSchemeHandlerOld() override { EXPECT_EQ(1, cancel_ct_); destroy_callback_.Run(); } @@ -679,6 +772,89 @@ class RequestRedirectSchemeHandler : public CefResourceHandler { cancel_ct_++; } + private: + CefRefPtr request_; + CefRefPtr response_; + base::Closure destroy_callback_; + + int cancel_ct_ = 0; + + IMPLEMENT_REFCOUNTING(RequestRedirectSchemeHandlerOld); + DISALLOW_COPY_AND_ASSIGN(RequestRedirectSchemeHandlerOld); +}; + +class RequestRedirectSchemeHandler : public CefResourceHandler { + public: + RequestRedirectSchemeHandler(CefRefPtr request, + CefRefPtr response, + const base::Closure& destroy_callback) + : request_(request), + response_(response), + destroy_callback_(destroy_callback) {} + + ~RequestRedirectSchemeHandler() override { + EXPECT_EQ(1, cancel_ct_); + destroy_callback_.Run(); + } + + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + // Verify that the request was sent correctly. + TestRequestEqual(request_, request, true); + + // Continue immediately. + handle_request = true; + return true; + } + + bool ProcessRequest(CefRefPtr request, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + return false; + } + + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) override { + EXPECT_IO_THREAD(); + + response->SetStatus(response_->GetStatus()); + response->SetStatusText(response_->GetStatusText()); + response->SetMimeType(response_->GetMimeType()); + + CefResponse::HeaderMap headerMap; + response_->GetHeaderMap(headerMap); + response->SetHeaderMap(headerMap); + + response_length = 0; + } + + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + bytes_read = -1; + return false; + } + + bool ReadResponse(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + bytes_read = -2; + return false; + } + + void Cancel() override { + EXPECT_IO_THREAD(); + cancel_ct_++; + } + private: CefRefPtr request_; CefRefPtr response_; @@ -687,19 +863,20 @@ class RequestRedirectSchemeHandler : public CefResourceHandler { int cancel_ct_ = 0; IMPLEMENT_REFCOUNTING(RequestRedirectSchemeHandler); + DISALLOW_COPY_AND_ASSIGN(RequestRedirectSchemeHandler); }; // Resource handler implementation that never completes. Used to test // destruction handling behavior for in-progress requests. -class IncompleteSchemeHandler : public CefResourceHandler { +class IncompleteSchemeHandlerOld : public CefResourceHandler { public: - IncompleteSchemeHandler(RequestRunSettings* settings, - const base::Closure& destroy_callback) + IncompleteSchemeHandlerOld(RequestRunSettings* settings, + const base::Closure& destroy_callback) : settings_(settings), destroy_callback_(destroy_callback) { EXPECT_NE(settings_->incomplete_type, RequestRunSettings::INCOMPLETE_NONE); } - ~IncompleteSchemeHandler() override { + ~IncompleteSchemeHandlerOld() override { EXPECT_EQ(1, process_request_ct_); EXPECT_EQ(1, cancel_ct_); @@ -783,6 +960,120 @@ class IncompleteSchemeHandler : public CefResourceHandler { CefRefPtr incomplete_callback_; + IMPLEMENT_REFCOUNTING(IncompleteSchemeHandlerOld); + DISALLOW_COPY_AND_ASSIGN(IncompleteSchemeHandlerOld); +}; + +class IncompleteSchemeHandler : public CefResourceHandler { + public: + IncompleteSchemeHandler(RequestRunSettings* settings, + const base::Closure& destroy_callback) + : settings_(settings), destroy_callback_(destroy_callback) { + EXPECT_NE(settings_->incomplete_type, RequestRunSettings::INCOMPLETE_NONE); + } + + ~IncompleteSchemeHandler() override { + EXPECT_EQ(1, open_ct_); + EXPECT_EQ(1, cancel_ct_); + + if (settings_->incomplete_type == + RequestRunSettings::INCOMPLETE_READ_RESPONSE) { + EXPECT_EQ(1, get_response_headers_ct_); + EXPECT_EQ(1, read_ct_); + } else { + EXPECT_EQ(0, get_response_headers_ct_); + EXPECT_EQ(0, read_ct_); + } + + destroy_callback_.Run(); + } + + bool Open(CefRefPtr request, + bool& handle_request, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + + open_ct_++; + + if (settings_->incomplete_type == + RequestRunSettings::INCOMPLETE_PROCESS_REQUEST) { + // Never release or execute this callback. + incomplete_open_callback_ = callback; + } else { + // Continue immediately. + handle_request = true; + } + return true; + } + + bool ProcessRequest(CefRefPtr request, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + return false; + } + + void GetResponseHeaders(CefRefPtr response, + int64& response_length, + CefString& redirectUrl) override { + EXPECT_IO_THREAD(); + EXPECT_EQ(settings_->incomplete_type, + RequestRunSettings::INCOMPLETE_READ_RESPONSE); + + get_response_headers_ct_++; + + response->SetStatus(settings_->response->GetStatus()); + response->SetStatusText(settings_->response->GetStatusText()); + response->SetMimeType(settings_->response->GetMimeType()); + + CefResponse::HeaderMap headerMap; + settings_->response->GetHeaderMap(headerMap); + settings_->response->SetHeaderMap(headerMap); + + response_length = static_cast(settings_->response_data.size()); + } + + bool Read(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); + EXPECT_EQ(settings_->incomplete_type, + RequestRunSettings::INCOMPLETE_READ_RESPONSE); + + read_ct_++; + + // Never release or execute this callback. + incomplete_read_callback_ = callback; + bytes_read = 0; + return true; + } + + bool ReadResponse(void* data_out, + int bytes_to_read, + int& bytes_read, + CefRefPtr callback) override { + EXPECT_TRUE(false); // Not reached. + bytes_read = -2; + return false; + } + + void Cancel() override { + EXPECT_IO_THREAD(); + cancel_ct_++; + } + + private: + RequestRunSettings* const settings_; + const base::Closure destroy_callback_; + + int open_ct_ = 0; + int get_response_headers_ct_ = 0; + int read_ct_ = 0; + int cancel_ct_ = 0; + + CefRefPtr incomplete_open_callback_; + CefRefPtr incomplete_read_callback_; + IMPLEMENT_REFCOUNTING(IncompleteSchemeHandler); DISALLOW_COPY_AND_ASSIGN(IncompleteSchemeHandler); }; @@ -805,10 +1096,21 @@ class RequestSchemeHandlerFactory : public CefSchemeHandlerFactory { if (entry.type == RequestDataMap::Entry::TYPE_NORMAL) { if (entry.settings->incomplete_type == RequestRunSettings::INCOMPLETE_NONE) { + if (TestOldResourceAPI()) { + return new RequestSchemeHandlerOld(entry.settings, destroy_callback); + } return new RequestSchemeHandler(entry.settings, destroy_callback); } + + if (TestOldResourceAPI()) { + return new IncompleteSchemeHandlerOld(entry.settings, destroy_callback); + } return new IncompleteSchemeHandler(entry.settings, destroy_callback); } else if (entry.type == RequestDataMap::Entry::TYPE_REDIRECT) { + if (TestOldResourceAPI()) { + return new RequestRedirectSchemeHandlerOld( + entry.redirect_request, entry.redirect_response, destroy_callback); + } return new RequestRedirectSchemeHandler( entry.redirect_request, entry.redirect_response, destroy_callback); } @@ -882,6 +1184,7 @@ class RequestSchemeHandlerFactory : public CefSchemeHandlerFactory { base::Closure shutdown_callback_; IMPLEMENT_REFCOUNTING(RequestSchemeHandlerFactory); + DISALLOW_COPY_AND_ASSIGN(RequestSchemeHandlerFactory); }; // SERVER BACKEND