diff options
author | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-12 22:12:49 +0000 |
---|---|---|
committer | abarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-05-12 22:12:49 +0000 |
commit | 34a160dad4c51a0b16263a91722865a5a92df2eb (patch) | |
tree | cdf69aee87316cced9b3c94b0baef82d180d8cf0 /net | |
parent | 69401287af172586685346e5dd6b7e22b923f224 (diff) | |
download | chromium_src-34a160dad4c51a0b16263a91722865a5a92df2eb.zip chromium_src-34a160dad4c51a0b16263a91722865a5a92df2eb.tar.gz chromium_src-34a160dad4c51a0b16263a91722865a5a92df2eb.tar.bz2 |
MAC Cookies (patch 3 of N)
Prepare the cookie monster for MAC cookies. According to the perftests in this
patch, the change to the cookie monster has a small but measurable effect
(83.963ms => 88.299ms).
Review URL: http://codereview.chromium.org/6901147
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@85200 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/cookie_monster.cc | 89 | ||||
-rw-r--r-- | net/base/cookie_monster.h | 6 | ||||
-rw-r--r-- | net/base/cookie_monster_perftest.cc | 47 | ||||
-rw-r--r-- | net/base/cookie_monster_unittest.cc | 31 | ||||
-rw-r--r-- | net/base/cookie_store.h | 31 | ||||
-rw-r--r-- | net/websockets/websocket_job_unittest.cc | 6 |
6 files changed, 187 insertions, 23 deletions
diff --git a/net/base/cookie_monster.cc b/net/base/cookie_monster.cc index 6dcd722..c7d5bca 100644 --- a/net/base/cookie_monster.cc +++ b/net/base/cookie_monster.cc @@ -54,7 +54,6 @@ #include "base/metrics/histogram.h" #include "base/string_tokenizer.h" #include "base/string_util.h" -#include "base/stringprintf.h" #include "googleurl/src/gurl.h" #include "googleurl/src/url_canon.h" #include "net/base/net_util.h" @@ -78,6 +77,8 @@ const int CookieMonster::kSafeFromGlobalPurgeDays = 30; namespace { +typedef std::vector<CookieMonster::CanonicalCookie*> CanonicalCookieVector; + // Default minimum delay after updating a cookie's LastAccessDate before we // will update it again. const int kDefaultAccessUpdateThresholdSeconds = 60; @@ -380,6 +381,38 @@ ChangeCausePair ChangeCauseMapping[] = { { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false } }; +std::string BuildCookieLine(const CanonicalCookieVector& cookies) { + std::string cookie_line; + for (CanonicalCookieVector::const_iterator it = cookies.begin(); + it != cookies.end(); ++it) { + if (it != cookies.begin()) + cookie_line += "; "; + // In Mozilla if you set a cookie like AAAA, it will have an empty token + // and a value of AAAA. When it sends the cookie back, it will send AAAA, + // so we need to avoid sending =AAAA for a blank token value. + if (!(*it)->Name().empty()) + cookie_line += (*it)->Name() + "="; + cookie_line += (*it)->Value(); + } + return cookie_line; +} + +void BuildCookieInfoList(const CanonicalCookieVector& cookies, + std::vector<CookieStore::CookieInfo>* cookie_infos) { + for (CanonicalCookieVector::const_iterator it = cookies.begin(); + it != cookies.end(); ++it) { + const CookieMonster::CanonicalCookie* cookie = *it; + CookieStore::CookieInfo cookie_info; + + cookie_info.name = cookie->Name(); + cookie_info.mac_key = cookie->MACKey(); + cookie_info.mac_algorithm = cookie->MACAlgorithm(); + cookie_info.source = cookie->Source(); + + cookie_infos->push_back(cookie_info); + } +} + } // namespace // static @@ -776,29 +809,16 @@ std::string CookieMonster::GetCookiesWithOptions(const GURL& url, base::AutoLock autolock(lock_); InitIfNecessary(); - if (!HasCookieableScheme(url)) { + if (!HasCookieableScheme(url)) return std::string(); - } TimeTicks start_time(TimeTicks::Now()); - // Get the cookies for this host and its domain(s). std::vector<CanonicalCookie*> cookies; FindCookiesForHostAndDomain(url, options, true, &cookies); std::sort(cookies.begin(), cookies.end(), CookieSorter); - std::string cookie_line; - for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin(); - it != cookies.end(); ++it) { - if (it != cookies.begin()) - cookie_line += "; "; - // In Mozilla if you set a cookie like AAAA, it will have an empty token - // and a value of AAAA. When it sends the cookie back, it will send AAAA, - // so we need to avoid sending =AAAA for a blank token value. - if (!(*it)->Name().empty()) - cookie_line += (*it)->Name() + "="; - cookie_line += (*it)->Value(); - } + std::string cookie_line = BuildCookieLine(cookies); histogram_time_get_->AddTime(TimeTicks::Now() - start_time); @@ -807,6 +827,33 @@ std::string CookieMonster::GetCookiesWithOptions(const GURL& url, return cookie_line; } +void CookieMonster::GetCookiesWithInfo(const GURL& url, + const CookieOptions& options, + std::string* cookie_line, + std::vector<CookieInfo>* cookie_infos) { + DCHECK(cookie_line->empty()); + DCHECK(cookie_infos->empty()); + + base::AutoLock autolock(lock_); + InitIfNecessary(); + + if (!HasCookieableScheme(url)) + return; + + TimeTicks start_time(TimeTicks::Now()); + + std::vector<CanonicalCookie*> cookies; + FindCookiesForHostAndDomain(url, options, true, &cookies); + std::sort(cookies.begin(), cookies.end(), CookieSorter); + *cookie_line = BuildCookieLine(cookies); + + histogram_time_get_->AddTime(TimeTicks::Now() - start_time); + + TimeTicks mac_start_time = TimeTicks::Now(); + BuildCookieInfoList(cookies, cookie_infos); + histogram_time_mac_->AddTime(TimeTicks::Now() - mac_start_time); +} + void CookieMonster::DeleteCookie(const GURL& url, const std::string& cookie_name) { base::AutoLock autolock(lock_); @@ -1216,10 +1263,9 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions( } std::string cookie_path = CanonPath(url, pc); - - // TODO(abarth): Take these values as parameters. - std::string mac_key; - std::string mac_algorithm; + std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string(); + std::string mac_algorithm = pc.HasMACAlgorithm() ? + pc.MACAlgorithm() : std::string(); scoped_ptr<CanonicalCookie> cc; Time cookie_expires = CanonExpiration(pc, creation_time, options); @@ -1626,6 +1672,9 @@ void CookieMonster::InitializeHistograms() { histogram_time_get_ = base::Histogram::FactoryTimeGet("Cookie.TimeGet", base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 50, base::Histogram::kUmaTargetedHistogramFlag); + histogram_time_mac_ = base::Histogram::FactoryTimeGet("Cookie.TimeGetMac", + base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), + 50, base::Histogram::kUmaTargetedHistogramFlag); histogram_time_load_ = base::Histogram::FactoryTimeGet("Cookie.TimeLoad", base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1), 50, base::Histogram::kUmaTargetedHistogramFlag); diff --git a/net/base/cookie_monster.h b/net/base/cookie_monster.h index 00e53e4..7fe279f 100644 --- a/net/base/cookie_monster.h +++ b/net/base/cookie_monster.h @@ -230,6 +230,11 @@ class CookieMonster : public CookieStore { virtual std::string GetCookiesWithOptions(const GURL& url, const CookieOptions& options); + virtual void GetCookiesWithInfo(const GURL& url, + const CookieOptions& options, + std::string* cookie_line, + std::vector<CookieInfo>* cookie_info); + // Deletes all cookies with that might apply to |url| that has |cookie_name|. virtual void DeleteCookie(const GURL& url, const std::string& cookie_name); @@ -479,6 +484,7 @@ class CookieMonster : public CookieStore { base::Histogram* histogram_number_duplicate_db_cookies_; base::Histogram* histogram_cookie_deletion_cause_; base::Histogram* histogram_time_get_; + base::Histogram* histogram_time_mac_; base::Histogram* histogram_time_load_; CookieMap cookies_; diff --git a/net/base/cookie_monster_perftest.cc b/net/base/cookie_monster_perftest.cc index 68ac4cc..cd2c35e 100644 --- a/net/base/cookie_monster_perftest.cc +++ b/net/base/cookie_monster_perftest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. @@ -102,6 +102,51 @@ TEST(CookieMonsterTest, TestAddCookieOnManyHosts) { timer3.Done(); } +TEST(CookieMonsterTest, TestGetCookiesWithOptions) { + scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); + std::string cookie(kCookieLine); + std::vector<GURL> gurls; + for (int i = 0; i < kNumCookies; ++i) + gurls.push_back(GURL(base::StringPrintf("http://a%04d.izzle", i))); + + for (std::vector<GURL>::const_iterator it = gurls.begin(); + it != gurls.end(); ++it) { + EXPECT_TRUE(cm->SetCookie(*it, cookie)); + } + + PerfTimeLogger timer("Cookie_monster_get_cookie_info"); + for (std::vector<GURL>::const_iterator it = gurls.begin(); + it != gurls.end(); ++it) { + CookieOptions options; + std::string cookie_line; + cookie_line = cm->GetCookiesWithOptions(*it, options); + } + timer.Done(); +} + +TEST(CookieMonsterTest, TestGetCookiesWithInfo) { + scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); + std::string cookie(kCookieLine); + std::vector<GURL> gurls; + for (int i = 0; i < kNumCookies; ++i) + gurls.push_back(GURL(base::StringPrintf("http://a%04d.izzle", i))); + + for (std::vector<GURL>::const_iterator it = gurls.begin(); + it != gurls.end(); ++it) { + EXPECT_TRUE(cm->SetCookie(*it, cookie)); + } + + PerfTimeLogger timer("Cookie_monster_get_cookie_info"); + for (std::vector<GURL>::const_iterator it = gurls.begin(); + it != gurls.end(); ++it) { + CookieOptions options; + std::string cookie_line; + std::vector<CookieStore::CookieInfo> cookie_infos; + cm->GetCookiesWithInfo(*it, options, &cookie_line, &cookie_infos); + } + timer.Done(); +} + static int CountInString(const std::string& str, char c) { return std::count(str.begin(), str.end(), c); } diff --git a/net/base/cookie_monster_unittest.cc b/net/base/cookie_monster_unittest.cc index 8233c7e..5487988 100644 --- a/net/base/cookie_monster_unittest.cc +++ b/net/base/cookie_monster_unittest.cc @@ -725,6 +725,37 @@ TEST(CookieMonsterTest, HttpOnlyTest) { EXPECT_EQ("A=C", cm->GetCookies(url_google)); } +TEST(CookieMonsterTest, GetCookiesWithInfo) { + GURL url_google(kUrlGoogle); + scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL)); + CookieOptions options; + + EXPECT_TRUE(cm->SetCookieWithOptions(url_google, "A=B", options)); + EXPECT_TRUE(cm->SetCookieWithOptions(url_google, + "C=D; Mac-Key=390jfn0awf3; Mac-Algorithm=hmac-sha-1", options)); + + EXPECT_EQ("A=B; C=D", cm->GetCookiesWithOptions(url_google, options)); + + std::string cookie_line; + std::vector<CookieStore::CookieInfo> cookie_infos; + + cm->GetCookiesWithInfo(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(url_google.spec(), cookie_infos[0].source); + + 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); + EXPECT_EQ(url_google.spec(), cookie_infos[1].source); +} + namespace { struct CookieDateParsingCase { diff --git a/net/base/cookie_store.h b/net/base/cookie_store.h index 7d64ee8..0d55ce4 100644 --- a/net/base/cookie_store.h +++ b/net/base/cookie_store.h @@ -26,18 +26,45 @@ class CookieMonster; // be thread safe as its methods can be accessed from IO as well as UI threads. class CookieStore : public base::RefCountedThreadSafe<CookieStore> { public: + // This struct contains additional consumer-specific information that might + // be stored with cookies; currently just MAC information, see: + // http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac + struct CookieInfo { + // The name of the cookie. + std::string name; + // TODO(abarth): Add value if any clients need it. + + // The value of the MAC-Key and MAC-Algorithm attributes, if present. + std::string mac_key; + std::string mac_algorithm; + + // The URL from which we received the cookie. + std::string source; + }; + // Sets a single cookie. Expects a cookie line, like "a=1; domain=b.com". virtual bool SetCookieWithOptions(const GURL& url, const std::string& cookie_line, const CookieOptions& options) = 0; - // TODO what if the total size of all the cookies >4k, can we have a header - // that big or do we need multiple Cookie: headers? + // TODO(???): what if the total size of all the cookies >4k, can we have a + // header that big or do we need multiple Cookie: headers? + // Note: Some sites, such as Facebook, occationally use Cookie headers >4k. + // // Simple interface, gets a cookie string "a=b; c=d" for the given URL. // Use options to access httponly cookies. virtual std::string GetCookiesWithOptions(const GURL& url, const CookieOptions& options) = 0; + // This function is similar to GetCookiesWithOptions same functionality as + // GetCookiesWithOptions except that it additionaly provides detailed + // information about the cookie contained in the cookie line. See |struct + // CookieInfo| above for details. + virtual void GetCookiesWithInfo(const GURL& url, + const CookieOptions& options, + std::string* cookie_line, + std::vector<CookieInfo>* cookie_info) = 0; + // Deletes the passed in cookie for the specified URL. virtual void DeleteCookie(const GURL& url, const std::string& cookie_name) = 0; diff --git a/net/websockets/websocket_job_unittest.cc b/net/websockets/websocket_job_unittest.cc index e8f629a..6643517 100644 --- a/net/websockets/websocket_job_unittest.cc +++ b/net/websockets/websocket_job_unittest.cc @@ -122,6 +122,12 @@ class MockCookieStore : public CookieStore { } return result; } + virtual void GetCookiesWithInfo(const GURL& url, + const CookieOptions& options, + std::string* cookie_line, + std::vector<CookieInfo>* cookie_infos) { + NOTREACHED(); + } virtual void DeleteCookie(const GURL& url, const std::string& cookie_name) {} virtual CookieMonster* GetCookieMonster() { return NULL; } |