diff options
author | battre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-18 13:13:34 +0000 |
---|---|---|
committer | battre@chromium.org <battre@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-18 13:13:34 +0000 |
commit | 5b9bc3505d5cd23898d0bdb350f33956070cc3a6 (patch) | |
tree | 2e28070459f0324ce2dd9288e803f8aa095781fd /net/cookies/cookie_monster.cc | |
parent | 64c186bdf8949a84c1b1e53da12710f50e51336b (diff) | |
download | chromium_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/cookie_monster.cc')
-rw-r--r-- | net/cookies/cookie_monster.cc | 453 |
1 files changed, 11 insertions, 442 deletions
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 |