| // Copyright (c) 2012 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 <vector> |
| |
| #include "include/base/cef_bind.h" |
| #include "include/base/cef_logging.h" |
| #include "include/base/cef_ref_counted.h" |
| #include "include/cef_cookie.h" |
| #include "include/cef_request_context_handler.h" |
| #include "include/cef_scheme.h" |
| #include "include/cef_server.h" |
| #include "include/cef_waitable_event.h" |
| #include "include/wrapper/cef_closure_task.h" |
| #include "tests/ceftests/routing_test_handler.h" |
| #include "tests/ceftests/test_handler.h" |
| #include "tests/ceftests/test_suite.h" |
| #include "tests/ceftests/test_util.h" |
| #include "tests/gtest/include/gtest/gtest.h" |
| |
| namespace { |
| |
| const char* kTestUrl = "http://www.test.com/path/to/cookietest/foo.html"; |
| const char* kTestDomain = "www.test.com"; |
| const char* kTestPath = "/path/to/cookietest"; |
| |
| const int kIgnoreNumDeleted = -2; |
| |
| typedef std::vector<CefCookie> CookieVector; |
| |
| class TestCompletionCallback : public CefCompletionCallback { |
| public: |
| explicit TestCompletionCallback(CefRefPtr<CefWaitableEvent> event) |
| : event_(event) {} |
| |
| void OnComplete() override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| event_->Signal(); |
| } |
| |
| private: |
| CefRefPtr<CefWaitableEvent> event_; |
| |
| IMPLEMENT_REFCOUNTING(TestCompletionCallback); |
| DISALLOW_COPY_AND_ASSIGN(TestCompletionCallback); |
| }; |
| |
| class TestSetCookieCallback : public CefSetCookieCallback { |
| public: |
| TestSetCookieCallback(bool expected_success, |
| CefRefPtr<CefWaitableEvent> event) |
| : expected_success_(expected_success), event_(event) {} |
| |
| void OnComplete(bool success) override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| EXPECT_EQ(expected_success_, success); |
| event_->Signal(); |
| } |
| |
| private: |
| bool expected_success_; |
| CefRefPtr<CefWaitableEvent> event_; |
| |
| IMPLEMENT_REFCOUNTING(TestSetCookieCallback); |
| DISALLOW_COPY_AND_ASSIGN(TestSetCookieCallback); |
| }; |
| |
| class TestDeleteCookiesCallback : public CefDeleteCookiesCallback { |
| public: |
| TestDeleteCookiesCallback(int expected_num_deleted, |
| CefRefPtr<CefWaitableEvent> event) |
| : expected_num_deleted_(expected_num_deleted), event_(event) {} |
| |
| void OnComplete(int num_deleted) override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| if (expected_num_deleted_ != kIgnoreNumDeleted) { |
| EXPECT_EQ(expected_num_deleted_, num_deleted); |
| } |
| event_->Signal(); |
| } |
| |
| private: |
| int expected_num_deleted_; |
| CefRefPtr<CefWaitableEvent> event_; |
| |
| IMPLEMENT_REFCOUNTING(TestDeleteCookiesCallback); |
| DISALLOW_COPY_AND_ASSIGN(TestDeleteCookiesCallback); |
| }; |
| |
| class TestVisitor : public CefCookieVisitor { |
| public: |
| TestVisitor(CookieVector* cookies, |
| bool deleteCookies, |
| const base::Closure& callback) |
| : cookies_(cookies), delete_cookies_(deleteCookies), callback_(callback) { |
| EXPECT_TRUE(cookies_); |
| EXPECT_FALSE(callback_.is_null()); |
| } |
| ~TestVisitor() override { callback_.Run(); } |
| |
| bool Visit(const CefCookie& cookie, |
| int count, |
| int total, |
| bool& deleteCookie) override { |
| EXPECT_TRUE(CefCurrentlyOn(TID_UI)); |
| cookies_->push_back(cookie); |
| if (delete_cookies_) |
| deleteCookie = true; |
| return true; |
| } |
| |
| private: |
| CookieVector* cookies_; |
| bool delete_cookies_; |
| base::Closure callback_; |
| |
| IMPLEMENT_REFCOUNTING(TestVisitor); |
| }; |
| |
| // Set the cookies. |
| void SetCookies(CefRefPtr<CefCookieManager> manager, |
| const CefString& url, |
| const CookieVector& cookies, |
| bool expected_success, |
| CefRefPtr<CefWaitableEvent> event) { |
| CookieVector::const_iterator it = cookies.begin(); |
| for (; it != cookies.end(); ++it) { |
| EXPECT_TRUE(manager->SetCookie( |
| url, *it, new TestSetCookieCallback(expected_success, event))); |
| event->Wait(); |
| } |
| } |
| |
| // Delete the cookie. |
| void DeleteCookies(CefRefPtr<CefCookieManager> manager, |
| const CefString& url, |
| const CefString& cookie_name, |
| int expected_num_deleted, |
| CefRefPtr<CefWaitableEvent> event) { |
| EXPECT_TRUE(manager->DeleteCookies( |
| url, cookie_name, |
| new TestDeleteCookiesCallback(expected_num_deleted, event))); |
| event->Wait(); |
| } |
| |
| // Create a test cookie. If |withDomain| is true a domain cookie will be |
| // created, otherwise a host cookie will be created. |
| void CreateCookie(CefRefPtr<CefCookieManager> manager, |
| CefCookie& cookie, |
| bool withDomain, |
| bool sessionCookie, |
| CefRefPtr<CefWaitableEvent> event) { |
| CefString(&cookie.name).FromASCII("my_cookie"); |
| CefString(&cookie.value).FromASCII("My Value"); |
| if (withDomain) |
| CefString(&cookie.domain).FromASCII(kTestDomain); |
| CefString(&cookie.path).FromASCII(kTestPath); |
| if (!sessionCookie) { |
| cookie.has_expires = true; |
| cookie.expires.year = 2200; |
| cookie.expires.month = 4; |
| cookie.expires.day_of_week = 5; |
| cookie.expires.day_of_month = 11; |
| } |
| |
| CookieVector cookies; |
| cookies.push_back(cookie); |
| |
| SetCookies(manager, kTestUrl, cookies, true, event); |
| } |
| |
| // Visit URL cookies. Execute |callback| on completion. |
| void VisitUrlCookies(CefRefPtr<CefCookieManager> manager, |
| const CefString& url, |
| bool includeHttpOnly, |
| CookieVector& cookies, |
| bool deleteCookies, |
| const base::Closure& callback) { |
| EXPECT_TRUE(manager->VisitUrlCookies( |
| url, includeHttpOnly, |
| new TestVisitor(&cookies, deleteCookies, callback))); |
| } |
| |
| // Visit URL cookies. Block on |event|. |
| void VisitUrlCookies(CefRefPtr<CefCookieManager> manager, |
| const CefString& url, |
| bool includeHttpOnly, |
| CookieVector& cookies, |
| bool deleteCookies, |
| CefRefPtr<CefWaitableEvent> event) { |
| VisitUrlCookies(manager, url, includeHttpOnly, cookies, deleteCookies, |
| base::Bind(&CefWaitableEvent::Signal, event)); |
| event->Wait(); |
| } |
| |
| // Visit all cookies. Execute |callback| on completion. |
| void VisitAllCookies(CefRefPtr<CefCookieManager> manager, |
| CookieVector& cookies, |
| bool deleteCookies, |
| const base::Closure& callback) { |
| EXPECT_TRUE(manager->VisitAllCookies( |
| new TestVisitor(&cookies, deleteCookies, callback))); |
| } |
| |
| // Visit all cookies. Block on |event|. |
| void VisitAllCookies(CefRefPtr<CefCookieManager> manager, |
| CookieVector& cookies, |
| bool deleteCookies, |
| CefRefPtr<CefWaitableEvent> event) { |
| VisitAllCookies(manager, cookies, deleteCookies, |
| base::Bind(&CefWaitableEvent::Signal, event)); |
| event->Wait(); |
| } |
| |
| // Retrieve the test cookie. If |withDomain| is true check that the cookie |
| // is a domain cookie, otherwise a host cookie. if |deleteCookies| is true |
| // the cookie will be deleted when it's retrieved. |
| void GetCookie(CefRefPtr<CefCookieManager> manager, |
| const CefCookie& cookie, |
| bool withDomain, |
| CefRefPtr<CefWaitableEvent> event, |
| bool deleteCookies) { |
| CookieVector cookies; |
| |
| // Get the cookie and delete it. |
| VisitUrlCookies(manager, kTestUrl, false, cookies, deleteCookies, event); |
| |
| EXPECT_EQ(1U, cookies.size()); |
| if (cookies.size() != 1U) |
| return; |
| |
| const CefCookie& cookie_read = cookies[0]; |
| EXPECT_EQ(CefString(&cookie_read.name), "my_cookie"); |
| EXPECT_EQ(CefString(&cookie_read.value), "My Value"); |
| if (withDomain) |
| EXPECT_EQ(CefString(&cookie_read.domain), ".www.test.com"); |
| else |
| EXPECT_EQ(CefString(&cookie_read.domain), kTestDomain); |
| EXPECT_EQ(CefString(&cookie_read.path), kTestPath); |
| EXPECT_EQ(cookie.has_expires, cookie_read.has_expires); |
| EXPECT_EQ(cookie.expires.year, cookie_read.expires.year); |
| EXPECT_EQ(cookie.expires.month, cookie_read.expires.month); |
| EXPECT_EQ(cookie.expires.day_of_week, cookie_read.expires.day_of_week); |
| EXPECT_EQ(cookie.expires.day_of_month, cookie_read.expires.day_of_month); |
| EXPECT_EQ(cookie.expires.hour, cookie_read.expires.hour); |
| EXPECT_EQ(cookie.expires.minute, cookie_read.expires.minute); |
| EXPECT_EQ(cookie.expires.second, cookie_read.expires.second); |
| EXPECT_EQ(cookie.expires.millisecond, cookie_read.expires.millisecond); |
| EXPECT_EQ(cookie.same_site, cookie_read.same_site); |
| EXPECT_EQ(cookie.priority, cookie_read.priority); |
| } |
| |
| // Verify that no cookies exist. If |withUrl| is true it will only check for |
| // cookies matching the URL. |
| void VerifyNoCookies(CefRefPtr<CefCookieManager> manager, |
| CefRefPtr<CefWaitableEvent> event, |
| bool withUrl) { |
| CookieVector cookies; |
| |
| // Verify that the cookie has been deleted. |
| if (withUrl) { |
| VisitUrlCookies(manager, kTestUrl, false, cookies, false, event); |
| } else { |
| VisitAllCookies(manager, cookies, false, event); |
| } |
| |
| EXPECT_EQ(0U, cookies.size()); |
| } |
| |
| // Delete all system cookies. |
| void DeleteAllCookies(CefRefPtr<CefCookieManager> manager, |
| CefRefPtr<CefWaitableEvent> event) { |
| DeleteCookies(manager, CefString(), CefString(), kIgnoreNumDeleted, event); |
| } |
| |
| void TestDomainCookie(CefRefPtr<CefCookieManager> manager, |
| CefRefPtr<CefWaitableEvent> event) { |
| CefCookie cookie; |
| |
| // Create a domain cookie. |
| CreateCookie(manager, cookie, true, false, event); |
| |
| // Retrieve, verify and delete the domain cookie. |
| GetCookie(manager, cookie, true, event, true); |
| |
| // Verify that the cookie was deleted. |
| VerifyNoCookies(manager, event, true); |
| } |
| |
| void TestHostCookie(CefRefPtr<CefCookieManager> manager, |
| CefRefPtr<CefWaitableEvent> event) { |
| CefCookie cookie; |
| |
| // Create a host cookie. |
| CreateCookie(manager, cookie, false, false, event); |
| |
| // Retrieve, verify and delete the host cookie. |
| GetCookie(manager, cookie, false, event, true); |
| |
| // Verify that the cookie was deleted. |
| VerifyNoCookies(manager, event, true); |
| } |
| |
| void TestInvalidCookie(CefRefPtr<CefCookieManager> manager, |
| CefRefPtr<CefWaitableEvent> event) { |
| CookieVector cookies; |
| |
| CefCookie cookie; |
| const char* kUrl = "http://www.xyz.com"; |
| CefString(&cookie.name).FromASCII("invalid1"); |
| CefString(&cookie.value).FromASCII("invalid1"); |
| CefString(&cookie.domain).FromASCII(".zyx.com"); // domain mismatch |
| |
| cookies.push_back(cookie); |
| |
| // No cookies will be set due to non canonical cookie |
| SetCookies(manager, kUrl, cookies, false, event); |
| } |
| |
| void TestMultipleCookies(CefRefPtr<CefCookieManager> manager, |
| CefRefPtr<CefWaitableEvent> event) { |
| std::stringstream ss; |
| int i; |
| |
| CookieVector cookies; |
| |
| const int kNumCookies = 4; |
| |
| // Create the cookies. |
| for (i = 0; i < kNumCookies; i++) { |
| CefCookie cookie; |
| |
| ss << "my_cookie" << i; |
| CefString(&cookie.name).FromASCII(ss.str().c_str()); |
| ss.str(""); |
| ss << "My Value " << i; |
| CefString(&cookie.value).FromASCII(ss.str().c_str()); |
| ss.str(""); |
| |
| cookies.push_back(cookie); |
| } |
| |
| // Set the cookies. |
| SetCookies(manager, kTestUrl, cookies, true, event); |
| cookies.clear(); |
| |
| // Get the cookies without deleting them. |
| VisitUrlCookies(manager, kTestUrl, false, cookies, false, event); |
| |
| EXPECT_EQ((CookieVector::size_type)kNumCookies, cookies.size()); |
| |
| CookieVector::const_iterator it = cookies.begin(); |
| for (i = 0; it != cookies.end(); ++it, ++i) { |
| const CefCookie& cookie = *it; |
| |
| ss << "my_cookie" << i; |
| EXPECT_EQ(CefString(&cookie.name), ss.str()); |
| ss.str(""); |
| ss << "My Value " << i; |
| EXPECT_EQ(CefString(&cookie.value), ss.str()); |
| ss.str(""); |
| } |
| |
| cookies.clear(); |
| |
| // Delete the 2nd cookie. |
| DeleteCookies(manager, kTestUrl, CefString("my_cookie1"), 1, event); |
| |
| // Verify that the cookie has been deleted. |
| VisitUrlCookies(manager, kTestUrl, false, cookies, false, event); |
| |
| EXPECT_EQ(3U, cookies.size()); |
| if (cookies.size() != 3U) |
| return; |
| |
| EXPECT_EQ(CefString(&cookies[0].name), "my_cookie0"); |
| EXPECT_EQ(CefString(&cookies[1].name), "my_cookie2"); |
| EXPECT_EQ(CefString(&cookies[2].name), "my_cookie3"); |
| |
| cookies.clear(); |
| |
| // Delete the rest of the cookies. |
| DeleteCookies(manager, kTestUrl, CefString(), 3, event); |
| |
| // Verify that the cookies have been deleted. |
| VisitUrlCookies(manager, kTestUrl, false, cookies, false, event); |
| |
| EXPECT_EQ(0U, cookies.size()); |
| |
| // Create the cookies. |
| for (i = 0; i < kNumCookies; i++) { |
| CefCookie cookie; |
| |
| ss << "my_cookie" << i; |
| CefString(&cookie.name).FromASCII(ss.str().c_str()); |
| ss.str(""); |
| ss << "My Value " << i; |
| CefString(&cookie.value).FromASCII(ss.str().c_str()); |
| ss.str(""); |
| |
| cookies.push_back(cookie); |
| } |
| |
| // Delete all of the cookies using the visitor. |
| VisitUrlCookies(manager, kTestUrl, false, cookies, true, event); |
| |
| cookies.clear(); |
| |
| // Verify that the cookies have been deleted. |
| VisitUrlCookies(manager, kTestUrl, false, cookies, false, event); |
| |
| EXPECT_EQ(0U, cookies.size()); |
| } |
| |
| void TestAllCookies(CefRefPtr<CefCookieManager> manager, |
| CefRefPtr<CefWaitableEvent> event) { |
| CookieVector cookies; |
| |
| // Delete all system cookies just in case something is left over from a |
| // different test. |
| DeleteAllCookies(manager, event); |
| |
| // Verify that all system cookies have been deleted. |
| VisitAllCookies(manager, cookies, false, event); |
| |
| EXPECT_EQ(0U, cookies.size()); |
| |
| // Create cookies with 2 separate hosts. |
| CefCookie cookie1; |
| const char* kUrl1 = "http://www.foo.com"; |
| CefString(&cookie1.name).FromASCII("my_cookie1"); |
| CefString(&cookie1.value).FromASCII("My Value 1"); |
| |
| cookies.push_back(cookie1); |
| SetCookies(manager, kUrl1, cookies, true, event); |
| cookies.clear(); |
| |
| CefCookie cookie2; |
| const char* kUrl2 = "http://www.bar.com"; |
| CefString(&cookie2.name).FromASCII("my_cookie2"); |
| CefString(&cookie2.value).FromASCII("My Value 2"); |
| |
| cookies.push_back(cookie2); |
| SetCookies(manager, kUrl2, cookies, true, event); |
| cookies.clear(); |
| |
| // Verify that all system cookies can be retrieved. |
| VisitAllCookies(manager, cookies, false, event); |
| |
| EXPECT_EQ(2U, cookies.size()); |
| if (cookies.size() != 2U) |
| return; |
| |
| EXPECT_EQ(CefString(&cookies[0].name), "my_cookie1"); |
| EXPECT_EQ(CefString(&cookies[0].value), "My Value 1"); |
| EXPECT_EQ(CefString(&cookies[0].domain), "www.foo.com"); |
| EXPECT_EQ(CefString(&cookies[1].name), "my_cookie2"); |
| EXPECT_EQ(CefString(&cookies[1].value), "My Value 2"); |
| EXPECT_EQ(CefString(&cookies[1].domain), "www.bar.com"); |
| cookies.clear(); |
| |
| // Verify that the cookies can be retrieved separately. |
| VisitUrlCookies(manager, kUrl1, false, cookies, false, event); |
| |
| EXPECT_EQ(1U, cookies.size()); |
| if (cookies.size() != 1U) |
| return; |
| |
| EXPECT_EQ(CefString(&cookies[0].name), "my_cookie1"); |
| EXPECT_EQ(CefString(&cookies[0].value), "My Value 1"); |
| EXPECT_EQ(CefString(&cookies[0].domain), "www.foo.com"); |
| cookies.clear(); |
| |
| VisitUrlCookies(manager, kUrl2, false, cookies, false, event); |
| |
| EXPECT_EQ(1U, cookies.size()); |
| if (cookies.size() != 1U) |
| return; |
| |
| EXPECT_EQ(CefString(&cookies[0].name), "my_cookie2"); |
| EXPECT_EQ(CefString(&cookies[0].value), "My Value 2"); |
| EXPECT_EQ(CefString(&cookies[0].domain), "www.bar.com"); |
| cookies.clear(); |
| |
| // Delete all of the system cookies. |
| DeleteAllCookies(manager, event); |
| |
| // Verify that all system cookies have been deleted. |
| VerifyNoCookies(manager, event, false); |
| } |
| |
| } // namespace |
| |
| // Test creation of a invalid cookie. |
| TEST(CookieTest, BasicInvalidCookie) { |
| CefRefPtr<CefWaitableEvent> event = |
| CefWaitableEvent::CreateWaitableEvent(true, false); |
| |
| CefRefPtr<CefCookieManager> manager = |
| CefCookieManager::GetGlobalManager(new TestCompletionCallback(event)); |
| event->Wait(); |
| EXPECT_TRUE(manager.get()); |
| |
| TestInvalidCookie(manager, event); |
| } |
| |
| // Test creation of a domain cookie. |
| TEST(CookieTest, BasicDomainCookie) { |
| CefRefPtr<CefWaitableEvent> event = |
| CefWaitableEvent::CreateWaitableEvent(true, false); |
| |
| CefRefPtr<CefCookieManager> manager = |
| CefCookieManager::GetGlobalManager(new TestCompletionCallback(event)); |
| event->Wait(); |
| EXPECT_TRUE(manager.get()); |
| |
| TestDomainCookie(manager, event); |
| } |
| |
| // Test creation of a host cookie. |
| TEST(CookieTest, BasicHostCookie) { |
| CefRefPtr<CefWaitableEvent> event = |
| CefWaitableEvent::CreateWaitableEvent(true, false); |
| |
| CefRefPtr<CefCookieManager> manager = |
| CefCookieManager::GetGlobalManager(new TestCompletionCallback(event)); |
| event->Wait(); |
| EXPECT_TRUE(manager.get()); |
| |
| TestHostCookie(manager, event); |
| } |
| |
| // Test creation of multiple cookies. |
| TEST(CookieTest, BasicMultipleCookies) { |
| CefRefPtr<CefWaitableEvent> event = |
| CefWaitableEvent::CreateWaitableEvent(true, false); |
| |
| CefRefPtr<CefCookieManager> manager = |
| CefCookieManager::GetGlobalManager(new TestCompletionCallback(event)); |
| event->Wait(); |
| EXPECT_TRUE(manager.get()); |
| |
| TestMultipleCookies(manager, event); |
| } |
| |
| TEST(CookieTest, BasicAllCookies) { |
| CefRefPtr<CefWaitableEvent> event = |
| CefWaitableEvent::CreateWaitableEvent(true, false); |
| |
| CefRefPtr<CefCookieManager> manager = |
| CefCookieManager::GetGlobalManager(new TestCompletionCallback(event)); |
| event->Wait(); |
| EXPECT_TRUE(manager.get()); |
| |
| TestAllCookies(manager, event); |
| } |
| |
| namespace { |
| |
| const char* kCookieJSUrl1 = "http://tests/cookie1.html"; |
| const char* kCookieJSUrl2 = "http://tests/cookie2.html"; |
| |
| class CookieTestJSHandler : public TestHandler { |
| public: |
| CookieTestJSHandler() {} |
| |
| void RunTest() override { |
| std::string page = |
| "<html><head>" |
| "<script>" |
| "document.cookie='name1=value1;" |
| // Invalid date should not cause a crash (see issue #2927). |
| " expires=Tue, 07 Nov 94276 07:58:05 GMT'" |
| "</script>" |
| "</head><body>COOKIE TEST1</body></html>"; |
| AddResource(kCookieJSUrl1, page, "text/html"); |
| |
| page = |
| "<html><head>" |
| "<script>" |
| "document.cookie='name2=value2';" |
| "</script>" |
| "</head><body>COOKIE TEST2</body></html>"; |
| AddResource(kCookieJSUrl2, page, "text/html"); |
| |
| // Create the request context that will use an in-memory cache. |
| CefRequestContextSettings settings; |
| CefRefPtr<CefRequestContext> request_context = |
| CefRequestContext::CreateContext(settings, nullptr); |
| manager_ = request_context->GetCookieManager(nullptr); |
| |
| // Create the browser. |
| CreateBrowser(kCookieJSUrl1, request_context); |
| |
| // Time out the test after a reasonable period of time. |
| SetTestTimeout(); |
| } |
| |
| // Go to the next URL. |
| void LoadNextURL(CefRefPtr<CefFrame> frame) { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, |
| base::Bind(&CookieTestJSHandler::LoadNextURL, this, frame)); |
| return; |
| } |
| |
| frame->LoadURL(kCookieJSUrl2); |
| } |
| |
| void CompleteTest() { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, base::Bind(&CookieTestJSHandler::CompleteTest, this)); |
| return; |
| } |
| |
| DestroyTest(); |
| } |
| |
| void OnLoadEnd(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| int httpStatusCode) override { |
| std::string url = frame->GetURL(); |
| if (url == kCookieJSUrl1) { |
| got_load_end1_.yes(); |
| VerifyCookie(manager_, url, "name1", "value1", true, &got_cookie1_, |
| base::Bind(&CookieTestJSHandler::LoadNextURL, this, frame)); |
| } else { |
| got_load_end2_.yes(); |
| VerifyCookie(manager_, url, "name2", "value2", true, &got_cookie2_, |
| base::Bind(&CookieTestJSHandler::CompleteTest, this)); |
| } |
| } |
| |
| // Verify that the cookie was set successfully. |
| void VerifyCookie(CefRefPtr<CefCookieManager> manager, |
| const std::string& url, |
| const std::string& name, |
| const std::string& value, |
| bool deleteCookie, |
| TrackCallback* callback, |
| const base::Closure& continue_callback) { |
| // Get the cookie. |
| EXPECT_TRUE(cookies_.empty()); |
| VisitUrlCookies(manager, url, false, cookies_, deleteCookie, |
| base::Bind(&CookieTestJSHandler::VerifyCookieComplete, this, |
| name, value, callback, continue_callback)); |
| } |
| |
| void VerifyCookieComplete(const std::string& name, |
| const std::string& value, |
| TrackCallback* callback, |
| const base::Closure& continue_callback) { |
| if (cookies_.size() == 1U && CefString(&cookies_[0].name) == name && |
| CefString(&cookies_[0].value) == value) { |
| callback->yes(); |
| } |
| |
| cookies_.clear(); |
| continue_callback.Run(); |
| } |
| |
| CefRefPtr<CefCookieManager> manager_; |
| |
| CookieVector cookies_; |
| |
| TrackCallback got_load_end1_; |
| TrackCallback got_load_end2_; |
| TrackCallback got_cookie1_; |
| TrackCallback got_cookie2_; |
| |
| IMPLEMENT_REFCOUNTING(CookieTestJSHandler); |
| }; |
| |
| } // namespace |
| |
| // Verify use of multiple cookie managers vis JS. |
| TEST(CookieTest, GetCookieManagerJS) { |
| CefRefPtr<CookieTestJSHandler> handler = new CookieTestJSHandler(); |
| handler->ExecuteTest(); |
| |
| EXPECT_TRUE(handler->got_load_end1_); |
| EXPECT_TRUE(handler->got_load_end2_); |
| EXPECT_TRUE(handler->got_cookie1_); |
| EXPECT_TRUE(handler->got_cookie2_); |
| |
| ReleaseAndWaitForDestructor(handler); |
| } |
| |
| namespace { |
| |
| const char kCustomCookieScheme[] = "ccustom"; |
| |
| class CompletionCallback : public CefCompletionCallback { |
| public: |
| explicit CompletionCallback(const base::Closure& callback) |
| : callback_(callback) {} |
| |
| void OnComplete() override { |
| callback_.Run(); |
| callback_.Reset(); |
| } |
| |
| private: |
| base::Closure callback_; |
| IMPLEMENT_REFCOUNTING(CompletionCallback); |
| }; |
| |
| class CookieTestSchemeHandler : public TestHandler { |
| public: |
| class SchemeHandler : public CefResourceHandler { |
| public: |
| explicit SchemeHandler(CookieTestSchemeHandler* handler) |
| : handler_(handler), offset_(0) {} |
| |
| bool Open(CefRefPtr<CefRequest> request, |
| bool& handle_request, |
| CefRefPtr<CefCallback> callback) override { |
| EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); |
| |
| std::string url = request->GetURL(); |
| if (url == handler_->url1_) { |
| content_ = "<html><body>COOKIE TEST1</body></html>"; |
| cookie_ = "name1=value1"; |
| handler_->got_process_request1_.yes(); |
| } else if (url == handler_->url2_) { |
| content_ = "<html><body>COOKIE TEST2</body></html>"; |
| cookie_ = "name2=value2"; |
| handler_->got_process_request2_.yes(); |
| } else if (url == handler_->url3_) { |
| content_ = "<html><body>COOKIE TEST3</body></html>"; |
| handler_->got_process_request3_.yes(); |
| |
| // Verify that the cookie was passed in. |
| CefRequest::HeaderMap headerMap; |
| request->GetHeaderMap(headerMap); |
| CefRequest::HeaderMap::iterator it = headerMap.find("Cookie"); |
| if (it != headerMap.end() && it->second == "name2=value2") |
| handler_->got_process_request_cookie_.yes(); |
| } |
| |
| // Continue immediately. |
| handle_request = true; |
| return true; |
| } |
| |
| void GetResponseHeaders(CefRefPtr<CefResponse> response, |
| int64& response_length, |
| CefString& redirectUrl) override { |
| response_length = content_.size(); |
| |
| response->SetStatus(200); |
| response->SetMimeType("text/html"); |
| |
| if (!cookie_.empty()) { |
| CefResponse::HeaderMap headerMap; |
| response->GetHeaderMap(headerMap); |
| headerMap.insert(std::make_pair("Set-Cookie", cookie_)); |
| response->SetHeaderMap(headerMap); |
| } |
| } |
| |
| bool Read(void* data_out, |
| int bytes_to_read, |
| int& bytes_read, |
| CefRefPtr<CefResourceReadCallback> callback) override { |
| EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); |
| |
| bool has_data = false; |
| bytes_read = 0; |
| |
| size_t size = content_.size(); |
| if (offset_ < size) { |
| int transfer_size = |
| std::min(bytes_to_read, static_cast<int>(size - offset_)); |
| memcpy(data_out, content_.c_str() + offset_, transfer_size); |
| offset_ += transfer_size; |
| |
| bytes_read = transfer_size; |
| has_data = true; |
| } |
| |
| return has_data; |
| } |
| |
| void Cancel() override {} |
| |
| private: |
| CookieTestSchemeHandler* handler_; |
| std::string content_; |
| size_t offset_; |
| std::string cookie_; |
| |
| IMPLEMENT_REFCOUNTING(SchemeHandler); |
| DISALLOW_COPY_AND_ASSIGN(SchemeHandler); |
| }; |
| |
| class SchemeHandlerFactory : public CefSchemeHandlerFactory { |
| public: |
| explicit SchemeHandlerFactory(CookieTestSchemeHandler* handler) |
| : handler_(handler) {} |
| |
| CefRefPtr<CefResourceHandler> Create( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| const CefString& scheme_name, |
| CefRefPtr<CefRequest> request) override { |
| std::string url = request->GetURL(); |
| if (url == handler_->url3_) { |
| // Verify that the cookie was not passed in. |
| CefRequest::HeaderMap headerMap; |
| request->GetHeaderMap(headerMap); |
| CefRequest::HeaderMap::iterator it = headerMap.find("Cookie"); |
| if (it != headerMap.end() && it->second == "name2=value2") |
| handler_->got_create_cookie_.yes(); |
| } |
| |
| return new SchemeHandler(handler_); |
| } |
| |
| private: |
| CookieTestSchemeHandler* handler_; |
| |
| IMPLEMENT_REFCOUNTING(SchemeHandlerFactory); |
| DISALLOW_COPY_AND_ASSIGN(SchemeHandlerFactory); |
| }; |
| |
| CookieTestSchemeHandler(const std::string& scheme, |
| bool use_global, |
| bool block_cookies = false) |
| : scheme_(scheme), |
| use_global_(use_global), |
| block_cookies_(block_cookies) { |
| url1_ = scheme + "://cookie-tests/cookie1.html"; |
| url2_ = scheme + "://cookie-tests/cookie2.html"; |
| url3_ = scheme + "://cookie-tests/cookie3.html"; |
| } |
| |
| void RunTest() override { |
| if (use_global_) { |
| request_context_ = CefRequestContext::GetGlobalContext(); |
| } else { |
| // Create the request context that will use an in-memory cache. |
| CefRequestContextSettings settings; |
| request_context_ = CefRequestContext::CreateContext(settings, nullptr); |
| } |
| |
| // Register the scheme handler. |
| request_context_->RegisterSchemeHandlerFactory( |
| scheme_, "cookie-tests", new SchemeHandlerFactory(this)); |
| manager_ = request_context_->GetCookieManager(nullptr); |
| if (!use_global_ && (scheme_ == kCustomCookieScheme || block_cookies_)) { |
| std::vector<CefString> schemes; |
| if (!block_cookies_) |
| schemes.push_back(kCustomCookieScheme); |
| |
| // Need to wait for completion before creating the browser. |
| manager_->SetSupportedSchemes( |
| schemes, !block_cookies_ /* include_defaults */, |
| new CompletionCallback(base::Bind( |
| &CookieTestSchemeHandler::CreateBrowserContinue, this))); |
| } else { |
| CreateBrowserContinue(); |
| } |
| |
| // Time out the test after a reasonable period of time. |
| SetTestTimeout(); |
| } |
| |
| void CreateBrowserContinue() { |
| // Create the browser. |
| CreateBrowser(url1_, request_context_); |
| } |
| |
| // Go to the next URL. |
| void LoadNextURL(CefRefPtr<CefFrame> frame, const std::string& url) { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, base::Bind(&CookieTestSchemeHandler::LoadNextURL, |
| this, frame, url)); |
| return; |
| } |
| |
| frame->LoadURL(url); |
| } |
| |
| void CompleteTest(CefRefPtr<CefBrowser> browser) { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, base::Bind(&CookieTestSchemeHandler::CompleteTest, |
| this, browser)); |
| return; |
| } |
| |
| // Unregister the scheme handler. |
| browser->GetHost()->GetRequestContext()->RegisterSchemeHandlerFactory( |
| scheme_, "cookie-tests", nullptr); |
| |
| DestroyTest(); |
| } |
| |
| void OnLoadEnd(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| int httpStatusCode) override { |
| std::string url = frame->GetURL(); |
| if (url == url1_) { |
| got_load_end1_.yes(); |
| VerifyCookie(manager_, url, "name1", "value1", true, &got_cookie1_, |
| base::Bind(&CookieTestSchemeHandler::LoadNextURL, this, |
| frame, url2_)); |
| } else if (url == url2_) { |
| got_load_end2_.yes(); |
| VerifyCookie(manager_, url, "name2", "value2", false, &got_cookie2_, |
| base::Bind(&CookieTestSchemeHandler::LoadNextURL, this, |
| frame, url3_)); |
| } else { |
| got_load_end3_.yes(); |
| VerifyCookie( |
| manager_, url, "name2", "value2", true, &got_cookie3_, |
| base::Bind(&CookieTestSchemeHandler::CompleteTest, this, browser)); |
| } |
| } |
| |
| void DestroyTest() override { |
| EXPECT_TRUE(got_process_request1_); |
| EXPECT_TRUE(got_process_request2_); |
| EXPECT_TRUE(got_process_request3_); |
| EXPECT_TRUE(got_load_end1_); |
| EXPECT_TRUE(got_load_end2_); |
| EXPECT_TRUE(got_load_end3_); |
| |
| if (block_cookies_) { |
| EXPECT_FALSE(got_create_cookie_); |
| EXPECT_FALSE(got_process_request_cookie_); |
| EXPECT_FALSE(got_cookie1_); |
| EXPECT_FALSE(got_cookie2_); |
| EXPECT_FALSE(got_cookie3_); |
| } else { |
| EXPECT_TRUE(got_create_cookie_); |
| EXPECT_TRUE(got_process_request_cookie_); |
| EXPECT_TRUE(got_cookie1_); |
| EXPECT_TRUE(got_cookie2_); |
| EXPECT_TRUE(got_cookie3_); |
| } |
| |
| // Unregister the scheme handler. |
| request_context_->RegisterSchemeHandlerFactory(scheme_, "cookie-tests", |
| nullptr); |
| request_context_ = nullptr; |
| |
| TestHandler::DestroyTest(); |
| } |
| |
| // Verify that the cookie was set successfully. |
| void VerifyCookie(CefRefPtr<CefCookieManager> manager, |
| const std::string& url, |
| const std::string& name, |
| const std::string& value, |
| bool deleteCookie, |
| TrackCallback* callback, |
| const base::Closure& continue_callback) { |
| // Get the cookie. |
| EXPECT_TRUE(cookies_.empty()); |
| VisitUrlCookies(manager, url, false, cookies_, deleteCookie, |
| base::Bind(&CookieTestSchemeHandler::VerifyCookieComplete, |
| this, name, value, callback, continue_callback)); |
| } |
| |
| void VerifyCookieComplete(const std::string& name, |
| const std::string& value, |
| TrackCallback* callback, |
| const base::Closure& continue_callback) { |
| if (cookies_.size() == 1U && CefString(&cookies_[0].name) == name && |
| CefString(&cookies_[0].value) == value) { |
| callback->yes(); |
| } |
| |
| cookies_.clear(); |
| continue_callback.Run(); |
| } |
| |
| const std::string scheme_; |
| const bool use_global_; |
| const bool block_cookies_; |
| std::string url1_; |
| std::string url2_; |
| std::string url3_; |
| |
| CefRefPtr<CefRequestContext> request_context_; |
| CefRefPtr<CefCookieManager> manager_; |
| |
| CookieVector cookies_; |
| |
| TrackCallback got_process_request1_; |
| TrackCallback got_process_request2_; |
| TrackCallback got_process_request3_; |
| TrackCallback got_create_cookie_; |
| TrackCallback got_process_request_cookie_; |
| TrackCallback got_load_end1_; |
| TrackCallback got_load_end2_; |
| TrackCallback got_load_end3_; |
| TrackCallback got_cookie1_; |
| TrackCallback got_cookie2_; |
| TrackCallback got_cookie3_; |
| |
| IMPLEMENT_REFCOUNTING(CookieTestSchemeHandler); |
| }; |
| |
| } // namespace |
| |
| // Verify use of the global cookie manager with HTTP. |
| TEST(CookieTest, GetCookieManagerHttpGlobal) { |
| CefRefPtr<CookieTestSchemeHandler> handler = |
| new CookieTestSchemeHandler("http", true); |
| handler->ExecuteTest(); |
| ReleaseAndWaitForDestructor(handler); |
| } |
| |
| // Verify use of an in-memory cookie manager with HTTP. |
| TEST(CookieTest, GetCookieManagerHttpInMemory) { |
| CefRefPtr<CookieTestSchemeHandler> handler = |
| new CookieTestSchemeHandler("http", false); |
| handler->ExecuteTest(); |
| ReleaseAndWaitForDestructor(handler); |
| } |
| |
| // Verify use of an in-memory cookie manager with HTTP to block all cookies. |
| TEST(CookieTest, GetCookieManagerHttpInMemoryBlocked) { |
| CefRefPtr<CookieTestSchemeHandler> handler = |
| new CookieTestSchemeHandler("http", false, true); |
| handler->ExecuteTest(); |
| ReleaseAndWaitForDestructor(handler); |
| } |
| |
| // Verify use of the global cookie manager with a custom scheme. |
| TEST(CookieTest, GetCookieManagerCustomGlobal) { |
| CefRefPtr<CookieTestSchemeHandler> handler = |
| new CookieTestSchemeHandler(kCustomCookieScheme, true); |
| handler->ExecuteTest(); |
| ReleaseAndWaitForDestructor(handler); |
| } |
| |
| // Verify use of an in-memory cookie manager with a custom scheme. |
| TEST(CookieTest, GetCookieManagerCustomInMemory) { |
| CefRefPtr<CookieTestSchemeHandler> handler = |
| new CookieTestSchemeHandler(kCustomCookieScheme, false); |
| 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(const std::string& scheme, |
| bool server_backend) { |
| std::stringstream ss; |
| if (server_backend) { |
| ss << scheme << "://" << kCookieAccessServerIP << ":" |
| << kCookieAccessServerPort; |
| } else { |
| ss << scheme << "://" << kCookieAccessDomain; |
| } |
| ss << "/"; |
| return ss.str(); |
| } |
| |
| std::string GetCookieAccessUrl1(const std::string& scheme, |
| bool server_backend) { |
| return GetCookieAccessOrigin(scheme, server_backend) + "cookie1.html"; |
| } |
| |
| std::string GetCookieAccessUrl2(const std::string& scheme, |
| bool server_backend) { |
| return GetCookieAccessOrigin(scheme, server_backend) + "cookie2.html"; |
| } |
| |
| void TestCookieString(const std::string& cookie_str, |
| int& cookie_js_ct, |
| int& cookie_net_ct) { |
| if (cookie_str.find("name_js=value_js") != std::string::npos) { |
| cookie_js_ct++; |
| } |
| if (cookie_str.find("name_net=value_net") != std::string::npos) { |
| cookie_net_ct++; |
| } |
| } |
| |
| struct CookieAccessData { |
| CefRefPtr<CefResponse> response; |
| std::string response_data; |
| |
| int request_ct_ = 0; |
| int cookie_js_ct_ = 0; |
| int cookie_net_ct_ = 0; |
| }; |
| |
| 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 Open(CefRefPtr<CefRequest> request, |
| bool& handle_request, |
| CefRefPtr<CefCallback> callback) override { |
| EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); |
| |
| CefRequest::HeaderMap headerMap; |
| request->GetHeaderMap(headerMap); |
| const std::string& cookie_str = GetHeaderValue(headerMap, "Cookie"); |
| TestCookieString(cookie_str, data_->cookie_js_ct_, data_->cookie_net_ct_); |
| |
| // Continue immediately. |
| handle_request = true; |
| return true; |
| } |
| |
| void GetResponseHeaders(CefRefPtr<CefResponse> response, |
| int64& response_length, |
| CefString& redirectUrl) override { |
| EXPECT_IO_THREAD(); |
| |
| 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 Read(void* data_out, |
| int bytes_to_read, |
| int& bytes_read, |
| CefRefPtr<CefResourceReadCallback> callback) override { |
| EXPECT_FALSE(CefCurrentlyOn(TID_UI) || CefCurrentlyOn(TID_IO)); |
| |
| bool has_data = false; |
| bytes_read = 0; |
| |
| size_t size = data_->response_data.length(); |
| if (offset_ < size) { |
| int transfer_size = |
| std::min(bytes_to_read, static_cast<int>(size - offset_)); |
| memcpy(data_out, data_->response_data.c_str() + offset_, transfer_size); |
| offset_ += transfer_size; |
| |
| bytes_read = transfer_size; |
| has_data = true; |
| } |
| |
| return has_data; |
| } |
| |
| void Cancel() override { EXPECT_IO_THREAD(); } |
| |
| 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); |
| DISALLOW_COPY_AND_ASSIGN(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_IO_THREAD(); |
| const std::string& url = request->GetURL(); |
| ResponseDataMap::const_iterator it = data_map_.find(url); |
| if (it != data_map_.end()) { |
| it->second->request_ct_++; |
| |
| 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->request_ct_++; |
| |
| CefRequest::HeaderMap headerMap; |
| request->GetHeaderMap(headerMap); |
| const std::string& cookie_str = GetHeaderValue(headerMap, "cookie"); |
| TestCookieString(cookie_str, it->second->cookie_js_ct_, |
| it->second->cookie_net_ct_); |
| |
| 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 CefCookieAccessFilter { |
| public: |
| enum TestMode { |
| ALLOW = 0, |
| BLOCK_READ = 1 << 0, |
| BLOCK_WRITE = 1 << 1, |
| BLOCK_READ_WRITE = BLOCK_READ | BLOCK_WRITE, |
| ALLOW_NO_FILTER = 1 << 2, |
| |
| // Block all cookies using SetSupportedSchemes. Can only be used with a |
| // non-global request context because it's too late (during test execution) |
| // to call this method on the global context. |
| BLOCK_ALL_COOKIES = 1 << 3, |
| |
| // Return nullptr from GetResourceRequestHandler. Can only be used in |
| // combination with the SERVER or SCHEME_HANDLER backend (the |
| // RESOURCE_HANDLER backend would not be called). |
| ALLOW_NO_HANDLER = 1 << 4, |
| }; |
| |
| enum TestBackend { |
| // Test an HTTP server backend. |
| SERVER, |
| |
| // Test a custom scheme handler backend. |
| SCHEME_HANDLER, |
| |
| // Test that GetResourceHandler behaves the same as a custom scheme handler. |
| RESOURCE_HANDLER, |
| }; |
| |
| CookieAccessTestHandler(TestMode test_mode, |
| TestBackend test_backend, |
| bool custom_scheme, |
| bool use_global) |
| : test_mode_(test_mode), |
| test_backend_(test_backend), |
| scheme_(custom_scheme ? kCustomCookieScheme : kCookieAccessScheme), |
| use_global_(use_global) { |
| if (test_mode_ == BLOCK_ALL_COOKIES) |
| CHECK(!use_global_); |
| else if (test_mode_ == ALLOW_NO_HANDLER) |
| CHECK_NE(RESOURCE_HANDLER, test_backend_); |
| if (test_backend_ == SERVER) |
| CHECK(!custom_scheme); |
| } |
| |
| void RunTest() override { |
| if (use_global_) { |
| context_ = CefRequestContext::GetGlobalContext(); |
| } else { |
| // Create the request context that will use an in-memory cache. |
| CefRequestContextSettings settings; |
| context_ = CefRequestContext::CreateContext(settings, nullptr); |
| } |
| |
| cookie_manager_ = context_->GetCookieManager(nullptr); |
| |
| SetTestTimeout(); |
| |
| const bool block_cookies = (test_mode_ == BLOCK_ALL_COOKIES); |
| if (!use_global_ && (scheme_ == kCustomCookieScheme || block_cookies)) { |
| std::vector<CefString> schemes; |
| if (!block_cookies) |
| schemes.push_back(kCustomCookieScheme); |
| |
| // Need to wait for completion before creating the browser. |
| cookie_manager_->SetSupportedSchemes( |
| schemes, !block_cookies /* include_defaults */, |
| new CompletionCallback(base::Bind( |
| &CookieAccessTestHandler::RunTestSetupContinue, this))); |
| } else { |
| RunTestSetupContinue(); |
| } |
| } |
| |
| void DestroyTest() override { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, |
| base::Bind(&CookieAccessTestHandler::DestroyTest, this)); |
| return; |
| } |
| |
| cookie_manager_ = nullptr; |
| context_ = nullptr; |
| |
| // Got both network requests. |
| EXPECT_EQ(1, data1_.request_ct_); |
| EXPECT_EQ(1, data2_.request_ct_); |
| |
| if (test_mode_ == ALLOW_NO_FILTER || test_mode_ == ALLOW_NO_HANDLER) { |
| EXPECT_EQ(0, can_save_cookie1_ct_); |
| EXPECT_EQ(0, can_send_cookie2_ct_); |
| } else { |
| // Get 1 call to CanSaveCookie for the 1st network request due to the |
| // network cookie. |
| EXPECT_EQ(1, can_save_cookie1_ct_); |
| if (test_mode_ == BLOCK_ALL_COOKIES) { |
| // Never send any cookies. |
| EXPECT_EQ(0, can_send_cookie2_ct_); |
| } else if (test_mode_ & BLOCK_WRITE) { |
| // Get 1 calls to CanSendCookie for the 2nd network request due to the |
| // JS cookie (network cookie is blocked). |
| EXPECT_EQ(1, can_send_cookie2_ct_); |
| } else { |
| // Get 2 calls to CanSendCookie for the 2nd network request due to the |
| // network cookie + JS cookie. |
| EXPECT_EQ(2, can_send_cookie2_ct_); |
| } |
| } |
| |
| if (test_mode_ == BLOCK_ALL_COOKIES) { |
| // Never get the JS cookie via JS. |
| EXPECT_EQ(0, cookie_js1_ct_); |
| EXPECT_EQ(0, cookie_js2_ct_); |
| EXPECT_EQ(0, cookie_js3_ct_); |
| } else { |
| // Always get the JS cookie via JS. |
| EXPECT_EQ(1, cookie_js1_ct_); |
| EXPECT_EQ(1, cookie_js2_ct_); |
| EXPECT_EQ(1, cookie_js3_ct_); |
| } |
| |
| // Only get the net cookie via JS if cookie write was allowed. |
| if ((test_mode_ & BLOCK_WRITE) || test_mode_ == BLOCK_ALL_COOKIES) { |
| EXPECT_EQ(0, cookie_net1_ct_); |
| EXPECT_EQ(0, cookie_net2_ct_); |
| EXPECT_EQ(0, cookie_net3_ct_); |
| } else { |
| EXPECT_EQ(1, cookie_net1_ct_); |
| EXPECT_EQ(1, cookie_net2_ct_); |
| EXPECT_EQ(1, cookie_net3_ct_); |
| } |
| |
| // No cookies sent for the 1st network request. |
| EXPECT_EQ(0, data1_.cookie_js_ct_); |
| EXPECT_EQ(0, data1_.cookie_net_ct_); |
| |
| // 2nd network request... |
| if ((test_mode_ & BLOCK_READ) || test_mode_ == BLOCK_ALL_COOKIES) { |
| // No cookies sent if reading was blocked. |
| EXPECT_EQ(0, data2_.cookie_js_ct_); |
| EXPECT_EQ(0, data2_.cookie_net_ct_); |
| } else if (test_mode_ & BLOCK_WRITE) { |
| // Only JS cookie sent if writing was blocked. |
| EXPECT_EQ(1, data2_.cookie_js_ct_); |
| EXPECT_EQ(0, data2_.cookie_net_ct_); |
| } else { |
| // All cookies sent. |
| EXPECT_EQ(1, data2_.cookie_js_ct_); |
| EXPECT_EQ(1, data2_.cookie_net_ct_); |
| } |
| |
| TestHandler::DestroyTest(); |
| } |
| |
| CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request) override { |
| EXPECT_IO_THREAD(); |
| |
| if (test_mode_ == ALLOW_NO_FILTER) |
| return nullptr; |
| |
| return this; |
| } |
| |
| CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| bool is_navigation, |
| bool is_download, |
| const CefString& request_initiator, |
| bool& disable_default_handling) override { |
| if (test_mode_ == ALLOW_NO_HANDLER) |
| return nullptr; |
| |
| return this; |
| } |
| |
| CefRefPtr<CefResourceHandler> GetResourceHandler( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request) override { |
| if (test_backend_ == RESOURCE_HANDLER) { |
| return scheme_factory_->Create(browser, frame, scheme_, request); |
| } |
| |
| return nullptr; |
| } |
| |
| bool CanSendCookie(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| const CefCookie& cookie) override { |
| EXPECT_IO_THREAD(); |
| |
| const std::string& url = request->GetURL(); |
| if (url == GetCookieAccessUrl2(scheme_, test_backend_ == SERVER)) { |
| can_send_cookie2_ct_++; |
| } else { |
| ADD_FAILURE() << "Unexpected url: " << url; |
| } |
| |
| return !(test_mode_ & BLOCK_READ); |
| } |
| |
| bool CanSaveCookie(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| CefRefPtr<CefResponse> response, |
| const CefCookie& cookie) override { |
| EXPECT_IO_THREAD(); |
| |
| // 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(scheme_, test_backend_ == SERVER)) { |
| can_save_cookie1_ct_++; |
| } 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(scheme_, test_backend_ == SERVER)) { |
| TestCookieString(cookie_str, cookie_js1_ct_, cookie_net1_ct_); |
| browser->GetMainFrame()->LoadURL( |
| GetCookieAccessUrl2(scheme_, test_backend_ == SERVER)); |
| } else if (url == GetCookieAccessUrl2(scheme_, test_backend_ == SERVER)) { |
| TestCookieString(cookie_str, cookie_js2_ct_, cookie_net2_ct_); |
| 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(scheme_, test_backend_ == SERVER), &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(scheme_, test_backend_ == SERVER), &data2_); |
| } |
| } |
| |
| void RunTestSetupContinue() { |
| CefPostTask(TID_UI, |
| base::Bind(&CookieAccessTestHandler::StartBackend, this, |
| base::Bind(&CookieAccessTestHandler::RunTestContinue, |
| this))); |
| } |
| |
| void StartBackend(const base::Closure& complete_callback) { |
| if (test_backend_ == SERVER) { |
| 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 (test_backend_ == SCHEME_HANDLER) { |
| context_->RegisterSchemeHandlerFactory(scheme_, kCookieAccessDomain, |
| scheme_factory_.get()); |
| } |
| |
| complete_callback.Run(); |
| } |
| |
| void RunTestContinue() { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, |
| base::Bind(&CookieAccessTestHandler::RunTestContinue, this)); |
| return; |
| } |
| |
| CreateBrowser(GetCookieAccessUrl1(scheme_, test_backend_ == SERVER), |
| 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_->cookie_js3_ct_++; |
| else if (name == "name_net" && value == "value_net") |
| handler_->cookie_net3_ct_++; |
| |
| // 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 (test_backend_ == SERVER) { |
| 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 (test_backend_ == SCHEME_HANDLER) { |
| context_->RegisterSchemeHandlerFactory(scheme_, kCookieAccessDomain, |
| nullptr); |
| } |
| scheme_factory_->Shutdown(complete_callback); |
| scheme_factory_ = nullptr; |
| } |
| |
| const TestMode test_mode_; |
| const TestBackend test_backend_; |
| const std::string scheme_; |
| const bool use_global_; |
| CefRefPtr<CefRequestContext> context_; |
| CefRefPtr<CefCookieManager> cookie_manager_; |
| |
| CefRefPtr<CookieAccessServerHandler> server_handler_; |
| CefRefPtr<CookieAccessSchemeHandlerFactory> scheme_factory_; |
| |
| CookieAccessData data1_; |
| CookieAccessData data2_; |
| |
| // 1st request. |
| int can_save_cookie1_ct_ = 0; |
| int cookie_js1_ct_ = 0; |
| int cookie_net1_ct_ = 0; |
| |
| // 2nd request. |
| int can_send_cookie2_ct_ = 0; |
| int cookie_js2_ct_ = 0; |
| int cookie_net2_ct_ = 0; |
| |
| // From cookie manager. |
| int cookie_js3_ct_ = 0; |
| int cookie_net3_ct_ = 0; |
| |
| DISALLOW_COPY_AND_ASSIGN(CookieAccessTestHandler); |
| IMPLEMENT_REFCOUNTING(CookieAccessTestHandler); |
| }; |
| |
| } // namespace |
| |
| #define ACCESS_TEST(name, test_mode, backend_mode, custom_scheme, use_global) \ |
| TEST(CookieTest, Access##name) { \ |
| CefRefPtr<CookieAccessTestHandler> handler = new CookieAccessTestHandler( \ |
| CookieAccessTestHandler::test_mode, \ |
| CookieAccessTestHandler::backend_mode, custom_scheme, use_global); \ |
| handler->ExecuteTest(); \ |
| ReleaseAndWaitForDestructor(handler); \ |
| } |
| |
| #define ACCESS_TEST_ALL_MODES(name, backend_mode, custom_scheme, use_global) \ |
| ACCESS_TEST(name##Allow, ALLOW, backend_mode, custom_scheme, use_global) \ |
| ACCESS_TEST(name##AllowNoFilter, ALLOW_NO_FILTER, backend_mode, \ |
| custom_scheme, use_global) \ |
| ACCESS_TEST(name##BlockRead, BLOCK_READ, backend_mode, custom_scheme, \ |
| use_global) \ |
| ACCESS_TEST(name##BlockWrite, BLOCK_WRITE, backend_mode, custom_scheme, \ |
| use_global) \ |
| ACCESS_TEST(name##BlockReadWrite, BLOCK_READ_WRITE, backend_mode, \ |
| custom_scheme, use_global) |
| |
| // These tests only work with a non-global context. |
| #define ACCESS_TEST_BLOCKALLCOOKIES_MODES(name, backend_mode, custom_scheme) \ |
| ACCESS_TEST(name##BlockAllCookies, BLOCK_ALL_COOKIES, backend_mode, \ |
| custom_scheme, false) |
| |
| // These tests only work with SERVER and SCHEME_HANDLER backends. |
| #define ACCESS_TEST_ALLOWNOHANDLER_MODES(name, backend_mode, custom_scheme) \ |
| ACCESS_TEST(name##GlobalAllowNoHandler, ALLOW_NO_HANDLER, backend_mode, \ |
| custom_scheme, false) \ |
| ACCESS_TEST(name##InMemoryAllowNoHandler, ALLOW_NO_HANDLER, backend_mode, \ |
| custom_scheme, true) |
| |
| #define ACCESS_TEST_CUSTOM(name, backend_mode) \ |
| ACCESS_TEST_ALL_MODES(name##CustomGlobal, backend_mode, true, true) \ |
| ACCESS_TEST_ALL_MODES(name##CustomInMemory, backend_mode, true, false) \ |
| ACCESS_TEST_BLOCKALLCOOKIES_MODES(name##CustomInMemory, backend_mode, true) |
| |
| #define ACCESS_TEST_STANDARD(name, backend_mode) \ |
| ACCESS_TEST_ALL_MODES(name##StandardGlobal, backend_mode, false, true) \ |
| ACCESS_TEST_ALL_MODES(name##StandardInMemory, backend_mode, false, false) \ |
| ACCESS_TEST_BLOCKALLCOOKIES_MODES(name##StandardInMemory, backend_mode, false) |
| |
| // Server backend only works with standard schemes. |
| ACCESS_TEST_STANDARD(Server, SERVER) |
| ACCESS_TEST_ALLOWNOHANDLER_MODES(ServerStandard, SERVER, false) |
| |
| // Other backends work with all schemes. |
| ACCESS_TEST_CUSTOM(Scheme, SCHEME_HANDLER) |
| ACCESS_TEST_ALLOWNOHANDLER_MODES(SchemeCustom, SCHEME_HANDLER, true) |
| ACCESS_TEST_STANDARD(Scheme, SCHEME_HANDLER) |
| ACCESS_TEST_ALLOWNOHANDLER_MODES(SchemeStandard, SCHEME_HANDLER, false) |
| |
| ACCESS_TEST_CUSTOM(Resource, RESOURCE_HANDLER) |
| ACCESS_TEST_STANDARD(Resource, RESOURCE_HANDLER) |
| |
| namespace { |
| |
| // Tests the behavior of restarting of a network request that sets cookies and |
| // a network request that includes cookies. |
| // 1. Begin loading URL1, then restart the request in OnResourceResponse. |
| // No cookies are saved. |
| // 2. Load URL1 successfully. Network and JS cookies are saved. |
| // 3. Begin loading URL2, then restart the request in OnResourceResponse. |
| // Cookies are sent with the request/response. |
| // 4. Load URL2 successfully. Cookies are sent with the request/response. |
| class CookieRestartTestHandler : public RoutingTestHandler, |
| public CefCookieAccessFilter { |
| public: |
| explicit CookieRestartTestHandler(bool use_global) |
| : scheme_(kCookieAccessScheme), use_global_(use_global) {} |
| |
| void RunTest() override { |
| if (use_global_) { |
| context_ = CefRequestContext::GetGlobalContext(); |
| } else { |
| // Create the request context that will use an in-memory cache. |
| CefRequestContextSettings settings; |
| context_ = CefRequestContext::CreateContext(settings, nullptr); |
| } |
| |
| cookie_manager_ = context_->GetCookieManager(nullptr); |
| |
| SetTestTimeout(); |
| RunTestSetupContinue(); |
| } |
| |
| void DestroyTest() override { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, |
| base::Bind(&CookieRestartTestHandler::DestroyTest, this)); |
| return; |
| } |
| |
| cookie_manager_ = nullptr; |
| context_ = nullptr; |
| |
| // Get 2 network requests for each URL. |
| EXPECT_EQ(2, data1_.request_ct_); |
| EXPECT_EQ(2, data2_.request_ct_); |
| |
| // Get resource request callbacks for all requests (2 for each URL). |
| EXPECT_EQ(4, before_resource_load_ct_); |
| EXPECT_EQ(4, resource_response_ct_); |
| |
| // Get JS query callbacks for the successful requests (1 for each URL). |
| EXPECT_EQ(2, query_ct_); |
| |
| // No cookies sent for the URL1 network requests because (a) we don't have |
| // any cookies set initially and (b) we don't save cookies from the 1st URL1 |
| // request which is restarted. |
| EXPECT_EQ(0, data1_.cookie_js_ct_); |
| EXPECT_EQ(0, data1_.cookie_net_ct_); |
| |
| // Net and JS cookies sent for both URL2 network requests. |
| EXPECT_EQ(2, data2_.cookie_js_ct_); |
| EXPECT_EQ(2, data2_.cookie_net_ct_); |
| |
| // 1 call to CanSaveCookie for the net cookie returned by the successful |
| // URL1 request. |
| EXPECT_EQ(1, can_save_cookie_ct_); |
| // 4 calls to CanSendCookie because both net and JS cookies are sent for |
| // each URL2 request. |
| EXPECT_EQ(4, can_send_cookie_ct_); |
| |
| // Get the net and JS cookies from the JS query for the successful requests |
| // (1 for each URL). |
| EXPECT_EQ(1, cookie_js1_ct_); |
| EXPECT_EQ(1, cookie_net1_ct_); |
| EXPECT_EQ(1, cookie_js2_ct_); |
| EXPECT_EQ(1, cookie_net2_ct_); |
| |
| // Get the net and JS cookies from the cookie manager at the end. |
| EXPECT_EQ(1, cookie_manager_js_ct_); |
| EXPECT_EQ(1, cookie_manager_net_ct_); |
| |
| TestHandler::DestroyTest(); |
| } |
| |
| CefRefPtr<CefCookieAccessFilter> GetCookieAccessFilter( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request) override { |
| EXPECT_IO_THREAD(); |
| return this; |
| } |
| |
| CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| bool is_navigation, |
| bool is_download, |
| const CefString& request_initiator, |
| bool& disable_default_handling) override { |
| return this; |
| } |
| |
| CefRefPtr<CefResourceHandler> GetResourceHandler( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request) override { |
| return nullptr; |
| } |
| |
| bool CanSendCookie(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| const CefCookie& cookie) override { |
| EXPECT_IO_THREAD(); |
| can_send_cookie_ct_++; |
| |
| // Called before the URL2 network requests. |
| EXPECT_LE(2, before_resource_load_ct_); |
| |
| return true; |
| } |
| |
| bool CanSaveCookie(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| CefRefPtr<CefResponse> response, |
| const CefCookie& cookie) override { |
| EXPECT_IO_THREAD(); |
| can_save_cookie_ct_++; |
| |
| // Called after the successful URL1 network request. |
| EXPECT_EQ(2, before_resource_load_ct_); |
| |
| // 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()); |
| |
| return true; |
| } |
| |
| cef_return_value_t OnBeforeResourceLoad( |
| CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| CefRefPtr<CefRequestCallback> callback) override { |
| EXPECT_IO_THREAD(); |
| before_resource_load_ct_++; |
| |
| const std::string& url = request->GetURL(); |
| |
| if (before_resource_load_ct_ <= 2) { |
| EXPECT_STREQ(GetCookieAccessUrl1(scheme_, true).c_str(), url.c_str()); |
| } else { |
| EXPECT_STREQ(GetCookieAccessUrl2(scheme_, true).c_str(), url.c_str()); |
| } |
| |
| const std::string& cookie_str = request->GetHeaderByName("Cookie"); |
| int cookie_js_ct = 0; |
| int cookie_net_ct = 0; |
| TestCookieString(cookie_str, cookie_js_ct, cookie_net_ct); |
| |
| // Expect both cookies with the URL2 requests only. |
| if (before_resource_load_ct_ >= 3) { |
| EXPECT_EQ(1, cookie_js_ct); |
| EXPECT_EQ(1, cookie_net_ct); |
| } else { |
| EXPECT_EQ(0, cookie_js_ct); |
| EXPECT_EQ(0, cookie_net_ct); |
| } |
| |
| return RV_CONTINUE; |
| } |
| |
| bool OnResourceResponse(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| CefRefPtr<CefRequest> request, |
| CefRefPtr<CefResponse> response) override { |
| EXPECT_IO_THREAD(); |
| resource_response_ct_++; |
| |
| const std::string& url = request->GetURL(); |
| const std::string& set_cookie_str = response->GetHeaderByName("Set-Cookie"); |
| |
| // Expect the network cookie with URL1 requests only. |
| if (resource_response_ct_ <= 2) { |
| EXPECT_STREQ(GetCookieAccessUrl1(scheme_, true).c_str(), url.c_str()); |
| EXPECT_STREQ("name_net=value_net", set_cookie_str.c_str()); |
| } else { |
| EXPECT_STREQ(GetCookieAccessUrl2(scheme_, true).c_str(), url.c_str()); |
| EXPECT_TRUE(set_cookie_str.empty()); |
| } |
| |
| if (resource_response_ct_ == 1 || resource_response_ct_ == 3) { |
| // Restart the request loading this data. |
| request->SetHeaderByName("X-Custom-Header", "value", false); |
| return true; |
| } |
| return false; |
| } |
| |
| bool OnQuery(CefRefPtr<CefBrowser> browser, |
| CefRefPtr<CefFrame> frame, |
| int64 query_id, |
| const CefString& request, |
| bool persistent, |
| CefRefPtr<Callback> callback) override { |
| query_ct_++; |
| |
| const std::string& url = frame->GetURL(); |
| const std::string& cookie_str = request.ToString(); |
| if (url == GetCookieAccessUrl1(scheme_, true)) { |
| TestCookieString(cookie_str, cookie_js1_ct_, cookie_net1_ct_); |
| browser->GetMainFrame()->LoadURL(GetCookieAccessUrl2(scheme_, true)); |
| } else if (url == GetCookieAccessUrl2(scheme_, true)) { |
| TestCookieString(cookie_str, cookie_js2_ct_, cookie_net2_ct_); |
| FinishTest(); |
| } else { |
| ADD_FAILURE() << "Unexpected url: " << url; |
| } |
| return true; |
| } |
| |
| private: |
| void AddResponses(CookieAccessResponseHandler* handler) { |
| // 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 RESTART TEST1</body></html>"; |
| |
| handler->AddResponse(GetCookieAccessUrl1(scheme_, true), &data1_); |
| } |
| |
| // 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 RESTART TEST2</body></html>"; |
| |
| handler->AddResponse(GetCookieAccessUrl2(scheme_, true), &data2_); |
| } |
| } |
| |
| void RunTestSetupContinue() { |
| CefPostTask( |
| TID_UI, |
| base::Bind( |
| &CookieRestartTestHandler::StartServer, this, |
| base::Bind(&CookieRestartTestHandler::RunTestContinue, this))); |
| } |
| |
| void StartServer(const base::Closure& complete_callback) { |
| EXPECT_FALSE(server_handler_); |
| |
| server_handler_ = new CookieAccessServerHandler(); |
| AddResponses(server_handler_.get()); |
| // 2 requests for each URL. |
| server_handler_->SetExpectedRequestCount(4); |
| server_handler_->CreateServer(complete_callback); |
| } |
| |
| void RunTestContinue() { |
| if (!CefCurrentlyOn(TID_UI)) { |
| CefPostTask(TID_UI, |
| base::Bind(&CookieRestartTestHandler::RunTestContinue, this)); |
| return; |
| } |
| |
| CreateBrowser(GetCookieAccessUrl1(scheme_, true), context_); |
| } |
| |
| void FinishTest() { |
| // Verify that cookies were set correctly. |
| class TestVisitor : public CefCookieVisitor { |
| public: |
| explicit TestVisitor(CookieRestartTestHandler* handler) |
| : handler_(handler) {} |
| ~TestVisitor() override { |
| // Destroy the test. |
| CefPostTask( |
| TID_UI, |
| base::Bind( |
| &CookieRestartTestHandler::ShutdownServer, handler_, |
| base::Bind(&CookieRestartTestHandler::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_->cookie_manager_js_ct_++; |
| else if (name == "name_net" && value == "value_net") |
| handler_->cookie_manager_net_ct_++; |
| |
| // Clean up the cookies. |
| deleteCookie = true; |
| |
| return true; |
| } |
| |
| private: |
| CookieRestartTestHandler* handler_; |
| IMPLEMENT_REFCOUNTING(TestVisitor); |
| }; |
| |
| cookie_manager_->VisitAllCookies(new TestVisitor(this)); |
| } |
| |
| void ShutdownServer(const base::Closure& complete_callback) { |
| EXPECT_TRUE(server_handler_); |
| |
| server_handler_->ShutdownServer(complete_callback); |
| server_handler_ = nullptr; |
| } |
| |
| const std::string scheme_; |
| const bool use_global_; |
| CefRefPtr<CefRequestContext> context_; |
| CefRefPtr<CefCookieManager> cookie_manager_; |
| |
| CefRefPtr<CookieAccessServerHandler> server_handler_; |
| |
| CookieAccessData data1_; |
| CookieAccessData data2_; |
| |
| int before_resource_load_ct_ = 0; |
| int resource_response_ct_ = 0; |
| int query_ct_ = 0; |
| |
| // From network requests. |
| int can_save_cookie_ct_ = 0; |
| int can_send_cookie_ct_ = 0; |
| int cookie_js1_ct_ = 0; |
| int cookie_net1_ct_ = 0; |
| int cookie_js2_ct_ = 0; |
| int cookie_net2_ct_ = 0; |
| |
| // From cookie manager. |
| int cookie_manager_js_ct_ = 0; |
| int cookie_manager_net_ct_ = 0; |
| |
| DISALLOW_COPY_AND_ASSIGN(CookieRestartTestHandler); |
| IMPLEMENT_REFCOUNTING(CookieRestartTestHandler); |
| }; |
| |
| } // namespace |
| |
| TEST(CookieTest, RestartGlobal) { |
| CefRefPtr<CookieRestartTestHandler> handler = |
| new CookieRestartTestHandler(true); |
| handler->ExecuteTest(); |
| ReleaseAndWaitForDestructor(handler); |
| } |
| |
| TEST(CookieTest, RestartInMemory) { |
| CefRefPtr<CookieRestartTestHandler> handler = |
| new CookieRestartTestHandler(false); |
| handler->ExecuteTest(); |
| ReleaseAndWaitForDestructor(handler); |
| } |
| |
| // Entry point for registering custom schemes. |
| // Called from client_app_delegates.cc. |
| void RegisterCookieCustomSchemes(CefRawPtr<CefSchemeRegistrar> registrar, |
| std::vector<CefString>& cookiable_schemes) { |
| // Used by GetCookieManagerCustom* tests. |
| registrar->AddCustomScheme( |
| kCustomCookieScheme, |
| CEF_SCHEME_OPTION_STANDARD | CEF_SCHEME_OPTION_CORS_ENABLED); |
| cookiable_schemes.push_back(kCustomCookieScheme); |
| } |