--- /dev/null
+// 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_scheme.h"
+#include "include/cef_waitable_event.h"
+#include "include/wrapper/cef_closure_task.h"
+#include "include/wrapper/cef_scoped_temp_dir.h"
+#include "tests/ceftests/test_handler.h"
+#include "tests/ceftests/test_suite.h"
+#include "tests/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int kCacheDeleteDelay = 50;
+
+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 {
+ 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_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 {
+ 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,
+ CefRefPtr<CefWaitableEvent> event)
+ : cookies_(cookies),
+ delete_cookies_(deleteCookies),
+ event_(event) {
+ }
+ ~TestVisitor() override {
+ event_->Signal();
+ }
+
+ bool Visit(const CefCookie& cookie, int count, int total,
+ bool& deleteCookie) override {
+ cookies_->push_back(cookie);
+ if (delete_cookies_)
+ deleteCookie = true;
+ return true;
+ }
+
+ CookieVector* cookies_;
+ bool delete_cookies_;
+ CefRefPtr<CefWaitableEvent> event_;
+
+ 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);
+}
+
+// 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.
+ EXPECT_TRUE(manager->VisitUrlCookies(kTestUrl, false,
+ new TestVisitor(&cookies, deleteCookies, event)));
+ event->Wait();
+
+ 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);
+}
+
+// Visit URL cookies.
+void VisitUrlCookies(CefRefPtr<CefCookieManager> manager,
+ const CefString& url,
+ bool includeHttpOnly,
+ CookieVector& cookies,
+ bool deleteCookies,
+ CefRefPtr<CefWaitableEvent> event) {
+ EXPECT_TRUE(manager->VisitUrlCookies(url, includeHttpOnly,
+ new TestVisitor(&cookies, deleteCookies, event)));
+ event->Wait();
+}
+
+// Visit all cookies.
+void VisitAllCookies(CefRefPtr<CefCookieManager> manager,
+ CookieVector& cookies,
+ bool deleteCookies,
+ CefRefPtr<CefWaitableEvent> event) {
+ EXPECT_TRUE(manager->VisitAllCookies(
+ new TestVisitor(&cookies, deleteCookies, event)));
+ event->Wait();
+}
+
+// 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) {
+ EXPECT_TRUE(manager->VisitUrlCookies(kTestUrl, false,
+ new TestVisitor(&cookies, false, event)));
+ } else {
+ EXPECT_TRUE(manager->VisitAllCookies(
+ new TestVisitor(&cookies, false, event)));
+ }
+ event->Wait();
+
+ 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 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);
+}
+
+void TestChangeDirectory(CefRefPtr<CefCookieManager> manager,
+ CefRefPtr<CefWaitableEvent> event,
+ const CefString& original_dir) {
+ CefCookie cookie;
+
+ CefScopedTempDir temp_dir;
+
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ // Delete all of the system cookies.
+ DeleteAllCookies(manager, event);
+
+ // Set the new temporary directory as the storage location.
+ EXPECT_TRUE(manager->SetStoragePath(temp_dir.GetPath(), false, NULL));
+
+ // Wait for the storage location change to complete on the IO thread.
+ WaitForIOThread();
+
+ // Verify that no cookies exist.
+ VerifyNoCookies(manager, event, true);
+
+ // Create a domain cookie.
+ CreateCookie(manager, cookie, true, false, event);
+
+ // Retrieve and verify the domain cookie.
+ GetCookie(manager, cookie, true, event, false);
+
+ // Restore the original storage location.
+ EXPECT_TRUE(manager->SetStoragePath(original_dir, false, NULL));
+
+ // Wait for the storage location change to complete on the IO thread.
+ WaitForIOThread();
+
+ // Verify that no cookies exist.
+ VerifyNoCookies(manager, event, true);
+
+ // Set the new temporary directory as the storage location.
+ EXPECT_TRUE(manager->SetStoragePath(temp_dir.GetPath(), false, NULL));
+
+ // Wait for the storage location change to complete on the IO thread.
+ WaitForIOThread();
+
+ // Retrieve and verify the domain cookie that was set previously.
+ GetCookie(manager, cookie, true, event, false);
+
+ // Restore the original storage location.
+ EXPECT_TRUE(manager->SetStoragePath(original_dir, false, NULL));
+
+ // Wait for the storage location change to complete on the IO thread.
+ WaitForIOThread();
+}
+
+} // namespace
+
+// Test creation of a domain cookie.
+TEST(CookieTest, DomainCookieGlobal) {
+ 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 domain cookie.
+TEST(CookieTest, DomainCookieInMemory) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(CefString(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestDomainCookie(manager, event);
+}
+
+// Test creation of a domain cookie.
+TEST(CookieTest, DomainCookieOnDisk) {
+ CefScopedTempDir temp_dir;
+
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(temp_dir.GetPath(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestDomainCookie(manager, event);
+
+ // The backing store will be closed on the DB thread after the CookieManager
+ // is destroyed.
+ manager = NULL;
+ WaitForDBThreadWithDelay(kCacheDeleteDelay);
+}
+
+// Test creation of a host cookie.
+TEST(CookieTest, HostCookieGlobal) {
+ 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 a host cookie.
+TEST(CookieTest, HostCookieInMemory) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(CefString(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestHostCookie(manager, event);
+}
+
+// Test creation of a host cookie.
+TEST(CookieTest, HostCookieOnDisk) {
+ CefScopedTempDir temp_dir;
+
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(temp_dir.GetPath(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestHostCookie(manager, event);
+
+ // The backing store will be closed on the DB thread after the CookieManager
+ // is destroyed.
+ manager = NULL;
+ WaitForDBThreadWithDelay(kCacheDeleteDelay);
+}
+
+// Test creation of multiple cookies.
+TEST(CookieTest, MultipleCookiesGlobal) {
+ 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 creation of multiple cookies.
+TEST(CookieTest, MultipleCookiesInMemory) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(CefString(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestMultipleCookies(manager, event);
+}
+
+// Test creation of multiple cookies.
+TEST(CookieTest, MultipleCookiesOnDisk) {
+ CefScopedTempDir temp_dir;
+
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(temp_dir.GetPath(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestMultipleCookies(manager, event);
+
+ // The backing store will be closed on the DB thread after the CookieManager
+ // is destroyed.
+ manager = NULL;
+ WaitForDBThreadWithDelay(kCacheDeleteDelay);
+}
+
+TEST(CookieTest, AllCookiesGlobal) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::GetGlobalManager(new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestAllCookies(manager, event);
+}
+
+TEST(CookieTest, AllCookiesInMemory) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(CefString(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestAllCookies(manager, event);
+}
+
+TEST(CookieTest, AllCookiesOnDisk) {
+ CefScopedTempDir temp_dir;
+
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(temp_dir.GetPath(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestAllCookies(manager, event);
+
+ // The backing store will be closed on the DB thread after the CookieManager
+ // is destroyed.
+ manager = NULL;
+ WaitForDBThreadWithDelay(kCacheDeleteDelay);
+}
+
+TEST(CookieTest, ChangeDirectoryGlobal) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::GetGlobalManager(new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ std::string cache_path;
+ CefTestSuite::GetInstance()->GetCachePath(cache_path);
+
+ TestChangeDirectory(manager, event, cache_path);
+}
+
+TEST(CookieTest, ChangeDirectoryCreated) {
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(CefString(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ TestChangeDirectory(manager, event, CefString());
+}
+
+TEST(CookieTest, SessionCookieNoPersist) {
+ CefScopedTempDir temp_dir;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefCookie cookie;
+
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(temp_dir.GetPath(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ // Create a session cookie.
+ CreateCookie(manager, cookie, true, true, event);
+
+ // Retrieve and verify the cookie.
+ GetCookie(manager, cookie, true, event, false);
+
+ // Flush the cookie store to disk.
+ manager->FlushStore(new TestCompletionCallback(event));
+ event->Wait();
+
+ // Create a new manager to read the same cookie store.
+ manager = CefCookieManager::CreateManager(temp_dir.GetPath(), false,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ // Verify that the cookie doesn't exist.
+ VerifyNoCookies(manager, event, true);
+}
+
+TEST(CookieTest, SessionCookieWillPersist) {
+ CefScopedTempDir temp_dir;
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CefCookie cookie;
+
+ // Create a new temporary directory.
+ EXPECT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ CefRefPtr<CefCookieManager> manager =
+ CefCookieManager::CreateManager(temp_dir.GetPath(), true,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ // Create a session cookie.
+ CreateCookie(manager, cookie, true, true, event);
+
+ // Retrieve and verify the cookie.
+ GetCookie(manager, cookie, true, event, false);
+
+ // Flush the cookie store to disk.
+ manager->FlushStore(new TestCompletionCallback(event));
+ event->Wait();
+
+ // Create a new manager to read the same cookie store.
+ manager = CefCookieManager::CreateManager(temp_dir.GetPath(), true,
+ new TestCompletionCallback(event));
+ event->Wait();
+ EXPECT_TRUE(manager.get());
+
+ // Verify that the cookie exists.
+ GetCookie(manager, cookie, true, event, false);
+}
+
+
+namespace {
+
+const char* kCookieJSUrl1 = "http://tests/cookie1.html";
+const char* kCookieJSUrl2 = "http://tests/cookie2.html";
+
+class CookieTestJSHandler : public TestHandler {
+ public:
+ class RequestContextHandler : public CefRequestContextHandler {
+ public:
+ explicit RequestContextHandler(CookieTestJSHandler* handler)
+ : handler_(handler) {}
+
+ CefRefPtr<CefCookieManager> GetCookieManager() override {
+ EXPECT_TRUE(handler_);
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ if (url_ == kCookieJSUrl1) {
+ // Return the first cookie manager.
+ handler_->got_cookie_manager1_.yes();
+ return handler_->manager1_;
+ } else {
+ // Return the second cookie manager.
+ handler_->got_cookie_manager2_.yes();
+ return handler_->manager2_;
+ }
+ }
+
+ void SetURL(const std::string& url) {
+ url_ = url;
+ }
+
+ void Detach() {
+ handler_ = NULL;
+ }
+
+ private:
+ std::string url_;
+ CookieTestJSHandler* handler_;
+
+ IMPLEMENT_REFCOUNTING(RequestContextHandler);
+ };
+
+ CookieTestJSHandler() {}
+
+ void RunTest() override {
+ // Create new in-memory managers.
+ manager1_ = CefCookieManager::CreateManager(CefString(), false, NULL);
+ manager2_ = CefCookieManager::CreateManager(CefString(), false, NULL);
+
+ std::string page =
+ "<html><head>"
+ "<script>"
+ "document.cookie='name1=value1';"
+ "</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");
+
+ context_handler_ = new RequestContextHandler(this);
+ context_handler_->SetURL(kCookieJSUrl1);
+
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::CreateContext(settings, context_handler_.get());
+
+ // 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;
+ }
+
+ context_handler_->SetURL(kCookieJSUrl2);
+ 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(manager1_, url, "name1", "value1", &got_cookie1_,
+ base::Bind(&CookieTestJSHandler::LoadNextURL, this, frame));
+ } else {
+ got_load_end2_.yes();
+ VerifyCookie(manager2_, url, "name2", "value2", &got_cookie2_,
+ base::Bind(&CookieTestJSHandler::CompleteTest, this));
+ }
+ }
+
+ void DestroyTest() override {
+ context_handler_->Detach();
+ context_handler_ = NULL;
+
+ 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,
+ TrackCallback* callback,
+ const base::Closure& continue_callback) {
+ if (!CefCurrentlyOn(TID_FILE)) {
+ CefPostTask(TID_FILE,
+ base::Bind(&CookieTestJSHandler::VerifyCookie, this, manager, url,
+ name, value, base::Unretained(callback),
+ continue_callback));
+ return;
+ }
+
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CookieVector cookies;
+
+ // Get the cookie.
+ VisitUrlCookies(manager, url, false, cookies, false, event);
+
+ if (cookies.size() == 1U && CefString(&cookies[0].name) == name &&
+ CefString(&cookies[0].value) == value) {
+ callback->yes();
+ }
+
+ continue_callback.Run();
+ }
+
+ CefRefPtr<RequestContextHandler> context_handler_;
+
+ CefRefPtr<CefCookieManager> manager1_;
+ CefRefPtr<CefCookieManager> manager2_;
+
+ TrackCallback got_cookie_manager1_;
+ TrackCallback got_cookie_manager2_;
+ 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_cookie_manager1_);
+ EXPECT_TRUE(handler->got_cookie_manager2_);
+ 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 {
+
+class CookieTestSchemeHandler : public TestHandler {
+ public:
+ class SchemeHandler : public CefResourceHandler {
+ public:
+ explicit SchemeHandler(CookieTestSchemeHandler* handler)
+ : handler_(handler),
+ offset_(0) {}
+
+ bool ProcessRequest(CefRefPtr<CefRequest> request,
+ CefRefPtr<CefCallback> callback) override {
+ 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();
+
+ }
+ callback->Continue();
+ 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 ReadResponse(void* data_out,
+ int bytes_to_read,
+ int& bytes_read,
+ CefRefPtr<CefCallback> callback) override {
+ 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);
+ };
+
+ 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);
+ };
+
+ class RequestContextHandler : public CefRequestContextHandler {
+ public:
+ explicit RequestContextHandler(CookieTestSchemeHandler* handler)
+ : handler_(handler) {}
+
+ CefRefPtr<CefCookieManager> GetCookieManager() override {
+ EXPECT_TRUE(handler_);
+ EXPECT_TRUE(CefCurrentlyOn(TID_IO));
+
+ if (url_ == handler_->url1_) {
+ // Return the first cookie manager.
+ handler_->got_cookie_manager1_.yes();
+ return handler_->manager1_;
+ } else {
+ // Return the second cookie manager.
+ handler_->got_cookie_manager2_.yes();
+ return handler_->manager2_;
+ }
+ }
+
+ void SetURL(const std::string& url) {
+ url_ = url;
+ }
+
+ void Detach() {
+ handler_ = NULL;
+ }
+
+ private:
+ std::string url_;
+ CookieTestSchemeHandler* handler_;
+
+ IMPLEMENT_REFCOUNTING(RequestContextHandler);
+ };
+
+ CookieTestSchemeHandler(const std::string& scheme) : scheme_(scheme) {
+ url1_ = scheme + "://cookie-tests/cookie1.html";
+ url2_ = scheme + "://cookie-tests/cookie2.html";
+ url3_ = scheme + "://cookie-tests/cookie3.html";
+ }
+
+ void RunTest() override {
+ // Create new in-memory managers.
+ manager1_ = CefCookieManager::CreateManager(CefString(), false, NULL);
+ manager2_ = CefCookieManager::CreateManager(CefString(), false, NULL);
+
+ if (scheme_ != "http") {
+ std::vector<CefString> schemes;
+ schemes.push_back(scheme_);
+
+ manager1_->SetSupportedSchemes(schemes, NULL);
+ manager2_->SetSupportedSchemes(schemes, NULL);
+ }
+
+ context_handler_ = new RequestContextHandler(this);
+ context_handler_->SetURL(url1_);
+
+ // Create the request context that will use an in-memory cache.
+ CefRequestContextSettings settings;
+ CefRefPtr<CefRequestContext> request_context =
+ CefRequestContext::CreateContext(settings, context_handler_.get());
+
+ // Register the scheme handler.
+ request_context->RegisterSchemeHandlerFactory(scheme_, "cookie-tests",
+ new SchemeHandlerFactory(this));
+
+ // Create the browser.
+ CreateBrowser(url1_, request_context);
+
+ // Time out the test after a reasonable period of time.
+ SetTestTimeout();
+ }
+
+ // 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;
+ }
+
+ context_handler_->SetURL(url);
+ 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", NULL);
+
+ 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(manager1_, url, "name1", "value1", &got_cookie1_,
+ base::Bind(&CookieTestSchemeHandler::LoadNextURL, this, frame,
+ url2_));
+ } else if (url == url2_) {
+ got_load_end2_.yes();
+ VerifyCookie(manager2_, url, "name2", "value2", &got_cookie2_,
+ base::Bind(&CookieTestSchemeHandler::LoadNextURL, this, frame,
+ url3_));
+ } else {
+ got_load_end3_.yes();
+ VerifyCookie(manager2_, url, "name2", "value2", &got_cookie3_,
+ base::Bind(&CookieTestSchemeHandler::CompleteTest, this, browser));
+ }
+ }
+
+ void DestroyTest() override {
+ context_handler_->Detach();
+ context_handler_ = NULL;
+
+ 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,
+ TrackCallback* callback,
+ const base::Closure& continue_callback) {
+ if (!CefCurrentlyOn(TID_FILE)) {
+ CefPostTask(TID_FILE,
+ base::Bind(&CookieTestSchemeHandler::VerifyCookie, this, manager, url,
+ name, value, base::Unretained(callback),
+ continue_callback));
+ return;
+ }
+
+ CefRefPtr<CefWaitableEvent> event =
+ CefWaitableEvent::CreateWaitableEvent(true, false);
+ CookieVector cookies;
+
+ // Get the cookie.
+ VisitUrlCookies(manager, url, false, cookies, false, event);
+
+ if (cookies.size() == 1U && CefString(&cookies[0].name) == name &&
+ CefString(&cookies[0].value) == value) {
+ callback->yes();
+ }
+
+ continue_callback.Run();
+ }
+
+ std::string scheme_;
+ std::string url1_;
+ std::string url2_;
+ std::string url3_;
+
+ CefRefPtr<RequestContextHandler> context_handler_;
+
+ CefRefPtr<CefCookieManager> manager1_;
+ CefRefPtr<CefCookieManager> manager2_;
+
+ TrackCallback got_process_request1_;
+ TrackCallback got_process_request2_;
+ TrackCallback got_process_request3_;
+ TrackCallback got_create_cookie_;
+ TrackCallback got_process_request_cookie_;
+ TrackCallback got_cookie_manager1_;
+ TrackCallback got_cookie_manager2_;
+ 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 multiple cookie managers via HTTP.
+TEST(CookieTest, GetCookieManagerHttp) {
+ CefRefPtr<CookieTestSchemeHandler> handler =
+ new CookieTestSchemeHandler("http");
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_process_request1_);
+ EXPECT_TRUE(handler->got_process_request2_);
+ EXPECT_TRUE(handler->got_process_request3_);
+ EXPECT_FALSE(handler->got_create_cookie_);
+ EXPECT_TRUE(handler->got_process_request_cookie_);
+ EXPECT_TRUE(handler->got_cookie_manager1_);
+ EXPECT_TRUE(handler->got_cookie_manager2_);
+ EXPECT_TRUE(handler->got_load_end1_);
+ EXPECT_TRUE(handler->got_load_end2_);
+ EXPECT_TRUE(handler->got_load_end3_);
+ EXPECT_TRUE(handler->got_cookie1_);
+ EXPECT_TRUE(handler->got_cookie2_);
+ EXPECT_TRUE(handler->got_cookie3_);
+
+ ReleaseAndWaitForDestructor(handler);
+}
+
+// Verify use of multiple cookie managers via a custom scheme.
+TEST(CookieTest, GetCookieManagerCustom) {
+ CefRefPtr<CookieTestSchemeHandler> handler =
+ new CookieTestSchemeHandler("ccustom");
+ handler->ExecuteTest();
+
+ EXPECT_TRUE(handler->got_process_request1_);
+ EXPECT_TRUE(handler->got_process_request2_);
+ EXPECT_TRUE(handler->got_process_request3_);
+ EXPECT_FALSE(handler->got_create_cookie_);
+ EXPECT_TRUE(handler->got_process_request_cookie_);
+ EXPECT_TRUE(handler->got_cookie_manager1_);
+ EXPECT_TRUE(handler->got_cookie_manager2_);
+ EXPECT_TRUE(handler->got_load_end1_);
+ EXPECT_TRUE(handler->got_load_end2_);
+ EXPECT_TRUE(handler->got_load_end3_);
+ EXPECT_TRUE(handler->got_cookie1_);
+ EXPECT_TRUE(handler->got_cookie2_);
+ EXPECT_TRUE(handler->got_cookie3_);
+
+ 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 test.
+ registrar->AddCustomScheme("ccustom", true, false, false, false, true, false);
+}