mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
Add callbacks for network request access to cookies (issue #2374)
This commit is contained in:
@@ -10,8 +10,10 @@
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/base/cef_scoped_ptr.h"
|
||||
#include "include/cef_cookie.h"
|
||||
#include "include/cef_server.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
#include "include/wrapper/cef_stream_resource_handler.h"
|
||||
#include "tests/ceftests/routing_test_handler.h"
|
||||
#include "tests/ceftests/test_handler.h"
|
||||
#include "tests/ceftests/test_util.h"
|
||||
#include "tests/gtest/include/gtest/gtest.h"
|
||||
@@ -1681,6 +1683,910 @@ TEST(RequestHandlerTest, ResponseFilterError) {
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const char kCookieAccessScheme[] = "http";
|
||||
const char kCookieAccessDomain[] = "test-cookies.com";
|
||||
const char kCookieAccessServerIP[] = "127.0.0.1";
|
||||
const uint16 kCookieAccessServerPort = 8099;
|
||||
|
||||
std::string GetCookieAccessOrigin(bool server_backend) {
|
||||
std::stringstream ss;
|
||||
if (server_backend) {
|
||||
ss << kCookieAccessScheme << "://" << kCookieAccessServerIP << ":"
|
||||
<< kCookieAccessServerPort;
|
||||
} else {
|
||||
ss << kCookieAccessScheme << "://" << kCookieAccessDomain;
|
||||
}
|
||||
ss << "/";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string GetCookieAccessUrl1(bool server_backend) {
|
||||
return GetCookieAccessOrigin(server_backend) + "cookie1.html";
|
||||
}
|
||||
|
||||
std::string GetCookieAccessUrl2(bool server_backend) {
|
||||
return GetCookieAccessOrigin(server_backend) + "cookie2.html";
|
||||
}
|
||||
|
||||
void TestCookieString(const std::string& cookie_str,
|
||||
TrackCallback& got_cookie_js,
|
||||
TrackCallback& got_cookie_net) {
|
||||
if (cookie_str.find("name_js=value_js") != std::string::npos) {
|
||||
got_cookie_js.yes();
|
||||
}
|
||||
if (cookie_str.find("name_net=value_net") != std::string::npos) {
|
||||
got_cookie_net.yes();
|
||||
}
|
||||
}
|
||||
|
||||
struct CookieAccessData {
|
||||
CefRefPtr<CefResponse> response;
|
||||
std::string response_data;
|
||||
|
||||
TrackCallback got_request_;
|
||||
TrackCallback got_cookie_js_;
|
||||
TrackCallback got_cookie_net_;
|
||||
|
||||
// Only used with scheme handler backend.
|
||||
TrackCallback got_can_set_cookie_js_;
|
||||
TrackCallback got_can_set_cookie_net_;
|
||||
TrackCallback got_can_get_cookie_js_;
|
||||
TrackCallback got_can_get_cookie_net_;
|
||||
};
|
||||
|
||||
class CookieAccessResponseHandler {
|
||||
public:
|
||||
CookieAccessResponseHandler() {}
|
||||
virtual void AddResponse(const std::string& url, CookieAccessData* data) = 0;
|
||||
|
||||
protected:
|
||||
virtual ~CookieAccessResponseHandler() {}
|
||||
};
|
||||
|
||||
std::string GetHeaderValue(const CefServer::HeaderMap& header_map,
|
||||
const std::string& header_name) {
|
||||
CefServer::HeaderMap::const_iterator it = header_map.find(header_name);
|
||||
if (it != header_map.end())
|
||||
return it->second;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// Serves request responses.
|
||||
class CookieAccessSchemeHandler : public CefResourceHandler {
|
||||
public:
|
||||
explicit CookieAccessSchemeHandler(CookieAccessData* data)
|
||||
: data_(data), offset_(0) {}
|
||||
|
||||
bool ProcessRequest(CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefCallback> callback) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
|
||||
CefRequest::HeaderMap headerMap;
|
||||
request->GetHeaderMap(headerMap);
|
||||
const std::string& cookie_str = GetHeaderValue(headerMap, "Cookie");
|
||||
TestCookieString(cookie_str, data_->got_cookie_js_, data_->got_cookie_net_);
|
||||
|
||||
// Continue immediately.
|
||||
callback->Continue();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GetResponseHeaders(CefRefPtr<CefResponse> response,
|
||||
int64& response_length,
|
||||
CefString& redirectUrl) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
|
||||
response->SetStatus(data_->response->GetStatus());
|
||||
response->SetStatusText(data_->response->GetStatusText());
|
||||
response->SetMimeType(data_->response->GetMimeType());
|
||||
|
||||
CefResponse::HeaderMap headerMap;
|
||||
data_->response->GetHeaderMap(headerMap);
|
||||
response->SetHeaderMap(headerMap);
|
||||
|
||||
response_length = data_->response_data.length();
|
||||
}
|
||||
|
||||
bool ReadResponse(void* response_data_out,
|
||||
int bytes_to_read,
|
||||
int& bytes_read,
|
||||
CefRefPtr<CefCallback> callback) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
|
||||
bool has_data = false;
|
||||
bytes_read = 0;
|
||||
|
||||
size_t size = data_->response_data.length();
|
||||
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);
|
||||
offset_ += transfer_size;
|
||||
|
||||
bytes_read = transfer_size;
|
||||
has_data = true;
|
||||
}
|
||||
|
||||
return has_data;
|
||||
}
|
||||
|
||||
bool CanGetCookie(const CefCookie& cookie) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
TestCookie(cookie, data_->got_can_get_cookie_js_,
|
||||
data_->got_can_get_cookie_net_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CanSetCookie(const CefCookie& cookie) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
TestCookie(cookie, data_->got_can_set_cookie_js_,
|
||||
data_->got_can_set_cookie_net_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Cancel() override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); }
|
||||
|
||||
private:
|
||||
static void TestCookie(const CefCookie& cookie,
|
||||
TrackCallback& got_cookie_js,
|
||||
TrackCallback& got_cookie_net) {
|
||||
const std::string& cookie_name = CefString(&cookie.name);
|
||||
const std::string& cookie_val = CefString(&cookie.value);
|
||||
if (cookie_name == "name_js") {
|
||||
EXPECT_STREQ("value_js", cookie_val.c_str());
|
||||
got_cookie_js.yes();
|
||||
} else if (cookie_name == "name_net") {
|
||||
EXPECT_STREQ("value_net", cookie_val.c_str());
|
||||
got_cookie_net.yes();
|
||||
} else {
|
||||
ADD_FAILURE() << "Unexpected cookie: " << cookie_name;
|
||||
}
|
||||
}
|
||||
|
||||
// |data_| is not owned by this object.
|
||||
CookieAccessData* data_;
|
||||
|
||||
size_t offset_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CookieAccessSchemeHandler);
|
||||
};
|
||||
|
||||
class CookieAccessSchemeHandlerFactory : public CefSchemeHandlerFactory,
|
||||
public CookieAccessResponseHandler {
|
||||
public:
|
||||
CookieAccessSchemeHandlerFactory() {}
|
||||
|
||||
CefRefPtr<CefResourceHandler> Create(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
const CefString& scheme_name,
|
||||
CefRefPtr<CefRequest> request) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
const std::string& url = request->GetURL();
|
||||
ResponseDataMap::const_iterator it = data_map_.find(url);
|
||||
if (it != data_map_.end()) {
|
||||
it->second->got_request_.yes();
|
||||
|
||||
// There should be no cookie data in this callback.
|
||||
CefRequest::HeaderMap headerMap;
|
||||
request->GetHeaderMap(headerMap);
|
||||
EXPECT_TRUE(headerMap.find("Cookie") == headerMap.end());
|
||||
|
||||
return new CookieAccessSchemeHandler(it->second);
|
||||
}
|
||||
|
||||
// Unknown test.
|
||||
ADD_FAILURE() << "Unexpected url: " << url;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AddResponse(const std::string& url, CookieAccessData* data) override {
|
||||
data_map_.insert(std::make_pair(url, data));
|
||||
}
|
||||
|
||||
void Shutdown(const base::Closure& complete_callback) {
|
||||
if (!CefCurrentlyOn(TID_IO)) {
|
||||
CefPostTask(TID_IO,
|
||||
base::Bind(&CookieAccessSchemeHandlerFactory::Shutdown, this,
|
||||
complete_callback));
|
||||
return;
|
||||
}
|
||||
|
||||
complete_callback.Run();
|
||||
}
|
||||
|
||||
private:
|
||||
// Map of URL to Data.
|
||||
typedef std::map<std::string, CookieAccessData*> ResponseDataMap;
|
||||
ResponseDataMap data_map_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CookieAccessSchemeHandlerFactory);
|
||||
};
|
||||
|
||||
// HTTP server handler.
|
||||
class CookieAccessServerHandler : public CefServerHandler,
|
||||
public CookieAccessResponseHandler {
|
||||
public:
|
||||
CookieAccessServerHandler()
|
||||
: initialized_(false),
|
||||
expected_connection_ct_(-1),
|
||||
actual_connection_ct_(0),
|
||||
expected_http_request_ct_(-1),
|
||||
actual_http_request_ct_(0) {}
|
||||
|
||||
virtual ~CookieAccessServerHandler() { RunCompleteCallback(); }
|
||||
|
||||
// Must be called before CreateServer().
|
||||
void AddResponse(const std::string& url, CookieAccessData* data) override {
|
||||
EXPECT_FALSE(initialized_);
|
||||
data_map_.insert(std::make_pair(url, data));
|
||||
}
|
||||
|
||||
// Must be called before CreateServer().
|
||||
void SetExpectedRequestCount(int count) {
|
||||
EXPECT_FALSE(initialized_);
|
||||
expected_connection_ct_ = expected_http_request_ct_ = count;
|
||||
}
|
||||
|
||||
// |complete_callback| will be executed on the UI thread after the server is
|
||||
// started.
|
||||
void CreateServer(const base::Closure& complete_callback) {
|
||||
EXPECT_UI_THREAD();
|
||||
|
||||
if (expected_connection_ct_ < 0) {
|
||||
// Default to the assumption of one request per registered URL.
|
||||
SetExpectedRequestCount(static_cast<int>(data_map_.size()));
|
||||
}
|
||||
|
||||
EXPECT_FALSE(initialized_);
|
||||
initialized_ = true;
|
||||
|
||||
EXPECT_TRUE(complete_callback_.is_null());
|
||||
complete_callback_ = complete_callback;
|
||||
|
||||
CefServer::CreateServer(kCookieAccessServerIP, kCookieAccessServerPort, 10,
|
||||
this);
|
||||
}
|
||||
|
||||
// Results in a call to VerifyResults() and eventual execution of the
|
||||
// |complete_callback| on the UI thread via CookieAccessServerHandler
|
||||
// destruction.
|
||||
void ShutdownServer(const base::Closure& complete_callback) {
|
||||
EXPECT_UI_THREAD();
|
||||
|
||||
EXPECT_TRUE(complete_callback_.is_null());
|
||||
complete_callback_ = complete_callback;
|
||||
|
||||
EXPECT_TRUE(server_);
|
||||
if (server_)
|
||||
server_->Shutdown();
|
||||
}
|
||||
|
||||
void OnServerCreated(CefRefPtr<CefServer> server) override {
|
||||
EXPECT_TRUE(server);
|
||||
EXPECT_TRUE(server->IsRunning());
|
||||
EXPECT_FALSE(server->HasConnection());
|
||||
|
||||
EXPECT_FALSE(got_server_created_);
|
||||
got_server_created_.yes();
|
||||
|
||||
EXPECT_FALSE(server_);
|
||||
server_ = server;
|
||||
|
||||
EXPECT_FALSE(server_runner_);
|
||||
server_runner_ = server_->GetTaskRunner();
|
||||
EXPECT_TRUE(server_runner_);
|
||||
EXPECT_TRUE(server_runner_->BelongsToCurrentThread());
|
||||
|
||||
CefPostTask(
|
||||
TID_UI,
|
||||
base::Bind(&CookieAccessServerHandler::RunCompleteCallback, this));
|
||||
}
|
||||
|
||||
void OnServerDestroyed(CefRefPtr<CefServer> server) override {
|
||||
EXPECT_TRUE(VerifyServer(server));
|
||||
EXPECT_FALSE(server->IsRunning());
|
||||
EXPECT_FALSE(server->HasConnection());
|
||||
|
||||
EXPECT_FALSE(got_server_destroyed_);
|
||||
got_server_destroyed_.yes();
|
||||
|
||||
server_ = nullptr;
|
||||
|
||||
VerifyResults();
|
||||
}
|
||||
|
||||
void OnClientConnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {
|
||||
EXPECT_TRUE(VerifyServer(server));
|
||||
EXPECT_TRUE(server->HasConnection());
|
||||
EXPECT_TRUE(server->IsValidConnection(connection_id));
|
||||
|
||||
EXPECT_TRUE(connection_id_set_.find(connection_id) ==
|
||||
connection_id_set_.end());
|
||||
connection_id_set_.insert(connection_id);
|
||||
|
||||
actual_connection_ct_++;
|
||||
}
|
||||
|
||||
void OnClientDisconnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {
|
||||
EXPECT_TRUE(VerifyServer(server));
|
||||
EXPECT_FALSE(server->IsValidConnection(connection_id));
|
||||
|
||||
ConnectionIdSet::iterator it = connection_id_set_.find(connection_id);
|
||||
EXPECT_TRUE(it != connection_id_set_.end());
|
||||
connection_id_set_.erase(it);
|
||||
}
|
||||
|
||||
void OnHttpRequest(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request) override {
|
||||
EXPECT_TRUE(VerifyServer(server));
|
||||
EXPECT_TRUE(VerifyConnection(connection_id));
|
||||
EXPECT_FALSE(client_address.empty());
|
||||
|
||||
// Log the requests for better error reporting.
|
||||
request_log_ += request->GetMethod().ToString() + " " +
|
||||
request->GetURL().ToString() + "\n";
|
||||
|
||||
HandleRequest(server, connection_id, request);
|
||||
|
||||
actual_http_request_ct_++;
|
||||
}
|
||||
|
||||
void OnWebSocketRequest(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
const CefString& client_address,
|
||||
CefRefPtr<CefRequest> request,
|
||||
CefRefPtr<CefCallback> callback) override {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OnWebSocketConnected(CefRefPtr<CefServer> server,
|
||||
int connection_id) override {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
void OnWebSocketMessage(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
const void* data,
|
||||
size_t data_size) override {
|
||||
NOTREACHED();
|
||||
}
|
||||
|
||||
private:
|
||||
bool RunningOnServerThread() {
|
||||
return server_runner_ && server_runner_->BelongsToCurrentThread();
|
||||
}
|
||||
|
||||
bool VerifyServer(CefRefPtr<CefServer> server) {
|
||||
V_DECLARE();
|
||||
V_EXPECT_TRUE(RunningOnServerThread());
|
||||
V_EXPECT_TRUE(server);
|
||||
V_EXPECT_TRUE(server_);
|
||||
V_EXPECT_TRUE(server->GetAddress().ToString() ==
|
||||
server_->GetAddress().ToString());
|
||||
V_RETURN();
|
||||
}
|
||||
|
||||
bool VerifyConnection(int connection_id) {
|
||||
return connection_id_set_.find(connection_id) != connection_id_set_.end();
|
||||
}
|
||||
|
||||
void VerifyResults() {
|
||||
EXPECT_TRUE(RunningOnServerThread());
|
||||
|
||||
EXPECT_TRUE(got_server_created_);
|
||||
EXPECT_TRUE(got_server_destroyed_);
|
||||
EXPECT_TRUE(connection_id_set_.empty());
|
||||
EXPECT_EQ(expected_connection_ct_, actual_connection_ct_) << request_log_;
|
||||
EXPECT_EQ(expected_http_request_ct_, actual_http_request_ct_)
|
||||
<< request_log_;
|
||||
}
|
||||
|
||||
void HandleRequest(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
CefRefPtr<CefRequest> request) {
|
||||
const std::string& url = request->GetURL();
|
||||
ResponseDataMap::const_iterator it = data_map_.find(url);
|
||||
if (it != data_map_.end()) {
|
||||
it->second->got_request_.yes();
|
||||
|
||||
CefRequest::HeaderMap headerMap;
|
||||
request->GetHeaderMap(headerMap);
|
||||
const std::string& cookie_str = GetHeaderValue(headerMap, "cookie");
|
||||
TestCookieString(cookie_str, it->second->got_cookie_js_,
|
||||
it->second->got_cookie_net_);
|
||||
|
||||
SendResponse(server, connection_id, it->second->response,
|
||||
it->second->response_data);
|
||||
} else {
|
||||
// Unknown test.
|
||||
ADD_FAILURE() << "Unexpected url: " << url;
|
||||
server->SendHttp500Response(connection_id, "Unknown test");
|
||||
}
|
||||
}
|
||||
|
||||
void SendResponse(CefRefPtr<CefServer> server,
|
||||
int connection_id,
|
||||
CefRefPtr<CefResponse> response,
|
||||
const std::string& response_data) {
|
||||
int response_code = response->GetStatus();
|
||||
const CefString& content_type = response->GetMimeType();
|
||||
int64 content_length = static_cast<int64>(response_data.size());
|
||||
|
||||
CefResponse::HeaderMap extra_headers;
|
||||
response->GetHeaderMap(extra_headers);
|
||||
|
||||
server->SendHttpResponse(connection_id, response_code, content_type,
|
||||
content_length, extra_headers);
|
||||
|
||||
if (content_length != 0) {
|
||||
server->SendRawData(connection_id, response_data.data(),
|
||||
response_data.size());
|
||||
server->CloseConnection(connection_id);
|
||||
}
|
||||
|
||||
// The connection should be closed.
|
||||
EXPECT_FALSE(server->IsValidConnection(connection_id));
|
||||
}
|
||||
|
||||
void RunCompleteCallback() {
|
||||
EXPECT_UI_THREAD();
|
||||
|
||||
EXPECT_FALSE(complete_callback_.is_null());
|
||||
complete_callback_.Run();
|
||||
complete_callback_.Reset();
|
||||
}
|
||||
|
||||
// Map of URL to Data.
|
||||
typedef std::map<std::string, CookieAccessData*> ResponseDataMap;
|
||||
ResponseDataMap data_map_;
|
||||
|
||||
CefRefPtr<CefServer> server_;
|
||||
CefRefPtr<CefTaskRunner> server_runner_;
|
||||
bool initialized_;
|
||||
|
||||
// Only accessed on the UI thread.
|
||||
base::Closure complete_callback_;
|
||||
|
||||
// After initialization the below members are only accessed on the server
|
||||
// thread.
|
||||
|
||||
TrackCallback got_server_created_;
|
||||
TrackCallback got_server_destroyed_;
|
||||
|
||||
typedef std::set<int> ConnectionIdSet;
|
||||
ConnectionIdSet connection_id_set_;
|
||||
|
||||
int expected_connection_ct_;
|
||||
int actual_connection_ct_;
|
||||
int expected_http_request_ct_;
|
||||
int actual_http_request_ct_;
|
||||
|
||||
std::string request_log_;
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CookieAccessServerHandler);
|
||||
DISALLOW_COPY_AND_ASSIGN(CookieAccessServerHandler);
|
||||
};
|
||||
|
||||
class CookieAccessTestHandler : public RoutingTestHandler {
|
||||
public:
|
||||
enum TestMode {
|
||||
ALLOW = 0,
|
||||
BLOCK_READ = 1 << 0,
|
||||
BLOCK_WRITE = 1 << 1,
|
||||
BLOCK_ALL = BLOCK_READ | BLOCK_WRITE,
|
||||
};
|
||||
|
||||
CookieAccessTestHandler(TestMode test_mode, bool server_backend)
|
||||
: test_mode_(test_mode), server_backend_(server_backend) {}
|
||||
|
||||
void RunTest() override {
|
||||
cookie_manager_ = CefCookieManager::GetGlobalManager(nullptr);
|
||||
SetTestTimeout();
|
||||
|
||||
CefPostTask(TID_UI,
|
||||
base::Bind(&CookieAccessTestHandler::StartBackend, this,
|
||||
base::Bind(&CookieAccessTestHandler::RunTestContinue,
|
||||
this)));
|
||||
}
|
||||
|
||||
void DestroyTest() override {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI,
|
||||
base::Bind(&CookieAccessTestHandler::DestroyTest, this));
|
||||
return;
|
||||
}
|
||||
|
||||
cookie_manager_ = NULL;
|
||||
|
||||
// Always get a call to CanSetCookie for the 1st network request due to the
|
||||
// network cookie.
|
||||
EXPECT_TRUE(got_can_set_cookie1_);
|
||||
// Always get a call to CanGetCookies for the 2nd network request due to the
|
||||
// JS cookie.
|
||||
EXPECT_TRUE(got_can_get_cookies2_);
|
||||
|
||||
// Always get the JS cookie via JS.
|
||||
EXPECT_TRUE(got_cookie_js1_);
|
||||
EXPECT_TRUE(got_cookie_js2_);
|
||||
EXPECT_TRUE(got_cookie_js3_);
|
||||
|
||||
// Only get the net cookie via JS if cookie write was allowed.
|
||||
if (test_mode_ & BLOCK_WRITE) {
|
||||
EXPECT_FALSE(got_cookie_net1_);
|
||||
EXPECT_FALSE(got_cookie_net2_);
|
||||
EXPECT_FALSE(got_cookie_net3_);
|
||||
} else {
|
||||
EXPECT_TRUE(got_cookie_net1_);
|
||||
EXPECT_TRUE(got_cookie_net2_);
|
||||
EXPECT_TRUE(got_cookie_net3_);
|
||||
}
|
||||
|
||||
// Got both network requests.
|
||||
EXPECT_TRUE(data1_.got_request_);
|
||||
EXPECT_TRUE(data2_.got_request_);
|
||||
|
||||
// No cookies sent for the 1st network request.
|
||||
EXPECT_FALSE(data1_.got_cookie_js_);
|
||||
EXPECT_FALSE(data1_.got_cookie_net_);
|
||||
|
||||
// 2nd network request...
|
||||
if (test_mode_ & BLOCK_READ) {
|
||||
// No cookies sent if reading was blocked.
|
||||
EXPECT_FALSE(data2_.got_cookie_js_);
|
||||
EXPECT_FALSE(data2_.got_cookie_net_);
|
||||
} else if (test_mode_ & BLOCK_WRITE) {
|
||||
// Only JS cookie sent if writing was blocked.
|
||||
EXPECT_TRUE(data2_.got_cookie_js_);
|
||||
EXPECT_FALSE(data2_.got_cookie_net_);
|
||||
} else {
|
||||
// All cookies sent.
|
||||
EXPECT_TRUE(data2_.got_cookie_js_);
|
||||
EXPECT_TRUE(data2_.got_cookie_net_);
|
||||
}
|
||||
|
||||
if (!server_backend_) {
|
||||
// No query to get cookies with the 1st network request because none have
|
||||
// been set yet.
|
||||
EXPECT_FALSE(data1_.got_can_get_cookie_js_);
|
||||
EXPECT_FALSE(data1_.got_can_get_cookie_net_);
|
||||
|
||||
// JS cookie is not set via a network request.
|
||||
EXPECT_FALSE(data1_.got_can_set_cookie_js_);
|
||||
EXPECT_FALSE(data2_.got_can_set_cookie_js_);
|
||||
|
||||
// No query to set the net cookie for the 1st network request if write was
|
||||
// blocked.
|
||||
if (test_mode_ & BLOCK_WRITE) {
|
||||
EXPECT_FALSE(data1_.got_can_set_cookie_net_);
|
||||
} else {
|
||||
EXPECT_TRUE(data1_.got_can_set_cookie_net_);
|
||||
}
|
||||
|
||||
// Net cookie is not set via the 2nd network request.
|
||||
EXPECT_FALSE(data2_.got_can_set_cookie_net_);
|
||||
|
||||
// No query to get the JS cookie for the 2nd network request if read was
|
||||
// blocked.
|
||||
if (test_mode_ & BLOCK_READ) {
|
||||
EXPECT_FALSE(data2_.got_can_get_cookie_js_);
|
||||
} else {
|
||||
EXPECT_TRUE(data2_.got_can_get_cookie_js_);
|
||||
}
|
||||
|
||||
// No query to get the net cookie for the 2nd network request if read or
|
||||
// write (of the net cookie) was blocked.
|
||||
if (test_mode_ & (BLOCK_READ | BLOCK_WRITE)) {
|
||||
EXPECT_FALSE(data2_.got_can_get_cookie_net_);
|
||||
} else {
|
||||
EXPECT_TRUE(data2_.got_can_get_cookie_net_);
|
||||
}
|
||||
}
|
||||
|
||||
TestHandler::DestroyTest();
|
||||
}
|
||||
|
||||
bool CanGetCookies(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
|
||||
const std::string& url = request->GetURL();
|
||||
if (url == GetCookieAccessUrl2(server_backend_)) {
|
||||
EXPECT_FALSE(got_can_get_cookies2_);
|
||||
got_can_get_cookies2_.yes();
|
||||
} else {
|
||||
ADD_FAILURE() << "Unexpected url: " << url;
|
||||
}
|
||||
|
||||
return !(test_mode_ & BLOCK_READ);
|
||||
}
|
||||
|
||||
bool CanSetCookie(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
CefRefPtr<CefRequest> request,
|
||||
const CefCookie& cookie) override {
|
||||
EXPECT_TRUE(CefCurrentlyOn(TID_IO));
|
||||
|
||||
// Expecting the network cookie only.
|
||||
EXPECT_STREQ("name_net", CefString(&cookie.name).ToString().c_str());
|
||||
EXPECT_STREQ("value_net", CefString(&cookie.value).ToString().c_str());
|
||||
|
||||
const std::string& url = request->GetURL();
|
||||
if (url == GetCookieAccessUrl1(server_backend_)) {
|
||||
EXPECT_FALSE(got_can_set_cookie1_);
|
||||
got_can_set_cookie1_.yes();
|
||||
} else {
|
||||
ADD_FAILURE() << "Unexpected url: " << url;
|
||||
}
|
||||
|
||||
return !(test_mode_ & BLOCK_WRITE);
|
||||
}
|
||||
|
||||
bool OnQuery(CefRefPtr<CefBrowser> browser,
|
||||
CefRefPtr<CefFrame> frame,
|
||||
int64 query_id,
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) override {
|
||||
const std::string& url = frame->GetURL();
|
||||
const std::string& cookie_str = request.ToString();
|
||||
if (url == GetCookieAccessUrl1(server_backend_)) {
|
||||
TestCookieString(cookie_str, got_cookie_js1_, got_cookie_net1_);
|
||||
browser->GetMainFrame()->LoadURL(GetCookieAccessUrl2(server_backend_));
|
||||
} else if (url == GetCookieAccessUrl2(server_backend_)) {
|
||||
TestCookieString(cookie_str, got_cookie_js2_, got_cookie_net2_);
|
||||
FinishTest();
|
||||
} else {
|
||||
ADD_FAILURE() << "Unexpected url: " << url;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
void AddResponses(CookieAccessResponseHandler* handler) {
|
||||
// 1st request sets a cookie via net response headers and JS, then retrieves
|
||||
// the cookies via JS.
|
||||
{
|
||||
data1_.response = CefResponse::Create();
|
||||
data1_.response->SetMimeType("text/html");
|
||||
data1_.response->SetStatus(200);
|
||||
data1_.response->SetStatusText("OK");
|
||||
|
||||
CefResponse::HeaderMap headerMap;
|
||||
data1_.response->GetHeaderMap(headerMap);
|
||||
headerMap.insert(std::make_pair("Set-Cookie", "name_net=value_net"));
|
||||
data1_.response->SetHeaderMap(headerMap);
|
||||
|
||||
data1_.response_data =
|
||||
"<html><head>"
|
||||
"<script>"
|
||||
"document.cookie='name_js=value_js';"
|
||||
"window.testQuery({request:document.cookie});"
|
||||
"</script>"
|
||||
"</head><body>COOKIE ACCESS TEST 1</body></html>";
|
||||
|
||||
handler->AddResponse(GetCookieAccessUrl1(server_backend_), &data1_);
|
||||
}
|
||||
|
||||
// 2nd request retrieves the cookies via JS.
|
||||
{
|
||||
data2_.response = CefResponse::Create();
|
||||
data2_.response->SetMimeType("text/html");
|
||||
data2_.response->SetStatus(200);
|
||||
data2_.response->SetStatusText("OK");
|
||||
|
||||
data2_.response_data =
|
||||
"<html><head>"
|
||||
"<script>"
|
||||
"window.testQuery({request:document.cookie});"
|
||||
"</script>"
|
||||
"</head><body>COOKIE ACCESS TEST 2</body></html>";
|
||||
|
||||
handler->AddResponse(GetCookieAccessUrl2(server_backend_), &data2_);
|
||||
}
|
||||
}
|
||||
|
||||
void StartBackend(const base::Closure& complete_callback) {
|
||||
if (server_backend_) {
|
||||
StartServer(complete_callback);
|
||||
} else {
|
||||
StartSchemeHandler(complete_callback);
|
||||
}
|
||||
}
|
||||
|
||||
void StartServer(const base::Closure& complete_callback) {
|
||||
EXPECT_FALSE(server_handler_);
|
||||
|
||||
server_handler_ = new CookieAccessServerHandler();
|
||||
AddResponses(server_handler_.get());
|
||||
server_handler_->CreateServer(complete_callback);
|
||||
}
|
||||
|
||||
void StartSchemeHandler(const base::Closure& complete_callback) {
|
||||
// Add the factory registration.
|
||||
scheme_factory_ = new CookieAccessSchemeHandlerFactory();
|
||||
AddResponses(scheme_factory_.get());
|
||||
CefRegisterSchemeHandlerFactory(kCookieAccessScheme, kCookieAccessDomain,
|
||||
scheme_factory_.get());
|
||||
|
||||
complete_callback.Run();
|
||||
}
|
||||
|
||||
void RunTestContinue() {
|
||||
if (!CefCurrentlyOn(TID_UI)) {
|
||||
CefPostTask(TID_UI,
|
||||
base::Bind(&CookieAccessTestHandler::RunTestContinue, this));
|
||||
return;
|
||||
}
|
||||
|
||||
CreateBrowser(GetCookieAccessUrl1(server_backend_));
|
||||
}
|
||||
|
||||
void FinishTest() {
|
||||
// Verify that cookies were set correctly.
|
||||
class TestVisitor : public CefCookieVisitor {
|
||||
public:
|
||||
explicit TestVisitor(CookieAccessTestHandler* handler)
|
||||
: handler_(handler) {}
|
||||
~TestVisitor() override {
|
||||
// Destroy the test.
|
||||
CefPostTask(
|
||||
TID_UI,
|
||||
base::Bind(
|
||||
&CookieAccessTestHandler::ShutdownBackend, handler_,
|
||||
base::Bind(&CookieAccessTestHandler::DestroyTest, handler_)));
|
||||
}
|
||||
|
||||
bool Visit(const CefCookie& cookie,
|
||||
int count,
|
||||
int total,
|
||||
bool& deleteCookie) override {
|
||||
const std::string& name = CefString(&cookie.name);
|
||||
const std::string& value = CefString(&cookie.value);
|
||||
if (name == "name_js" && value == "value_js")
|
||||
handler_->got_cookie_js3_.yes();
|
||||
else if (name == "name_net" && value == "value_net")
|
||||
handler_->got_cookie_net3_.yes();
|
||||
|
||||
// Clean up the cookies.
|
||||
deleteCookie = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
CookieAccessTestHandler* handler_;
|
||||
IMPLEMENT_REFCOUNTING(TestVisitor);
|
||||
};
|
||||
|
||||
cookie_manager_->VisitAllCookies(new TestVisitor(this));
|
||||
}
|
||||
|
||||
void ShutdownBackend(const base::Closure& complete_callback) {
|
||||
if (server_backend_) {
|
||||
ShutdownServer(complete_callback);
|
||||
} else {
|
||||
ShutdownSchemeHandler(complete_callback);
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownServer(const base::Closure& complete_callback) {
|
||||
EXPECT_TRUE(server_handler_);
|
||||
|
||||
server_handler_->ShutdownServer(complete_callback);
|
||||
server_handler_ = nullptr;
|
||||
}
|
||||
|
||||
void ShutdownSchemeHandler(const base::Closure& complete_callback) {
|
||||
EXPECT_TRUE(scheme_factory_);
|
||||
|
||||
CefRegisterSchemeHandlerFactory(kCookieAccessScheme, kCookieAccessDomain,
|
||||
nullptr);
|
||||
scheme_factory_->Shutdown(complete_callback);
|
||||
scheme_factory_ = nullptr;
|
||||
}
|
||||
|
||||
TestMode test_mode_;
|
||||
bool server_backend_;
|
||||
CefRefPtr<CefCookieManager> cookie_manager_;
|
||||
|
||||
CefRefPtr<CookieAccessServerHandler> server_handler_;
|
||||
CefRefPtr<CookieAccessSchemeHandlerFactory> scheme_factory_;
|
||||
|
||||
CookieAccessData data1_;
|
||||
CookieAccessData data2_;
|
||||
|
||||
// 1st request.
|
||||
TrackCallback got_can_set_cookie1_;
|
||||
TrackCallback got_cookie_js1_;
|
||||
TrackCallback got_cookie_net1_;
|
||||
|
||||
// 2nd request.
|
||||
TrackCallback got_can_get_cookies2_;
|
||||
TrackCallback got_cookie_js2_;
|
||||
TrackCallback got_cookie_net2_;
|
||||
|
||||
// From cookie manager.
|
||||
TrackCallback got_cookie_js3_;
|
||||
TrackCallback got_cookie_net3_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(CookieAccessTestHandler);
|
||||
IMPLEMENT_REFCOUNTING(CookieAccessTestHandler);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// Allow reading and writing of cookies with server backend.
|
||||
TEST(RequestHandlerTest, CookieAccessServerAllow) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::ALLOW, true);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Block reading of cookies with server backend.
|
||||
TEST(RequestHandlerTest, CookieAccessServerBlockRead) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_READ, true);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Block writing of cookies with server backend.
|
||||
TEST(RequestHandlerTest, CookieAccessServerBlockWrite) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_WRITE, true);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Block reading and writing of cookies with server backend.
|
||||
TEST(RequestHandlerTest, CookieAccessServerBlockAll) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_ALL, true);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Allow reading and writing of cookies with scheme handler backend.
|
||||
TEST(RequestHandlerTest, CookieAccessSchemeAllow) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::ALLOW, false);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Block reading of cookies with scheme handler backend.
|
||||
TEST(RequestHandlerTest, CookieAccessSchemeBlockRead) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_READ, false);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Block writing of cookies with scheme handler backend.
|
||||
TEST(RequestHandlerTest, CookieAccessSchemeBlockWrite) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_WRITE, false);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Block reading and writing of cookies with scheme handler backend.
|
||||
TEST(RequestHandlerTest, CookieAccessSchemeBlockAll) {
|
||||
CefRefPtr<CookieAccessTestHandler> handler =
|
||||
new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_ALL, false);
|
||||
handler->ExecuteTest();
|
||||
ReleaseAndWaitForDestructor(handler);
|
||||
}
|
||||
|
||||
// Entry point for creating request handler browser test objects.
|
||||
// Called from client_app_delegates.cc.
|
||||
void CreateRequestHandlerBrowserTests(
|
||||
|
Reference in New Issue
Block a user