summaryrefslogtreecommitdiffstats
path: root/net/cookies
diff options
context:
space:
mode:
authorbattre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-18 13:13:34 +0000
committerbattre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-07-18 13:13:34 +0000
commit5b9bc3505d5cd23898d0bdb350f33956070cc3a6 (patch)
tree2e28070459f0324ce2dd9288e803f8aa095781fd /net/cookies
parent64c186bdf8949a84c1b1e53da12710f50e51336b (diff)
downloadchromium_src-5b9bc3505d5cd23898d0bdb350f33956070cc3a6.zip
chromium_src-5b9bc3505d5cd23898d0bdb350f33956070cc3a6.tar.gz
chromium_src-5b9bc3505d5cd23898d0bdb350f33956070cc3a6.tar.bz2
Move CanonicalCookie into separate files
BUG=137014,112155 TEST=no TBR=sky@chromium.org, erg@chromium.org, tony@chromium.org, eroman@chromium.org Review URL: https://chromiumcodereview.appspot.com/10785017 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@147222 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/cookies')
-rw-r--r--net/cookies/canonical_cookie.cc380
-rw-r--r--net/cookies/canonical_cookie.h156
-rw-r--r--net/cookies/canonical_cookie_unittest.cc42
-rw-r--r--net/cookies/cookie_monster.cc453
-rw-r--r--net/cookies/cookie_monster.h140
-rw-r--r--net/cookies/cookie_monster_perftest.cc3
-rw-r--r--net/cookies/cookie_monster_store_test.cc59
-rw-r--r--net/cookies/cookie_monster_store_test.h45
-rw-r--r--net/cookies/cookie_monster_unittest.cc157
-rw-r--r--net/cookies/cookie_util.cc124
-rw-r--r--net/cookies/cookie_util.h4
-rw-r--r--net/cookies/cookie_util_unittest.cc88
12 files changed, 877 insertions, 774 deletions
diff --git a/net/cookies/canonical_cookie.cc b/net/cookies/canonical_cookie.cc
new file mode 100644
index 0000000..ebd2428
--- /dev/null
+++ b/net/cookies/canonical_cookie.cc
@@ -0,0 +1,380 @@
+// 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.
+
+// Portions of this code based on Mozilla:
+// (netwerk/cookie/src/nsCookieService.cpp)
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2003
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Daniel Witte (dwitte@stanford.edu)
+ * Michiel van Leeuwen (mvl@exedo.nl)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "net/cookies/canonical_cookie.h"
+
+#include "base/basictypes.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "googleurl/src/gurl.h"
+#include "googleurl/src/url_canon.h"
+#include "net/cookies/cookie_util.h"
+#include "net/cookies/parsed_cookie.h"
+
+using base::Time;
+using base::TimeDelta;
+
+namespace net {
+
+namespace {
+
+#if defined(ENABLE_PERSISTENT_SESSION_COOKIES)
+const int kPersistentSessionCookieExpiryInDays = 14;
+#endif
+
+// Determine the cookie domain to use for setting the specified cookie.
+bool GetCookieDomain(const GURL& url,
+ const ParsedCookie& pc,
+ std::string* result) {
+ std::string domain_string;
+ if (pc.HasDomain())
+ domain_string = pc.Domain();
+ return cookie_util::GetCookieDomainWithString(url, domain_string, result);
+}
+
+std::string CanonPathWithString(const GURL& url,
+ const std::string& path_string) {
+ // The RFC says the path should be a prefix of the current URL path.
+ // However, Mozilla allows you to set any path for compatibility with
+ // broken websites. We unfortunately will mimic this behavior. We try
+ // to be generous and accept cookies with an invalid path attribute, and
+ // default the path to something reasonable.
+
+ // The path was supplied in the cookie, we'll take it.
+ if (!path_string.empty() && path_string[0] == '/')
+ return path_string;
+
+ // The path was not supplied in the cookie or invalid, we will default
+ // to the current URL path.
+ // """Defaults to the path of the request URL that generated the
+ // Set-Cookie response, up to, but not including, the
+ // right-most /."""
+ // How would this work for a cookie on /? We will include it then.
+ const std::string& url_path = url.path();
+
+ size_t idx = url_path.find_last_of('/');
+
+ // The cookie path was invalid or a single '/'.
+ if (idx == 0 || idx == std::string::npos)
+ return std::string("/");
+
+ // Return up to the rightmost '/'.
+ return url_path.substr(0, idx);
+}
+
+} // namespace
+
+CanonicalCookie::CanonicalCookie()
+ : secure_(false),
+ httponly_(false) {
+ SetSessionCookieExpiryTime();
+}
+
+CanonicalCookie::CanonicalCookie(
+ const GURL& url, const std::string& name, const std::string& value,
+ const std::string& domain, const std::string& path,
+ const std::string& mac_key, const std::string& mac_algorithm,
+ const base::Time& creation, const base::Time& expiration,
+ const base::Time& last_access, bool secure, bool httponly)
+ : source_(GetCookieSourceFromURL(url)),
+ name_(name),
+ value_(value),
+ domain_(domain),
+ path_(path),
+ mac_key_(mac_key),
+ mac_algorithm_(mac_algorithm),
+ creation_date_(creation),
+ expiry_date_(expiration),
+ last_access_date_(last_access),
+ secure_(secure),
+ httponly_(httponly) {
+ if (expiration.is_null())
+ SetSessionCookieExpiryTime();
+}
+
+CanonicalCookie::CanonicalCookie(const GURL& url, const ParsedCookie& pc)
+ : source_(GetCookieSourceFromURL(url)),
+ name_(pc.Name()),
+ value_(pc.Value()),
+ path_(CanonPath(url, pc)),
+ mac_key_(pc.MACKey()),
+ mac_algorithm_(pc.MACAlgorithm()),
+ creation_date_(Time::Now()),
+ last_access_date_(Time()),
+ secure_(pc.IsSecure()),
+ httponly_(pc.IsHttpOnly()) {
+ if (pc.HasExpires())
+ expiry_date_ = CanonExpiration(pc, creation_date_, creation_date_);
+ else
+ SetSessionCookieExpiryTime();
+
+ // Do the best we can with the domain.
+ std::string cookie_domain;
+ std::string domain_string;
+ if (pc.HasDomain()) {
+ domain_string = pc.Domain();
+ }
+ bool result
+ = cookie_util::GetCookieDomainWithString(url, domain_string,
+ &cookie_domain);
+ // Caller is responsible for passing in good arguments.
+ DCHECK(result);
+ domain_ = cookie_domain;
+}
+
+CanonicalCookie::~CanonicalCookie() {
+}
+
+std::string CanonicalCookie::GetCookieSourceFromURL(const GURL& url) {
+ if (url.SchemeIsFile())
+ return url.spec();
+
+ url_canon::Replacements<char> replacements;
+ replacements.ClearPort();
+ if (url.SchemeIsSecure())
+ replacements.SetScheme("http", url_parse::Component(0, 4));
+
+ return url.GetOrigin().ReplaceComponents(replacements).spec();
+}
+
+// static
+std::string CanonicalCookie::CanonPath(const GURL& url,
+ const ParsedCookie& pc) {
+ std::string path_string;
+ if (pc.HasPath())
+ path_string = pc.Path();
+ return CanonPathWithString(url, path_string);
+}
+
+// static
+Time CanonicalCookie::CanonExpiration(const ParsedCookie& pc,
+ const Time& current,
+ const Time& server_time) {
+ // First, try the Max-Age attribute.
+ uint64 max_age = 0;
+ if (pc.HasMaxAge() &&
+#ifdef COMPILER_MSVC
+ sscanf_s(
+#else
+ sscanf(
+#endif
+ pc.MaxAge().c_str(), " %" PRIu64, &max_age) == 1) {
+ return current + TimeDelta::FromSeconds(max_age);
+ }
+
+ // Try the Expires attribute.
+ if (pc.HasExpires()) {
+ // Adjust for clock skew between server and host.
+ return current + (cookie_util::ParseCookieTime(pc.Expires()) - server_time);
+ }
+
+ // Invalid or no expiration, persistent cookie.
+ return Time();
+}
+
+void CanonicalCookie::SetSessionCookieExpiryTime() {
+#if defined(ENABLE_PERSISTENT_SESSION_COOKIES)
+ // Mobile apps can sometimes be shut down without any warning, so the session
+ // cookie has to be persistent and given a default expiration time.
+ expiry_date_ = base::Time::Now() +
+ base::TimeDelta::FromDays(kPersistentSessionCookieExpiryInDays);
+#endif
+}
+
+CanonicalCookie* CanonicalCookie::Create(const GURL& url,
+ const ParsedCookie& pc) {
+ if (!pc.IsValid()) {
+ return NULL;
+ }
+
+ std::string domain_string;
+ if (!GetCookieDomain(url, pc, &domain_string)) {
+ return NULL;
+ }
+ std::string path_string = CanonPath(url, pc);
+ std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string();
+ std::string mac_algorithm = pc.HasMACAlgorithm() ?
+ pc.MACAlgorithm() : std::string();
+ Time creation_time = Time::Now();
+ Time expiration_time;
+ if (pc.HasExpires())
+ expiration_time = cookie_util::ParseCookieTime(pc.Expires());
+
+ return (Create(url, pc.Name(), pc.Value(), domain_string, path_string,
+ mac_key, mac_algorithm, creation_time, expiration_time,
+ pc.IsSecure(), pc.IsHttpOnly()));
+}
+
+CanonicalCookie* CanonicalCookie::Create(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const std::string& mac_key,
+ const std::string& mac_algorithm,
+ const base::Time& creation,
+ const base::Time& expiration,
+ bool secure,
+ bool http_only) {
+ // Expect valid attribute tokens and values, as defined by the ParsedCookie
+ // logic, otherwise don't create the cookie.
+ std::string parsed_name = ParsedCookie::ParseTokenString(name);
+ if (parsed_name != name)
+ return NULL;
+ std::string parsed_value = ParsedCookie::ParseValueString(value);
+ if (parsed_value != value)
+ return NULL;
+
+ std::string parsed_domain = ParsedCookie::ParseValueString(domain);
+ if (parsed_domain != domain)
+ return NULL;
+ std::string cookie_domain;
+ if (!cookie_util::GetCookieDomainWithString(url, parsed_domain,
+ &cookie_domain)) {
+ return NULL;
+ }
+
+ std::string parsed_path = ParsedCookie::ParseValueString(path);
+ if (parsed_path != path)
+ return NULL;
+
+ std::string cookie_path = CanonPathWithString(url, parsed_path);
+ // Expect that the path was either not specified (empty), or is valid.
+ if (!parsed_path.empty() && cookie_path != parsed_path)
+ return NULL;
+ // Canonicalize path again to make sure it escapes characters as needed.
+ url_parse::Component path_component(0, cookie_path.length());
+ url_canon::RawCanonOutputT<char> canon_path;
+ url_parse::Component canon_path_component;
+ url_canon::CanonicalizePath(cookie_path.data(), path_component,
+ &canon_path, &canon_path_component);
+ cookie_path = std::string(canon_path.data() + canon_path_component.begin,
+ canon_path_component.len);
+
+ return new CanonicalCookie(url, parsed_name, parsed_value, cookie_domain,
+ cookie_path, mac_key, mac_algorithm, creation,
+ expiration, creation, secure, http_only);
+}
+
+bool CanonicalCookie::IsOnPath(const std::string& url_path) const {
+
+ // A zero length would be unsafe for our trailing '/' checks, and
+ // would also make no sense for our prefix match. The code that
+ // creates a CanonicalCookie should make sure the path is never zero length,
+ // but we double check anyway.
+ if (path_.empty())
+ return false;
+
+ // The Mozilla code broke this into three cases, based on if the cookie path
+ // was longer, the same length, or shorter than the length of the url path.
+ // I think the approach below is simpler.
+
+ // Make sure the cookie path is a prefix of the url path. If the
+ // url path is shorter than the cookie path, then the cookie path
+ // can't be a prefix.
+ if (url_path.find(path_) != 0)
+ return false;
+
+ // Now we know that url_path is >= cookie_path, and that cookie_path
+ // is a prefix of url_path. If they are the are the same length then
+ // they are identical, otherwise we need an additional check:
+
+ // In order to avoid in correctly matching a cookie path of /blah
+ // with a request path of '/blahblah/', we need to make sure that either
+ // the cookie path ends in a trailing '/', or that we prefix up to a '/'
+ // in the url path. Since we know that the url path length is greater
+ // than the cookie path length, it's safe to index one byte past.
+ if (path_.length() != url_path.length() &&
+ path_[path_.length() - 1] != '/' &&
+ url_path[path_.length()] != '/')
+ return false;
+
+ return true;
+}
+
+bool CanonicalCookie::IsDomainMatch(const std::string& scheme,
+ const std::string& host) const {
+ // Can domain match in two ways; as a domain cookie (where the cookie
+ // domain begins with ".") or as a host cookie (where it doesn't).
+
+ // Some consumers of the CookieMonster expect to set cookies on
+ // URLs like http://.strange.url. To retrieve cookies in this instance,
+ // we allow matching as a host cookie even when the domain_ starts with
+ // a period.
+ if (host == domain_)
+ return true;
+
+ // Domain cookie must have an initial ".". To match, it must be
+ // equal to url's host with initial period removed, or a suffix of
+ // it.
+
+ // Arguably this should only apply to "http" or "https" cookies, but
+ // extension cookie tests currently use the funtionality, and if we
+ // ever decide to implement that it should be done by preventing
+ // such cookies from being set.
+ if (domain_.empty() || domain_[0] != '.')
+ return false;
+
+ // The host with a "." prefixed.
+ if (domain_.compare(1, std::string::npos, host) == 0)
+ return true;
+
+ // A pure suffix of the host (ok since we know the domain already
+ // starts with a ".")
+ return (host.length() > domain_.length() &&
+ host.compare(host.length() - domain_.length(),
+ domain_.length(), domain_) == 0);
+}
+
+std::string CanonicalCookie::DebugString() const {
+ return base::StringPrintf(
+ "name: %s value: %s domain: %s path: %s creation: %"
+ PRId64,
+ name_.c_str(), value_.c_str(),
+ domain_.c_str(), path_.c_str(),
+ static_cast<int64>(creation_date_.ToTimeT()));
+}
+
+} // namespace
diff --git a/net/cookies/canonical_cookie.h b/net/cookies/canonical_cookie.h
new file mode 100644
index 0000000..4a710b2
--- /dev/null
+++ b/net/cookies/canonical_cookie.h
@@ -0,0 +1,156 @@
+// 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_COOKIES_CANONICAL_COOKIE_H_
+#define NET_COOKIES_CANONICAL_COOKIE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/time.h"
+#include "net/base/net_export.h"
+
+class GURL;
+
+namespace net {
+
+class ParsedCookie;
+
+class NET_EXPORT CanonicalCookie {
+ public:
+
+ // These constructors do no validation or canonicalization of their inputs;
+ // the resulting CanonicalCookies should not be relied on to be canonical
+ // unless the caller has done appropriate validation and canonicalization
+ // themselves.
+ CanonicalCookie();
+ CanonicalCookie(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const std::string& mac_key,
+ const std::string& mac_algorithm,
+ const base::Time& creation,
+ const base::Time& expiration,
+ const base::Time& last_access,
+ bool secure,
+ bool httponly);
+
+ // This constructor does canonicalization but not validation.
+ // The result of this constructor should not be relied on in contexts
+ // in which pre-validation of the ParsedCookie has not been done.
+ CanonicalCookie(const GURL& url, const ParsedCookie& pc);
+
+ ~CanonicalCookie();
+
+ // Supports the default copy constructor.
+
+ // Creates a canonical cookie from parsed cookie.
+ // Canonicalizes and validates inputs. May return NULL if an attribute
+ // value is invalid.
+ static CanonicalCookie* Create(const GURL& url,
+ const ParsedCookie& pc);
+
+ // Creates a canonical cookie from unparsed attribute values.
+ // Canonicalizes and validates inputs. May return NULL if an attribute
+ // value is invalid.
+ static CanonicalCookie* Create(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ const std::string& mac_key,
+ const std::string& mac_algorithm,
+ const base::Time& creation,
+ const base::Time& expiration,
+ bool secure,
+ bool http_only);
+
+ const std::string& Source() const { return source_; }
+ const std::string& Name() const { return name_; }
+ const std::string& Value() const { return value_; }
+ const std::string& Domain() const { return domain_; }
+ const std::string& Path() const { return path_; }
+ const std::string& MACKey() const { return mac_key_; }
+ const std::string& MACAlgorithm() const { return mac_algorithm_; }
+ const base::Time& CreationDate() const { return creation_date_; }
+ const base::Time& LastAccessDate() const { return last_access_date_; }
+ bool IsPersistent() const { return !expiry_date_.is_null(); }
+ const base::Time& ExpiryDate() const { return expiry_date_; }
+ bool IsSecure() const { return secure_; }
+ bool IsHttpOnly() const { return httponly_; }
+ bool IsDomainCookie() const {
+ return !domain_.empty() && domain_[0] == '.'; }
+ bool IsHostCookie() const { return !IsDomainCookie(); }
+
+ bool IsExpired(const base::Time& current) {
+ return !expiry_date_.is_null() && current >= expiry_date_;
+ }
+
+ // Are the cookies considered equivalent in the eyes of RFC 2965.
+ // The RFC says that name must match (case-sensitive), domain must
+ // match (case insensitive), and path must match (case sensitive).
+ // For the case insensitive domain compare, we rely on the domain
+ // having been canonicalized (in
+ // GetCookieDomainWithString->CanonicalizeHost).
+ bool IsEquivalent(const CanonicalCookie& ecc) const {
+ // It seems like it would make sense to take secure and httponly into
+ // account, but the RFC doesn't specify this.
+ // NOTE: Keep this logic in-sync with TrimDuplicateCookiesForHost().
+ return (name_ == ecc.Name() && domain_ == ecc.Domain()
+ && path_ == ecc.Path());
+ }
+
+ void SetLastAccessDate(const base::Time& date) {
+ last_access_date_ = date;
+ }
+
+ bool IsOnPath(const std::string& url_path) const;
+ bool IsDomainMatch(const std::string& scheme, const std::string& host) const;
+
+ std::string DebugString() const;
+
+ // Returns the cookie source when cookies are set for |url|. This function
+ // is public for unit test purposes only.
+ static std::string GetCookieSourceFromURL(const GURL& url);
+ static std::string CanonPath(const GURL& url, const ParsedCookie& pc);
+ static base::Time CanonExpiration(const ParsedCookie& pc,
+ const base::Time& current,
+ const base::Time& server_time);
+
+ private:
+ // Gives the session cookie an expiration time if needed
+ void SetSessionCookieExpiryTime();
+
+ // The source member of a canonical cookie is the origin of the URL that tried
+ // to set this cookie, minus the port number if any. This field is not
+ // persistent though; its only used in the in-tab cookies dialog to show the
+ // user the source URL. This is used for both allowed and blocked cookies.
+ // When a CanonicalCookie is constructed from the backing store (common case)
+ // this field will be null. CanonicalCookie consumers should not rely on
+ // this field unless they guarantee that the creator of those
+ // CanonicalCookies properly initialized the field.
+ // TODO(abarth): We might need to make this field persistent for MAC cookies.
+ std::string source_;
+ std::string name_;
+ std::string value_;
+ std::string domain_;
+ std::string path_;
+ std::string mac_key_; // TODO(abarth): Persist to disk.
+ std::string mac_algorithm_; // TODO(abarth): Persist to disk.
+ base::Time creation_date_;
+ base::Time expiry_date_;
+ base::Time last_access_date_;
+ bool secure_;
+ bool httponly_;
+};
+
+class CookieList : public std::vector<CanonicalCookie> {
+};
+
+} // namespace net
+
+#endif // NET_COOKIES_CANONICAL_COOKIE_H_
diff --git a/net/cookies/canonical_cookie_unittest.cc b/net/cookies/canonical_cookie_unittest.cc
new file mode 100644
index 0000000..9dab3ce
--- /dev/null
+++ b/net/cookies/canonical_cookie_unittest.cc
@@ -0,0 +1,42 @@
+// 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/cookies/canonical_cookie.h"
+
+#include "googleurl/src/gurl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+TEST(CanonicalCookieTest, GetCookieSourceFromURL) {
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("http://example.com")));
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("http://example.com/")));
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("http://example.com/test")));
+ EXPECT_EQ("file:///tmp/test.html",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("file:///tmp/test.html")));
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("http://example.com:1234/")));
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("https://example.com/")));
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("http://user:pwd@example.com/")));
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("http://example.com/test?foo")));
+ EXPECT_EQ("http://example.com/",
+ CanonicalCookie::GetCookieSourceFromURL(
+ GURL("http://example.com/test#foo")));
+}
+
+} // namespace net
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 9851c9a..3d6656e6 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -50,17 +50,15 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
-#include "base/format_macros.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#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/cookies/canonical_cookie.h"
#include "net/cookies/cookie_util.h"
#include "net/cookies/parsed_cookie.h"
#include "net/base/registry_controlled_domain.h"
@@ -103,7 +101,7 @@ const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
namespace {
-typedef std::vector<CookieMonster::CanonicalCookie*> CanonicalCookieVector;
+typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
// Default minimum delay after updating a cookie's LastAccessDate before we
// will update it again.
@@ -125,15 +123,10 @@ const int kVlogGarbageCollection = 5;
const int kVlogSetCookies = 7;
const int kVlogGetCookies = 9;
-#if defined(ENABLE_PERSISTENT_SESSION_COOKIES)
-const int kPersistentSessionCookieExpiryInDays = 14;
-#endif
-
// Mozilla sorts on the path length (longest first), and then it
// sorts by creation time (oldest first).
// The RFC says the sort order for the domain attribute is undefined.
-bool CookieSorter(CookieMonster::CanonicalCookie* cc1,
- CookieMonster::CanonicalCookie* cc2) {
+bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
if (cc1->Path().length() == cc2->Path().length())
return cc1->CreationDate() < cc2->CreationDate();
return cc1->Path().length() > cc2->Path().length();
@@ -199,69 +192,6 @@ bool GetCookieDomain(const GURL& url,
return cookie_util::GetCookieDomainWithString(url, domain_string, result);
}
-std::string CanonPathWithString(const GURL& url,
- const std::string& path_string) {
- // The RFC says the path should be a prefix of the current URL path.
- // However, Mozilla allows you to set any path for compatibility with
- // broken websites. We unfortunately will mimic this behavior. We try
- // to be generous and accept cookies with an invalid path attribute, and
- // default the path to something reasonable.
-
- // The path was supplied in the cookie, we'll take it.
- if (!path_string.empty() && path_string[0] == '/')
- return path_string;
-
- // The path was not supplied in the cookie or invalid, we will default
- // to the current URL path.
- // """Defaults to the path of the request URL that generated the
- // Set-Cookie response, up to, but not including, the
- // right-most /."""
- // How would this work for a cookie on /? We will include it then.
- const std::string& url_path = url.path();
-
- size_t idx = url_path.find_last_of('/');
-
- // The cookie path was invalid or a single '/'.
- if (idx == 0 || idx == std::string::npos)
- return std::string("/");
-
- // Return up to the rightmost '/'.
- return url_path.substr(0, idx);
-}
-
-std::string CanonPath(const GURL& url, const ParsedCookie& pc) {
- std::string path_string;
- if (pc.HasPath())
- path_string = pc.Path();
- return CanonPathWithString(url, path_string);
-}
-
-Time CanonExpiration(const ParsedCookie& pc,
- const Time& current,
- const Time& server_time) {
- // First, try the Max-Age attribute.
- uint64 max_age = 0;
- if (pc.HasMaxAge() &&
-#ifdef COMPILER_MSVC
- sscanf_s(
-#else
- sscanf(
-#endif
- pc.MaxAge().c_str(), " %" PRIu64, &max_age) == 1) {
- return current + TimeDelta::FromSeconds(max_age);
- }
-
- // Try the Expires attribute.
- if (pc.HasExpires()) {
- // Adjust for clock skew between server and host.
- return current + (CookieMonster::ParseCookieTime(pc.Expires()) -
- server_time);
- }
-
- // Invalid or no expiration, persistent cookie.
- return Time();
-}
-
// Helper for GarbageCollection. If |cookie_its->size() > num_max|, remove the
// |num_max - num_purge| most recently accessed cookies from cookie_its.
// (In other words, leave the entries that are candidates for
@@ -348,7 +278,7 @@ 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;
+ const CanonicalCookie* cookie = *it;
CookieStore::CookieInfo cookie_info;
cookie_info.name = cookie->Name();
@@ -395,123 +325,6 @@ CookieMonster::CookieMonster(PersistentCookieStore* store,
SetDefaultCookieableSchemes();
}
-// Parse a cookie expiration time. We try to be lenient, but we need to
-// assume some order to distinguish the fields. The basic rules:
-// - The month name must be present and prefix the first 3 letters of the
-// full month name (jan for January, jun for June).
-// - If the year is <= 2 digits, it must occur after the day of month.
-// - The time must be of the format hh:mm:ss.
-// An average cookie expiration will look something like this:
-// Sat, 15-Apr-17 21:01:22 GMT
-Time CookieMonster::ParseCookieTime(const std::string& time_string) {
- static const char* kMonths[] = { "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec" };
- static const int kMonthsLen = arraysize(kMonths);
- // We want to be pretty liberal, and support most non-ascii and non-digit
- // characters as a delimiter. We can't treat : as a delimiter, because it
- // is the delimiter for hh:mm:ss, and we want to keep this field together.
- // We make sure to include - and +, since they could prefix numbers.
- // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes
- // will be preserved, and we will get them here. So we make sure to include
- // quote characters, and also \ for anything that was internally escaped.
- static const char* kDelimiters = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~";
-
- Time::Exploded exploded = {0};
-
- StringTokenizer tokenizer(time_string, kDelimiters);
-
- bool found_day_of_month = false;
- bool found_month = false;
- bool found_time = false;
- bool found_year = false;
-
- while (tokenizer.GetNext()) {
- const std::string token = tokenizer.token();
- DCHECK(!token.empty());
- bool numerical = IsAsciiDigit(token[0]);
-
- // String field
- if (!numerical) {
- if (!found_month) {
- for (int i = 0; i < kMonthsLen; ++i) {
- // Match prefix, so we could match January, etc
- if (base::strncasecmp(token.c_str(), kMonths[i], 3) == 0) {
- exploded.month = i + 1;
- found_month = true;
- break;
- }
- }
- } else {
- // If we've gotten here, it means we've already found and parsed our
- // month, and we have another string, which we would expect to be the
- // the time zone name. According to the RFC and my experiments with
- // how sites format their expirations, we don't have much of a reason
- // to support timezones. We don't want to ever barf on user input,
- // but this DCHECK should pass for well-formed data.
- // DCHECK(token == "GMT");
- }
- // Numeric field w/ a colon
- } else if (token.find(':') != std::string::npos) {
- if (!found_time &&
-#ifdef COMPILER_MSVC
- sscanf_s(
-#else
- sscanf(
-#endif
- token.c_str(), "%2u:%2u:%2u", &exploded.hour,
- &exploded.minute, &exploded.second) == 3) {
- found_time = true;
- } else {
- // We should only ever encounter one time-like thing. If we're here,
- // it means we've found a second, which shouldn't happen. We keep
- // the first. This check should be ok for well-formed input:
- // NOTREACHED();
- }
- // Numeric field
- } else {
- // Overflow with atoi() is unspecified, so we enforce a max length.
- if (!found_day_of_month && token.length() <= 2) {
- exploded.day_of_month = atoi(token.c_str());
- found_day_of_month = true;
- } else if (!found_year && token.length() <= 5) {
- exploded.year = atoi(token.c_str());
- found_year = true;
- } else {
- // If we're here, it means we've either found an extra numeric field,
- // or a numeric field which was too long. For well-formed input, the
- // following check would be reasonable:
- // NOTREACHED();
- }
- }
- }
-
- if (!found_day_of_month || !found_month || !found_time || !found_year) {
- // We didn't find all of the fields we need. For well-formed input, the
- // following check would be reasonable:
- // NOTREACHED() << "Cookie parse expiration failed: " << time_string;
- return Time();
- }
-
- // Normalize the year to expand abbreviated years to the full year.
- if (exploded.year >= 69 && exploded.year <= 99)
- exploded.year += 1900;
- if (exploded.year >= 0 && exploded.year <= 68)
- exploded.year += 2000;
-
- // If our values are within their correct ranges, we got our time.
- if (exploded.day_of_month >= 1 && exploded.day_of_month <= 31 &&
- exploded.month >= 1 && exploded.month <= 12 &&
- exploded.year >= 1601 && exploded.year <= 30827 &&
- exploded.hour <= 23 && exploded.minute <= 59 && exploded.second <= 59) {
- return Time::FromUTCExploded(exploded);
- }
-
- // One of our values was out of expected range. For well-formed input,
- // the following check would be reasonable:
- // NOTREACHED() << "Cookie exploded expiration failed: " << time_string;
-
- return Time();
-}
// Task classes for queueing the coming request.
@@ -798,7 +611,7 @@ class CookieMonster::DeleteCanonicalCookieTask
public:
DeleteCanonicalCookieTask(
CookieMonster* cookie_monster,
- const CookieMonster::CanonicalCookie& cookie,
+ const CanonicalCookie& cookie,
const CookieMonster::DeleteCookieCallback& callback)
: CookieMonsterTask(cookie_monster),
cookie_(cookie),
@@ -812,7 +625,7 @@ class CookieMonster::DeleteCanonicalCookieTask
virtual ~DeleteCanonicalCookieTask() {}
private:
- CookieMonster::CanonicalCookie cookie_;
+ CanonicalCookie cookie_;
CookieMonster::DeleteCookieCallback callback_;
DISALLOW_COPY_AND_ASSIGN(DeleteCanonicalCookieTask);
@@ -1211,14 +1024,11 @@ bool CookieMonster::InitializeFrom(const CookieList& list) {
InitIfNecessary();
for (net::CookieList::const_iterator iter = list.begin();
iter != list.end(); ++iter) {
- scoped_ptr<net::CookieMonster::CanonicalCookie> cookie;
- cookie.reset(new net::CookieMonster::CanonicalCookie(*iter));
+ scoped_ptr<CanonicalCookie> cookie(new CanonicalCookie(*iter));
net::CookieOptions options;
options.set_include_httponly();
- if (!SetCanonicalCookie(&cookie, cookie->CreationDate(),
- options)) {
+ if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), options))
return false;
- }
}
return true;
}
@@ -1917,13 +1727,14 @@ bool CookieMonster::SetCookieWithCreationTimeAndOptions(
return false;
}
- std::string cookie_path = CanonPath(url, pc);
+ std::string cookie_path = CanonicalCookie::CanonPath(url, pc);
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, server_time);
+ Time cookie_expires =
+ CanonicalCookie::CanonExpiration(pc, creation_time, server_time);
cc.reset(new CanonicalCookie(url, pc.Name(), pc.Value(), cookie_domain,
cookie_path, mac_key, mac_algorithm,
@@ -2344,246 +2155,4 @@ Time CookieMonster::CurrentTime() {
Time::FromInternalValue(last_time_seen_.ToInternalValue() + 1));
}
-CookieMonster::CanonicalCookie::CanonicalCookie()
- : secure_(false),
- httponly_(false) {
- SetSessionCookieExpiryTime();
-}
-
-CookieMonster::CanonicalCookie::CanonicalCookie(
- const GURL& url, const std::string& name, const std::string& value,
- const std::string& domain, const std::string& path,
- const std::string& mac_key, const std::string& mac_algorithm,
- const base::Time& creation, const base::Time& expiration,
- const base::Time& last_access, bool secure, bool httponly)
- : source_(GetCookieSourceFromURL(url)),
- name_(name),
- value_(value),
- domain_(domain),
- path_(path),
- mac_key_(mac_key),
- mac_algorithm_(mac_algorithm),
- creation_date_(creation),
- expiry_date_(expiration),
- last_access_date_(last_access),
- secure_(secure),
- httponly_(httponly) {
- if (expiration.is_null())
- SetSessionCookieExpiryTime();
-}
-
-CookieMonster::CanonicalCookie::CanonicalCookie(const GURL& url,
- const ParsedCookie& pc)
- : source_(GetCookieSourceFromURL(url)),
- name_(pc.Name()),
- value_(pc.Value()),
- path_(CanonPath(url, pc)),
- mac_key_(pc.MACKey()),
- mac_algorithm_(pc.MACAlgorithm()),
- creation_date_(Time::Now()),
- last_access_date_(Time()),
- secure_(pc.IsSecure()),
- httponly_(pc.IsHttpOnly()) {
- if (pc.HasExpires())
- expiry_date_ = CanonExpiration(pc, creation_date_, creation_date_);
- else
- SetSessionCookieExpiryTime();
-
- // Do the best we can with the domain.
- std::string cookie_domain;
- std::string domain_string;
- if (pc.HasDomain()) {
- domain_string = pc.Domain();
- }
- bool result
- = cookie_util::GetCookieDomainWithString(url, domain_string,
- &cookie_domain);
- // Caller is responsible for passing in good arguments.
- DCHECK(result);
- domain_ = cookie_domain;
-}
-
-CookieMonster::CanonicalCookie::~CanonicalCookie() {
-}
-
-std::string CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- const GURL& url) {
- if (url.SchemeIsFile())
- return url.spec();
-
- url_canon::Replacements<char> replacements;
- replacements.ClearPort();
- if (url.SchemeIsSecure())
- replacements.SetScheme("http", url_parse::Component(0, 4));
-
- return url.GetOrigin().ReplaceComponents(replacements).spec();
-}
-
-void CookieMonster::CanonicalCookie::SetSessionCookieExpiryTime() {
-#if defined(ENABLE_PERSISTENT_SESSION_COOKIES)
- // Mobile apps can sometimes be shut down without any warning, so the session
- // cookie has to be persistent and given a default expiration time.
- expiry_date_ = base::Time::Now() +
- base::TimeDelta::FromDays(kPersistentSessionCookieExpiryInDays);
-#endif
-}
-
-CookieMonster::CanonicalCookie* CookieMonster::CanonicalCookie::Create(
- const GURL& url,
- const ParsedCookie& pc) {
- if (!pc.IsValid()) {
- return NULL;
- }
-
- std::string domain_string;
- if (!GetCookieDomain(url, pc, &domain_string)) {
- return NULL;
- }
- std::string path_string = CanonPath(url, pc);
- std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string();
- std::string mac_algorithm = pc.HasMACAlgorithm() ?
- pc.MACAlgorithm() : std::string();
- Time creation_time = Time::Now();
- Time expiration_time;
- if (pc.HasExpires())
- expiration_time = net::CookieMonster::ParseCookieTime(pc.Expires());
-
- return (Create(url, pc.Name(), pc.Value(), domain_string, path_string,
- mac_key, mac_algorithm, creation_time, expiration_time,
- pc.IsSecure(), pc.IsHttpOnly()));
-}
-
-CookieMonster::CanonicalCookie* CookieMonster::CanonicalCookie::Create(
- const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const std::string& mac_key,
- const std::string& mac_algorithm,
- const base::Time& creation,
- const base::Time& expiration,
- bool secure,
- bool http_only) {
- // Expect valid attribute tokens and values, as defined by the ParsedCookie
- // logic, otherwise don't create the cookie.
- std::string parsed_name = ParsedCookie::ParseTokenString(name);
- if (parsed_name != name)
- return NULL;
- std::string parsed_value = ParsedCookie::ParseValueString(value);
- if (parsed_value != value)
- return NULL;
-
- std::string parsed_domain = ParsedCookie::ParseValueString(domain);
- if (parsed_domain != domain)
- return NULL;
- std::string cookie_domain;
- if (!cookie_util::GetCookieDomainWithString(url, parsed_domain,
- &cookie_domain)) {
- return NULL;
- }
-
- std::string parsed_path = ParsedCookie::ParseValueString(path);
- if (parsed_path != path)
- return NULL;
-
- std::string cookie_path = CanonPathWithString(url, parsed_path);
- // Expect that the path was either not specified (empty), or is valid.
- if (!parsed_path.empty() && cookie_path != parsed_path)
- return NULL;
- // Canonicalize path again to make sure it escapes characters as needed.
- url_parse::Component path_component(0, cookie_path.length());
- url_canon::RawCanonOutputT<char> canon_path;
- url_parse::Component canon_path_component;
- url_canon::CanonicalizePath(cookie_path.data(), path_component,
- &canon_path, &canon_path_component);
- cookie_path = std::string(canon_path.data() + canon_path_component.begin,
- canon_path_component.len);
-
- return new CanonicalCookie(url, parsed_name, parsed_value, cookie_domain,
- cookie_path, mac_key, mac_algorithm, creation,
- expiration, creation, secure, http_only);
-}
-
-bool CookieMonster::CanonicalCookie::IsOnPath(
- const std::string& url_path) const {
-
- // A zero length would be unsafe for our trailing '/' checks, and
- // would also make no sense for our prefix match. The code that
- // creates a CanonicalCookie should make sure the path is never zero length,
- // but we double check anyway.
- if (path_.empty())
- return false;
-
- // The Mozilla code broke this into three cases, based on if the cookie path
- // was longer, the same length, or shorter than the length of the url path.
- // I think the approach below is simpler.
-
- // Make sure the cookie path is a prefix of the url path. If the
- // url path is shorter than the cookie path, then the cookie path
- // can't be a prefix.
- if (url_path.find(path_) != 0)
- return false;
-
- // Now we know that url_path is >= cookie_path, and that cookie_path
- // is a prefix of url_path. If they are the are the same length then
- // they are identical, otherwise we need an additional check:
-
- // In order to avoid in correctly matching a cookie path of /blah
- // with a request path of '/blahblah/', we need to make sure that either
- // the cookie path ends in a trailing '/', or that we prefix up to a '/'
- // in the url path. Since we know that the url path length is greater
- // than the cookie path length, it's safe to index one byte past.
- if (path_.length() != url_path.length() &&
- path_[path_.length() - 1] != '/' &&
- url_path[path_.length()] != '/')
- return false;
-
- return true;
-}
-
-bool CookieMonster::CanonicalCookie::IsDomainMatch(
- const std::string& scheme,
- const std::string& host) const {
- // Can domain match in two ways; as a domain cookie (where the cookie
- // domain begins with ".") or as a host cookie (where it doesn't).
-
- // Some consumers of the CookieMonster expect to set cookies on
- // URLs like http://.strange.url. To retrieve cookies in this instance,
- // we allow matching as a host cookie even when the domain_ starts with
- // a period.
- if (host == domain_)
- return true;
-
- // Domain cookie must have an initial ".". To match, it must be
- // equal to url's host with initial period removed, or a suffix of
- // it.
-
- // Arguably this should only apply to "http" or "https" cookies, but
- // extension cookie tests currently use the funtionality, and if we
- // ever decide to implement that it should be done by preventing
- // such cookies from being set.
- if (domain_.empty() || domain_[0] != '.')
- return false;
-
- // The host with a "." prefixed.
- if (domain_.compare(1, std::string::npos, host) == 0)
- return true;
-
- // A pure suffix of the host (ok since we know the domain already
- // starts with a ".")
- return (host.length() > domain_.length() &&
- host.compare(host.length() - domain_.length(),
- domain_.length(), domain_) == 0);
-}
-
-std::string CookieMonster::CanonicalCookie::DebugString() const {
- return base::StringPrintf(
- "name: %s value: %s domain: %s path: %s creation: %"
- PRId64,
- name_.c_str(), value_.c_str(),
- domain_.c_str(), path_.c_str(),
- static_cast<int64>(creation_date_.ToTimeT()));
-}
-
} // namespace
diff --git a/net/cookies/cookie_monster.h b/net/cookies/cookie_monster.h
index 4561a1c..ef5f9ab 100644
--- a/net/cookies/cookie_monster.h
+++ b/net/cookies/cookie_monster.h
@@ -34,6 +34,7 @@ class TimeTicks;
namespace net {
+class CanonicalCookie;
class CookieList;
class ParsedCookie;
@@ -63,7 +64,6 @@ class ParsedCookie;
// - Verify that our domain enforcement and non-dotted handling is correct
class NET_EXPORT CookieMonster : public CookieStore {
public:
- class CanonicalCookie;
class Delegate;
class PersistentCookieStore;
@@ -119,9 +119,6 @@ class NET_EXPORT CookieMonster : public CookieStore {
Delegate* delegate,
int last_access_threshold_milliseconds);
- // Parses the string with the cookie time (very forgivingly).
- static base::Time ParseCookieTime(const std::string& time_string);
-
// Helper function that adds all cookies from |list| into this instance.
bool InitializeFrom(const CookieList& list);
@@ -660,132 +657,6 @@ class NET_EXPORT CookieMonster : public CookieStore {
DISALLOW_COPY_AND_ASSIGN(CookieMonster);
};
-class NET_EXPORT CookieMonster::CanonicalCookie {
- public:
-
- // These constructors do no validation or canonicalization of their inputs;
- // the resulting CanonicalCookies should not be relied on to be canonical
- // unless the caller has done appropriate validation and canonicalization
- // themselves.
- CanonicalCookie();
- CanonicalCookie(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const std::string& mac_key,
- const std::string& mac_algorithm,
- const base::Time& creation,
- const base::Time& expiration,
- const base::Time& last_access,
- bool secure,
- bool httponly);
-
- // This constructor does canonicalization but not validation.
- // The result of this constructor should not be relied on in contexts
- // in which pre-validation of the ParsedCookie has not been done.
- CanonicalCookie(const GURL& url, const ParsedCookie& pc);
-
- ~CanonicalCookie();
-
- // Supports the default copy constructor.
-
- // Creates a canonical cookie from parsed cookie.
- // Canonicalizes and validates inputs. May return NULL if an attribute
- // value is invalid.
- static CanonicalCookie* Create(const GURL& url,
- const ParsedCookie& pc);
-
- // Creates a canonical cookie from unparsed attribute values.
- // Canonicalizes and validates inputs. May return NULL if an attribute
- // value is invalid.
- static CanonicalCookie* Create(const GURL& url,
- const std::string& name,
- const std::string& value,
- const std::string& domain,
- const std::string& path,
- const std::string& mac_key,
- const std::string& mac_algorithm,
- const base::Time& creation,
- const base::Time& expiration,
- bool secure,
- bool http_only);
-
- const std::string& Source() const { return source_; }
- const std::string& Name() const { return name_; }
- const std::string& Value() const { return value_; }
- const std::string& Domain() const { return domain_; }
- const std::string& Path() const { return path_; }
- const std::string& MACKey() const { return mac_key_; }
- const std::string& MACAlgorithm() const { return mac_algorithm_; }
- const base::Time& CreationDate() const { return creation_date_; }
- const base::Time& LastAccessDate() const { return last_access_date_; }
- bool IsPersistent() const { return !expiry_date_.is_null(); }
- const base::Time& ExpiryDate() const { return expiry_date_; }
- bool IsSecure() const { return secure_; }
- bool IsHttpOnly() const { return httponly_; }
- bool IsDomainCookie() const {
- return !domain_.empty() && domain_[0] == '.'; }
- bool IsHostCookie() const { return !IsDomainCookie(); }
-
- bool IsExpired(const base::Time& current) {
- return !expiry_date_.is_null() && current >= expiry_date_;
- }
-
- // Are the cookies considered equivalent in the eyes of RFC 2965.
- // The RFC says that name must match (case-sensitive), domain must
- // match (case insensitive), and path must match (case sensitive).
- // For the case insensitive domain compare, we rely on the domain
- // having been canonicalized (in
- // GetCookieDomainWithString->CanonicalizeHost).
- bool IsEquivalent(const CanonicalCookie& ecc) const {
- // It seems like it would make sense to take secure and httponly into
- // account, but the RFC doesn't specify this.
- // NOTE: Keep this logic in-sync with TrimDuplicateCookiesForHost().
- return (name_ == ecc.Name() && domain_ == ecc.Domain()
- && path_ == ecc.Path());
- }
-
- void SetLastAccessDate(const base::Time& date) {
- last_access_date_ = date;
- }
-
- bool IsOnPath(const std::string& url_path) const;
- bool IsDomainMatch(const std::string& scheme, const std::string& host) const;
-
- std::string DebugString() const;
-
- // Returns the cookie source when cookies are set for |url|. This function
- // is public for unit test purposes only.
- static std::string GetCookieSourceFromURL(const GURL& url);
-
- private:
- // Gives the session cookie an expiration time if needed
- void SetSessionCookieExpiryTime();
-
- // The source member of a canonical cookie is the origin of the URL that tried
- // to set this cookie, minus the port number if any. This field is not
- // persistent though; its only used in the in-tab cookies dialog to show the
- // user the source URL. This is used for both allowed and blocked cookies.
- // When a CanonicalCookie is constructed from the backing store (common case)
- // this field will be null. CanonicalCookie consumers should not rely on
- // this field unless they guarantee that the creator of those
- // CanonicalCookies properly initialized the field.
- // TODO(abarth): We might need to make this field persistent for MAC cookies.
- std::string source_;
- std::string name_;
- std::string value_;
- std::string domain_;
- std::string path_;
- std::string mac_key_; // TODO(abarth): Persist to disk.
- std::string mac_algorithm_; // TODO(abarth): Persist to disk.
- base::Time creation_date_;
- base::Time expiry_date_;
- base::Time last_access_date_;
- bool secure_;
- bool httponly_;
-};
-
class CookieMonster::Delegate
: public base::RefCountedThreadSafe<CookieMonster::Delegate> {
public:
@@ -815,7 +686,7 @@ class CookieMonster::Delegate
// generating a notification with cause CHANGE_COOKIE_OVERWRITE. Afterwards,
// a new cookie is written with the updated values, generating a notification
// with cause CHANGE_COOKIE_EXPLICIT.
- virtual void OnCookieChanged(const CookieMonster::CanonicalCookie& cookie,
+ virtual void OnCookieChanged(const CanonicalCookie& cookie,
bool removed,
ChangeCause cause) = 0;
protected:
@@ -829,8 +700,8 @@ typedef base::RefCountedThreadSafe<CookieMonster::PersistentCookieStore>
class CookieMonster::PersistentCookieStore
: public RefcountedPersistentCookieStore {
public:
- typedef base::Callback<void(const std::vector<
- CookieMonster::CanonicalCookie*>&)> LoadedCallback;
+ typedef base::Callback<void(const std::vector<CanonicalCookie*>&)>
+ LoadedCallback;
// Initializes the store and retrieves the existing cookies. This will be
// called only once at startup. The callback will return all the cookies
@@ -864,9 +735,6 @@ class CookieMonster::PersistentCookieStore
DISALLOW_COPY_AND_ASSIGN(PersistentCookieStore);
};
-class CookieList : public std::vector<CookieMonster::CanonicalCookie> {
-};
-
} // namespace net
#endif // NET_COOKIES_COOKIE_MONSTER_H_
diff --git a/net/cookies/cookie_monster_perftest.cc b/net/cookies/cookie_monster_perftest.cc
index 2e8aa27..7e755f0 100644
--- a/net/cookies/cookie_monster_perftest.cc
+++ b/net/cookies/cookie_monster_perftest.cc
@@ -10,6 +10,7 @@
#include "base/string_util.h"
#include "base/stringprintf.h"
#include "googleurl/src/gurl.h"
+#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_monster_store_test.h"
#include "net/cookies/parsed_cookie.h"
@@ -324,7 +325,7 @@ TEST_F(CookieMonsterTest, TestDomainLine) {
TEST_F(CookieMonsterTest, TestImport) {
scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
- std::vector<CookieMonster::CanonicalCookie*> initial_cookies;
+ std::vector<CanonicalCookie*> initial_cookies;
GetCookiesCallback getCookiesCallback;
// We want to setup a fairly large backing store, with 300 domains of 50
diff --git a/net/cookies/cookie_monster_store_test.cc b/net/cookies/cookie_monster_store_test.cc
index 6724d9d..6e0965d 100644
--- a/net/cookies/cookie_monster_store_test.cc
+++ b/net/cookies/cookie_monster_store_test.cc
@@ -9,12 +9,13 @@
#include "base/stringprintf.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
+#include "net/cookies/cookie_util.h"
#include "net/cookies/parsed_cookie.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
LoadedCallbackTask::LoadedCallbackTask(LoadedCallback loaded_callback,
- std::vector<CookieMonster::CanonicalCookie*> cookies)
+ std::vector<CanonicalCookie*> cookies)
: loaded_callback_(loaded_callback),
cookies_(cookies) {
}
@@ -28,13 +29,13 @@ MockPersistentCookieStore::MockPersistentCookieStore()
void MockPersistentCookieStore::SetLoadExpectation(
bool return_value,
- const std::vector<CookieMonster::CanonicalCookie*>& result) {
+ const std::vector<CanonicalCookie*>& result) {
load_return_value_ = return_value;
load_result_ = result;
}
void MockPersistentCookieStore::Load(const LoadedCallback& loaded_callback) {
- std::vector<CookieMonster::CanonicalCookie*> out_cookies;
+ std::vector<CanonicalCookie*> out_cookies;
if (load_return_value_) {
out_cookies = load_result_;
loaded_ = true;
@@ -44,32 +45,31 @@ void MockPersistentCookieStore::Load(const LoadedCallback& loaded_callback) {
new LoadedCallbackTask(loaded_callback, out_cookies)));
}
-void MockPersistentCookieStore::LoadCookiesForKey(const std::string& key,
+void MockPersistentCookieStore::LoadCookiesForKey(
+ const std::string& key,
const LoadedCallback& loaded_callback) {
if (!loaded_) {
Load(loaded_callback);
} else {
MessageLoop::current()->PostTask(FROM_HERE,
- base::Bind(&LoadedCallbackTask::Run,
- new LoadedCallbackTask(loaded_callback,
- std::vector<CookieMonster::CanonicalCookie*>())));
+ base::Bind(&LoadedCallbackTask::Run,
+ new LoadedCallbackTask(loaded_callback,
+ std::vector<CanonicalCookie*>())));
}
}
-void MockPersistentCookieStore::AddCookie(
- const CookieMonster::CanonicalCookie& cookie) {
+void MockPersistentCookieStore::AddCookie(const CanonicalCookie& cookie) {
commands_.push_back(
CookieStoreCommand(CookieStoreCommand::ADD, cookie));
}
void MockPersistentCookieStore::UpdateCookieAccessTime(
- const CookieMonster::CanonicalCookie& cookie) {
+ const CanonicalCookie& cookie) {
commands_.push_back(CookieStoreCommand(
CookieStoreCommand::UPDATE_ACCESS_TIME, cookie));
}
-void MockPersistentCookieStore::DeleteCookie(
- const CookieMonster::CanonicalCookie& cookie) {
+void MockPersistentCookieStore::DeleteCookie(const CanonicalCookie& cookie) {
commands_.push_back(
CookieStoreCommand(CookieStoreCommand::REMOVE, cookie));
}
@@ -87,7 +87,7 @@ MockPersistentCookieStore::~MockPersistentCookieStore() {}
MockCookieMonsterDelegate::MockCookieMonsterDelegate() {}
void MockCookieMonsterDelegate::OnCookieChanged(
- const CookieMonster::CanonicalCookie& cookie,
+ const CanonicalCookie& cookie,
bool removed,
CookieMonster::Delegate::ChangeCause cause) {
CookieNotification notification(cookie, removed);
@@ -96,10 +96,9 @@ void MockCookieMonsterDelegate::OnCookieChanged(
MockCookieMonsterDelegate::~MockCookieMonsterDelegate() {}
-CookieMonster::CanonicalCookie BuildCanonicalCookie(
- const std::string& key,
- const std::string& cookie_line,
- const base::Time& creation_time) {
+CanonicalCookie BuildCanonicalCookie(const std::string& key,
+ const std::string& cookie_line,
+ const base::Time& creation_time) {
// Parse the cookie line.
ParsedCookie pc(cookie_line);
@@ -111,10 +110,10 @@ CookieMonster::CanonicalCookie BuildCanonicalCookie(
EXPECT_FALSE(pc.HasMaxAge());
EXPECT_TRUE(pc.HasPath());
base::Time cookie_expires = pc.HasExpires() ?
- CookieMonster::ParseCookieTime(pc.Expires()) : base::Time();
+ cookie_util::ParseCookieTime(pc.Expires()) : base::Time();
std::string cookie_path = pc.Path();
- return CookieMonster::CanonicalCookie(
+ return CanonicalCookie(
GURL(), pc.Name(), pc.Value(), key, cookie_path,
pc.MACKey(), pc.MACAlgorithm(),
creation_time, cookie_expires, creation_time,
@@ -125,9 +124,9 @@ void AddCookieToList(
const std::string& key,
const std::string& cookie_line,
const base::Time& creation_time,
- std::vector<CookieMonster::CanonicalCookie*>* out_list) {
- scoped_ptr<CookieMonster::CanonicalCookie> cookie(
- new CookieMonster::CanonicalCookie(
+ std::vector<CanonicalCookie*>* out_list) {
+ scoped_ptr<CanonicalCookie> cookie(
+ new CanonicalCookie(
BuildCanonicalCookie(key, cookie_line, creation_time)));
out_list->push_back(cookie.release());
@@ -139,12 +138,11 @@ MockSimplePersistentCookieStore::MockSimplePersistentCookieStore()
void MockSimplePersistentCookieStore::Load(
const LoadedCallback& loaded_callback) {
- std::vector<CookieMonster::CanonicalCookie*> out_cookies;
+ std::vector<CanonicalCookie*> out_cookies;
for (CanonicalCookieMap::const_iterator it = cookies_.begin();
it != cookies_.end(); it++)
- out_cookies.push_back(
- new CookieMonster::CanonicalCookie(it->second));
+ out_cookies.push_back(new CanonicalCookie(it->second));
MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&LoadedCallbackTask::Run,
@@ -160,26 +158,25 @@ void MockSimplePersistentCookieStore::LoadCookiesForKey(const std::string& key,
MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&LoadedCallbackTask::Run,
new LoadedCallbackTask(loaded_callback,
- std::vector<CookieMonster::CanonicalCookie*>())));
+ std::vector<CanonicalCookie*>())));
}
}
-void MockSimplePersistentCookieStore::AddCookie(
- const CookieMonster::CanonicalCookie& cookie) {
+void MockSimplePersistentCookieStore::AddCookie(const CanonicalCookie& cookie) {
int64 creation_time = cookie.CreationDate().ToInternalValue();
EXPECT_TRUE(cookies_.find(creation_time) == cookies_.end());
cookies_[creation_time] = cookie;
}
void MockSimplePersistentCookieStore::UpdateCookieAccessTime(
- const CookieMonster::CanonicalCookie& cookie) {
+ const CanonicalCookie& cookie) {
int64 creation_time = cookie.CreationDate().ToInternalValue();
ASSERT_TRUE(cookies_.find(creation_time) != cookies_.end());
cookies_[creation_time].SetLastAccessDate(base::Time::Now());
}
void MockSimplePersistentCookieStore::DeleteCookie(
- const CookieMonster::CanonicalCookie& cookie) {
+ const CanonicalCookie& cookie) {
int64 creation_time = cookie.CreationDate().ToInternalValue();
CanonicalCookieMap::iterator it = cookies_.find(creation_time);
ASSERT_TRUE(it != cookies_.end());
@@ -214,7 +211,7 @@ CookieMonster* CreateMonsterFromStoreForGC(
std::string mac_key;
std::string mac_algorithm;
- CookieMonster::CanonicalCookie cc(
+ CanonicalCookie cc(
GURL(), "a", "1", base::StringPrintf("h%05d.izzle", i), "/path",
mac_key, mac_algorithm, creation_time, expiration_time,
last_access_time, false, false);
diff --git a/net/cookies/cookie_monster_store_test.h b/net/cookies/cookie_monster_store_test.h
index 265bd77..d7da521 100644
--- a/net/cookies/cookie_monster_store_test.h
+++ b/net/cookies/cookie_monster_store_test.h
@@ -14,6 +14,7 @@
#include <string>
#include <utility>
#include <vector>
+#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_monster.h"
namespace base {
@@ -31,7 +32,7 @@ class LoadedCallbackTask
typedef CookieMonster::PersistentCookieStore::LoadedCallback LoadedCallback;
LoadedCallbackTask(LoadedCallback loaded_callback,
- std::vector<CookieMonster::CanonicalCookie*> cookies);
+ std::vector<CanonicalCookie*> cookies);
void Run() {
loaded_callback_.Run(cookies_);
@@ -42,7 +43,7 @@ class LoadedCallbackTask
~LoadedCallbackTask();
LoadedCallback loaded_callback_;
- std::vector<CookieMonster::CanonicalCookie*> cookies_;
+ std::vector<CanonicalCookie*> cookies_;
DISALLOW_COPY_AND_ASSIGN(LoadedCallbackTask);
}; // Wrapper class LoadedCallbackTask
@@ -55,13 +56,12 @@ struct CookieStoreCommand {
REMOVE,
};
- CookieStoreCommand(Type type,
- const CookieMonster::CanonicalCookie& cookie)
+ CookieStoreCommand(Type type, const CanonicalCookie& cookie)
: type(type),
cookie(cookie) {}
Type type;
- CookieMonster::CanonicalCookie cookie;
+ CanonicalCookie cookie;
};
// Implementation of PersistentCookieStore that captures the
@@ -76,7 +76,7 @@ class MockPersistentCookieStore
void SetLoadExpectation(
bool return_value,
- const std::vector<CookieMonster::CanonicalCookie*>& result);
+ const std::vector<CanonicalCookie*>& result);
const CommandList& commands() const {
return commands_;
@@ -87,13 +87,13 @@ class MockPersistentCookieStore
virtual void LoadCookiesForKey(const std::string& key,
const LoadedCallback& loaded_callback) OVERRIDE;
- virtual void AddCookie(const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+ virtual void AddCookie(const CanonicalCookie& cookie) OVERRIDE;
virtual void UpdateCookieAccessTime(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+ const CanonicalCookie& cookie) OVERRIDE;
virtual void DeleteCookie(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+ const CanonicalCookie& cookie) OVERRIDE;
virtual void Flush(const base::Closure& callback) OVERRIDE;
@@ -107,7 +107,7 @@ class MockPersistentCookieStore
// Deferred result to use when Load() is called.
bool load_return_value_;
- std::vector<CookieMonster::CanonicalCookie*> load_result_;
+ std::vector<CanonicalCookie*> load_result_;
// Indicates if the store has been fully loaded to avoid returning duplicate
// cookies.
bool loaded_;
@@ -118,7 +118,7 @@ class MockPersistentCookieStore
// Mock for CookieMonster::Delegate
class MockCookieMonsterDelegate : public CookieMonster::Delegate {
public:
- typedef std::pair<CookieMonster::CanonicalCookie, bool>
+ typedef std::pair<CanonicalCookie, bool>
CookieNotification;
MockCookieMonsterDelegate();
@@ -128,7 +128,7 @@ class MockCookieMonsterDelegate : public CookieMonster::Delegate {
void reset() { changes_.clear(); }
virtual void OnCookieChanged(
- const CookieMonster::CanonicalCookie& cookie,
+ const CanonicalCookie& cookie,
bool removed,
CookieMonster::Delegate::ChangeCause cause) OVERRIDE;
@@ -141,17 +141,16 @@ class MockCookieMonsterDelegate : public CookieMonster::Delegate {
};
// Helper to build a single CanonicalCookie.
-CookieMonster::CanonicalCookie BuildCanonicalCookie(
- const std::string& key,
- const std::string& cookie_line,
- const base::Time& creation_time);
+CanonicalCookie BuildCanonicalCookie(const std::string& key,
+ const std::string& cookie_line,
+ const base::Time& creation_time);
// Helper to build a list of CanonicalCookie*s.
void AddCookieToList(
const std::string& key,
const std::string& cookie_line,
const base::Time& creation_time,
- std::vector<CookieMonster::CanonicalCookie*>* out_list);
+ std::vector<CanonicalCookie*>* out_list);
// Just act like a backing database. Keep cookie information from
// Add/Update/Delete and regurgitate it when Load is called.
@@ -165,14 +164,11 @@ class MockSimplePersistentCookieStore
virtual void LoadCookiesForKey(const std::string& key,
const LoadedCallback& loaded_callback) OVERRIDE;
- virtual void AddCookie(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+ virtual void AddCookie(const CanonicalCookie& cookie) OVERRIDE;
- virtual void UpdateCookieAccessTime(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+ virtual void UpdateCookieAccessTime(const CanonicalCookie& cookie) OVERRIDE;
- virtual void DeleteCookie(
- const CookieMonster::CanonicalCookie& cookie) OVERRIDE;
+ virtual void DeleteCookie(const CanonicalCookie& cookie) OVERRIDE;
virtual void Flush(const base::Closure& callback) OVERRIDE;
@@ -182,8 +178,7 @@ class MockSimplePersistentCookieStore
virtual ~MockSimplePersistentCookieStore();
private:
- typedef std::map<int64, CookieMonster::CanonicalCookie>
- CanonicalCookieMap;
+ typedef std::map<int64, CanonicalCookie> CanonicalCookieMap;
CanonicalCookieMap cookies_;
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 7c04aeb..24636da 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -4,7 +4,6 @@
#include "net/cookies/cookie_store_unittest.h"
-#include <time.h>
#include <string>
#include "base/basictypes.h"
@@ -18,6 +17,7 @@
#include "base/threading/thread.h"
#include "base/time.h"
#include "googleurl/src/gurl.h"
+#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_monster_store_test.h" // For CookieStore mock
#include "net/cookies/cookie_util.h"
@@ -40,10 +40,9 @@ class NewMockPersistentCookieStore
MOCK_METHOD1(Load, void(const LoadedCallback& loaded_callback));
MOCK_METHOD2(LoadCookiesForKey, void(const std::string& key,
const LoadedCallback& loaded_callback));
- MOCK_METHOD1(AddCookie, void(const CookieMonster::CanonicalCookie& cc));
- MOCK_METHOD1(UpdateCookieAccessTime,
- void(const CookieMonster::CanonicalCookie& cc));
- MOCK_METHOD1(DeleteCookie, void(const CookieMonster::CanonicalCookie& cc));
+ MOCK_METHOD1(AddCookie, void(const CanonicalCookie& cc));
+ MOCK_METHOD1(UpdateCookieAccessTime, void(const CanonicalCookie& cc));
+ MOCK_METHOD1(DeleteCookie, void(const CanonicalCookie& cc));
MOCK_METHOD1(Flush, void(const base::Closure& callback));
MOCK_METHOD0(SetForceKeepSessionState, void());
@@ -190,8 +189,7 @@ class CookieMonsterTest : public CookieStoreTest<CookieMonsterTestTraits> {
return callback.num_deleted();
}
- bool DeleteCanonicalCookie(CookieMonster*cm,
- const CookieMonster::CanonicalCookie& cookie) {
+ bool DeleteCanonicalCookie(CookieMonster*cm, const CanonicalCookie& cookie) {
DCHECK(cm);
SetCookieCallback callback;
cm->DeleteCanonicalCookieAsync(
@@ -586,7 +584,7 @@ class DeferredCookieTaskTest : public CookieMonsterTest {
testing::InSequence in_sequence_;
// Holds cookies to be returned from PersistentCookieStore::Load or
// PersistentCookieStore::LoadCookiesForKey.
- std::vector<CookieMonster::CanonicalCookie*> loaded_cookies_;
+ std::vector<CanonicalCookie*> loaded_cookies_;
// Stores the callback passed from the CookieMonster to the
// PersistentCookieStore::Load
CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback_;
@@ -809,8 +807,8 @@ TEST_F(DeferredCookieTaskTest, DeferredDeleteAllForHostCookies) {
}
TEST_F(DeferredCookieTaskTest, DeferredDeleteCanonicalCookie) {
- std::vector<CookieMonster::CanonicalCookie*> cookies;
- CookieMonster::CanonicalCookie cookie = BuildCanonicalCookie(
+ std::vector<CanonicalCookie*> cookies;
+ CanonicalCookie cookie = BuildCanonicalCookie(
"www.google.com", "X=1; path=/", base::Time::Now());
MockDeleteCookieCallback delete_cookie_callback;
@@ -881,94 +879,6 @@ TEST_F(DeferredCookieTaskTest, DeferredTaskOrder) {
CompleteLoadingAndWait();
}
-TEST_F(CookieMonsterTest, TestCookieDateParsing) {
- const struct {
- const char* str;
- const bool valid;
- const time_t epoch;
- } tests[] = {
- { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 },
- { "Thu, 19-Apr-2007 16:00:00 GMT", true, 1176998400 },
- { "Wed, 25 Apr 2007 21:02:13 GMT", true, 1177534933 },
- { "Thu, 19/Apr\\2007 16:00:00 GMT", true, 1176998400 },
- { "Fri, 1 Jan 2010 01:01:50 GMT", true, 1262307710 },
- { "Wednesday, 1-Jan-2003 00:00:00 GMT", true, 1041379200 },
- { ", 1-Jan-2003 00:00:00 GMT", true, 1041379200 },
- { " 1-Jan-2003 00:00:00 GMT", true, 1041379200 },
- { "1-Jan-2003 00:00:00 GMT", true, 1041379200 },
- { "Wed,18-Apr-07 22:50:12 GMT", true, 1176936612 },
- { "WillyWonka , 18-Apr-07 22:50:12 GMT", true, 1176936612 },
- { "WillyWonka , 18-Apr-07 22:50:12", true, 1176936612 },
- { "WillyWonka , 18-apr-07 22:50:12", true, 1176936612 },
- { "Mon, 18-Apr-1977 22:50:13 GMT", true, 230251813 },
- { "Mon, 18-Apr-77 22:50:13 GMT", true, 230251813 },
- // If the cookie came in with the expiration quoted (which in terms of
- // the RFC you shouldn't do), we will get string quoted. Bug 1261605.
- { "\"Sat, 15-Apr-17\\\"21:01:22\\\"GMT\"", true, 1492290082 },
- // Test with full month names and partial names.
- { "Partyday, 18- April-07 22:50:12", true, 1176936612 },
- { "Partyday, 18 - Apri-07 22:50:12", true, 1176936612 },
- { "Wednes, 1-Januar-2003 00:00:00 GMT", true, 1041379200 },
- // Test that we always take GMT even with other time zones or bogus
- // values. The RFC says everything should be GMT, and in the worst case
- // we are 24 hours off because of zone issues.
- { "Sat, 15-Apr-17 21:01:22", true, 1492290082 },
- { "Sat, 15-Apr-17 21:01:22 GMT-2", true, 1492290082 },
- { "Sat, 15-Apr-17 21:01:22 GMT BLAH", true, 1492290082 },
- { "Sat, 15-Apr-17 21:01:22 GMT-0400", true, 1492290082 },
- { "Sat, 15-Apr-17 21:01:22 GMT-0400 (EDT)",true, 1492290082 },
- { "Sat, 15-Apr-17 21:01:22 DST", true, 1492290082 },
- { "Sat, 15-Apr-17 21:01:22 -0400", true, 1492290082 },
- { "Sat, 15-Apr-17 21:01:22 (hello there)", true, 1492290082 },
- // Test that if we encounter multiple : fields, that we take the first
- // that correctly parses.
- { "Sat, 15-Apr-17 21:01:22 11:22:33", true, 1492290082 },
- { "Sat, 15-Apr-17 ::00 21:01:22", true, 1492290082 },
- { "Sat, 15-Apr-17 boink:z 21:01:22", true, 1492290082 },
- // We take the first, which in this case is invalid.
- { "Sat, 15-Apr-17 91:22:33 21:01:22", false, 0 },
- // amazon.com formats their cookie expiration like this.
- { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 },
- // Test that hh:mm:ss can occur anywhere.
- { "22:50:12 Thu Apr 18 2007 GMT", true, 1176936612 },
- { "Thu 22:50:12 Apr 18 2007 GMT", true, 1176936612 },
- { "Thu Apr 22:50:12 18 2007 GMT", true, 1176936612 },
- { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 },
- { "Thu Apr 18 2007 22:50:12 GMT", true, 1176936612 },
- { "Thu Apr 18 2007 GMT 22:50:12", true, 1176936612 },
- // Test that the day and year can be anywhere if they are unambigious.
- { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 },
- { "15-Sat, Apr-17 21:01:22 GMT", true, 1492290082 },
- { "15-Sat, Apr 21:01:22 GMT 17", true, 1492290082 },
- { "15-Sat, Apr 21:01:22 GMT 2017", true, 1492290082 },
- { "15 Apr 21:01:22 2017", true, 1492290082 },
- { "15 17 Apr 21:01:22", true, 1492290082 },
- { "Apr 15 17 21:01:22", true, 1492290082 },
- { "Apr 15 21:01:22 17", true, 1492290082 },
- { "2017 April 15 21:01:22", true, 1492290082 },
- { "15 April 2017 21:01:22", true, 1492290082 },
- // Some invalid dates
- { "98 April 17 21:01:22", false, 0 },
- { "Thu, 012-Aug-2008 20:49:07 GMT", false, 0 },
- { "Thu, 12-Aug-31841 20:49:07 GMT", false, 0 },
- { "Thu, 12-Aug-9999999999 20:49:07 GMT", false, 0 },
- { "Thu, 999999999999-Aug-2007 20:49:07 GMT", false, 0 },
- { "Thu, 12-Aug-2007 20:61:99999999999 GMT", false, 0 },
- { "IAintNoDateFool", false, 0 },
- };
-
- Time parsed_time;
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
- parsed_time = CookieMonster::ParseCookieTime(tests[i].str);
- if (!tests[i].valid) {
- EXPECT_FALSE(!parsed_time.is_null()) << tests[i].str;
- continue;
- }
- EXPECT_TRUE(!parsed_time.is_null()) << tests[i].str;
- EXPECT_EQ(tests[i].epoch, parsed_time.ToTimeT()) << tests[i].str;
- }
-}
-
TEST_F(CookieMonsterTest, TestCookieDeleteAll) {
scoped_refptr<MockPersistentCookieStore> store(
new MockPersistentCookieStore);
@@ -1292,7 +1202,7 @@ TEST_F(CookieMonsterTest, DontImportDuplicateCookies) {
// be careful not to have any duplicate creation times at all (as it's a
// violation of a CookieMonster invariant) even if Time::Now() doesn't
// move between calls.
- std::vector<CookieMonster::CanonicalCookie*> initial_cookies;
+ std::vector<CanonicalCookie*> initial_cookies;
// Insert 4 cookies with name "X" on path "/", with varying creation
// dates. We expect only the most recent one to be preserved following
@@ -1377,7 +1287,7 @@ TEST_F(CookieMonsterTest, DontImportDuplicateCreationTimes) {
// four with the earlier time as creation times. We should only get
// two cookies remaining, but which two (other than that there should
// be one from each set) will be random.
- std::vector<CookieMonster::CanonicalCookie*> initial_cookies;
+ std::vector<CanonicalCookie*> initial_cookies;
AddCookieToList("www.google.com", "X=1; path=/", now, &initial_cookies);
AddCookieToList("www.google.com", "X=2; path=/", now, &initial_cookies);
AddCookieToList("www.google.com", "X=3; path=/", now, &initial_cookies);
@@ -1658,7 +1568,7 @@ TEST_F(CookieMonsterTest, UniqueCreationTime) {
// Now we check
CookieList cookie_list(GetAllCookies(cm));
- typedef std::map<int64, CookieMonster::CanonicalCookie> TimeCookieMap;
+ typedef std::map<int64, CanonicalCookie> TimeCookieMap;
TimeCookieMap check_map;
for (CookieList::const_iterator it = cookie_list.begin();
it != cookie_list.end(); it++) {
@@ -1758,7 +1668,7 @@ TEST_F(CookieMonsterTest, BackingStoreCommunication) {
for (int output_index = 0; output_index < 2; output_index++) {
int input_index = output_index * 2;
const CookiesInputInfo* input = &input_info[input_index];
- const CookieMonster::CanonicalCookie* output = &cookies[output_index];
+ const CanonicalCookie* output = &cookies[output_index];
EXPECT_EQ(input->name, output->Name());
EXPECT_EQ(input->value, output->Value());
@@ -1933,7 +1843,7 @@ class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
FlushablePersistentStore() : flush_count_(0) {}
void Load(const LoadedCallback& loaded_callback) {
- std::vector<CookieMonster::CanonicalCookie*> out_cookies;
+ std::vector<CanonicalCookie*> out_cookies;
MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&net::LoadedCallbackTask::Run,
new net::LoadedCallbackTask(loaded_callback, out_cookies)));
@@ -1944,9 +1854,9 @@ class FlushablePersistentStore : public CookieMonster::PersistentCookieStore {
Load(loaded_callback);
}
- void AddCookie(const CookieMonster::CanonicalCookie&) {}
- void UpdateCookieAccessTime(const CookieMonster::CanonicalCookie&) {}
- void DeleteCookie(const CookieMonster::CanonicalCookie&) {}
+ void AddCookie(const CanonicalCookie&) {}
+ void UpdateCookieAccessTime(const CanonicalCookie&) {}
+ void DeleteCookie(const CanonicalCookie&) {}
void SetForceKeepSessionState() {}
void Flush(const base::Closure& callback) {
@@ -2039,36 +1949,6 @@ TEST_F(CookieMonsterTest, FlushStore) {
ASSERT_EQ(3, counter->callback_count());
}
-TEST_F(CookieMonsterTest, GetCookieSourceFromURL) {
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("http://example.com")));
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("http://example.com/")));
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("http://example.com/test")));
- EXPECT_EQ("file:///tmp/test.html",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("file:///tmp/test.html")));
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("http://example.com:1234/")));
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("https://example.com/")));
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("http://user:pwd@example.com/")));
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("http://example.com/test?foo")));
- EXPECT_EQ("http://example.com/",
- CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
- GURL("http://example.com/test#foo")));
-}
-
TEST_F(CookieMonsterTest, HistogramCheck) {
scoped_refptr<CookieMonster> cm(new CookieMonster(NULL, NULL));
// Should match call in InitializeHistograms, but doesn't really matter
@@ -2170,7 +2050,7 @@ class MultiThreadedCookieMonsterTest : public CookieMonsterTest {
}
void DeleteCanonicalCookieTask(CookieMonster* cm,
- const CookieMonster::CanonicalCookie& cookie,
+ const CanonicalCookie& cookie,
SetCookieCallback* callback) {
cm->DeleteCanonicalCookieAsync(
cookie,
@@ -2336,8 +2216,7 @@ TEST_F(MultiThreadedCookieMonsterTest, ThreadCheckDeleteCanonicalCookie) {
TEST_F(CookieMonsterTest, InvalidExpiryTime) {
ParsedCookie pc(std::string(kValidCookieLine) + "; expires=Blarg arg arg");
- scoped_ptr<CookieMonster::CanonicalCookie> cookie(
- CookieMonster::CanonicalCookie::Create(url_google_, pc));
+ scoped_ptr<CanonicalCookie> cookie(CanonicalCookie::Create(url_google_, pc));
#if defined(ENABLE_PERSISTENT_SESSION_COOKIES)
ASSERT_TRUE(cookie->IsPersistent());
diff --git a/net/cookies/cookie_util.cc b/net/cookies/cookie_util.cc
index 6e1833f..bd1019d 100644
--- a/net/cookies/cookie_util.cc
+++ b/net/cookies/cookie_util.cc
@@ -4,7 +4,13 @@
#include "net/cookies/cookie_util.h"
+#include <cstdio>
+#include <cstdlib>
+
#include "base/logging.h"
+#include "base/string_tokenizer.h"
+#include "base/string_util.h"
+#include "build/build_config.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"
#include "net/base/registry_controlled_domain.h"
@@ -74,6 +80,124 @@ bool GetCookieDomainWithString(const GURL& url,
return true;
}
+// Parse a cookie expiration time. We try to be lenient, but we need to
+// assume some order to distinguish the fields. The basic rules:
+// - The month name must be present and prefix the first 3 letters of the
+// full month name (jan for January, jun for June).
+// - If the year is <= 2 digits, it must occur after the day of month.
+// - The time must be of the format hh:mm:ss.
+// An average cookie expiration will look something like this:
+// Sat, 15-Apr-17 21:01:22 GMT
+base::Time ParseCookieTime(const std::string& time_string) {
+ static const char* kMonths[] = { "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec" };
+ static const int kMonthsLen = arraysize(kMonths);
+ // We want to be pretty liberal, and support most non-ascii and non-digit
+ // characters as a delimiter. We can't treat : as a delimiter, because it
+ // is the delimiter for hh:mm:ss, and we want to keep this field together.
+ // We make sure to include - and +, since they could prefix numbers.
+ // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes
+ // will be preserved, and we will get them here. So we make sure to include
+ // quote characters, and also \ for anything that was internally escaped.
+ static const char* kDelimiters = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~";
+
+ base::Time::Exploded exploded = {0};
+
+ StringTokenizer tokenizer(time_string, kDelimiters);
+
+ bool found_day_of_month = false;
+ bool found_month = false;
+ bool found_time = false;
+ bool found_year = false;
+
+ while (tokenizer.GetNext()) {
+ const std::string token = tokenizer.token();
+ DCHECK(!token.empty());
+ bool numerical = IsAsciiDigit(token[0]);
+
+ // String field
+ if (!numerical) {
+ if (!found_month) {
+ for (int i = 0; i < kMonthsLen; ++i) {
+ // Match prefix, so we could match January, etc
+ if (base::strncasecmp(token.c_str(), kMonths[i], 3) == 0) {
+ exploded.month = i + 1;
+ found_month = true;
+ break;
+ }
+ }
+ } else {
+ // If we've gotten here, it means we've already found and parsed our
+ // month, and we have another string, which we would expect to be the
+ // the time zone name. According to the RFC and my experiments with
+ // how sites format their expirations, we don't have much of a reason
+ // to support timezones. We don't want to ever barf on user input,
+ // but this DCHECK should pass for well-formed data.
+ // DCHECK(token == "GMT");
+ }
+ // Numeric field w/ a colon
+ } else if (token.find(':') != std::string::npos) {
+ if (!found_time &&
+#ifdef COMPILER_MSVC
+ sscanf_s(
+#else
+ sscanf(
+#endif
+ token.c_str(), "%2u:%2u:%2u", &exploded.hour,
+ &exploded.minute, &exploded.second) == 3) {
+ found_time = true;
+ } else {
+ // We should only ever encounter one time-like thing. If we're here,
+ // it means we've found a second, which shouldn't happen. We keep
+ // the first. This check should be ok for well-formed input:
+ // NOTREACHED();
+ }
+ // Numeric field
+ } else {
+ // Overflow with atoi() is unspecified, so we enforce a max length.
+ if (!found_day_of_month && token.length() <= 2) {
+ exploded.day_of_month = atoi(token.c_str());
+ found_day_of_month = true;
+ } else if (!found_year && token.length() <= 5) {
+ exploded.year = atoi(token.c_str());
+ found_year = true;
+ } else {
+ // If we're here, it means we've either found an extra numeric field,
+ // or a numeric field which was too long. For well-formed input, the
+ // following check would be reasonable:
+ // NOTREACHED();
+ }
+ }
+ }
+
+ if (!found_day_of_month || !found_month || !found_time || !found_year) {
+ // We didn't find all of the fields we need. For well-formed input, the
+ // following check would be reasonable:
+ // NOTREACHED() << "Cookie parse expiration failed: " << time_string;
+ return base::Time();
+ }
+
+ // Normalize the year to expand abbreviated years to the full year.
+ if (exploded.year >= 69 && exploded.year <= 99)
+ exploded.year += 1900;
+ if (exploded.year >= 0 && exploded.year <= 68)
+ exploded.year += 2000;
+
+ // If our values are within their correct ranges, we got our time.
+ if (exploded.day_of_month >= 1 && exploded.day_of_month <= 31 &&
+ exploded.month >= 1 && exploded.month <= 12 &&
+ exploded.year >= 1601 && exploded.year <= 30827 &&
+ exploded.hour <= 23 && exploded.minute <= 59 && exploded.second <= 59) {
+ return base::Time::FromUTCExploded(exploded);
+ }
+
+ // One of our values was out of expected range. For well-formed input,
+ // the following check would be reasonable:
+ // NOTREACHED() << "Cookie exploded expiration failed: " << time_string;
+
+ return base::Time();
+}
+
} // namespace cookie_utils
} // namespace net
diff --git a/net/cookies/cookie_util.h b/net/cookies/cookie_util.h
index 39cf786..1475cd5 100644
--- a/net/cookies/cookie_util.h
+++ b/net/cookies/cookie_util.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/time.h"
#include "net/base/net_export.h"
class GURL;
@@ -33,6 +34,9 @@ NET_EXPORT bool GetCookieDomainWithString(const GURL& url,
// i.e. it doesn't begin with a leading '.' character.
NET_EXPORT bool DomainIsHostOnly(const std::string& domain_string);
+// Parses the string with the cookie time (very forgivingly).
+NET_EXPORT base::Time ParseCookieTime(const std::string& time_string);
+
} // namspace cookie_util
} // namespace net
diff --git a/net/cookies/cookie_util_unittest.cc b/net/cookies/cookie_util_unittest.cc
index 5d2a420..f297afd 100644
--- a/net/cookies/cookie_util_unittest.cc
+++ b/net/cookies/cookie_util_unittest.cc
@@ -21,3 +21,91 @@ TEST(CookieUtilTest, TestDomainIsHostOnly) {
net::cookie_util::DomainIsHostOnly(tests[i].str));
}
}
+
+TEST(CookieUtilTest, TestCookieDateParsing) {
+ const struct {
+ const char* str;
+ const bool valid;
+ const time_t epoch;
+ } tests[] = {
+ { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 },
+ { "Thu, 19-Apr-2007 16:00:00 GMT", true, 1176998400 },
+ { "Wed, 25 Apr 2007 21:02:13 GMT", true, 1177534933 },
+ { "Thu, 19/Apr\\2007 16:00:00 GMT", true, 1176998400 },
+ { "Fri, 1 Jan 2010 01:01:50 GMT", true, 1262307710 },
+ { "Wednesday, 1-Jan-2003 00:00:00 GMT", true, 1041379200 },
+ { ", 1-Jan-2003 00:00:00 GMT", true, 1041379200 },
+ { " 1-Jan-2003 00:00:00 GMT", true, 1041379200 },
+ { "1-Jan-2003 00:00:00 GMT", true, 1041379200 },
+ { "Wed,18-Apr-07 22:50:12 GMT", true, 1176936612 },
+ { "WillyWonka , 18-Apr-07 22:50:12 GMT", true, 1176936612 },
+ { "WillyWonka , 18-Apr-07 22:50:12", true, 1176936612 },
+ { "WillyWonka , 18-apr-07 22:50:12", true, 1176936612 },
+ { "Mon, 18-Apr-1977 22:50:13 GMT", true, 230251813 },
+ { "Mon, 18-Apr-77 22:50:13 GMT", true, 230251813 },
+ // If the cookie came in with the expiration quoted (which in terms of
+ // the RFC you shouldn't do), we will get string quoted. Bug 1261605.
+ { "\"Sat, 15-Apr-17\\\"21:01:22\\\"GMT\"", true, 1492290082 },
+ // Test with full month names and partial names.
+ { "Partyday, 18- April-07 22:50:12", true, 1176936612 },
+ { "Partyday, 18 - Apri-07 22:50:12", true, 1176936612 },
+ { "Wednes, 1-Januar-2003 00:00:00 GMT", true, 1041379200 },
+ // Test that we always take GMT even with other time zones or bogus
+ // values. The RFC says everything should be GMT, and in the worst case
+ // we are 24 hours off because of zone issues.
+ { "Sat, 15-Apr-17 21:01:22", true, 1492290082 },
+ { "Sat, 15-Apr-17 21:01:22 GMT-2", true, 1492290082 },
+ { "Sat, 15-Apr-17 21:01:22 GMT BLAH", true, 1492290082 },
+ { "Sat, 15-Apr-17 21:01:22 GMT-0400", true, 1492290082 },
+ { "Sat, 15-Apr-17 21:01:22 GMT-0400 (EDT)",true, 1492290082 },
+ { "Sat, 15-Apr-17 21:01:22 DST", true, 1492290082 },
+ { "Sat, 15-Apr-17 21:01:22 -0400", true, 1492290082 },
+ { "Sat, 15-Apr-17 21:01:22 (hello there)", true, 1492290082 },
+ // Test that if we encounter multiple : fields, that we take the first
+ // that correctly parses.
+ { "Sat, 15-Apr-17 21:01:22 11:22:33", true, 1492290082 },
+ { "Sat, 15-Apr-17 ::00 21:01:22", true, 1492290082 },
+ { "Sat, 15-Apr-17 boink:z 21:01:22", true, 1492290082 },
+ // We take the first, which in this case is invalid.
+ { "Sat, 15-Apr-17 91:22:33 21:01:22", false, 0 },
+ // amazon.com formats their cookie expiration like this.
+ { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 },
+ // Test that hh:mm:ss can occur anywhere.
+ { "22:50:12 Thu Apr 18 2007 GMT", true, 1176936612 },
+ { "Thu 22:50:12 Apr 18 2007 GMT", true, 1176936612 },
+ { "Thu Apr 22:50:12 18 2007 GMT", true, 1176936612 },
+ { "Thu Apr 18 22:50:12 2007 GMT", true, 1176936612 },
+ { "Thu Apr 18 2007 22:50:12 GMT", true, 1176936612 },
+ { "Thu Apr 18 2007 GMT 22:50:12", true, 1176936612 },
+ // Test that the day and year can be anywhere if they are unambigious.
+ { "Sat, 15-Apr-17 21:01:22 GMT", true, 1492290082 },
+ { "15-Sat, Apr-17 21:01:22 GMT", true, 1492290082 },
+ { "15-Sat, Apr 21:01:22 GMT 17", true, 1492290082 },
+ { "15-Sat, Apr 21:01:22 GMT 2017", true, 1492290082 },
+ { "15 Apr 21:01:22 2017", true, 1492290082 },
+ { "15 17 Apr 21:01:22", true, 1492290082 },
+ { "Apr 15 17 21:01:22", true, 1492290082 },
+ { "Apr 15 21:01:22 17", true, 1492290082 },
+ { "2017 April 15 21:01:22", true, 1492290082 },
+ { "15 April 2017 21:01:22", true, 1492290082 },
+ // Some invalid dates
+ { "98 April 17 21:01:22", false, 0 },
+ { "Thu, 012-Aug-2008 20:49:07 GMT", false, 0 },
+ { "Thu, 12-Aug-31841 20:49:07 GMT", false, 0 },
+ { "Thu, 12-Aug-9999999999 20:49:07 GMT", false, 0 },
+ { "Thu, 999999999999-Aug-2007 20:49:07 GMT", false, 0 },
+ { "Thu, 12-Aug-2007 20:61:99999999999 GMT", false, 0 },
+ { "IAintNoDateFool", false, 0 },
+ };
+
+ base::Time parsed_time;
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
+ parsed_time = net::cookie_util::ParseCookieTime(tests[i].str);
+ if (!tests[i].valid) {
+ EXPECT_FALSE(!parsed_time.is_null()) << tests[i].str;
+ continue;
+ }
+ EXPECT_TRUE(!parsed_time.is_null()) << tests[i].str;
+ EXPECT_EQ(tests[i].epoch, parsed_time.ToTimeT()) << tests[i].str;
+ }
+}