// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights // reserved. Use of this source code is governed by a BSD-style license that // can be found in the LICENSE file. #include #include #include #include #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" #include "tests/shared/browser/client_app_browser.h" #include "tests/shared/renderer/client_app_renderer.h" using client::ClientAppBrowser; using client::ClientAppRenderer; namespace { enum NetNotifyTestType { NNTT_NONE = 0, NNTT_NORMAL, NNTT_DELAYED_RENDERER, NNTT_DELAYED_BROWSER, }; const char kNetNotifyOrigin1[] = "http://tests-netnotify1/"; const char kNetNotifyOrigin2[] = "http://tests-netnotify2/"; const char kNetNotifyMsg[] = "RequestHandlerTest.NetNotify"; bool g_net_notify_test = false; // Browser side. class NetNotifyBrowserTest : public ClientAppBrowser::Delegate { public: NetNotifyBrowserTest() {} void OnBeforeChildProcessLaunch( CefRefPtr app, CefRefPtr command_line) override { if (!g_net_notify_test) return; // Indicate to the render process that the test should be run. command_line->AppendSwitchWithValue("test", kNetNotifyMsg); } protected: IMPLEMENT_REFCOUNTING(NetNotifyBrowserTest); }; // Browser side. class NetNotifyTestHandler : public TestHandler { public: class RequestContextHandler : public CefRequestContextHandler { public: explicit RequestContextHandler(NetNotifyTestHandler* handler) : handler_(handler) {} CefRefPtr GetCookieManager() override { EXPECT_TRUE(handler_); EXPECT_TRUE(CefCurrentlyOn(TID_IO)); if (url_.find(handler_->url1_) == 0) handler_->got_get_cookie_manager1_.yes(); else if (url_.find(handler_->url2_) == 0) handler_->got_get_cookie_manager2_.yes(); else EXPECT_TRUE(false); // Not reached return handler_->cookie_manager_; } void SetURL(const std::string& url) { url_ = url; } void Detach() { handler_ = NULL; } private: std::string url_; NetNotifyTestHandler* handler_; IMPLEMENT_REFCOUNTING(RequestContextHandler); }; NetNotifyTestHandler(CompletionState* completion_state, NetNotifyTestType test_type, bool same_origin) : TestHandler(completion_state), test_type_(test_type), same_origin_(same_origin) {} void SetupTest() override { std::stringstream ss; ss << kNetNotifyOrigin1 << "nav1.html?t=" << test_type_; url1_ = ss.str(); ss.str(""); ss << (same_origin_ ? kNetNotifyOrigin1 : kNetNotifyOrigin2) << "nav2.html?t=" << test_type_; url2_ = ss.str(); cookie_manager_ = CefCookieManager::CreateManager(CefString(), true, NULL); const std::string& resource1 = "" "" "Nav1" ""; response_length1_ = static_cast(resource1.size()); AddResource(url1_, resource1, "text/html"); const std::string& resource2 = "" "" "Nav2" ""; response_length2_ = static_cast(resource2.size()); AddResource(url2_, resource2, "text/html"); context_handler_ = new RequestContextHandler(this); context_handler_->SetURL(url1_); // Create the request context that will use an in-memory cache. CefRequestContextSettings settings; CefRefPtr request_context = CefRequestContext::CreateContext(settings, context_handler_.get()); // Create browser that loads the 1st URL. CreateBrowser(url1_, request_context); } void RunTest() override { // Navigate to the 2nd URL. context_handler_->SetURL(url2_); GetBrowser()->GetMainFrame()->LoadURL(url2_); // Time out the test after a reasonable period of time. SetTestTimeout(); } cef_return_value_t OnBeforeResourceLoad( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr callback) override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); const std::string& url = request->GetURL(); if (url.find(url1_) == 0) got_before_resource_load1_.yes(); else if (url.find(url2_) == 0) got_before_resource_load2_.yes(); else EXPECT_TRUE(false); // Not reached return RV_CONTINUE; } CefRefPtr GetResourceHandler( CefRefPtr browser, CefRefPtr frame, CefRefPtr request) override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); const std::string& url = request->GetURL(); if (url.find(url1_) == 0) got_get_resource_handler1_.yes(); else if (url.find(url2_) == 0) got_get_resource_handler2_.yes(); else EXPECT_TRUE(false); // Not reached return TestHandler::GetResourceHandler(browser, frame, request); } void OnResourceLoadComplete(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response, URLRequestStatus status, int64 received_content_length) override { EXPECT_TRUE(CefCurrentlyOn(TID_IO)); EXPECT_EQ(UR_SUCCESS, status); const std::string& url = request->GetURL(); if (url.find(url1_) == 0) { got_resource_load_complete1_.yes(); EXPECT_EQ(response_length1_, received_content_length); } else if (url.find(url2_) == 0) { got_resource_load_complete2_.yes(); EXPECT_EQ(response_length2_, received_content_length); } else { EXPECT_TRUE(false); // Not reached } } bool OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool user_gesture, bool is_redirect) override { std::string url = request->GetURL(); // Check if the load has already been delayed. bool delay_loaded = (url.find("delayed=true") != std::string::npos); if (url.find(url1_) == 0) { got_before_browse1_.yes(); EXPECT_FALSE(delay_loaded); } else if (url.find(url2_) == 0) { got_before_browse2_.yes(); if (delay_loaded) { got_before_browse2_delayed_.yes(); } else if (test_type_ == NNTT_DELAYED_RENDERER || test_type_ == NNTT_DELAYED_BROWSER) { got_before_browse2_will_delay_.yes(); // Navigating cross-origin from the browser process will cause a new // render process to be created. We therefore need some information in // the request itself to tell us that the navigation has already been // delayed. url += "&delayed=true"; if (test_type_ == NNTT_DELAYED_RENDERER) { // Load the URL from the render process. CefRefPtr message = CefProcessMessage::Create(kNetNotifyMsg); CefRefPtr args = message->GetArgumentList(); args->SetInt(0, test_type_); args->SetString(1, url); EXPECT_TRUE(browser->SendProcessMessage(PID_RENDERER, message)); } else { // Load the URL from the browser process. browser->GetMainFrame()->LoadURL(url); } // Cancel the load. return true; } } else { EXPECT_TRUE(false); // Not reached } // Allow the load to continue. return false; } void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) override { const std::string& url = frame->GetURL(); if (url.find(url1_) == 0) { got_load_end1_.yes(); SetupCompleteIfDone(); } else if (url.find(url2_) == 0) { got_load_end2_.yes(); FinishTestIfDone(); } else { EXPECT_TRUE(false); // Not reached } } bool OnProcessMessageReceived(CefRefPtr browser, CefProcessId source_process, CefRefPtr message) override { if (message->GetName().ToString() == kNetNotifyMsg) { CefRefPtr args = message->GetArgumentList(); EXPECT_TRUE(args.get()); std::string url = args->GetString(0); if (url.find(url1_) == 0) { got_process_message1_.yes(); SetupCompleteIfDone(); } else if (url.find(url2_) == 0) { got_process_message2_.yes(); FinishTestIfDone(); } else { EXPECT_TRUE(false); // Not reached } return true; } // Message not handled. return false; } protected: void SetupCompleteIfDone() { if (got_load_end1_ && got_process_message1_) SetupComplete(); } void FinishTestIfDone() { if (got_load_end2_ && got_process_message2_) FinishTest(); } void FinishTest() { // Verify that cookies were set correctly. class TestVisitor : public CefCookieVisitor { public: explicit TestVisitor(NetNotifyTestHandler* handler) : handler_(handler) {} ~TestVisitor() override { // Destroy the test. CefPostTask(TID_UI, base::Bind(&NetNotifyTestHandler::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 == "name1" && value == "value1") handler_->got_cookie1_.yes(); else if (name == "name2" && value == "value2") handler_->got_cookie2_.yes(); return true; } private: NetNotifyTestHandler* handler_; IMPLEMENT_REFCOUNTING(TestVisitor); }; cookie_manager_->VisitAllCookies(new TestVisitor(this)); } void DestroyTest() override { int browser_id = GetBrowser()->GetIdentifier(); // Verify test expectations. EXPECT_TRUE(got_before_browse1_) << " browser " << browser_id; EXPECT_TRUE(got_load_end1_) << " browser " << browser_id; EXPECT_TRUE(got_before_resource_load1_) << " browser " << browser_id; EXPECT_TRUE(got_get_resource_handler1_) << " browser " << browser_id; EXPECT_TRUE(got_resource_load_complete1_) << " browser " << browser_id; EXPECT_TRUE(got_get_cookie_manager1_) << " browser " << browser_id; EXPECT_TRUE(got_cookie1_) << " browser " << browser_id; EXPECT_TRUE(got_process_message1_) << " browser " << browser_id; EXPECT_TRUE(got_before_browse2_) << " browser " << browser_id; EXPECT_TRUE(got_load_end2_) << " browser " << browser_id; EXPECT_TRUE(got_before_resource_load2_) << " browser " << browser_id; EXPECT_TRUE(got_get_resource_handler2_) << " browser " << browser_id; EXPECT_TRUE(got_resource_load_complete2_) << " browser " << browser_id; EXPECT_TRUE(got_get_cookie_manager2_) << " browser " << browser_id; EXPECT_TRUE(got_cookie2_) << " browser " << browser_id; EXPECT_TRUE(got_process_message2_) << " browser " << browser_id; if (test_type_ == NNTT_DELAYED_RENDERER || test_type_ == NNTT_DELAYED_BROWSER) { EXPECT_TRUE(got_before_browse2_will_delay_) << " browser " << browser_id; EXPECT_TRUE(got_before_browse2_delayed_) << " browser " << browser_id; } else { EXPECT_FALSE(got_before_browse2_will_delay_) << " browser " << browser_id; EXPECT_FALSE(got_before_browse2_delayed_) << " browser " << browser_id; } context_handler_->Detach(); context_handler_ = NULL; cookie_manager_ = NULL; TestHandler::DestroyTest(); } NetNotifyTestType test_type_; bool same_origin_; std::string url1_; std::string url2_; CefRefPtr context_handler_; CefRefPtr cookie_manager_; TrackCallback got_before_browse1_; TrackCallback got_load_end1_; TrackCallback got_before_resource_load1_; TrackCallback got_get_resource_handler1_; TrackCallback got_resource_load_complete1_; TrackCallback got_get_cookie_manager1_; TrackCallback got_cookie1_; TrackCallback got_process_message1_; TrackCallback got_before_browse2_; TrackCallback got_load_end2_; TrackCallback got_before_resource_load2_; TrackCallback got_get_resource_handler2_; TrackCallback got_resource_load_complete2_; TrackCallback got_get_cookie_manager2_; TrackCallback got_cookie2_; TrackCallback got_process_message2_; TrackCallback got_before_browse2_will_delay_; TrackCallback got_before_browse2_delayed_; int64 response_length1_; int64 response_length2_; IMPLEMENT_REFCOUNTING(NetNotifyTestHandler); }; // Renderer side. class NetNotifyRendererTest : public ClientAppRenderer::Delegate, public CefLoadHandler { public: NetNotifyRendererTest() : run_test_(false) {} void OnRenderThreadCreated(CefRefPtr app, CefRefPtr extra_info) override { if (!g_net_notify_test) { // Check that the test should be run. CefRefPtr command_line = CefCommandLine::GetGlobalCommandLine(); const std::string& test = command_line->GetSwitchValue("test"); if (test != kNetNotifyMsg) return; } run_test_ = true; } CefRefPtr GetLoadHandler( CefRefPtr app) override { if (run_test_) return this; return NULL; } void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) override { if (!run_test_) return; const std::string& url = frame->GetURL(); // Continue in the browser process. CefRefPtr message = CefProcessMessage::Create(kNetNotifyMsg); CefRefPtr args = message->GetArgumentList(); args->SetString(0, url); EXPECT_TRUE(browser->SendProcessMessage(PID_BROWSER, message)); } bool OnProcessMessageReceived(CefRefPtr app, CefRefPtr browser, CefProcessId source_process, CefRefPtr message) override { if (message->GetName().ToString() == kNetNotifyMsg) { CefRefPtr args = message->GetArgumentList(); EXPECT_TRUE(args.get()); NetNotifyTestType test_type = static_cast(args->GetInt(0)); EXPECT_EQ(test_type, NNTT_DELAYED_RENDERER); const std::string& url = args->GetString(1); // Load the URL from the render process. browser->GetMainFrame()->LoadURL(url); return true; } // Message not handled. return false; } private: bool run_test_; IMPLEMENT_REFCOUNTING(NetNotifyRendererTest); }; void RunNetNotifyTest(NetNotifyTestType test_type, bool same_origin) { g_net_notify_test = true; TestHandler::CompletionState completion_state(3); CefRefPtr handler1 = new NetNotifyTestHandler(&completion_state, test_type, same_origin); CefRefPtr handler2 = new NetNotifyTestHandler(&completion_state, test_type, same_origin); CefRefPtr handler3 = new NetNotifyTestHandler(&completion_state, test_type, same_origin); TestHandler::Collection collection(&completion_state); collection.AddTestHandler(handler1.get()); collection.AddTestHandler(handler2.get()); collection.AddTestHandler(handler3.get()); collection.ExecuteTests(); ReleaseAndWaitForDestructor(handler1); ReleaseAndWaitForDestructor(handler2); ReleaseAndWaitForDestructor(handler3); g_net_notify_test = false; } } // namespace // Verify network notifications for multiple browsers existing simultaniously. // URL loading is from the same origin and is not delayed. TEST(RequestHandlerTest, NotificationsSameOriginDirect) { RunNetNotifyTest(NNTT_NORMAL, true); } // Verify network notifications for multiple browsers existing simultaniously. // URL loading is from the same origin and is continued asynchronously from the // render process. TEST(RequestHandlerTest, NotificationsSameOriginDelayedRenderer) { RunNetNotifyTest(NNTT_DELAYED_RENDERER, true); } // Verify network notifications for multiple browsers existing simultaniously. // URL loading is from the same origin and is continued asynchronously from the // browser process. TEST(RequestHandlerTest, NotificationsSameOriginDelayedBrowser) { RunNetNotifyTest(NNTT_DELAYED_BROWSER, true); } // Verify network notifications for multiple browsers existing simultaniously. // URL loading is from a different origin and is not delayed. TEST(RequestHandlerTest, NotificationsCrossOriginDirect) { RunNetNotifyTest(NNTT_NORMAL, false); } // Verify network notifications for multiple browsers existing simultaniously. // URL loading is from a different origin and is continued asynchronously from // the render process. TEST(RequestHandlerTest, NotificationsCrossOriginDelayedRenderer) { RunNetNotifyTest(NNTT_DELAYED_RENDERER, false); } // Verify network notifications for multiple browsers existing simultaniously. // URL loading is from a different origin and is continued asynchronously from // the browser process. TEST(RequestHandlerTest, NotificationsCrossOriginDelayedBrowser) { RunNetNotifyTest(NNTT_DELAYED_BROWSER, false); } namespace { const char kResourceTestHtml[] = "http://test.com/resource.html"; class ResourceResponseTest : public TestHandler { public: enum TestMode { URL, HEADER, POST, }; explicit ResourceResponseTest(TestMode mode) : browser_id_(0), main_request_id_(0U), sub_request_id_(0U) { if (mode == URL) resource_test_.reset(new UrlResourceTest); else if (mode == HEADER) resource_test_.reset(new HeaderResourceTest); else resource_test_.reset(new PostResourceTest); } void RunTest() override { AddResource(kResourceTestHtml, GetHtml(), "text/html"); CreateBrowser(kResourceTestHtml); SetTestTimeout(); } bool OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool user_gesture, bool is_redirect) override { EXPECT_UI_THREAD(); EXPECT_EQ(0, browser_id_); browser_id_ = browser->GetIdentifier(); EXPECT_GT(browser_id_, 0); // This method is only called for the main resource. EXPECT_STREQ(kResourceTestHtml, request->GetURL().ToString().c_str()); // Browser-side navigation no longer exposes the actual request information. EXPECT_EQ(0U, request->GetIdentifier()); return false; } cef_return_value_t OnBeforeResourceLoad( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr callback) override { EXPECT_IO_THREAD(); EXPECT_EQ(browser_id_, browser->GetIdentifier()); if (request->GetURL() == kResourceTestHtml) { // All loads of the main resource should keep the same request id. EXPECT_EQ(0U, main_request_id_); main_request_id_ = request->GetIdentifier(); EXPECT_GT(main_request_id_, 0U); return RV_CONTINUE; } // All redirects of the sub-resource should keep the same request id. if (sub_request_id_ == 0U) { sub_request_id_ = request->GetIdentifier(); EXPECT_GT(sub_request_id_, 0U); } else { EXPECT_EQ(sub_request_id_, request->GetIdentifier()); } return resource_test_->OnBeforeResourceLoad(browser, frame, request) ? RV_CANCEL : RV_CONTINUE; } CefRefPtr GetResourceHandler( CefRefPtr browser, CefRefPtr frame, CefRefPtr request) override { EXPECT_IO_THREAD(); EXPECT_EQ(browser_id_, browser->GetIdentifier()); if (request->GetURL() == kResourceTestHtml) { EXPECT_EQ(main_request_id_, request->GetIdentifier()); return TestHandler::GetResourceHandler(browser, frame, request); } EXPECT_EQ(sub_request_id_, request->GetIdentifier()); return resource_test_->GetResourceHandler(browser, frame, request); } void OnResourceRedirect(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response, CefString& new_url) override { EXPECT_IO_THREAD(); EXPECT_EQ(browser_id_, browser->GetIdentifier()); EXPECT_EQ(sub_request_id_, request->GetIdentifier()); resource_test_->OnResourceRedirect(browser, frame, request, new_url); } bool OnResourceResponse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { EXPECT_IO_THREAD(); EXPECT_TRUE(browser.get()); EXPECT_EQ(browser_id_, browser->GetIdentifier()); EXPECT_TRUE(frame.get()); EXPECT_TRUE(frame->IsMain()); if (request->GetURL() == kResourceTestHtml) { EXPECT_EQ(main_request_id_, request->GetIdentifier()); return false; } EXPECT_EQ(sub_request_id_, request->GetIdentifier()); return resource_test_->OnResourceResponse(browser, frame, request, response); } void OnResourceLoadComplete(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response, URLRequestStatus status, int64 received_content_length) override { EXPECT_IO_THREAD(); EXPECT_TRUE(browser.get()); EXPECT_EQ(browser_id_, browser->GetIdentifier()); EXPECT_TRUE(frame.get()); EXPECT_TRUE(frame->IsMain()); if (request->GetURL() == kResourceTestHtml) { EXPECT_EQ(main_request_id_, request->GetIdentifier()); return; } EXPECT_EQ(sub_request_id_, request->GetIdentifier()); resource_test_->OnResourceLoadComplete(browser, frame, request, response, status, received_content_length); } void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) override { EXPECT_UI_THREAD(); EXPECT_EQ(browser_id_, browser->GetIdentifier()); TestHandler::OnLoadEnd(browser, frame, httpStatusCode); DestroyTest(); } void DestroyTest() override { resource_test_->CheckExpected(); resource_test_.reset(NULL); TestHandler::DestroyTest(); } private: std::string GetHtml() const { std::stringstream html; html << ""; const std::string& url = resource_test_->start_url(); html << ""; html << "

Main

"; return html.str(); } class ResourceTest { public: ResourceTest(const std::string& start_url, size_t expected_resource_response_ct = 2U, size_t expected_before_resource_load_ct = 1U, size_t expected_resource_redirect_ct = 0U, size_t expected_resource_load_complete_ct = 1U) : start_url_(start_url), resource_response_ct_(0U), expected_resource_response_ct_(expected_resource_response_ct), before_resource_load_ct_(0), expected_before_resource_load_ct_(expected_before_resource_load_ct), get_resource_handler_ct_(0U), resource_redirect_ct_(0U), expected_resource_redirect_ct_(expected_resource_redirect_ct), resource_load_complete_ct_(0U), expected_resource_load_complete_ct_( expected_resource_load_complete_ct) {} virtual ~ResourceTest() {} const std::string& start_url() const { return start_url_; } virtual bool OnBeforeResourceLoad(CefRefPtr browser, CefRefPtr frame, CefRefPtr request) { before_resource_load_ct_++; return false; } virtual CefRefPtr GetResourceHandler( CefRefPtr browser, CefRefPtr frame, CefRefPtr request) { get_resource_handler_ct_++; const std::string& js_content = ""; CefRefPtr stream = CefStreamReader::CreateForData( const_cast(js_content.c_str()), js_content.size()); return new CefStreamResourceHandler(200, "OK", "text/javascript", CefResponse::HeaderMap(), stream); } virtual void OnResourceRedirect(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefString& new_url) { resource_redirect_ct_++; } bool OnResourceResponse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) { EXPECT_TRUE(CheckUrl(request->GetURL())); // Verify the response returned by GetResourceHandler. EXPECT_EQ(200, response->GetStatus()); EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str()); EXPECT_STREQ("text/javascript", response->GetMimeType().ToString().c_str()); if (resource_response_ct_++ == 0U) { // Always redirect at least one time. OnResourceReceived(browser, frame, request, response); return true; } OnRetryReceived(browser, frame, request, response); return (resource_response_ct_ < expected_resource_response_ct_); } void OnResourceLoadComplete(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response, URLRequestStatus status, int64 received_content_length) { EXPECT_TRUE(CheckUrl(request->GetURL())); // Verify the response returned by GetResourceHandler. EXPECT_EQ(200, response->GetStatus()); EXPECT_STREQ("OK", response->GetStatusText().ToString().c_str()); EXPECT_STREQ("text/javascript", response->GetMimeType().ToString().c_str()); resource_load_complete_ct_++; } virtual bool CheckUrl(const std::string& url) const { return (url == start_url_); } virtual void CheckExpected() { EXPECT_TRUE(got_resource_); EXPECT_TRUE(got_resource_retry_); EXPECT_EQ(expected_resource_response_ct_, resource_response_ct_); EXPECT_EQ(expected_resource_response_ct_, get_resource_handler_ct_); EXPECT_EQ(expected_before_resource_load_ct_, before_resource_load_ct_); EXPECT_EQ(expected_resource_redirect_ct_, resource_redirect_ct_); EXPECT_EQ(expected_resource_load_complete_ct_, resource_load_complete_ct_); } protected: virtual void OnResourceReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) { got_resource_.yes(); } virtual void OnRetryReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) { got_resource_retry_.yes(); } private: std::string start_url_; size_t resource_response_ct_; size_t expected_resource_response_ct_; size_t before_resource_load_ct_; size_t expected_before_resource_load_ct_; size_t get_resource_handler_ct_; size_t resource_redirect_ct_; size_t expected_resource_redirect_ct_; size_t resource_load_complete_ct_; size_t expected_resource_load_complete_ct_; TrackCallback got_resource_; TrackCallback got_resource_retry_; }; class UrlResourceTest : public ResourceTest { public: UrlResourceTest() : ResourceTest("http://test.com/start_url.js", 3U, 2U, 1U) { redirect_url_ = "http://test.com/redirect_url.js"; } bool CheckUrl(const std::string& url) const override { if (url == redirect_url_) return true; return ResourceTest::CheckUrl(url); } void OnResourceRedirect(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefString& new_url) override { ResourceTest::OnResourceRedirect(browser, frame, request, new_url); const std::string& old_url = request->GetURL(); EXPECT_STREQ(start_url().c_str(), old_url.c_str()); EXPECT_STREQ(redirect_url_.c_str(), new_url.ToString().c_str()); } private: void OnResourceReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { ResourceTest::OnResourceReceived(browser, frame, request, response); request->SetURL(redirect_url_); } void OnRetryReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { ResourceTest::OnRetryReceived(browser, frame, request, response); const std::string& new_url = request->GetURL(); EXPECT_STREQ(redirect_url_.c_str(), new_url.c_str()); } std::string redirect_url_; }; class HeaderResourceTest : public ResourceTest { public: HeaderResourceTest() : ResourceTest("http://test.com/start_header.js") { expected_headers_.insert(std::make_pair("Test-Key1", "Value1")); expected_headers_.insert(std::make_pair("Test-Key2", "Value2")); } private: void OnResourceReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { ResourceTest::OnResourceReceived(browser, frame, request, response); request->SetHeaderMap(expected_headers_); } void OnRetryReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { ResourceTest::OnRetryReceived(browser, frame, request, response); CefRequest::HeaderMap actual_headers; request->GetHeaderMap(actual_headers); TestMapEqual(expected_headers_, actual_headers, true); } CefRequest::HeaderMap expected_headers_; }; class PostResourceTest : public ResourceTest { public: PostResourceTest() : ResourceTest("http://test.com/start_post.js") { CefRefPtr elem = CefPostDataElement::Create(); const std::string data("Test Post Data"); elem->SetToBytes(data.size(), data.c_str()); expected_post_ = CefPostData::Create(); expected_post_->AddElement(elem); } private: void OnResourceReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { ResourceTest::OnResourceReceived(browser, frame, request, response); request->SetPostData(expected_post_); } void OnRetryReceived(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { ResourceTest::OnRetryReceived(browser, frame, request, response); CefRefPtr actual_post = request->GetPostData(); TestPostDataEqual(expected_post_, actual_post); } CefRefPtr expected_post_; }; int browser_id_; uint64 main_request_id_; uint64 sub_request_id_; scoped_ptr resource_test_; IMPLEMENT_REFCOUNTING(ResourceResponseTest); }; } // namespace TEST(RequestHandlerTest, ResourceResponseURL) { CefRefPtr handler = new ResourceResponseTest(ResourceResponseTest::URL); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } TEST(RequestHandlerTest, ResourceResponseHeader) { CefRefPtr handler = new ResourceResponseTest(ResourceResponseTest::HEADER); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } TEST(RequestHandlerTest, ResourceResponsePost) { CefRefPtr handler = new ResourceResponseTest(ResourceResponseTest::POST); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } namespace { const char kResourceTestHtml2[] = "http://test.com/resource2.html"; class BeforeResourceLoadTest : public TestHandler { public: enum TestMode { CANCEL, CANCEL_ASYNC, CANCEL_NAV, CONTINUE, CONTINUE_ASYNC, }; explicit BeforeResourceLoadTest(TestMode mode) : test_mode_(mode) {} void RunTest() override { AddResource(kResourceTestHtml, "Test", "text/html"); AddResource(kResourceTestHtml2, "Test2", "text/html"); CreateBrowser(kResourceTestHtml); SetTestTimeout(); } cef_return_value_t OnBeforeResourceLoad( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr callback) override { EXPECT_IO_THREAD(); // Allow the 2nd navigation to continue. const std::string& url = request->GetURL(); if (url == kResourceTestHtml2) { got_before_resource_load2_.yes(); EXPECT_EQ(CANCEL_NAV, test_mode_); return RV_CONTINUE; } EXPECT_FALSE(got_before_resource_load_); got_before_resource_load_.yes(); if (test_mode_ == CANCEL) { // Cancel immediately. return RV_CANCEL; } else if (test_mode_ == CONTINUE) { // Continue immediately. return RV_CONTINUE; } else { if (test_mode_ == CANCEL_NAV) { // Cancel the request by navigating to a new URL. browser->GetMainFrame()->LoadURL(kResourceTestHtml2); } else { // Continue or cancel asynchronously. CefPostTask(TID_UI, base::Bind(&CefRequestCallback::Continue, callback.get(), test_mode_ == CONTINUE_ASYNC)); } return RV_CONTINUE_ASYNC; } } void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) override { EXPECT_UI_THREAD(); EXPECT_FALSE(got_load_end_); got_load_end_.yes(); const std::string& url = frame->GetURL(); if (test_mode_ == CANCEL_NAV) EXPECT_STREQ(kResourceTestHtml2, url.data()); else EXPECT_STREQ(kResourceTestHtml, url.data()); TestHandler::OnLoadEnd(browser, frame, httpStatusCode); DestroyTest(); } void OnLoadError(CefRefPtr browser, CefRefPtr frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) override { EXPECT_UI_THREAD(); EXPECT_FALSE(got_load_error_); got_load_error_.yes(); const std::string& url = failedUrl; EXPECT_STREQ(kResourceTestHtml, url.data()); TestHandler::OnLoadError(browser, frame, errorCode, errorText, failedUrl); if (test_mode_ != CANCEL_NAV) DestroyTest(); } void DestroyTest() override { EXPECT_TRUE(got_before_resource_load_); if (test_mode_ == CANCEL_NAV) EXPECT_TRUE(got_before_resource_load2_); else EXPECT_FALSE(got_before_resource_load2_); if (test_mode_ == CONTINUE || test_mode_ == CONTINUE_ASYNC) { EXPECT_TRUE(got_load_end_); EXPECT_FALSE(got_load_error_); } else if (test_mode_ == CANCEL || test_mode_ == CANCEL_ASYNC) { EXPECT_FALSE(got_load_end_); EXPECT_TRUE(got_load_error_); } TestHandler::DestroyTest(); } private: const TestMode test_mode_; TrackCallback got_before_resource_load_; TrackCallback got_before_resource_load2_; TrackCallback got_load_end_; TrackCallback got_load_error_; IMPLEMENT_REFCOUNTING(BeforeResourceLoadTest); }; } // namespace TEST(RequestHandlerTest, BeforeResourceLoadCancel) { CefRefPtr handler = new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } TEST(RequestHandlerTest, BeforeResourceLoadCancelAsync) { CefRefPtr handler = new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_ASYNC); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } TEST(RequestHandlerTest, BeforeResourceLoadCancelNav) { CefRefPtr handler = new BeforeResourceLoadTest(BeforeResourceLoadTest::CANCEL_NAV); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } TEST(RequestHandlerTest, BeforeResourceLoadContinue) { CefRefPtr handler = new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } TEST(RequestHandlerTest, BeforeResourceLoadContinueAsync) { CefRefPtr handler = new BeforeResourceLoadTest(BeforeResourceLoadTest::CONTINUE_ASYNC); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } namespace { // For response filtering we need to test: // - Passing through content unchanged. // - Not reading all of the input buffer. // - Needing more input and getting it. // - Needing more input and not getting it. // - Filter error. const char kResponseFilterTestUrl[] = "http://tests.com/response_filter.html"; const size_t kResponseBufferSize = 1024 * 32; // 32kb const char kInputHeader[] = ""; const char kInputFooter[] = ""; // Repeat |content| the minimum number of times necessary to satisfy // |desired_min_size|. If |calculated_repeat_ct| is non-NULL it will be set to // the number of times that |content| was repeated. std::string CreateInput(const std::string& content, size_t desired_min_size, size_t* calculated_repeat_ct = nullptr) { const size_t header_footer_size = sizeof(kInputHeader) + sizeof(kInputFooter) - 2; EXPECT_GE(desired_min_size, header_footer_size + content.size()); desired_min_size -= header_footer_size; size_t repeat_ct = static_cast(std::ceil(static_cast(desired_min_size) / static_cast(content.size()))); if (calculated_repeat_ct) *calculated_repeat_ct = repeat_ct; std::string result; result.reserve(header_footer_size + (content.size() * repeat_ct)); result = kInputHeader; while (repeat_ct--) result += content; result += kInputFooter; return result; } std::string CreateOutput(const std::string& content, size_t repeat_ct) { const size_t header_footer_size = sizeof(kInputHeader) + sizeof(kInputFooter) - 2; std::string result; result.reserve(header_footer_size + (content.size() * repeat_ct)); result = kInputHeader; while (repeat_ct--) result += content; result += kInputFooter; return result; } // Base class for test filters. class ResponseFilterTestBase : public CefResponseFilter { public: ResponseFilterTestBase() : filter_count_(0U) {} bool InitFilter() override { EXPECT_FALSE(got_init_filter_); got_init_filter_.yes(); return true; } FilterStatus Filter(void* data_in, size_t data_in_size, size_t& data_in_read, void* data_out, size_t data_out_size, size_t& data_out_written) override { if (data_in_size == 0U) EXPECT_FALSE(data_in); else EXPECT_TRUE(data_in); EXPECT_EQ(data_in_read, 0U); EXPECT_TRUE(data_out); EXPECT_GT(data_out_size, 0U); EXPECT_EQ(data_out_written, 0U); filter_count_++; return RESPONSE_FILTER_ERROR; } // Returns the input that will be fed into the filter. virtual std::string GetInput() = 0; // Verify the output from the filter. virtual void VerifyOutput(cef_urlrequest_status_t status, int64 received_content_length, const std::string& received_content) { EXPECT_TRUE(got_init_filter_); EXPECT_GT(filter_count_, 0U); } protected: TrackCallback got_init_filter_; size_t filter_count_; IMPLEMENT_REFCOUNTING(ResponseFilterTestBase); }; // Pass through the contents unchanged. class ResponseFilterPassThru : public ResponseFilterTestBase { public: explicit ResponseFilterPassThru(bool limit_read) : limit_read_(limit_read) {} FilterStatus Filter(void* data_in, size_t data_in_size, size_t& data_in_read, void* data_out, size_t data_out_size, size_t& data_out_written) override { ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read, data_out, data_out_size, data_out_written); if (limit_read_) { // Read at most 1k bytes. data_in_read = std::min(data_in_size, static_cast(1024U)); } else { // Read all available bytes. data_in_read = data_in_size; } data_out_written = std::min(data_in_read, data_out_size); memcpy(data_out, data_in, data_out_written); return RESPONSE_FILTER_DONE; } std::string GetInput() override { input_ = CreateInput("FOOBAR ", kResponseBufferSize * 2U); return input_; } void VerifyOutput(cef_urlrequest_status_t status, int64 received_content_length, const std::string& received_content) override { ResponseFilterTestBase::VerifyOutput(status, received_content_length, received_content); if (limit_read_) // Expected to read 2 full buffers of kResponseBufferSize at 1kb // increments (2 * 32) and one partial buffer. EXPECT_EQ(2U * 32U + 1U, filter_count_); else { // Expected to read 2 full buffers of kResponseBufferSize and one partial // buffer. EXPECT_EQ(3U, filter_count_); } EXPECT_STREQ(input_.c_str(), received_content.c_str()); // Input size and content size should match. EXPECT_EQ(input_.size(), static_cast(received_content_length)); EXPECT_EQ(input_.size(), received_content.size()); } private: std::string input_; bool limit_read_; }; const char kFindString[] = "REPLACE_THIS_STRING"; const char kReplaceString[] = "This is the replaced string!"; // Helper for passing params to Write(). #define WRITE_PARAMS data_out_ptr, data_out_size, data_out_written // Replace all instances of |kFindString| with |kReplaceString|. // This implementation is similar to the example in // tests/shared/response_filter_test.cc. class ResponseFilterNeedMore : public ResponseFilterTestBase { public: ResponseFilterNeedMore() : find_match_offset_(0U), replace_overflow_size_(0U), input_size_(0U), repeat_ct_(0U) {} FilterStatus Filter(void* data_in, size_t data_in_size, size_t& data_in_read, void* data_out, size_t data_out_size, size_t& data_out_written) override { ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read, data_out, data_out_size, data_out_written); // All data will be read. data_in_read = data_in_size; const size_t find_size = sizeof(kFindString) - 1; const char* data_in_ptr = static_cast(data_in); char* data_out_ptr = static_cast(data_out); // Reset the overflow. std::string old_overflow; if (!overflow_.empty()) { old_overflow = overflow_; overflow_.clear(); } const size_t likely_out_size = data_in_size + replace_overflow_size_ + old_overflow.size(); if (data_out_size < likely_out_size) { // We'll likely need to use the overflow buffer. Size it appropriately. overflow_.reserve(likely_out_size - data_out_size); } if (!old_overflow.empty()) { // Write the overflow from last time. Write(old_overflow.c_str(), old_overflow.size(), WRITE_PARAMS); } // Evaluate each character in the input buffer. Track how many characters in // a row match kFindString. If kFindString is completely matched then write // kReplaceString. Otherwise, write the input characters as-is. for (size_t i = 0U; i < data_in_size; ++i) { if (data_in_ptr[i] == kFindString[find_match_offset_]) { // Matched the next character in the find string. if (++find_match_offset_ == find_size) { // Complete match of the find string. Write the replace string. Write(kReplaceString, sizeof(kReplaceString) - 1, WRITE_PARAMS); // Start over looking for a match. find_match_offset_ = 0; } continue; } // Character did not match the find string. if (find_match_offset_ > 0) { // Write the portion of the find string that has matched so far. Write(kFindString, find_match_offset_, WRITE_PARAMS); // Start over looking for a match. find_match_offset_ = 0; } // Write the current character. Write(&data_in_ptr[i], 1, WRITE_PARAMS); } // If a match is currently in-progress and input was provided then we need // more data. Otherwise, we're done. return find_match_offset_ > 0 && data_in_size > 0 ? RESPONSE_FILTER_NEED_MORE_DATA : RESPONSE_FILTER_DONE; } std::string GetInput() override { const std::string& input = CreateInput( std::string(kFindString) + " ", kResponseBufferSize * 2U, &repeat_ct_); input_size_ = input.size(); const size_t find_size = sizeof(kFindString) - 1; const size_t replace_size = sizeof(kReplaceString) - 1; // Determine a reasonable amount of space for find/replace overflow. if (replace_size > find_size) replace_overflow_size_ = (replace_size - find_size) * repeat_ct_; return input; } void VerifyOutput(cef_urlrequest_status_t status, int64 received_content_length, const std::string& received_content) override { ResponseFilterTestBase::VerifyOutput(status, received_content_length, received_content); const std::string& output = CreateOutput(std::string(kReplaceString) + " ", repeat_ct_); EXPECT_STREQ(output.c_str(), received_content.c_str()); // Pre-filter content length should be the original input size. EXPECT_EQ(input_size_, static_cast(received_content_length)); // Filtered content length should be the output size. EXPECT_EQ(output.size(), received_content.size()); // Expected to read 2 full buffers of kResponseBufferSize and one partial // buffer, and then one additional call to drain the overflow. EXPECT_EQ(4U, filter_count_); } private: inline void Write(const char* str, size_t str_size, char*& data_out_ptr, size_t data_out_size, size_t& data_out_written) { // Number of bytes remaining in the output buffer. const size_t remaining_space = data_out_size - data_out_written; // Maximum number of bytes we can write into the output buffer. const size_t max_write = std::min(str_size, remaining_space); // Write the maximum portion that fits in the output buffer. if (max_write == 1) { // Small optimization for single character writes. *data_out_ptr = str[0]; data_out_ptr += 1; data_out_written += 1; } else if (max_write > 1) { memcpy(data_out_ptr, str, max_write); data_out_ptr += max_write; data_out_written += max_write; } if (max_write < str_size) { // Need to write more bytes than will fit in the output buffer. Store the // remainder in the overflow buffer. overflow_ += std::string(str + max_write, str_size - max_write); } } // The portion of the find string that is currently matching. size_t find_match_offset_; // The likely amount of overflow. size_t replace_overflow_size_; // Overflow from the output buffer. std::string overflow_; // The original input size. size_t input_size_; // The number of times the find string was repeated. size_t repeat_ct_; }; // Return a filter error. class ResponseFilterError : public ResponseFilterTestBase { public: ResponseFilterError() {} FilterStatus Filter(void* data_in, size_t data_in_size, size_t& data_in_read, void* data_out, size_t data_out_size, size_t& data_out_written) override { ResponseFilterTestBase::Filter(data_in, data_in_size, data_in_read, data_out, data_out_size, data_out_written); return RESPONSE_FILTER_ERROR; } std::string GetInput() override { return kInputHeader + std::string("ERROR") + kInputFooter; } void VerifyOutput(cef_urlrequest_status_t status, int64 received_content_length, const std::string& received_content) override { ResponseFilterTestBase::VerifyOutput(status, received_content_length, received_content); EXPECT_EQ(UR_FAILED, status); // Expect empty content. const std::string& output = std::string(kInputHeader) + kInputFooter; EXPECT_STREQ(output.c_str(), received_content.c_str()); EXPECT_EQ(0U, received_content_length); // Expect to only be called one time. EXPECT_EQ(filter_count_, 1U); } }; // Browser side. class ResponseFilterTestHandler : public TestHandler { public: explicit ResponseFilterTestHandler( CefRefPtr response_filter) : response_filter_(response_filter) {} void RunTest() override { const std::string& resource = response_filter_->GetInput(); AddResource(kResponseFilterTestUrl, resource, "text/html"); // Create the browser. CreateBrowser(kResponseFilterTestUrl); // Time out the test after a reasonable period of time. SetTestTimeout(); } CefRefPtr GetResourceResponseFilter( CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response) override { EXPECT_IO_THREAD(); DCHECK(!got_resource_response_filter_); got_resource_response_filter_.yes(); return response_filter_; } void OnResourceLoadComplete(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, CefRefPtr response, URLRequestStatus status, int64 received_content_length) override { EXPECT_IO_THREAD(); DCHECK(!got_resource_load_complete_); got_resource_load_complete_.yes(); status_ = status; received_content_length_ = received_content_length; } void OnLoadEnd(CefRefPtr browser, CefRefPtr frame, int httpStatusCode) override { DCHECK(!got_load_end_); got_load_end_.yes(); EXPECT_TRUE(httpStatusCode == 0 || httpStatusCode == 200); GetOutputContent(frame); } private: // Retrieve the output content using a StringVisitor. This effectively // serializes the DOM from the renderer process so any comparison to the // filter output is somewhat error-prone. void GetOutputContent(CefRefPtr frame) { class StringVisitor : public CefStringVisitor { public: typedef base::Callback VisitorCallback; explicit StringVisitor(const VisitorCallback& callback) : callback_(callback) {} void Visit(const CefString& string) override { callback_.Run(string); callback_.Reset(); } private: VisitorCallback callback_; IMPLEMENT_REFCOUNTING(StringVisitor); }; frame->GetSource(new StringVisitor( base::Bind(&ResponseFilterTestHandler::VerifyOutput, this))); } void VerifyOutput(const std::string& received_content) { response_filter_->VerifyOutput(status_, received_content_length_, received_content); response_filter_ = nullptr; DestroyTest(); } void DestroyTest() override { EXPECT_TRUE(got_resource_response_filter_); EXPECT_TRUE(got_resource_load_complete_); EXPECT_TRUE(got_load_end_); TestHandler::DestroyTest(); } CefRefPtr response_filter_; TrackCallback got_resource_response_filter_; TrackCallback got_resource_load_complete_; TrackCallback got_load_end_; URLRequestStatus status_; int64 received_content_length_; IMPLEMENT_REFCOUNTING(ResponseFilterTestHandler); }; } // namespace // Pass through contents unchanged. Read all available input. TEST(RequestHandlerTest, ResponseFilterPassThruReadAll) { CefRefPtr handler = new ResponseFilterTestHandler(new ResponseFilterPassThru(false)); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Pass through contents unchanged. Read limited input. TEST(RequestHandlerTest, ResponseFilterPassThruReadLimited) { CefRefPtr handler = new ResponseFilterTestHandler(new ResponseFilterPassThru(true)); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Find/replace contents such that we occasionally need more data. TEST(RequestHandlerTest, ResponseFilterNeedMore) { CefRefPtr handler = new ResponseFilterTestHandler(new ResponseFilterNeedMore()); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Error during filtering. TEST(RequestHandlerTest, ResponseFilterError) { CefRefPtr handler = new ResponseFilterTestHandler(new ResponseFilterError()); handler->ExecuteTest(); 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 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 request, CefRefPtr 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 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 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(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 Create(CefRefPtr browser, CefRefPtr frame, const CefString& scheme_name, CefRefPtr 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 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(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 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 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 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 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 server, int connection_id, const CefString& client_address, CefRefPtr 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 server, int connection_id, const CefString& client_address, CefRefPtr request, CefRefPtr callback) override { NOTREACHED(); } void OnWebSocketConnected(CefRefPtr server, int connection_id) override { NOTREACHED(); } void OnWebSocketMessage(CefRefPtr 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 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 server, int connection_id, CefRefPtr 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 server, int connection_id, CefRefPtr response, const std::string& response_data) { int response_code = response->GetStatus(); const CefString& content_type = response->GetMimeType(); int64 content_length = static_cast(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 ResponseDataMap; ResponseDataMap data_map_; CefRefPtr server_; CefRefPtr 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 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_READ_WRITE = BLOCK_READ | BLOCK_WRITE, BLOCK_ALL = 1 << 2, }; class RequestContextHandler : public CefRequestContextHandler { public: explicit RequestContextHandler(CookieAccessTestHandler* handler) : handler_(handler) {} CefRefPtr GetCookieManager() override { EXPECT_TRUE(handler_); EXPECT_TRUE(CefCurrentlyOn(TID_IO)); handler_->got_cookie_manager_.yes(); return handler_->cookie_manager_; } void Detach() { handler_ = NULL; } private: CookieAccessTestHandler* handler_; IMPLEMENT_REFCOUNTING(RequestContextHandler); }; CookieAccessTestHandler(TestMode test_mode, bool server_backend) : test_mode_(test_mode), server_backend_(server_backend) {} void RunTest() override { if (test_mode_ == BLOCK_ALL) { cookie_manager_ = CefCookieManager::GetBlockingManager(); context_handler_ = new RequestContextHandler(this); // Create a request context that uses |context_handler_|. CefRequestContextSettings settings; context_ = CefRequestContext::CreateContext(settings, context_handler_.get()); } else { 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; if (context_) context_ = NULL; if (context_handler_) { context_handler_->Detach(); context_handler_ = NULL; } // Got both network requests. EXPECT_TRUE(data1_.got_request_); EXPECT_TRUE(data2_.got_request_); if (test_mode_ == BLOCK_ALL) { EXPECT_TRUE(got_cookie_manager_); // The callback to set the cookie comes before the actual storage fails. EXPECT_TRUE(got_can_set_cookie1_); if (!server_backend_) { // The callback to set the cookie comes before the actual storage fails. EXPECT_TRUE(data1_.got_can_set_cookie_net_); } else { EXPECT_FALSE(data1_.got_can_set_cookie_net_); } // No cookies stored anywhere. EXPECT_FALSE(got_can_get_cookies2_); EXPECT_FALSE(got_cookie_js1_); EXPECT_FALSE(got_cookie_js2_); EXPECT_FALSE(got_cookie_js3_); EXPECT_FALSE(got_cookie_net1_); EXPECT_FALSE(got_cookie_net2_); EXPECT_FALSE(got_cookie_net3_); EXPECT_FALSE(data1_.got_cookie_js_); EXPECT_FALSE(data1_.got_cookie_net_); EXPECT_FALSE(data1_.got_can_get_cookie_js_); EXPECT_FALSE(data1_.got_can_get_cookie_net_); EXPECT_FALSE(data1_.got_can_set_cookie_js_); EXPECT_FALSE(data2_.got_cookie_js_); EXPECT_FALSE(data2_.got_cookie_net_); EXPECT_FALSE(data2_.got_can_get_cookie_js_); EXPECT_FALSE(data2_.got_can_get_cookie_net_); EXPECT_FALSE(data2_.got_can_set_cookie_js_); EXPECT_FALSE(data2_.got_can_set_cookie_net_); } else { EXPECT_FALSE(got_cookie_manager_); // 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_); } // 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 browser, CefRefPtr frame, CefRefPtr 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 browser, CefRefPtr frame, CefRefPtr 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 browser, CefRefPtr frame, int64 query_id, const CefString& request, bool persistent, CefRefPtr 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 = "" "" "COOKIE ACCESS TEST 1"; 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 = "" "" "COOKIE ACCESS TEST 2"; 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()); if (context_) { context_->RegisterSchemeHandlerFactory( kCookieAccessScheme, kCookieAccessDomain, scheme_factory_.get()); } else { 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_), context_); } 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_); if (context_) { context_->RegisterSchemeHandlerFactory(kCookieAccessScheme, kCookieAccessDomain, nullptr); } else { CefRegisterSchemeHandlerFactory(kCookieAccessScheme, kCookieAccessDomain, nullptr); } scheme_factory_->Shutdown(complete_callback); scheme_factory_ = nullptr; } TestMode test_mode_; bool server_backend_; CefRefPtr context_handler_; CefRefPtr context_; CefRefPtr cookie_manager_; CefRefPtr server_handler_; CefRefPtr scheme_factory_; CookieAccessData data1_; CookieAccessData data2_; TrackCallback got_cookie_manager_; // 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 handler = new CookieAccessTestHandler(CookieAccessTestHandler::ALLOW, true); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block reading of cookies with server backend. TEST(RequestHandlerTest, CookieAccessServerBlockRead) { CefRefPtr handler = new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_READ, true); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block writing of cookies with server backend. TEST(RequestHandlerTest, CookieAccessServerBlockWrite) { CefRefPtr handler = new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_WRITE, true); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block reading and writing of cookies with server backend. TEST(RequestHandlerTest, CookieAccessServerBlockReadWrite) { CefRefPtr handler = new CookieAccessTestHandler( CookieAccessTestHandler::BLOCK_READ_WRITE, true); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block all cookies with server backend. TEST(RequestHandlerTest, CookieAccessServerBlockAll) { CefRefPtr 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 handler = new CookieAccessTestHandler(CookieAccessTestHandler::ALLOW, false); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block reading of cookies with scheme handler backend. TEST(RequestHandlerTest, CookieAccessSchemeBlockRead) { CefRefPtr handler = new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_READ, false); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block writing of cookies with scheme handler backend. TEST(RequestHandlerTest, CookieAccessSchemeBlockWrite) { CefRefPtr handler = new CookieAccessTestHandler(CookieAccessTestHandler::BLOCK_WRITE, false); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block reading and writing of cookies with scheme handler backend. TEST(RequestHandlerTest, CookieAccessSchemeBlockReadWrite) { CefRefPtr handler = new CookieAccessTestHandler( CookieAccessTestHandler::BLOCK_READ_WRITE, false); handler->ExecuteTest(); ReleaseAndWaitForDestructor(handler); } // Block all cookies with scheme handler backend. TEST(RequestHandlerTest, CookieAccessSchemeBlockAll) { CefRefPtr 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( ClientAppBrowser::DelegateSet& delegates) { delegates.insert(new NetNotifyBrowserTest); } // Entry point for creating request handler renderer test objects. // Called from client_app_delegates.cc. void CreateRequestHandlerRendererTests( ClientAppRenderer::DelegateSet& delegates) { delegates.insert(new NetNotifyRendererTest); }