diff options
author | droger@google.com <droger@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-03 18:19:15 +0000 |
---|---|---|
committer | droger@google.com <droger@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-02-03 18:19:15 +0000 |
commit | b0d7aa366edee8b275be64678728c5add3515cdd (patch) | |
tree | 0b6f2371be42984e90f1f417b12dd4e4992009ed /net | |
parent | 0436978ca57f7acf9fcc26aa701906972bfe1aed (diff) | |
download | chromium_src-b0d7aa366edee8b275be64678728c5add3515cdd.zip chromium_src-b0d7aa366edee8b275be64678728c5add3515cdd.tar.gz chromium_src-b0d7aa366edee8b275be64678728c5add3515cdd.tar.bz2 |
Move CookieStore unittests to a separate file.
This is a follow up from http://codereview.chromium.org/8953028/.
This allows other CookieStore implementations to benefit from the tests.
BUG=NONE
TEST=NONE
Review URL: http://codereview.chromium.org/9310051
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@120355 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/cookie_monster_unittest.cc | 1130 | ||||
-rw-r--r-- | net/base/cookie_store_test_callbacks.cc | 65 | ||||
-rw-r--r-- | net/base/cookie_store_test_callbacks.h | 137 | ||||
-rw-r--r-- | net/base/cookie_store_unittest.h | 993 | ||||
-rw-r--r-- | net/base/cookie_util_unittest.cc | 23 | ||||
-rw-r--r-- | net/net.gyp | 8 |
6 files changed, 1234 insertions, 1122 deletions
diff --git a/net/base/cookie_monster_unittest.cc b/net/base/cookie_monster_unittest.cc index a7477e3..c3a24f52 100644 --- a/net/base/cookie_monster_unittest.cc +++ b/net/base/cookie_monster_unittest.cc @@ -2,16 +2,15 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <time.h> +#include "net/base/cookie_store_unittest.h" -#include <algorithm> +#include <time.h> #include <string> #include "base/basictypes.h" #include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" -#include "base/memory/weak_ptr.h" #include "base/message_loop.h" #include "base/metrics/histogram.h" #include "base/stringprintf.h" @@ -29,7 +28,6 @@ namespace net { using base::Time; using base::TimeDelta; -using base::Thread; namespace { @@ -49,136 +47,13 @@ class NewMockPersistentCookieStore MOCK_METHOD1(Flush, void(const base::Closure& callback)); }; -const int kTimeout = 1000; - const char* kTopLevelDomainPlus1 = "http://www.harvard.edu"; const char* kTopLevelDomainPlus2 = "http://www.math.harvard.edu"; const char* kTopLevelDomainPlus2Secure = "https://www.math.harvard.edu"; const char* kTopLevelDomainPlus3 = "http://www.bourbaki.math.harvard.edu"; const char* kOtherDomain = "http://www.mit.edu"; - -const char kUrlGoogle[] = "http://www.google.izzle"; -const char kUrlGoogleFoo[] = "http://www.google.izzle/foo"; -const char kUrlGoogleBar[] = "http://www.google.izzle/bar"; const char kUrlGoogleSpecific[] = "http://www.gmail.google.izzle"; -const char kUrlGoogleSecure[] = "https://www.google.izzle"; -const char kUrlFtp[] = "ftp://ftp.google.izzle/"; -const char kValidCookieLine[] = "A=B; path=/"; -const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle"; - -// Defines common behaviour for the callbacks from GetCookies, SetCookies, etc. -// Asserts that the current thread is the expected invocation thread, sends a -// quit to the thread in which it was constructed. -class CookieCallback { - public: - // Indicates whether the callback has been called. - bool did_run() { return did_run_; } - - protected: - // Constructs a callback that expects to be called in the given thread and - // will, upon execution, send a QUIT to the constructing thread. - explicit CookieCallback(Thread* run_in_thread) - : did_run_(false), - run_in_thread_(run_in_thread), - run_in_loop_(NULL), - parent_loop_(MessageLoop::current()), - loop_to_quit_(MessageLoop::current()) {} - - // Constructs a callback that expects to be called in current thread and will - // send a QUIT to the constructing thread. - CookieCallback() - : did_run_(false), - run_in_thread_(NULL), - run_in_loop_(MessageLoop::current()), - parent_loop_(NULL), - loop_to_quit_(MessageLoop::current()) {} - - // Tests whether the current thread was the caller's thread. - // Sends a QUIT to the constructing thread. - void CallbackEpilogue() { - MessageLoop* expected_loop = NULL; - if (run_in_thread_) { - DCHECK(!run_in_loop_); - expected_loop = run_in_thread_->message_loop(); - } else if (run_in_loop_) { - expected_loop = run_in_loop_; - } - ASSERT_TRUE(expected_loop != NULL); - - did_run_ = true; - EXPECT_EQ(expected_loop, MessageLoop::current()); - loop_to_quit_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); - } - - private: - bool did_run_; - Thread* run_in_thread_; - MessageLoop* run_in_loop_; - MessageLoop* parent_loop_; - MessageLoop* loop_to_quit_; -}; - -// Callback implementations for the asynchronous CookieStore methods. - -class SetCookieCallback : public CookieCallback { - public: - SetCookieCallback() : result_(false) {} - explicit SetCookieCallback(Thread* run_in_thread) - : CookieCallback(run_in_thread), - result_(false) {} - - void Run(bool result) { - result_ = result; - CallbackEpilogue(); - } - - bool result() { return result_; } - - private: - bool result_; -}; - -class GetCookieStringCallback : public CookieCallback { - public: - GetCookieStringCallback() {} - explicit GetCookieStringCallback(Thread* run_in_thread) - : CookieCallback(run_in_thread) {} - - void Run(const std::string& cookie) { - cookie_ = cookie; - CallbackEpilogue(); - } - - const std::string& cookie() { return cookie_; } - - private: - std::string cookie_; -}; - -class GetCookiesWithInfoCallback : public CookieCallback { - public: - GetCookiesWithInfoCallback() {} - explicit GetCookiesWithInfoCallback(Thread* run_in_thread) - : CookieCallback(run_in_thread) {} - - void Run( - const std::string& cookie_line, - const std::vector<CookieStore::CookieInfo>& cookie_info) { - cookie_line_ = cookie_line; - cookie_info_ = cookie_info; - CallbackEpilogue(); - } - - const std::string& cookie_line() { return cookie_line_; } - const std::vector<CookieStore::CookieInfo>& cookie_info() { - return cookie_info_; - } - - private: - std::string cookie_line_; - std::vector<CookieStore::CookieInfo> cookie_info_; -}; class GetCookieListCallback : public CookieCallback { public: @@ -197,35 +72,6 @@ class GetCookieListCallback : public CookieCallback { CookieList cookies_; }; -class DeleteCallback : public CookieCallback { - public: - DeleteCallback() : num_deleted_(0) {} - explicit DeleteCallback(Thread* run_in_thread) - : CookieCallback(run_in_thread), - num_deleted_(0) {} - - void Run(int num_deleted) { - num_deleted_ = num_deleted; - CallbackEpilogue(); - } - - int num_deleted() { return num_deleted_; } - - private: - int num_deleted_; -}; - -class DeleteCookieCallback : public CookieCallback { - public: - DeleteCookieCallback() {} - explicit DeleteCookieCallback(Thread* run_in_thread) - : CookieCallback(run_in_thread) {} - - void Run() { - CallbackEpilogue(); - } -}; - class ParsedCookieTest : public testing::Test { }; } // namespace @@ -501,42 +347,12 @@ TEST(ParsedCookieTest, ParseTokensAndValues) { namespace { -// The CookieStoreTestTraits must have the following members: -// struct CookieStoreTestTraits { -// // Factory function. -// static scoped_refptr<CookieStore> Create(); -// -// // The cookie store supports cookies with the exclude_httponly() option. -// static const bool supports_http_only; -// -// // The cookie store supports the GetCookiesWithInfoAsync() method. -// static const bool supports_cookies_with_info; -// -// // The cookie store is able to make the difference between the ".com" -// // and the "com" domains. -// static const bool supports_non_dotted_domains; -// -// // The cookie store handles the domains with trailing dots (such as "com.") -// // correctly. -// static const bool supports_trailing_dots; -// -// // The cookie store rejects cookies for invalid schemes such as ftp. -// static const bool filters_schemes; -// -// // The cookie store has a bug happening when a path is a substring of -// // another. -// static const bool has_path_prefix_bug; -// -// // Time to wait between two cookie insertions to ensure that cookies have -// // different creation times. -// static const int creation_time_granularity_in_ms; -// }; - struct CookieMonsterTestTraits { static scoped_refptr<CookieStore> Create() { return new CookieMonster(NULL, NULL); } + static const bool is_cookie_monster = true; static const bool supports_http_only = true; static const bool supports_cookies_with_info = true; static const bool supports_non_dotted_domains = true; @@ -546,157 +362,13 @@ struct CookieMonsterTestTraits { static const int creation_time_granularity_in_ms = 0; }; -template <class CookieStoreTestTraits> -class CookieStoreTest : public testing::Test { - protected: - CookieStoreTest() - : url_google_(kUrlGoogle), - url_google_secure_(kUrlGoogleSecure), - url_google_foo_(kUrlGoogleFoo), - url_google_bar_(kUrlGoogleBar), - weak_factory_(MessageLoop::current()) {} - - // Helper methods for the asynchronous Cookie Store API that call the - // asynchronous method and then pump the loop until the callback is invoked, - // finally returning the value. - - std::string GetCookies(CookieStore* cs, const GURL& url) { - DCHECK(cs); - CookieOptions options; - if (!CookieStoreTestTraits::supports_http_only) - options.set_include_httponly(); - GetCookieStringCallback callback; - cs->GetCookiesWithOptionsAsync( - url, options, - base::Bind(&GetCookieStringCallback::Run, base::Unretained(&callback))); - RunFor(kTimeout); - EXPECT_TRUE(callback.did_run()); - return callback.cookie(); - } - - std::string GetCookiesWithOptions(CookieStore* cs, - const GURL& url, - const CookieOptions& options) { - DCHECK(cs); - GetCookieStringCallback callback; - cs->GetCookiesWithOptionsAsync( - url, options, base::Bind(&GetCookieStringCallback::Run, - base::Unretained(&callback))); - RunFor(kTimeout); - EXPECT_TRUE(callback.did_run()); - return callback.cookie(); - } - - void GetCookiesWithInfo(CookieStore* cs, - const GURL& url, - const CookieOptions& options, - std::string* cookie_line, - std::vector<CookieStore::CookieInfo>* cookie_info) { - DCHECK(cs); - DCHECK(cookie_line); - DCHECK(cookie_info); - GetCookiesWithInfoCallback callback; - cs->GetCookiesWithInfoAsync( - url, options, base::Bind(&GetCookiesWithInfoCallback::Run, - base::Unretained(&callback))); - RunFor(kTimeout); - EXPECT_TRUE(callback.did_run()); - *cookie_line = callback.cookie_line(); - *cookie_info = callback.cookie_info(); - } - - bool SetCookieWithOptions(CookieStore* cs, - const GURL& url, - const std::string& cookie_line, - const CookieOptions& options) { - DCHECK(cs); - SetCookieCallback callback; - cs->SetCookieWithOptionsAsync( - url, cookie_line, options, - base::Bind(&SetCookieCallback::Run, base::Unretained(&callback))); - RunFor(kTimeout); - EXPECT_TRUE(callback.did_run()); - return callback.result(); - } - - bool SetCookie(CookieStore* cs, - const GURL& url, - const std::string& cookie_line) { - CookieOptions options; - if (!CookieStoreTestTraits::supports_http_only) - options.set_include_httponly(); - return SetCookieWithOptions(cs, url, cookie_line, options); - } - - void DeleteCookie(CookieStore* cs, - const GURL& url, - const std::string& cookie_name) { - DCHECK(cs); - DeleteCookieCallback callback; - cs->DeleteCookieAsync( - url, cookie_name, - base::Bind(&DeleteCookieCallback::Run, base::Unretained(&callback))); - RunFor(kTimeout); - EXPECT_TRUE(callback.did_run()); - } - - void RunFor(int ms) { - // Runs the test thread message loop for up to |ms| milliseconds. - MessageLoop::current()->PostDelayedTask( - FROM_HERE, base::Bind(&MessageLoop::Quit, weak_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(ms)); - MessageLoop::current()->Run(); - weak_factory_.InvalidateWeakPtrs(); - } - - scoped_refptr<CookieStore> GetCookieStore() { - return CookieStoreTestTraits::Create(); - } - - // Compares two cookie lines. - void MatchCookieLines(const std::string& line1, const std::string& line2) { - EXPECT_EQ(TokenizeCookieLine(line1), TokenizeCookieLine(line2)); - } - - // Check the cookie line by polling until equality or a timeout is reached. - void MatchCookieLineWithTimeout(CookieStore* cs, - const GURL& url, - const std::string& line) { - std::string cookies = GetCookies(cs, url); - bool matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); - base::Time polling_end_date = base::Time::Now() + - base::TimeDelta::FromMilliseconds( - CookieStoreTestTraits::creation_time_granularity_in_ms); - - while (!matched && base::Time::Now() <= polling_end_date) { - base::PlatformThread::Sleep(10); - cookies = GetCookies(cs, url); - matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); - } - - EXPECT_TRUE(matched) << "\"" << cookies - << "\" does not match \"" << line << "\""; - } - - GURL url_google_; - GURL url_google_secure_; - GURL url_google_foo_; - GURL url_google_bar_; - - base::WeakPtrFactory<MessageLoop> weak_factory_; - - private: - // Returns a set of strings of type "name=value". Fails in case of duplicate. - std::set<std::string> TokenizeCookieLine(const std::string& line) { - std::set<std::string> tokens; - StringTokenizer tokenizer(line, " ;"); - while (tokenizer.GetNext()) - EXPECT_TRUE(tokens.insert(tokenizer.token()).second); - return tokens; - } -}; +INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, + CookieStoreTest, + CookieMonsterTestTraits); -TYPED_TEST_CASE_P(CookieStoreTest); +INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, + MultiThreadedCookieStoreTest, + CookieMonsterTestTraits); class CookieMonsterTest : public CookieStoreTest<CookieMonsterTestTraits> { protected: @@ -1107,6 +779,7 @@ ACTION_P3(GetAllCookiesForUrlAction, cookie_monster, url, callback) { ACTION_P(PushCallbackAction, callback_vector) { callback_vector->push(arg1); } + } // namespace // This test suite verifies the task deferral behaviour of the CookieMonster. @@ -1482,404 +1155,6 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) { CompleteLoadingAndWait(); } -TYPED_TEST_P(CookieStoreTest, DomainTest) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - "C=D; domain=.google.izzle")); - this->MatchCookieLines("A=B; C=D", this->GetCookies(cs, this->url_google_)); - - // Verify that A=B was set as a host cookie rather than a domain - // cookie -- should not be accessible from a sub sub-domain. - this->MatchCookieLines("C=D", - this->GetCookies(cs, GURL("http://foo.www.google.izzle"))); - - // Test and make sure we find domain cookies on the same domain. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - "E=F; domain=.www.google.izzle")); - this->MatchCookieLines("A=B; C=D; E=F", - this->GetCookies(cs, this->url_google_)); - - // Test setting a domain= that doesn't start w/ a dot, should - // treat it as a domain cookie, as if there was a pre-pended dot. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - "G=H; domain=www.google.izzle")); - this->MatchCookieLines("A=B; C=D; E=F; G=H", - this->GetCookies(cs, this->url_google_)); - - // Test domain enforcement, should fail on a sub-domain or something too deep. - EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "I=J; domain=.izzle")); - this->MatchCookieLines("", this->GetCookies(cs, GURL("http://a.izzle"))); - EXPECT_FALSE(this->SetCookie(cs, this->url_google_, - "K=L; domain=.bla.www.google.izzle")); - this->MatchCookieLines("C=D; E=F; G=H", - this->GetCookies(cs, GURL("http://bla.www.google.izzle"))); - this->MatchCookieLines("A=B; C=D; E=F; G=H", - this->GetCookies(cs, this->url_google_)); -} - -// FireFox recognizes domains containing trailing periods as valid. -// IE and Safari do not. Assert the expected policy here. -TYPED_TEST_P(CookieStoreTest, DomainWithTrailingDotTest) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_FALSE(this->SetCookie(cs, this->url_google_, - "a=1; domain=.www.google.com.")); - EXPECT_FALSE(this->SetCookie(cs, this->url_google_, - "b=2; domain=.www.google.com..")); - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); -} - -// Test that cookies can bet set on higher level domains. -// http://b/issue?id=896491 -TYPED_TEST_P(CookieStoreTest, ValidSubdomainTest) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url_abcd("http://a.b.c.d.com"); - GURL url_bcd("http://b.c.d.com"); - GURL url_cd("http://c.d.com"); - GURL url_d("http://d.com"); - - EXPECT_TRUE(this->SetCookie(cs, url_abcd, "a=1; domain=.a.b.c.d.com")); - EXPECT_TRUE(this->SetCookie(cs, url_abcd, "b=2; domain=.b.c.d.com")); - EXPECT_TRUE(this->SetCookie(cs, url_abcd, "c=3; domain=.c.d.com")); - EXPECT_TRUE(this->SetCookie(cs, url_abcd, "d=4; domain=.d.com")); - - this->MatchCookieLines("a=1; b=2; c=3; d=4", this->GetCookies(cs, url_abcd)); - this->MatchCookieLines("b=2; c=3; d=4", this->GetCookies(cs, url_bcd)); - this->MatchCookieLines("c=3; d=4", this->GetCookies(cs, url_cd)); - this->MatchCookieLines("d=4", this->GetCookies(cs, url_d)); - - // Check that the same cookie can exist on different sub-domains. - EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=bcd; domain=.b.c.d.com")); - EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=cd; domain=.c.d.com")); - this->MatchCookieLines("b=2; c=3; d=4; X=bcd; X=cd", - this->GetCookies(cs, url_bcd)); - this->MatchCookieLines("c=3; d=4; X=cd", this->GetCookies(cs, url_cd)); -} - -// Test that setting a cookie which specifies an invalid domain has -// no side-effect. An invalid domain in this context is one which does -// not match the originating domain. -// http://b/issue?id=896472 -TYPED_TEST_P(CookieStoreTest, InvalidDomainTest) { - { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url_foobar("http://foo.bar.com"); - - // More specific sub-domain than allowed. - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "a=1; domain=.yo.foo.bar.com")); - - EXPECT_FALSE(this->SetCookie(cs, url_foobar, "b=2; domain=.foo.com")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, "c=3; domain=.bar.foo.com")); - - // Different TLD, but the rest is a substring. - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "d=4; domain=.foo.bar.com.net")); - - // A substring that isn't really a parent domain. - EXPECT_FALSE(this->SetCookie(cs, url_foobar, "e=5; domain=ar.com")); - - // Completely invalid domains: - EXPECT_FALSE(this->SetCookie(cs, url_foobar, "f=6; domain=.")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, "g=7; domain=/")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "h=8; domain=http://foo.bar.com")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, "i=9; domain=..foo.bar.com")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, "j=10; domain=..bar.com")); - - // Make sure there isn't something quirky in the domain canonicalization - // that supports full URL semantics. - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "k=11; domain=.foo.bar.com?blah")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "l=12; domain=.foo.bar.com/blah")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "m=13; domain=.foo.bar.com:80")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "n=14; domain=.foo.bar.com:")); - EXPECT_FALSE(this->SetCookie(cs, url_foobar, - "o=15; domain=.foo.bar.com#sup")); - - this->MatchCookieLines("", this->GetCookies(cs, url_foobar)); - } - - { - // Make sure the cookie code hasn't gotten its subdomain string handling - // reversed, missed a suffix check, etc. It's important here that the two - // hosts below have the same domain + registry. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url_foocom("http://foo.com.com"); - EXPECT_FALSE(this->SetCookie(cs, url_foocom, - "a=1; domain=.foo.com.com.com")); - this->MatchCookieLines("", this->GetCookies(cs, url_foocom)); - } -} - -// Test the behavior of omitting dot prefix from domain, should -// function the same as FireFox. -// http://b/issue?id=889898 -TYPED_TEST_P(CookieStoreTest, DomainWithoutLeadingDotTest) { - { // The omission of dot results in setting a domain cookie. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url_hosted("http://manage.hosted.filefront.com"); - GURL url_filefront("http://www.filefront.com"); - EXPECT_TRUE(this->SetCookie(cs, url_hosted, - "sawAd=1; domain=filefront.com")); - this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_hosted)); - this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_filefront)); - } - - { // Even when the domains match exactly, don't consider it host cookie. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://www.google.com"); - EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=www.google.com")); - this->MatchCookieLines("a=1", this->GetCookies(cs, url)); - this->MatchCookieLines("a=1", - this->GetCookies(cs, GURL("http://sub.www.google.com"))); - this->MatchCookieLines("", - this->GetCookies(cs, GURL("http://something-else.com"))); - } -} - -// Test that the domain specified in cookie string is treated case-insensitive -// http://b/issue?id=896475. -TYPED_TEST_P(CookieStoreTest, CaseInsensitiveDomainTest) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://www.google.com"); - EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=.GOOGLE.COM")); - EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.wWw.gOOgLE.coM")); - this->MatchCookieLines("a=1; b=2", this->GetCookies(cs, url)); -} - -TYPED_TEST_P(CookieStoreTest, TestIpAddress) { - GURL url_ip("http://1.2.3.4/weee"); - { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_TRUE(this->SetCookie(cs, url_ip, kValidCookieLine)); - this->MatchCookieLines("A=B", this->GetCookies(cs, url_ip)); - } - - { // IP addresses should not be able to set domain cookies. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=.1.2.3.4")); - EXPECT_FALSE(this->SetCookie(cs, url_ip, "c=3; domain=.3.4")); - this->MatchCookieLines("", this->GetCookies(cs, url_ip)); - // It should be allowed to set a cookie if domain= matches the IP address - // exactly. This matches IE/Firefox, even though it seems a bit wrong. - EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.3")); - this->MatchCookieLines("", this->GetCookies(cs, url_ip)); - EXPECT_TRUE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.4")); - this->MatchCookieLines("b=2", this->GetCookies(cs, url_ip)); - } -} - -// Test host cookies, and setting of cookies on TLD. -TYPED_TEST_P(CookieStoreTest, TestNonDottedAndTLD) { - { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://com/"); - // Allow setting on "com", (but only as a host cookie). - EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); - EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.com")); - EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=com")); - this->MatchCookieLines("a=1", this->GetCookies(cs, url)); - // Make sure it doesn't show up for a normal .com, it should be a host - // not a domain cookie. - this->MatchCookieLines("", - this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/"))); - if (TypeParam::supports_non_dotted_domains) { - this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/"))); - } - } - - { - // http://com. should be treated the same as http://com. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://com./index.html"); - if (TypeParam::supports_trailing_dots) { - EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); - this->MatchCookieLines("a=1", this->GetCookies(cs, url)); - this->MatchCookieLines("", - this->GetCookies(cs, GURL("http://hopefully-no-cookies.com./"))); - } else { - EXPECT_FALSE(this->SetCookie(cs, url, "a=1")); - } - } - - { // Should not be able to set host cookie from a subdomain. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://a.b"); - EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.b")); - EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=b")); - this->MatchCookieLines("", this->GetCookies(cs, url)); - } - - { // Same test as above, but explicitly on a known TLD (com). - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://google.com"); - EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.com")); - EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=com")); - this->MatchCookieLines("", this->GetCookies(cs, url)); - } - - { // Make sure can't set cookie on TLD which is dotted. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://google.co.uk"); - EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.co.uk")); - EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.uk")); - this->MatchCookieLines("", this->GetCookies(cs, url)); - this->MatchCookieLines("", - this->GetCookies(cs, GURL("http://something-else.co.uk"))); - this->MatchCookieLines("", - this->GetCookies(cs, GURL("http://something-else.uk"))); - } - - { // Intranet URLs should only be able to set host cookies. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://b"); - EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); - EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.b")); - EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=b")); - this->MatchCookieLines("a=1", this->GetCookies(cs, url)); - } -} - -// Test reading/writing cookies when the domain ends with a period, -// as in "www.google.com." -TYPED_TEST_P(CookieStoreTest, TestHostEndsWithDot) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - GURL url("http://www.google.com"); - GURL url_with_dot("http://www.google.com."); - EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); - this->MatchCookieLines("a=1", this->GetCookies(cs, url)); - - if (TypeParam::supports_trailing_dots) { - // Do not share cookie space with the dot version of domain. - // Note: this is not what FireFox does, but it _is_ what IE+Safari do. - EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.www.google.com.")); - this->MatchCookieLines("a=1", this->GetCookies(cs, url)); - - EXPECT_TRUE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com.")); - this->MatchCookieLines("b=2", this->GetCookies(cs, url_with_dot)); - } else { - EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.www.google.com.")); - EXPECT_FALSE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com.")); - } - - // Make sure there weren't any side effects. - this->MatchCookieLines("", - this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/"))); - this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/"))); -} - -TYPED_TEST_P(CookieStoreTest, InvalidScheme) { - if (!TypeParam::filters_schemes) - return; - - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_FALSE(this->SetCookie(cs, GURL(kUrlFtp), kValidCookieLine)); -} - -TYPED_TEST_P(CookieStoreTest, InvalidScheme_Read) { - if (!TypeParam::filters_schemes) - return; - - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_TRUE(this->SetCookie(cs, GURL(kUrlGoogle), kValidDomainCookieLine)); - this->MatchCookieLines("", this->GetCookies(cs, GURL(kUrlFtp))); -} - -TYPED_TEST_P(CookieStoreTest, PathTest) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - std::string url("http://www.google.izzle"); - EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=B; path=/wee")); - this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee"))); - this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/"))); - this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/war"))); - this->MatchCookieLines("A=B", - this->GetCookies(cs, GURL(url + "/wee/war/more/more"))); - if (!TypeParam::has_path_prefix_bug) - this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/weehee"))); - this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/"))); - - // If we add a 0 length path, it should default to / - EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=C; path=")); - this->MatchCookieLines("A=B; A=C", this->GetCookies(cs, GURL(url + "/wee"))); - this->MatchCookieLines("A=C", this->GetCookies(cs, GURL(url + "/"))); -} - -TYPED_TEST_P(CookieStoreTest, HttpOnlyTest) { - if (!TypeParam::supports_http_only) - return; - - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - CookieOptions options; - options.set_include_httponly(); - - // Create a httponly cookie. - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B; httponly", - options)); - - // Check httponly read protection. - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); - this->MatchCookieLines("A=B", - this->GetCookiesWithOptions(cs, this->url_google_, options)); - - // Check httponly overwrite protection. - EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "A=C")); - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); - this->MatchCookieLines("A=B", - this->GetCookiesWithOptions(cs, this->url_google_, options)); - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=C", - options)); - this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_)); - - // Check httponly create protection. - EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "B=A; httponly")); - this->MatchCookieLines("A=C", - this->GetCookiesWithOptions(cs, this->url_google_, options)); - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "B=A; httponly", - options)); - this->MatchCookieLines("A=C; B=A", - this->GetCookiesWithOptions(cs, this->url_google_, options)); - this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_)); -} - -TYPED_TEST_P(CookieStoreTest, TestGetCookiesWithInfo) { - if (!TypeParam::supports_cookies_with_info) - return; - - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - CookieOptions options; - - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", - options)); - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, - "C=D; Mac-Key=390jfn0awf3; Mac-Algorithm=hmac-sha-1", options)); - - this->MatchCookieLines("A=B; C=D", - this->GetCookiesWithOptions(cs, this->url_google_, options)); - - std::string cookie_line; - std::vector<CookieStore::CookieInfo> cookie_infos; - - this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line, - &cookie_infos); - - EXPECT_EQ("A=B; C=D", cookie_line); - - EXPECT_EQ(2U, cookie_infos.size()); - - EXPECT_EQ("A", cookie_infos[0].name); - EXPECT_EQ("", cookie_infos[0].mac_key); - EXPECT_EQ("", cookie_infos[0].mac_algorithm); - - EXPECT_EQ("C", cookie_infos[1].name); - EXPECT_EQ("390jfn0awf3", cookie_infos[1].mac_key); - EXPECT_EQ("hmac-sha-1", cookie_infos[1].mac_algorithm); -} - TEST_F(CookieMonsterTest, TestCookieDateParsing) { const struct { const char* str; @@ -1968,76 +1243,6 @@ TEST_F(CookieMonsterTest, TestCookieDateParsing) { } } -TEST_F(CookieMonsterTest, TestDomainIsHostOnly) { - const struct { - const char* str; - const bool is_host_only; - } tests[] = { - { "", true }, - { "www.google.com", true }, - { ".google.com", false } - }; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { - EXPECT_EQ(tests[i].is_host_only, - cookie_util::DomainIsHostOnly(tests[i].str)); - } -} - -TYPED_TEST_P(CookieStoreTest, TestCookieDeletion) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - - // Create a session cookie. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine)); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - // Delete it via Max-Age. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + "; max-age=0")); - this->MatchCookieLineWithTimeout(cs, this->url_google_, ""); - - // Create a session cookie. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine)); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - // Delete it via Expires. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + - "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); - - // Create a persistent cookie. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + - "; expires=Mon, 18-Apr-22 22:50:13 GMT")); - - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - // Delete it via Max-Age. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + "; max-age=0")); - this->MatchCookieLineWithTimeout(cs, this->url_google_, ""); - - // Create a persistent cookie. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + - "; expires=Mon, 18-Apr-22 22:50:13 GMT")); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - // Delete it via Expires. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + - "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); - - // Create a persistent cookie. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + - "; expires=Mon, 18-Apr-22 22:50:13 GMT")); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - // Delete it via Expires, with a unix epoch of 0. - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, - std::string(kValidCookieLine) + - "; expires=Thu, 1-Jan-1970 00:00:00 GMT")); - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); -} - TEST_F(CookieMonsterTest, TestCookieDeleteAll) { scoped_refptr<MockPersistentCookieStore> store( new MockPersistentCookieStore); @@ -2109,31 +1314,6 @@ TEST_F(CookieMonsterTest, TestCookieDeleteAllCreatedBetweenTimestamps) { EXPECT_EQ(0, DeleteAll(cm)); } -TYPED_TEST_P(CookieStoreTest, TestSecure) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_)); - - EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B; secure")); - // The secure should overwrite the non-secure. - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_)); - - EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "D=E; secure")); - this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); - this->MatchCookieLines("A=B; D=E", - this->GetCookies(cs, this->url_google_secure_)); - - EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B")); - // The non-secure should overwrite the secure. - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - this->MatchCookieLines("D=E; A=B", - this->GetCookies(cs, this->url_google_secure_)); -} - -static const int kLastAccessThresholdMilliseconds = 200; static const int kAccessDelayMs = kLastAccessThresholdMilliseconds + 20; TEST_F(CookieMonsterTest, TestLastAccess) { @@ -2164,26 +1344,6 @@ TEST_F(CookieMonsterTest, TestHostGarbageCollection) { CookieMonster::EKS_DISCARD_RECENT_AND_PURGE_DOMAIN); } -// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling. -TYPED_TEST_P(CookieStoreTest, NetUtilCookieTest) { - const GURL test_url("http://mojo.jojo.google.izzle/"); - - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - - EXPECT_TRUE(this->SetCookie(cs, test_url, "foo=bar")); - std::string value = this->GetCookies(cs, test_url); - this->MatchCookieLines("foo=bar", value); - - // test that we can retrieve all cookies: - EXPECT_TRUE(this->SetCookie(cs, test_url, "x=1")); - EXPECT_TRUE(this->SetCookie(cs, test_url, "y=2")); - - std::string result = this->GetCookies(cs, test_url); - EXPECT_FALSE(result.empty()); - EXPECT_NE(result.find("x=1"), std::string::npos) << result; - EXPECT_NE(result.find("y=2"), std::string::npos) << result; -} - TEST_F(CookieMonsterTest, TestDeleteSingleCookie) { scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); @@ -2381,62 +1541,6 @@ TEST_F(CookieMonsterTest, InitializeFromCookieMonster) { EXPECT_EQ("/", it->Path()); } -TYPED_TEST_P(CookieStoreTest, OverwritePersistentCookie) { - GURL url_google("http://www.google.com/"); - GURL url_chromium("http://chromium.org"); - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - - // Insert a cookie "a" for path "/path1" - EXPECT_TRUE( - this->SetCookie(cs, url_google, "a=val1; path=/path1; " - "expires=Mon, 18-Apr-22 22:50:13 GMT")); - - // Insert a cookie "b" for path "/path1" - EXPECT_TRUE( - this->SetCookie(cs, url_google, "b=val1; path=/path1; " - "expires=Mon, 18-Apr-22 22:50:14 GMT")); - - // Insert a cookie "b" for path "/path1", that is httponly. This should - // overwrite the non-http-only version. - CookieOptions allow_httponly; - allow_httponly.set_include_httponly(); - EXPECT_TRUE( - this->SetCookieWithOptions(cs, url_google, - "b=val2; path=/path1; httponly; " - "expires=Mon, 18-Apr-22 22:50:14 GMT", - allow_httponly)); - - // Insert a cookie "a" for path "/path1". This should overwrite. - EXPECT_TRUE(this->SetCookie(cs, url_google, - "a=val33; path=/path1; " - "expires=Mon, 18-Apr-22 22:50:14 GMT")); - - // Insert a cookie "a" for path "/path2". This should NOT overwrite - // cookie "a", since the path is different. - EXPECT_TRUE(this->SetCookie(cs, url_google, - "a=val9; path=/path2; " - "expires=Mon, 18-Apr-22 22:50:14 GMT")); - - // Insert a cookie "a" for path "/path1", but this time for "chromium.org". - // Although the name and path match, the hostnames do not, so shouldn't - // overwrite. - EXPECT_TRUE(this->SetCookie(cs, url_chromium, - "a=val99; path=/path1; " - "expires=Mon, 18-Apr-22 22:50:14 GMT")); - - if (TypeParam::supports_http_only) { - this->MatchCookieLines("a=val33", - this->GetCookies(cs, GURL("http://www.google.com/path1"))); - } else { - this->MatchCookieLines("a=val33; b=val2", - this->GetCookies(cs, GURL("http://www.google.com/path1"))); - } - this->MatchCookieLines("a=val9", - this->GetCookies(cs, GURL("http://www.google.com/path2"))); - this->MatchCookieLines("a=val99", - this->GetCookies(cs, GURL("http://chromium.org/path1"))); -} - // Tests importing from a persistent cookie store that contains duplicate // equivalent cookies. This situation should be handled by removing the // duplicate cookie (both from the in-memory cache, and from the backing store). @@ -2922,31 +2026,6 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) { } } -TYPED_TEST_P(CookieStoreTest, CookieOrdering) { - // Put a random set of cookies into a store and make sure they're returned in - // the right order. - // Cookies should be sorted by path length and creation time, as per RFC6265. - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_TRUE(this->SetCookie(cs, GURL("http://d.c.b.a.google.com/aa/x.html"), - "c=1")); - EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"), - "d=1; domain=b.a.google.com")); - base::PlatformThread::Sleep(TypeParam::creation_time_granularity_in_ms); - EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"), - "a=4; domain=b.a.google.com")); - base::PlatformThread::Sleep(TypeParam::creation_time_granularity_in_ms); - EXPECT_TRUE(this->SetCookie(cs, - GURL("http://c.b.a.google.com/aa/bb/cc/x.html"), - "e=1; domain=c.b.a.google.com")); - EXPECT_TRUE(this->SetCookie(cs, - GURL("http://d.c.b.a.google.com/aa/bb/x.html"), - "b=1")); - EXPECT_TRUE(this->SetCookie(cs, GURL("http://news.bbc.co.uk/midpath/x.html"), - "g=10")); - EXPECT_EQ("d=1; a=4; e=1; b=1; c=1", - this->GetCookies(cs, GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"))); -} - TEST_F(CookieMonsterTest, CookieListOrdering) { // Put a random set of cookies into a monster and make sure // they're returned in the right order. @@ -3132,17 +2211,6 @@ TEST_F(CookieMonsterTest, KeepExpiredCookies) { ASSERT_TRUE(cookie_list[0].IsExpired(Time::Now())); } -REGISTER_TYPED_TEST_CASE_P(CookieStoreTest, - DomainTest, DomainWithTrailingDotTest, ValidSubdomainTest, InvalidDomainTest, - DomainWithoutLeadingDotTest, CaseInsensitiveDomainTest, TestIpAddress, - TestNonDottedAndTLD, TestHostEndsWithDot, InvalidScheme, InvalidScheme_Read, - PathTest, HttpOnlyTest, TestGetCookiesWithInfo, TestCookieDeletion, - TestSecure, NetUtilCookieTest, OverwritePersistentCookie, CookieOrdering); - -INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, - CookieStoreTest, - CookieMonsterTestTraits); - namespace { // Mock PersistentCookieStore that keeps track of the number of Flush() calls. @@ -3314,77 +2382,6 @@ TEST_F(CookieMonsterTest, HistogramCheck) { namespace { -template<class CookieStoreTestTraits> -class MultiThreadedCookieStoreTest : - public CookieStoreTest<CookieStoreTestTraits> { - public: - MultiThreadedCookieStoreTest() : other_thread_("CMTthread") {} - - // Helper methods for calling the asynchronous CookieStore methods - // from a different thread. - - void GetCookiesTask(CookieStore* cs, - const GURL& url, - GetCookieStringCallback* callback) { - CookieOptions options; - if (!CookieStoreTestTraits::supports_http_only) - options.set_include_httponly(); - cs->GetCookiesWithOptionsAsync( - url, options, - base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback))); - } - - void GetCookiesWithOptionsTask(CookieStore* cs, - const GURL& url, - const CookieOptions& options, - GetCookieStringCallback* callback) { - cs->GetCookiesWithOptionsAsync( - url, options, - base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback))); - } - - void GetCookiesWithInfoTask(CookieStore* cs, - const GURL& url, - const CookieOptions& options, - GetCookiesWithInfoCallback* callback) { - cs->GetCookiesWithInfoAsync( - url, options, - base::Bind(&GetCookiesWithInfoCallback::Run, - base::Unretained(callback))); - } - - void SetCookieWithOptionsTask(CookieStore* cs, - const GURL& url, - const std::string& cookie_line, - const CookieOptions& options, - SetCookieCallback* callback) { - cs->SetCookieWithOptionsAsync( - url, cookie_line, options, - base::Bind(&SetCookieCallback::Run, base::Unretained(callback))); - } - - void DeleteCookieTask(CookieStore* cs, - const GURL& url, - const std::string& cookie_name, - DeleteCookieCallback* callback) { - cs->DeleteCookieAsync( - url, cookie_name, - base::Bind(&DeleteCookieCallback::Run, base::Unretained(callback))); - } - - protected: - void RunOnOtherThread(const base::Closure& task) { - other_thread_.Start(); - other_thread_.message_loop()->PostTask(FROM_HERE, task); - CookieStoreTest<CookieStoreTestTraits>::RunFor(kTimeout); - other_thread_.Stop(); - } - - Thread other_thread_; -}; - -TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest); - class MultiThreadedCookieMonsterTest : public CookieMonsterTest { public: MultiThreadedCookieMonsterTest() : other_thread_("CMTthread") {} @@ -3470,69 +2467,6 @@ class MultiThreadedCookieMonsterTest : public CookieMonsterTest { } // namespace -// TODO(ycxiao): Eventually, we will need to create a separate thread, create -// the cookie store on that thread (or at least its store, i.e., the DB -// thread). -TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookies) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); - this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); - GetCookieStringCallback callback(&this->other_thread_); - base::Closure task = base::Bind( - &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask, - base::Unretained(this), - cs, this->url_google_, &callback); - this->RunOnOtherThread(task); - EXPECT_TRUE(callback.did_run()); - EXPECT_EQ("A=B", callback.cookie()); -} - -TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithOptions) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - CookieOptions options; - if (!TypeParam::supports_http_only) - options.set_include_httponly(); - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); - this->MatchCookieLines("A=B", - this->GetCookiesWithOptions(cs, this->url_google_, options)); - GetCookieStringCallback callback(&this->other_thread_); - base::Closure task = base::Bind( - &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithOptionsTask, - base::Unretained(this), - cs, this->url_google_, options, &callback); - this->RunOnOtherThread(task); - EXPECT_TRUE(callback.did_run()); - EXPECT_EQ("A=B", callback.cookie()); -} - -TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithInfo) { - if (!TypeParam::supports_cookies_with_info) - return; - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - CookieOptions options; - std::string cookie_line; - std::vector<CookieStore::CookieInfo> cookie_infos; - EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); - this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line, - &cookie_infos); - this->MatchCookieLines("A=B", cookie_line); - EXPECT_EQ(1U, cookie_infos.size()); - EXPECT_EQ("A", cookie_infos[0].name); - EXPECT_EQ("", cookie_infos[0].mac_key); - EXPECT_EQ("", cookie_infos[0].mac_algorithm); - GetCookiesWithInfoCallback callback(&this->other_thread_); - base::Closure task = base::Bind( - &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithInfoTask, - base::Unretained(this), cs, this->url_google_, options, &callback); - this->RunOnOtherThread(task); - EXPECT_TRUE(callback.did_run()); - this->MatchCookieLines("A=B", callback.cookie_line()); - EXPECT_EQ(1U, callback.cookie_info().size()); - EXPECT_EQ("A", callback.cookie_info()[0].name); - EXPECT_EQ("", callback.cookie_info()[0].mac_key); - EXPECT_EQ("", callback.cookie_info()[0].mac_algorithm); -} - TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookies) { scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); EXPECT_TRUE(SetCookie(cm, url_google_, "A=B")); @@ -3604,23 +2538,6 @@ TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckGetAllCookiesForURLWithOpt) { ASSERT_TRUE(++it == callback.cookies().end()); } -TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckSetCookieWithOptions) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - CookieOptions options; - if (!TypeParam::supports_http_only) - options.set_include_httponly(); - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", - options)); - SetCookieCallback callback(&this->other_thread_); - base::Closure task = base::Bind( - &net::MultiThreadedCookieStoreTest<TypeParam>::SetCookieWithOptionsTask, - base::Unretained(this), - cs, this->url_google_, "A=B", options, &callback); - this->RunOnOtherThread(task); - EXPECT_TRUE(callback.did_run()); - EXPECT_TRUE(callback.result()); -} - TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) { scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); EXPECT_TRUE(SetCookieWithDetails( @@ -3637,24 +2554,6 @@ TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckSetCookieWithDetails) { EXPECT_TRUE(callback.result()); } -TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckDeleteCookie) { - scoped_refptr<CookieStore> cs(this->GetCookieStore()); - CookieOptions options; - if (!TypeParam::supports_http_only) - options.set_include_httponly(); - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", - options)); - this->DeleteCookie(cs, this->url_google_, "A"); - EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", - options)); - DeleteCookieCallback callback(&this->other_thread_); - base::Closure task = base::Bind( - &net::MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask, - base::Unretained(this), - cs, this->url_google_, "A", &callback); - this->RunOnOtherThread(task); - EXPECT_TRUE(callback.did_run()); -} TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteAllCreatedBetween) { scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); @@ -3712,15 +2611,6 @@ TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) { EXPECT_TRUE(callback.result()); } -REGISTER_TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest, - ThreadCheckGetCookies, ThreadCheckGetCookiesWithOptions, - ThreadCheckGetCookiesWithInfo, ThreadCheckSetCookieWithOptions, - ThreadCheckDeleteCookie); - -INSTANTIATE_TYPED_TEST_CASE_P(CookieMonster, - MultiThreadedCookieStoreTest, - CookieMonsterTestTraits); - TEST_F(CookieMonsterTest, ShortLivedSessionCookies) { scoped_refptr<MockPersistentCookieStore> store( new MockPersistentCookieStore); diff --git a/net/base/cookie_store_test_callbacks.cc b/net/base/cookie_store_test_callbacks.cc new file mode 100644 index 0000000..e16df06 --- /dev/null +++ b/net/base/cookie_store_test_callbacks.cc @@ -0,0 +1,65 @@ +// Copyright (c) 2012 The Chromium 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 "net/base/cookie_store_test_callbacks.h" + +#include "base/message_loop.h" +#include "base/threading/thread.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +CookieCallback::CookieCallback(base::Thread* run_in_thread) + : did_run_(false), + run_in_thread_(run_in_thread), + run_in_loop_(NULL), + parent_loop_(MessageLoop::current()), + loop_to_quit_(MessageLoop::current()) {} + +CookieCallback::CookieCallback() + : did_run_(false), + run_in_thread_(NULL), + run_in_loop_(MessageLoop::current()), + parent_loop_(NULL), + loop_to_quit_(MessageLoop::current()) {} + +void CookieCallback::CallbackEpilogue() { + MessageLoop* expected_loop = NULL; + if (run_in_thread_) { + DCHECK(!run_in_loop_); + expected_loop = run_in_thread_->message_loop(); + } else if (run_in_loop_) { + expected_loop = run_in_loop_; + } + ASSERT_TRUE(expected_loop != NULL); + + did_run_ = true; + EXPECT_EQ(expected_loop, MessageLoop::current()); + loop_to_quit_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); +} + +SetCookieCallback::SetCookieCallback() : result_(false) {} +SetCookieCallback::SetCookieCallback(base::Thread* run_in_thread) + : CookieCallback(run_in_thread), + result_(false) {} + +GetCookieStringCallback::GetCookieStringCallback() {} +GetCookieStringCallback::GetCookieStringCallback(base::Thread* run_in_thread) + : CookieCallback(run_in_thread) {} + +GetCookiesWithInfoCallback::GetCookiesWithInfoCallback() {} +GetCookiesWithInfoCallback::GetCookiesWithInfoCallback( + base::Thread* run_in_thread) : CookieCallback(run_in_thread) {} +GetCookiesWithInfoCallback::~GetCookiesWithInfoCallback() {} + +DeleteCallback::DeleteCallback() : num_deleted_(0) {} +DeleteCallback::DeleteCallback(base::Thread* run_in_thread) + : CookieCallback(run_in_thread), + num_deleted_(0) {} + +DeleteCookieCallback::DeleteCookieCallback() {} +DeleteCookieCallback::DeleteCookieCallback(base::Thread* run_in_thread) + : CookieCallback(run_in_thread) {} + +} // namespace net diff --git a/net/base/cookie_store_test_callbacks.h b/net/base/cookie_store_test_callbacks.h new file mode 100644 index 0000000..0957839 --- /dev/null +++ b/net/base/cookie_store_test_callbacks.h @@ -0,0 +1,137 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_BASE_COOKIE_STORE_TEST_CALLBACKS_H_ +#define NET_BASE_COOKIE_STORE_TEST_CALLBACKS_H_ +#pragma once + +#include <string> +#include <vector> + +#include "net/base/cookie_store.h" + +class MessageLoop; + +namespace base { +class Thread; +} + +namespace net { + +// Defines common behaviour for the callbacks from GetCookies, SetCookies, etc. +// Asserts that the current thread is the expected invocation thread, sends a +// quit to the thread in which it was constructed. +class CookieCallback { + public: + // Indicates whether the callback has been called. + bool did_run() { return did_run_; } + + protected: + // Constructs a callback that expects to be called in the given thread and + // will, upon execution, send a QUIT to the constructing thread. + explicit CookieCallback(base::Thread* run_in_thread); + + // Constructs a callback that expects to be called in current thread and will + // send a QUIT to the constructing thread. + CookieCallback(); + + // Tests whether the current thread was the caller's thread. + // Sends a QUIT to the constructing thread. + void CallbackEpilogue(); + + private: + bool did_run_; + base::Thread* run_in_thread_; + MessageLoop* run_in_loop_; + MessageLoop* parent_loop_; + MessageLoop* loop_to_quit_; +}; + +// Callback implementations for the asynchronous CookieStore methods. + +class SetCookieCallback : public CookieCallback { + public: + SetCookieCallback(); + explicit SetCookieCallback(base::Thread* run_in_thread); + + void Run(bool result) { + result_ = result; + CallbackEpilogue(); + } + + bool result() { return result_; } + + private: + bool result_; +}; + +class GetCookieStringCallback : public CookieCallback { + public: + GetCookieStringCallback(); + explicit GetCookieStringCallback(base::Thread* run_in_thread); + + void Run(const std::string& cookie) { + cookie_ = cookie; + CallbackEpilogue(); + } + + const std::string& cookie() { return cookie_; } + + private: + std::string cookie_; +}; + +class GetCookiesWithInfoCallback : public CookieCallback { + public: + GetCookiesWithInfoCallback(); + explicit GetCookiesWithInfoCallback(base::Thread* run_in_thread); + ~GetCookiesWithInfoCallback(); + + void Run( + const std::string& cookie_line, + const std::vector<CookieStore::CookieInfo>& cookie_info) { + cookie_line_ = cookie_line; + cookie_info_ = cookie_info; + CallbackEpilogue(); + } + + const std::string& cookie_line() { return cookie_line_; } + const std::vector<CookieStore::CookieInfo>& cookie_info() { + return cookie_info_; + } + + private: + std::string cookie_line_; + std::vector<CookieStore::CookieInfo> cookie_info_; +}; + +class DeleteCallback : public CookieCallback { + public: + DeleteCallback(); + explicit DeleteCallback(base::Thread* run_in_thread); + + void Run(int num_deleted) { + num_deleted_ = num_deleted; + CallbackEpilogue(); + } + + int num_deleted() { return num_deleted_; } + + private: + int num_deleted_; +}; + +class DeleteCookieCallback : public CookieCallback { + public: + DeleteCookieCallback(); + explicit DeleteCookieCallback(base::Thread* run_in_thread); + + void Run() { + CallbackEpilogue(); + } +}; + +} // namespace net + +#endif // NET_BASE_COOKIE_STORE_TEST_CALLBACKS_H_ diff --git a/net/base/cookie_store_unittest.h b/net/base/cookie_store_unittest.h new file mode 100644 index 0000000..a537c9a --- /dev/null +++ b/net/base/cookie_store_unittest.h @@ -0,0 +1,993 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NET_BASE_COOKIE_STORE_UNITTEST_H_ +#define NET_BASE_COOKIE_STORE_UNITTEST_H_ +#pragma once + +#include "base/bind.h" +#include "base/message_loop.h" +#include "base/string_tokenizer.h" +#include "base/threading/thread.h" +#include "googleurl/src/gurl.h" +#include "net/base/cookie_store.h" +#include "net/base/cookie_store_test_callbacks.h" +#include "testing/gtest/include/gtest/gtest.h" + +// This file declares unittest templates that can be used to test common +// behavior of any CookieStore implementation. +// See cookie_monster_unittest.cc for an example of an implementation. + +namespace net { + +using base::Thread; + +const int kTimeout = 1000; + +const char kUrlFtp[] = "ftp://ftp.google.izzle/"; +const char kUrlGoogle[] = "http://www.google.izzle"; +const char kUrlGoogleFoo[] = "http://www.google.izzle/foo"; +const char kUrlGoogleBar[] = "http://www.google.izzle/bar"; +const char kUrlGoogleSecure[] = "https://www.google.izzle"; +const char kValidCookieLine[] = "A=B; path=/"; +const char kValidDomainCookieLine[] = "A=B; path=/; domain=google.izzle"; + +// The CookieStoreTestTraits must have the following members: +// struct CookieStoreTestTraits { +// // Factory function. +// static scoped_refptr<CookieStore> Create(); +// +// // The cookie store is a CookieMonster. Only used to test +// // GetCookieMonster(). +// static const bool is_cookie_monster; +// +// // The cookie store supports cookies with the exclude_httponly() option. +// static const bool supports_http_only; +// +// // The cookie store supports the GetCookiesWithInfoAsync() method. +// static const bool supports_cookies_with_info; +// +// // The cookie store is able to make the difference between the ".com" +// // and the "com" domains. +// static const bool supports_non_dotted_domains; +// +// // The cookie store handles the domains with trailing dots (such as "com.") +// // correctly. +// static const bool supports_trailing_dots; +// +// // The cookie store rejects cookies for invalid schemes such as ftp. +// static const bool filters_schemes; +// +// // The cookie store has a bug happening when a path is a substring of +// // another. +// static const bool has_path_prefix_bug; +// +// // Time to wait between two cookie insertions to ensure that cookies have +// // different creation times. +// static const int creation_time_granularity_in_ms; +// }; + +template <class CookieStoreTestTraits> +class CookieStoreTest : public testing::Test { + protected: + CookieStoreTest() + : url_google_(kUrlGoogle), + url_google_secure_(kUrlGoogleSecure), + url_google_foo_(kUrlGoogleFoo), + url_google_bar_(kUrlGoogleBar), + weak_factory_(MessageLoop::current()) {} + + // Helper methods for the asynchronous Cookie Store API that call the + // asynchronous method and then pump the loop until the callback is invoked, + // finally returning the value. + + std::string GetCookies(CookieStore* cs, const GURL& url) { + DCHECK(cs); + CookieOptions options; + if (!CookieStoreTestTraits::supports_http_only) + options.set_include_httponly(); + GetCookieStringCallback callback; + cs->GetCookiesWithOptionsAsync( + url, options, + base::Bind(&GetCookieStringCallback::Run, base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + return callback.cookie(); + } + + std::string GetCookiesWithOptions(CookieStore* cs, + const GURL& url, + const CookieOptions& options) { + DCHECK(cs); + GetCookieStringCallback callback; + cs->GetCookiesWithOptionsAsync( + url, options, base::Bind(&GetCookieStringCallback::Run, + base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + return callback.cookie(); + } + + void GetCookiesWithInfo(CookieStore* cs, + const GURL& url, + const CookieOptions& options, + std::string* cookie_line, + std::vector<CookieStore::CookieInfo>* cookie_info) { + DCHECK(cs); + DCHECK(cookie_line); + DCHECK(cookie_info); + GetCookiesWithInfoCallback callback; + cs->GetCookiesWithInfoAsync( + url, options, base::Bind(&GetCookiesWithInfoCallback::Run, + base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + *cookie_line = callback.cookie_line(); + *cookie_info = callback.cookie_info(); + } + + bool SetCookieWithOptions(CookieStore* cs, + const GURL& url, + const std::string& cookie_line, + const CookieOptions& options) { + DCHECK(cs); + SetCookieCallback callback; + cs->SetCookieWithOptionsAsync( + url, cookie_line, options, + base::Bind(&SetCookieCallback::Run, base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + return callback.result(); + } + + bool SetCookie(CookieStore* cs, + const GURL& url, + const std::string& cookie_line) { + CookieOptions options; + if (!CookieStoreTestTraits::supports_http_only) + options.set_include_httponly(); + return SetCookieWithOptions(cs, url, cookie_line, options); + } + + void DeleteCookie(CookieStore* cs, + const GURL& url, + const std::string& cookie_name) { + DCHECK(cs); + DeleteCookieCallback callback; + cs->DeleteCookieAsync( + url, cookie_name, + base::Bind(&DeleteCookieCallback::Run, base::Unretained(&callback))); + RunFor(kTimeout); + EXPECT_TRUE(callback.did_run()); + } + + void RunFor(int ms) { + // Runs the test thread message loop for up to |ms| milliseconds. + MessageLoop::current()->PostDelayedTask( + FROM_HERE, base::Bind(&MessageLoop::Quit, weak_factory_.GetWeakPtr()), + base::TimeDelta::FromMilliseconds(ms)); + MessageLoop::current()->Run(); + weak_factory_.InvalidateWeakPtrs(); + } + + scoped_refptr<CookieStore> GetCookieStore() { + return CookieStoreTestTraits::Create(); + } + + // Compares two cookie lines. + void MatchCookieLines(const std::string& line1, const std::string& line2) { + EXPECT_EQ(TokenizeCookieLine(line1), TokenizeCookieLine(line2)); + } + + // Check the cookie line by polling until equality or a timeout is reached. + void MatchCookieLineWithTimeout(CookieStore* cs, + const GURL& url, + const std::string& line) { + std::string cookies = GetCookies(cs, url); + bool matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); + base::Time polling_end_date = base::Time::Now() + + base::TimeDelta::FromMilliseconds( + CookieStoreTestTraits::creation_time_granularity_in_ms); + + while (!matched && base::Time::Now() <= polling_end_date) { + base::PlatformThread::Sleep(10); + cookies = GetCookies(cs, url); + matched = (TokenizeCookieLine(line) == TokenizeCookieLine(cookies)); + } + + EXPECT_TRUE(matched) << "\"" << cookies + << "\" does not match \"" << line << "\""; + } + + GURL url_google_; + GURL url_google_secure_; + GURL url_google_foo_; + GURL url_google_bar_; + + base::WeakPtrFactory<MessageLoop> weak_factory_; + + private: + // Returns a set of strings of type "name=value". Fails in case of duplicate. + std::set<std::string> TokenizeCookieLine(const std::string& line) { + std::set<std::string> tokens; + StringTokenizer tokenizer(line, " ;"); + while (tokenizer.GetNext()) + EXPECT_TRUE(tokens.insert(tokenizer.token()).second); + return tokens; + } +}; + +TYPED_TEST_CASE_P(CookieStoreTest); + +TYPED_TEST_P(CookieStoreTest, TypeTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_EQ(cs->GetCookieMonster(), + (TypeParam::is_cookie_monster) ? cs.get() : NULL); +} + +TYPED_TEST_P(CookieStoreTest, DomainTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + "C=D; domain=.google.izzle")); + this->MatchCookieLines("A=B; C=D", this->GetCookies(cs, this->url_google_)); + + // Verify that A=B was set as a host cookie rather than a domain + // cookie -- should not be accessible from a sub sub-domain. + this->MatchCookieLines("C=D", + this->GetCookies(cs, GURL("http://foo.www.google.izzle"))); + + // Test and make sure we find domain cookies on the same domain. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + "E=F; domain=.www.google.izzle")); + this->MatchCookieLines("A=B; C=D; E=F", + this->GetCookies(cs, this->url_google_)); + + // Test setting a domain= that doesn't start w/ a dot, should + // treat it as a domain cookie, as if there was a pre-pended dot. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + "G=H; domain=www.google.izzle")); + this->MatchCookieLines("A=B; C=D; E=F; G=H", + this->GetCookies(cs, this->url_google_)); + + // Test domain enforcement, should fail on a sub-domain or something too deep. + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "I=J; domain=.izzle")); + this->MatchCookieLines("", this->GetCookies(cs, GURL("http://a.izzle"))); + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, + "K=L; domain=.bla.www.google.izzle")); + this->MatchCookieLines("C=D; E=F; G=H", + this->GetCookies(cs, GURL("http://bla.www.google.izzle"))); + this->MatchCookieLines("A=B; C=D; E=F; G=H", + this->GetCookies(cs, this->url_google_)); +} + +// FireFox recognizes domains containing trailing periods as valid. +// IE and Safari do not. Assert the expected policy here. +TYPED_TEST_P(CookieStoreTest, DomainWithTrailingDotTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, + "a=1; domain=.www.google.com.")); + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, + "b=2; domain=.www.google.com..")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); +} + +// Test that cookies can bet set on higher level domains. +// http://b/issue?id=896491 +TYPED_TEST_P(CookieStoreTest, ValidSubdomainTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_abcd("http://a.b.c.d.com"); + GURL url_bcd("http://b.c.d.com"); + GURL url_cd("http://c.d.com"); + GURL url_d("http://d.com"); + + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "a=1; domain=.a.b.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "b=2; domain=.b.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "c=3; domain=.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_abcd, "d=4; domain=.d.com")); + + this->MatchCookieLines("a=1; b=2; c=3; d=4", this->GetCookies(cs, url_abcd)); + this->MatchCookieLines("b=2; c=3; d=4", this->GetCookies(cs, url_bcd)); + this->MatchCookieLines("c=3; d=4", this->GetCookies(cs, url_cd)); + this->MatchCookieLines("d=4", this->GetCookies(cs, url_d)); + + // Check that the same cookie can exist on different sub-domains. + EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=bcd; domain=.b.c.d.com")); + EXPECT_TRUE(this->SetCookie(cs, url_bcd, "X=cd; domain=.c.d.com")); + this->MatchCookieLines("b=2; c=3; d=4; X=bcd; X=cd", + this->GetCookies(cs, url_bcd)); + this->MatchCookieLines("c=3; d=4; X=cd", this->GetCookies(cs, url_cd)); +} + +// Test that setting a cookie which specifies an invalid domain has +// no side-effect. An invalid domain in this context is one which does +// not match the originating domain. +// http://b/issue?id=896472 +TYPED_TEST_P(CookieStoreTest, InvalidDomainTest) { + { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_foobar("http://foo.bar.com"); + + // More specific sub-domain than allowed. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "a=1; domain=.yo.foo.bar.com")); + + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "b=2; domain=.foo.com")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "c=3; domain=.bar.foo.com")); + + // Different TLD, but the rest is a substring. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "d=4; domain=.foo.bar.com.net")); + + // A substring that isn't really a parent domain. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "e=5; domain=ar.com")); + + // Completely invalid domains: + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "f=6; domain=.")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "g=7; domain=/")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "h=8; domain=http://foo.bar.com")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "i=9; domain=..foo.bar.com")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, "j=10; domain=..bar.com")); + + // Make sure there isn't something quirky in the domain canonicalization + // that supports full URL semantics. + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "k=11; domain=.foo.bar.com?blah")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "l=12; domain=.foo.bar.com/blah")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "m=13; domain=.foo.bar.com:80")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "n=14; domain=.foo.bar.com:")); + EXPECT_FALSE(this->SetCookie(cs, url_foobar, + "o=15; domain=.foo.bar.com#sup")); + + this->MatchCookieLines("", this->GetCookies(cs, url_foobar)); + } + + { + // Make sure the cookie code hasn't gotten its subdomain string handling + // reversed, missed a suffix check, etc. It's important here that the two + // hosts below have the same domain + registry. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_foocom("http://foo.com.com"); + EXPECT_FALSE(this->SetCookie(cs, url_foocom, + "a=1; domain=.foo.com.com.com")); + this->MatchCookieLines("", this->GetCookies(cs, url_foocom)); + } +} + +// Test the behavior of omitting dot prefix from domain, should +// function the same as FireFox. +// http://b/issue?id=889898 +TYPED_TEST_P(CookieStoreTest, DomainWithoutLeadingDotTest) { + { // The omission of dot results in setting a domain cookie. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url_hosted("http://manage.hosted.filefront.com"); + GURL url_filefront("http://www.filefront.com"); + EXPECT_TRUE(this->SetCookie(cs, url_hosted, + "sawAd=1; domain=filefront.com")); + this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_hosted)); + this->MatchCookieLines("sawAd=1", this->GetCookies(cs, url_filefront)); + } + + { // Even when the domains match exactly, don't consider it host cookie. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://www.google.com"); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=www.google.com")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + this->MatchCookieLines("a=1", + this->GetCookies(cs, GURL("http://sub.www.google.com"))); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://something-else.com"))); + } +} + +// Test that the domain specified in cookie string is treated case-insensitive +// http://b/issue?id=896475. +TYPED_TEST_P(CookieStoreTest, CaseInsensitiveDomainTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://www.google.com"); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1; domain=.GOOGLE.COM")); + EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.wWw.gOOgLE.coM")); + this->MatchCookieLines("a=1; b=2", this->GetCookies(cs, url)); +} + +TYPED_TEST_P(CookieStoreTest, TestIpAddress) { + GURL url_ip("http://1.2.3.4/weee"); + { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, url_ip, kValidCookieLine)); + this->MatchCookieLines("A=B", this->GetCookies(cs, url_ip)); + } + + { // IP addresses should not be able to set domain cookies. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=.1.2.3.4")); + EXPECT_FALSE(this->SetCookie(cs, url_ip, "c=3; domain=.3.4")); + this->MatchCookieLines("", this->GetCookies(cs, url_ip)); + // It should be allowed to set a cookie if domain= matches the IP address + // exactly. This matches IE/Firefox, even though it seems a bit wrong. + EXPECT_FALSE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.3")); + this->MatchCookieLines("", this->GetCookies(cs, url_ip)); + EXPECT_TRUE(this->SetCookie(cs, url_ip, "b=2; domain=1.2.3.4")); + this->MatchCookieLines("b=2", this->GetCookies(cs, url_ip)); + } +} + +// Test host cookies, and setting of cookies on TLD. +TYPED_TEST_P(CookieStoreTest, TestNonDottedAndTLD) { + { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://com/"); + // Allow setting on "com", (but only as a host cookie). + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.com")); + EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=com")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + // Make sure it doesn't show up for a normal .com, it should be a host + // not a domain cookie. + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/"))); + if (TypeParam::supports_non_dotted_domains) { + this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/"))); + } + } + + { + // http://com. should be treated the same as http://com. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://com./index.html"); + if (TypeParam::supports_trailing_dots) { + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://hopefully-no-cookies.com./"))); + } else { + EXPECT_FALSE(this->SetCookie(cs, url, "a=1")); + } + } + + { // Should not be able to set host cookie from a subdomain. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://a.b"); + EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.b")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=b")); + this->MatchCookieLines("", this->GetCookies(cs, url)); + } + + { // Same test as above, but explicitly on a known TLD (com). + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://google.com"); + EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.com")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=com")); + this->MatchCookieLines("", this->GetCookies(cs, url)); + } + + { // Make sure can't set cookie on TLD which is dotted. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://google.co.uk"); + EXPECT_FALSE(this->SetCookie(cs, url, "a=1; domain=.co.uk")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.uk")); + this->MatchCookieLines("", this->GetCookies(cs, url)); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://something-else.co.uk"))); + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://something-else.uk"))); + } + + { // Intranet URLs should only be able to set host cookies. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://b"); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.b")); + EXPECT_FALSE(this->SetCookie(cs, url, "c=3; domain=b")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + } +} + +// Test reading/writing cookies when the domain ends with a period, +// as in "www.google.com." +TYPED_TEST_P(CookieStoreTest, TestHostEndsWithDot) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + GURL url("http://www.google.com"); + GURL url_with_dot("http://www.google.com."); + EXPECT_TRUE(this->SetCookie(cs, url, "a=1")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + + if (TypeParam::supports_trailing_dots) { + // Do not share cookie space with the dot version of domain. + // Note: this is not what FireFox does, but it _is_ what IE+Safari do. + EXPECT_FALSE(this->SetCookie(cs, url, "b=2; domain=.www.google.com.")); + this->MatchCookieLines("a=1", this->GetCookies(cs, url)); + + EXPECT_TRUE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com.")); + this->MatchCookieLines("b=2", this->GetCookies(cs, url_with_dot)); + } else { + EXPECT_TRUE(this->SetCookie(cs, url, "b=2; domain=.www.google.com.")); + EXPECT_FALSE(this->SetCookie(cs, url_with_dot, "b=2; domain=.google.com.")); + } + + // Make sure there weren't any side effects. + this->MatchCookieLines("", + this->GetCookies(cs, GURL("http://hopefully-no-cookies.com/"))); + this->MatchCookieLines("", this->GetCookies(cs, GURL("http://.com/"))); +} + +TYPED_TEST_P(CookieStoreTest, InvalidScheme) { + if (!TypeParam::filters_schemes) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_FALSE(this->SetCookie(cs, GURL(kUrlFtp), kValidCookieLine)); +} + +TYPED_TEST_P(CookieStoreTest, InvalidScheme_Read) { + if (!TypeParam::filters_schemes) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, GURL(kUrlGoogle), kValidDomainCookieLine)); + this->MatchCookieLines("", this->GetCookies(cs, GURL(kUrlFtp))); +} + +TYPED_TEST_P(CookieStoreTest, PathTest) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + std::string url("http://www.google.izzle"); + EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=B; path=/wee")); + this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee"))); + this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/"))); + this->MatchCookieLines("A=B", this->GetCookies(cs, GURL(url + "/wee/war"))); + this->MatchCookieLines("A=B", + this->GetCookies(cs, GURL(url + "/wee/war/more/more"))); + if (!TypeParam::has_path_prefix_bug) + this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/weehee"))); + this->MatchCookieLines("", this->GetCookies(cs, GURL(url + "/"))); + + // If we add a 0 length path, it should default to / + EXPECT_TRUE(this->SetCookie(cs, GURL(url), "A=C; path=")); + this->MatchCookieLines("A=B; A=C", this->GetCookies(cs, GURL(url + "/wee"))); + this->MatchCookieLines("A=C", this->GetCookies(cs, GURL(url + "/"))); +} + +TYPED_TEST_P(CookieStoreTest, HttpOnlyTest) { + if (!TypeParam::supports_http_only) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + options.set_include_httponly(); + + // Create a httponly cookie. + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B; httponly", + options)); + + // Check httponly read protection. + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + + // Check httponly overwrite protection. + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "A=C")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=C", + options)); + this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_)); + + // Check httponly create protection. + EXPECT_FALSE(this->SetCookie(cs, this->url_google_, "B=A; httponly")); + this->MatchCookieLines("A=C", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "B=A; httponly", + options)); + this->MatchCookieLines("A=C; B=A", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + this->MatchCookieLines("A=C", this->GetCookies(cs, this->url_google_)); +} + +TYPED_TEST_P(CookieStoreTest, TestGetCookiesWithInfo) { + if (!TypeParam::supports_cookies_with_info) + return; + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, + "C=D; Mac-Key=390jfn0awf3; Mac-Algorithm=hmac-sha-1", options)); + + this->MatchCookieLines("A=B; C=D", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + + std::string cookie_line; + std::vector<CookieStore::CookieInfo> cookie_infos; + + this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line, + &cookie_infos); + + EXPECT_EQ("A=B; C=D", cookie_line); + + EXPECT_EQ(2U, cookie_infos.size()); + + EXPECT_EQ("A", cookie_infos[0].name); + EXPECT_EQ("", cookie_infos[0].mac_key); + EXPECT_EQ("", cookie_infos[0].mac_algorithm); + + EXPECT_EQ("C", cookie_infos[1].name); + EXPECT_EQ("390jfn0awf3", cookie_infos[1].mac_key); + EXPECT_EQ("hmac-sha-1", cookie_infos[1].mac_algorithm); +} + +TYPED_TEST_P(CookieStoreTest, TestCookieDeletion) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + // Create a session cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Max-Age. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + "; max-age=0")); + this->MatchCookieLineWithTimeout(cs, this->url_google_, ""); + + // Create a session cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, kValidCookieLine)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Expires. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + + // Create a persistent cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); + + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Max-Age. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + "; max-age=0")); + this->MatchCookieLineWithTimeout(cs, this->url_google_, ""); + + // Create a persistent cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Expires. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-1977 22:50:13 GMT")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + + // Create a persistent cookie. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Mon, 18-Apr-22 22:50:13 GMT")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + // Delete it via Expires, with a unix epoch of 0. + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, + std::string(kValidCookieLine) + + "; expires=Thu, 1-Jan-1970 00:00:00 GMT")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); +} + +TYPED_TEST_P(CookieStoreTest, TestSecure) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_)); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B; secure")); + // The secure should overwrite the non-secure. + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_secure_)); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "D=E; secure")); + this->MatchCookieLines("", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("A=B; D=E", + this->GetCookies(cs, this->url_google_secure_)); + + EXPECT_TRUE(this->SetCookie(cs, this->url_google_secure_, "A=B")); + // The non-secure should overwrite the secure. + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + this->MatchCookieLines("D=E; A=B", + this->GetCookies(cs, this->url_google_secure_)); +} + +static const int kLastAccessThresholdMilliseconds = 200; + +// Formerly NetUtilTest.CookieTest back when we used wininet's cookie handling. +TYPED_TEST_P(CookieStoreTest, NetUtilCookieTest) { + const GURL test_url("http://mojo.jojo.google.izzle/"); + + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + EXPECT_TRUE(this->SetCookie(cs, test_url, "foo=bar")); + std::string value = this->GetCookies(cs, test_url); + this->MatchCookieLines("foo=bar", value); + + // test that we can retrieve all cookies: + EXPECT_TRUE(this->SetCookie(cs, test_url, "x=1")); + EXPECT_TRUE(this->SetCookie(cs, test_url, "y=2")); + + std::string result = this->GetCookies(cs, test_url); + EXPECT_FALSE(result.empty()); + EXPECT_NE(result.find("x=1"), std::string::npos) << result; + EXPECT_NE(result.find("y=2"), std::string::npos) << result; +} + +TYPED_TEST_P(CookieStoreTest, OverwritePersistentCookie) { + GURL url_google("http://www.google.com/"); + GURL url_chromium("http://chromium.org"); + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + + // Insert a cookie "a" for path "/path1" + EXPECT_TRUE( + this->SetCookie(cs, url_google, "a=val1; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:13 GMT")); + + // Insert a cookie "b" for path "/path1" + EXPECT_TRUE( + this->SetCookie(cs, url_google, "b=val1; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + // Insert a cookie "b" for path "/path1", that is httponly. This should + // overwrite the non-http-only version. + CookieOptions allow_httponly; + allow_httponly.set_include_httponly(); + EXPECT_TRUE( + this->SetCookieWithOptions(cs, url_google, + "b=val2; path=/path1; httponly; " + "expires=Mon, 18-Apr-22 22:50:14 GMT", + allow_httponly)); + + // Insert a cookie "a" for path "/path1". This should overwrite. + EXPECT_TRUE(this->SetCookie(cs, url_google, + "a=val33; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + // Insert a cookie "a" for path "/path2". This should NOT overwrite + // cookie "a", since the path is different. + EXPECT_TRUE(this->SetCookie(cs, url_google, + "a=val9; path=/path2; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + // Insert a cookie "a" for path "/path1", but this time for "chromium.org". + // Although the name and path match, the hostnames do not, so shouldn't + // overwrite. + EXPECT_TRUE(this->SetCookie(cs, url_chromium, + "a=val99; path=/path1; " + "expires=Mon, 18-Apr-22 22:50:14 GMT")); + + if (TypeParam::supports_http_only) { + this->MatchCookieLines("a=val33", + this->GetCookies(cs, GURL("http://www.google.com/path1"))); + } else { + this->MatchCookieLines("a=val33; b=val2", + this->GetCookies(cs, GURL("http://www.google.com/path1"))); + } + this->MatchCookieLines("a=val9", + this->GetCookies(cs, GURL("http://www.google.com/path2"))); + this->MatchCookieLines("a=val99", + this->GetCookies(cs, GURL("http://chromium.org/path1"))); +} + +TYPED_TEST_P(CookieStoreTest, CookieOrdering) { + // Put a random set of cookies into a store and make sure they're returned in + // the right order. + // Cookies should be sorted by path length and creation time, as per RFC6265. + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://d.c.b.a.google.com/aa/x.html"), + "c=1")); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"), + "d=1; domain=b.a.google.com")); + base::PlatformThread::Sleep(TypeParam::creation_time_granularity_in_ms); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://b.a.google.com/aa/bb/cc/x.html"), + "a=4; domain=b.a.google.com")); + base::PlatformThread::Sleep(TypeParam::creation_time_granularity_in_ms); + EXPECT_TRUE(this->SetCookie(cs, + GURL("http://c.b.a.google.com/aa/bb/cc/x.html"), + "e=1; domain=c.b.a.google.com")); + EXPECT_TRUE(this->SetCookie(cs, + GURL("http://d.c.b.a.google.com/aa/bb/x.html"), + "b=1")); + EXPECT_TRUE(this->SetCookie(cs, GURL("http://news.bbc.co.uk/midpath/x.html"), + "g=10")); + EXPECT_EQ("d=1; a=4; e=1; b=1; c=1", + this->GetCookies(cs, GURL("http://d.c.b.a.google.com/aa/bb/cc/dd"))); +} + +REGISTER_TYPED_TEST_CASE_P(CookieStoreTest, + TypeTest, DomainTest, DomainWithTrailingDotTest, ValidSubdomainTest, + InvalidDomainTest, DomainWithoutLeadingDotTest, CaseInsensitiveDomainTest, + TestIpAddress, TestNonDottedAndTLD, TestHostEndsWithDot, InvalidScheme, + InvalidScheme_Read, PathTest, HttpOnlyTest, TestGetCookiesWithInfo, + TestCookieDeletion, TestSecure, NetUtilCookieTest, + OverwritePersistentCookie, CookieOrdering); + +template<class CookieStoreTestTraits> +class MultiThreadedCookieStoreTest : + public CookieStoreTest<CookieStoreTestTraits> { + public: + MultiThreadedCookieStoreTest() : other_thread_("CMTthread") {} + + // Helper methods for calling the asynchronous CookieStore methods + // from a different thread. + + void GetCookiesTask(CookieStore* cs, + const GURL& url, + GetCookieStringCallback* callback) { + CookieOptions options; + if (!CookieStoreTestTraits::supports_http_only) + options.set_include_httponly(); + cs->GetCookiesWithOptionsAsync( + url, options, + base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback))); + } + + void GetCookiesWithOptionsTask(CookieStore* cs, + const GURL& url, + const CookieOptions& options, + GetCookieStringCallback* callback) { + cs->GetCookiesWithOptionsAsync( + url, options, + base::Bind(&GetCookieStringCallback::Run, base::Unretained(callback))); + } + + void GetCookiesWithInfoTask(CookieStore* cs, + const GURL& url, + const CookieOptions& options, + GetCookiesWithInfoCallback* callback) { + cs->GetCookiesWithInfoAsync( + url, options, + base::Bind(&GetCookiesWithInfoCallback::Run, + base::Unretained(callback))); + } + + void SetCookieWithOptionsTask(CookieStore* cs, + const GURL& url, + const std::string& cookie_line, + const CookieOptions& options, + SetCookieCallback* callback) { + cs->SetCookieWithOptionsAsync( + url, cookie_line, options, + base::Bind(&SetCookieCallback::Run, base::Unretained(callback))); + } + + void DeleteCookieTask(CookieStore* cs, + const GURL& url, + const std::string& cookie_name, + DeleteCookieCallback* callback) { + cs->DeleteCookieAsync( + url, cookie_name, + base::Bind(&DeleteCookieCallback::Run, base::Unretained(callback))); + } + + protected: + void RunOnOtherThread(const base::Closure& task) { + other_thread_.Start(); + other_thread_.message_loop()->PostTask(FROM_HERE, task); + CookieStoreTest<CookieStoreTestTraits>::RunFor(kTimeout); + other_thread_.Stop(); + } + + Thread other_thread_; +}; + +TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest); + +// TODO(ycxiao): Eventually, we will need to create a separate thread, create +// the cookie store on that thread (or at least its store, i.e., the DB +// thread). +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookies) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", this->GetCookies(cs, this->url_google_)); + GetCookieStringCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesTask, + base::Unretained(this), + cs, this->url_google_, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + EXPECT_EQ("A=B", callback.cookie()); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithOptions) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + if (!TypeParam::supports_http_only) + options.set_include_httponly(); + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->MatchCookieLines("A=B", + this->GetCookiesWithOptions(cs, this->url_google_, options)); + GetCookieStringCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithOptionsTask, + base::Unretained(this), + cs, this->url_google_, options, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + EXPECT_EQ("A=B", callback.cookie()); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckGetCookiesWithInfo) { + if (!TypeParam::supports_cookies_with_info) + return; + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + std::string cookie_line; + std::vector<CookieStore::CookieInfo> cookie_infos; + EXPECT_TRUE(this->SetCookie(cs, this->url_google_, "A=B")); + this->GetCookiesWithInfo(cs, this->url_google_, options, &cookie_line, + &cookie_infos); + this->MatchCookieLines("A=B", cookie_line); + EXPECT_EQ(1U, cookie_infos.size()); + EXPECT_EQ("A", cookie_infos[0].name); + EXPECT_EQ("", cookie_infos[0].mac_key); + EXPECT_EQ("", cookie_infos[0].mac_algorithm); + GetCookiesWithInfoCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::GetCookiesWithInfoTask, + base::Unretained(this), cs, this->url_google_, options, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + this->MatchCookieLines("A=B", callback.cookie_line()); + EXPECT_EQ(1U, callback.cookie_info().size()); + EXPECT_EQ("A", callback.cookie_info()[0].name); + EXPECT_EQ("", callback.cookie_info()[0].mac_key); + EXPECT_EQ("", callback.cookie_info()[0].mac_algorithm); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckSetCookieWithOptions) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + if (!TypeParam::supports_http_only) + options.set_include_httponly(); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + SetCookieCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::SetCookieWithOptionsTask, + base::Unretained(this), + cs, this->url_google_, "A=B", options, &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); + EXPECT_TRUE(callback.result()); +} + +TYPED_TEST_P(MultiThreadedCookieStoreTest, ThreadCheckDeleteCookie) { + scoped_refptr<CookieStore> cs(this->GetCookieStore()); + CookieOptions options; + if (!TypeParam::supports_http_only) + options.set_include_httponly(); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + this->DeleteCookie(cs, this->url_google_, "A"); + EXPECT_TRUE(this->SetCookieWithOptions(cs, this->url_google_, "A=B", + options)); + DeleteCookieCallback callback(&this->other_thread_); + base::Closure task = base::Bind( + &net::MultiThreadedCookieStoreTest<TypeParam>::DeleteCookieTask, + base::Unretained(this), + cs, this->url_google_, "A", &callback); + this->RunOnOtherThread(task); + EXPECT_TRUE(callback.did_run()); +} + +REGISTER_TYPED_TEST_CASE_P(MultiThreadedCookieStoreTest, + ThreadCheckGetCookies, ThreadCheckGetCookiesWithOptions, + ThreadCheckGetCookiesWithInfo, ThreadCheckSetCookieWithOptions, + ThreadCheckDeleteCookie); + +} // namespace net + +#endif // NET_BASE_COOKIE_STORE_UNITTEST_H_ diff --git a/net/base/cookie_util_unittest.cc b/net/base/cookie_util_unittest.cc new file mode 100644 index 0000000..4c3db80 --- /dev/null +++ b/net/base/cookie_util_unittest.cc @@ -0,0 +1,23 @@ +// Copyright (c) 2012 The Chromium 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 "base/basictypes.h" +#include "net/base/cookie_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(CookieUtilTest, TestDomainIsHostOnly) { + const struct { + const char* str; + const bool is_host_only; + } tests[] = { + { "", true }, + { "www.google.com", true }, + { ".google.com", false } + }; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { + EXPECT_EQ(tests[i].is_host_only, + net::cookie_util::DomainIsHostOnly(tests[i].str)); + } +} diff --git a/net/net.gyp b/net/net.gyp index 46327a1..f991318 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1008,6 +1008,8 @@ 'base/cert_database_nss_unittest.cc', 'base/cert_verifier_unittest.cc', 'base/cookie_monster_unittest.cc', + 'base/cookie_store_unittest.h', + 'base/cookie_util_unittest.cc', 'base/crl_set_unittest.cc', 'base/data_url_unittest.cc', 'base/default_origin_bound_cert_store_unittest.cc', @@ -1088,7 +1090,7 @@ 'ftp/ftp_network_transaction_unittest.cc', 'ftp/ftp_util_unittest.cc', 'http/des_unittest.cc', - 'http/disk_cache_based_ssl_host_info_unittest.cc', + 'http/disk_cache_based_ssl_host_info_unittest.cc', 'http/http_auth_cache_unittest.cc', 'http/http_auth_controller_unittest.cc', 'http/http_auth_filter_unittest.cc', @@ -1129,7 +1131,7 @@ 'http/mock_gssapi_library_posix.cc', 'http/mock_gssapi_library_posix.h', 'http/mock_http_cache.cc', - 'http/mock_http_cache.h', + 'http/mock_http_cache.h', 'http/mock_sspi_library_win.h', 'http/mock_sspi_library_win.cc', 'http/url_security_manager_unittest.cc', @@ -1393,6 +1395,8 @@ 'base/cert_test_util.h', 'base/cookie_monster_store_test.cc', 'base/cookie_monster_store_test.h', + 'base/cookie_store_test_callbacks.cc', + 'base/cookie_store_test_callbacks.h', 'base/cookie_store_test_helpers.cc', 'base/cookie_store_test_helpers.h', 'base/mock_file_stream.cc', |