summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-12 22:12:49 +0000
committerabarth@chromium.org <abarth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-05-12 22:12:49 +0000
commit34a160dad4c51a0b16263a91722865a5a92df2eb (patch)
treecdf69aee87316cced9b3c94b0baef82d180d8cf0 /net
parent69401287af172586685346e5dd6b7e22b923f224 (diff)
downloadchromium_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.cc89
-rw-r--r--net/base/cookie_monster.h6
-rw-r--r--net/base/cookie_monster_perftest.cc47
-rw-r--r--net/base/cookie_monster_unittest.cc31
-rw-r--r--net/base/cookie_store.h31
-rw-r--r--net/websockets/websocket_job_unittest.cc6
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; }