Convert usage and tests to the new CefResourceHandler API (see issue #2622)

Limited test coverage for the old API is still available by passing the
`--test-old-resource-api` command-line flag to ceftests.
This commit is contained in:
Marshall Greenblatt 2019-12-31 14:24:10 +02:00
parent dfcfb51bef
commit 1c88c74f86
12 changed files with 1293 additions and 409 deletions

View File

@ -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<CefStreamReader> stream);
virtual ~CefStreamResourceHandler();
// CefResourceHandler methods.
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) OVERRIDE;
virtual void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length,
CefString& redirectUrl) OVERRIDE;
virtual bool ReadResponse(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefCallback> callback) OVERRIDE;
virtual void Cancel() OVERRIDE;
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> callback) OVERRIDE;
void GetResponseHeaders(CefRefPtr<CefResponse> response,
int64& response_length,
CefString& redirectUrl) OVERRIDE;
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> callback) OVERRIDE;
void Cancel() OVERRIDE;
private:
void ReadOnFileThread(int bytes_to_read, CefRefPtr<CefCallback> callback);
const int status_code_;
const CefString status_text_;
const CefString mime_type_;
const CefResponse::HeaderMap header_map_;
const CefRefPtr<CefStreamReader> stream_;
bool read_on_file_thread_;
class Buffer;
scoped_ptr<Buffer> 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);

View File

@ -52,9 +52,11 @@ class RedirectHandler : public CefResourceHandler {
public:
explicit RedirectHandler(const GURL& url) : url_(url) {}
bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
callback->Continue();
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefCallback> callback) override {
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
callback->Continue();
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefCallback> 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<CefResourceReadCallback> 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<int>(
reader_->Read(static_cast<char*>(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<InternalHandlerDelegate> delegate_;
IMPLEMENT_REFCOUNTING(InternalHandlerFactory);
DISALLOW_COPY_AND_ASSIGN(InternalHandlerFactory);
};
} // namespace

View File

@ -6,84 +6,19 @@
#include <algorithm>
#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<CefStreamReader> 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<int>(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<char[]> buffer_;
int size_;
int bytes_requested_;
int bytes_written_;
int bytes_read_;
DISALLOW_COPY_AND_ASSIGN(Buffer);
};
CefStreamResourceHandler::CefStreamResourceHandler(
const CefString& mime_type,
CefRefPtr<CefStreamReader> 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<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> callback) {
DCHECK(!CefCurrentlyOn(TID_UI) && !CefCurrentlyOn(TID_IO));
bool CefStreamResourceHandler::ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) {
callback->Continue();
// Continue the request immediately.
handle_request = true;
return true;
}
@ -119,6 +50,8 @@ void CefStreamResourceHandler::GetResponseHeaders(
CefRefPtr<CefResponse> 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<CefCallback> callback) {
bool CefStreamResourceHandler::Read(
void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<int>(
stream_->Read(static_cast<char*>(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<int>(
stream_->Read(static_cast<char*>(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<CefCallback> 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();
}

View File

@ -28,9 +28,13 @@ class ClientSchemeHandler : public CefResourceHandler {
public:
ClientSchemeHandler() : offset_(0) {}
virtual bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) OVERRIDE {
CEF_REQUIRE_IO_THREAD();
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefResponse> response,
int64& response_length,
CefString& redirectUrl) OVERRIDE {
void GetResponseHeaders(CefRefPtr<CefResponse> 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<CefCallback> callback) OVERRIDE {
CEF_REQUIRE_IO_THREAD();
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefResourceHandler> Create(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& scheme_name,
CefRefPtr<CefRequest> request) OVERRIDE {
CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
const CefString& scheme_name,
CefRefPtr<CefRequest> request) OVERRIDE {
CEF_REQUIRE_IO_THREAD();
return new ClientSchemeHandler();
}
IMPLEMENT_REFCOUNTING(ClientSchemeHandlerFactory);
DISALLOW_COPY_AND_ASSIGN(ClientSchemeHandlerFactory);
};
} // namespace

View File

@ -709,8 +709,11 @@ class CookieTestSchemeHandler : public TestHandler {
explicit SchemeHandler(CookieTestSchemeHandler* handler)
: handler_(handler), offset_(0) {}
bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> callback) override {
EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO));
std::string url = request->GetURL();
if (url == handler_->url1_) {
content_ = "<html><body>COOKIE TEST1</body></html>";
@ -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<CefCallback> callback) override {
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_IO_THREAD();
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefCallback> callback) override {
EXPECT_IO_THREAD();
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<int>(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,

View File

@ -22,7 +22,7 @@ const char kTestContentDisposition[] =
const char kTestMimeType[] = "text/plain";
const char kTestContent[] = "Download test text";
typedef base::Callback<void(CefRefPtr<CefCallback> /*callback*/)> DelayCallback;
typedef base::Callback<void(const base::Closure& /*callback*/)> DelayCallback;
class DownloadSchemeHandler : public CefResourceHandler {
public:
@ -33,8 +33,11 @@ class DownloadSchemeHandler : public CefResourceHandler {
should_delay_(false),
offset_(0) {}
bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefCallback> callback) override {
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefResourceReadCallback> 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<CefResourceReadCallback> 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<CefCallback> 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<CefRequestContext> request_context_;
// Used with NAVIGATED and PENDING test modes.
CefRefPtr<CefCallback> delay_callback_;
base::Closure delay_callback_;
// Used with PENDING test mode.
CefRefPtr<CefDownloadItemCallback> download_item_callback_;

View File

@ -688,9 +688,10 @@ class RedirectSchemeHandler : public CefResourceHandler {
public:
RedirectSchemeHandler() : offset_(0), status_(0) {}
bool ProcessRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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_ = "<html><body>Nav4</body></html>";
}
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<CefResponse> 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<CefCallback> callback) override {
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
callback->Continue();
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefCallback> callback) override {
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefCallback> callback_;
CefRefPtr<CefResourceReadCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
callback->Continue();
bool Open(CefRefPtr<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefCallback> callback) override {
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefCallback> callback_;
CefRefPtr<CefResourceReadCallback> callback_;
IMPLEMENT_REFCOUNTING(StalledSchemeHandler);
DISALLOW_COPY_AND_ASSIGN(StalledSchemeHandler);
};
// Browser side.

View File

@ -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<CefStreamReader> 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<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefResponse> 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<CefResourceReadCallback> 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<CefResourceReadCallback> 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<int>(
stream_->Read(static_cast<char*>(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<CefStreamReader> 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<CefCallback> 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<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
return false;
}
void GetResponseHeaders(CefRefPtr<CefResponse> 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<CefResourceReadCallback> 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<CefCallback> 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<CefCallback> incomplete_open_callback_;
CefRefPtr<CefResourceReadCallback> 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<CefResourceHandler> 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<CefResourceHandler> GetResource(int status_code,
const CefString& status_text,
const CefString& mime_type,
CefResponse::HeaderMap header_map,
const std::string& body) {
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
const_cast<char*>(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<CefResourceHandler> GetOKResource() {
return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
GetResponseBody());
}
CefRefPtr<CefResourceHandler> GetRedirectResource(
const std::string& redirect_url) {
const std::string& body = GetRedirectBody();
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
const_cast<char*>(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<CefResourceHandler> 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<CefResourceHandler> 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<CefResourceHandler> GetResource(int status_code,
const CefString& status_text,
const CefString& mime_type,
CefResponse::HeaderMap header_map,
const std::string& body) {
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
const_cast<char*>(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<CefResourceHandler> GetMainResource() {
return GetResource(200, "OK", "text/html", CefResponse::HeaderMap(),
GetMainResponseBody());
}
CefRefPtr<CefResourceHandler> GetSubResource() {
const std::string& body = GetSubResponseBody();
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
const_cast<char*>(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<CefResourceHandler> GetOKResource() {
const std::string& body = GetResponseBody();
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
const_cast<char*>(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<CefResourceHandler> GetRedirectResource(
const std::string& redirect_url) {
const std::string& body = GetRedirectBody();
CefRefPtr<CefStreamReader> stream = CefStreamReader::CreateForData(
const_cast<char*>(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<CefResourceHandler> 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)

View File

@ -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<CefRequest> 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<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
return false;
}
void GetResponseHeaders(CefRefPtr<CefResponse> 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<CefResourceReadCallback> 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<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
bytes_read = -2;
return false;
}
private:
void ContinueAfterDelay(void* data_out,
int bytes_to_read,
CefRefPtr<CefResourceReadCallback> 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<int>(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<CefRequest> 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.

View File

@ -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<CefString>& val1,
EXPECT_STREQ(val1[i].ToString().c_str(), val2[i].ToString().c_str());
}
bool TestOldResourceAPI() {
static int state = -1;
if (state == -1) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
state = command_line->HasSwitch("test-old-resource-api") ? 1 : 0;
}
return state ? true : false;
}
CefRefPtr<CefRequestContext> CreateTestRequestContext(
TestRequestContextMode mode,
const std::string& cache_path) {

View File

@ -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.

View File

@ -546,13 +546,13 @@ bool IsAuthorized(CefRefPtr<CefRequest> 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<CefCallback> callback) override {
@ -593,8 +593,7 @@ class RequestSchemeHandler : public CefResourceHandler {
if (offset_ < size) {
int transfer_size =
std::min(bytes_to_read, static_cast<int>(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<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
return false;
}
void GetResponseHeaders(CefRefPtr<CefResponse> 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<CefResourceReadCallback> 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<int>(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<CefCallback> 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<CefRequest> request,
CefRefPtr<CefResponse> response,
const base::Closure& destroy_callback)
RequestRedirectSchemeHandlerOld(CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> 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<CefRequest> request_;
CefRefPtr<CefResponse> response_;
base::Closure destroy_callback_;
int cancel_ct_ = 0;
IMPLEMENT_REFCOUNTING(RequestRedirectSchemeHandlerOld);
DISALLOW_COPY_AND_ASSIGN(RequestRedirectSchemeHandlerOld);
};
class RequestRedirectSchemeHandler : public CefResourceHandler {
public:
RequestRedirectSchemeHandler(CefRefPtr<CefRequest> request,
CefRefPtr<CefResponse> 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<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
return false;
}
void GetResponseHeaders(CefRefPtr<CefResponse> 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<CefResourceReadCallback> 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<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
bytes_read = -2;
return false;
}
void Cancel() override {
EXPECT_IO_THREAD();
cancel_ct_++;
}
private:
CefRefPtr<CefRequest> request_;
CefRefPtr<CefResponse> 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<CefCallback> 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<CefRequest> request,
bool& handle_request,
CefRefPtr<CefCallback> 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<CefRequest> request,
CefRefPtr<CefCallback> callback) override {
EXPECT_TRUE(false); // Not reached.
return false;
}
void GetResponseHeaders(CefRefPtr<CefResponse> 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<int64>(settings_->response_data.size());
}
bool Read(void* data_out,
int bytes_to_read,
int& bytes_read,
CefRefPtr<CefResourceReadCallback> 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<CefCallback> 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<CefCallback> incomplete_open_callback_;
CefRefPtr<CefResourceReadCallback> 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