Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Portions of this code based on Mozilla:
      6 //   (netwerk/cookie/src/nsCookieService.cpp)
      7 /* ***** BEGIN LICENSE BLOCK *****
      8  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
      9  *
     10  * The contents of this file are subject to the Mozilla Public License Version
     11  * 1.1 (the "License"); you may not use this file except in compliance with
     12  * the License. You may obtain a copy of the License at
     13  * http://www.mozilla.org/MPL/
     14  *
     15  * Software distributed under the License is distributed on an "AS IS" basis,
     16  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     17  * for the specific language governing rights and limitations under the
     18  * License.
     19  *
     20  * The Original Code is mozilla.org code.
     21  *
     22  * The Initial Developer of the Original Code is
     23  * Netscape Communications Corporation.
     24  * Portions created by the Initial Developer are Copyright (C) 2003
     25  * the Initial Developer. All Rights Reserved.
     26  *
     27  * Contributor(s):
     28  *   Daniel Witte (dwitte (at) stanford.edu)
     29  *   Michiel van Leeuwen (mvl (at) exedo.nl)
     30  *
     31  * Alternatively, the contents of this file may be used under the terms of
     32  * either the GNU General Public License Version 2 or later (the "GPL"), or
     33  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
     34  * in which case the provisions of the GPL or the LGPL are applicable instead
     35  * of those above. If you wish to allow use of your version of this file only
     36  * under the terms of either the GPL or the LGPL, and not to allow others to
     37  * use your version of this file under the terms of the MPL, indicate your
     38  * decision by deleting the provisions above and replace them with the notice
     39  * and other provisions required by the GPL or the LGPL. If you do not delete
     40  * the provisions above, a recipient may use your version of this file under
     41  * the terms of any one of the MPL, the GPL or the LGPL.
     42  *
     43  * ***** END LICENSE BLOCK ***** */
     44 
     45 #include "net/base/cookie_monster.h"
     46 
     47 #include <algorithm>
     48 
     49 #include "base/basictypes.h"
     50 #include "base/format_macros.h"
     51 #include "base/logging.h"
     52 #include "base/memory/scoped_ptr.h"
     53 #include "base/message_loop.h"
     54 #include "base/metrics/histogram.h"
     55 #include "base/string_tokenizer.h"
     56 #include "base/string_util.h"
     57 #include "base/stringprintf.h"
     58 #include "googleurl/src/gurl.h"
     59 #include "googleurl/src/url_canon.h"
     60 #include "net/base/net_util.h"
     61 #include "net/base/registry_controlled_domain.h"
     62 
     63 using base::Time;
     64 using base::TimeDelta;
     65 using base::TimeTicks;
     66 
     67 static const int kMinutesInTenYears = 10 * 365 * 24 * 60;
     68 
     69 namespace net {
     70 
     71 // See comments at declaration of these variables in cookie_monster.h
     72 // for details.
     73 const size_t CookieMonster::kDomainMaxCookies           = 180;
     74 const size_t CookieMonster::kDomainPurgeCookies         = 30;
     75 const size_t CookieMonster::kMaxCookies                 = 3300;
     76 const size_t CookieMonster::kPurgeCookies               = 300;
     77 const int CookieMonster::kSafeFromGlobalPurgeDays       = 30;
     78 
     79 namespace {
     80 
     81 // Default minimum delay after updating a cookie's LastAccessDate before we
     82 // will update it again.
     83 const int kDefaultAccessUpdateThresholdSeconds = 60;
     84 
     85 // Comparator to sort cookies from highest creation date to lowest
     86 // creation date.
     87 struct OrderByCreationTimeDesc {
     88   bool operator()(const CookieMonster::CookieMap::iterator& a,
     89                   const CookieMonster::CookieMap::iterator& b) const {
     90     return a->second->CreationDate() > b->second->CreationDate();
     91   }
     92 };
     93 
     94 // Constants for use in VLOG
     95 const int kVlogPerCookieMonster = 1;
     96 const int kVlogPeriodic = 3;
     97 const int kVlogGarbageCollection = 5;
     98 const int kVlogSetCookies = 7;
     99 const int kVlogGetCookies = 9;
    100 
    101 // Mozilla sorts on the path length (longest first), and then it
    102 // sorts by creation time (oldest first).
    103 // The RFC says the sort order for the domain attribute is undefined.
    104 bool CookieSorter(CookieMonster::CanonicalCookie* cc1,
    105                   CookieMonster::CanonicalCookie* cc2) {
    106   if (cc1->Path().length() == cc2->Path().length())
    107     return cc1->CreationDate() < cc2->CreationDate();
    108   return cc1->Path().length() > cc2->Path().length();
    109 }
    110 
    111 bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1,
    112                      const CookieMonster::CookieMap::iterator& it2) {
    113   // Cookies accessed less recently should be deleted first.
    114   if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
    115     return it1->second->LastAccessDate() < it2->second->LastAccessDate();
    116 
    117   // In rare cases we might have two cookies with identical last access times.
    118   // To preserve the stability of the sort, in these cases prefer to delete
    119   // older cookies over newer ones.  CreationDate() is guaranteed to be unique.
    120   return it1->second->CreationDate() < it2->second->CreationDate();
    121 }
    122 
    123 // Our strategy to find duplicates is:
    124 // (1) Build a map from (cookiename, cookiepath) to
    125 //     {list of cookies with this signature, sorted by creation time}.
    126 // (2) For each list with more than 1 entry, keep the cookie having the
    127 //     most recent creation time, and delete the others.
    128 //
    129 // Two cookies are considered equivalent if they have the same domain,
    130 // name, and path.
    131 struct CookieSignature {
    132  public:
    133   CookieSignature(const std::string& name, const std::string& domain,
    134                   const std::string& path)
    135       : name(name),
    136         domain(domain),
    137         path(path) {}
    138 
    139   // To be a key for a map this class needs to be assignable, copyable,
    140   // and have an operator<.  The default assignment operator
    141   // and copy constructor are exactly what we want.
    142 
    143   bool operator<(const CookieSignature& cs) const {
    144     // Name compare dominates, then domain, then path.
    145     int diff = name.compare(cs.name);
    146     if (diff != 0)
    147       return diff < 0;
    148 
    149     diff = domain.compare(cs.domain);
    150     if (diff != 0)
    151       return diff < 0;
    152 
    153     return path.compare(cs.path) < 0;
    154   }
    155 
    156   std::string name;
    157   std::string domain;
    158   std::string path;
    159 };
    160 
    161 // Returns the effective TLD+1 for a given host. This only makes sense for http
    162 // and https schemes. For other schemes, the host will be returned unchanged
    163 // (minus any leading period).
    164 std::string GetEffectiveDomain(const std::string& scheme,
    165                                const std::string& host) {
    166   if (scheme == "http" || scheme == "https")
    167     return RegistryControlledDomainService::GetDomainAndRegistry(host);
    168 
    169   if (!CookieMonster::DomainIsHostOnly(host))
    170     return host.substr(1);
    171   return host;
    172 }
    173 
    174 // Determine the actual cookie domain based on the domain string passed
    175 // (if any) and the URL from which the cookie came.
    176 // On success returns true, and sets cookie_domain to either a
    177 //   -host cookie domain (ex: "google.com")
    178 //   -domain cookie domain (ex: ".google.com")
    179 bool GetCookieDomainWithString(const GURL& url,
    180                                const std::string& domain_string,
    181                                std::string* result) {
    182   const std::string url_host(url.host());
    183 
    184   // If no domain was specified in the domain string, default to a host cookie.
    185   // We match IE/Firefox in allowing a domain=IPADDR if it matches the url
    186   // ip address hostname exactly.  It should be treated as a host cookie.
    187   if (domain_string.empty() ||
    188       (url.HostIsIPAddress() && url_host == domain_string)) {
    189     *result = url_host;
    190     DCHECK(CookieMonster::DomainIsHostOnly(*result));
    191     return true;
    192   }
    193 
    194   // Get the normalized domain specified in cookie line.
    195   // Note: The RFC says we can reject a cookie if the domain
    196   // attribute does not start with a dot. IE/FF/Safari however, allow a cookie
    197   // of the form domain=my.domain.com, treating it the same as
    198   // domain=.my.domain.com -- for compatibility we do the same here.  Firefox
    199   // also treats domain=.....my.domain.com like domain=.my.domain.com, but
    200   // neither IE nor Safari do this, and we don't either.
    201   url_canon::CanonHostInfo ignored;
    202   std::string cookie_domain(CanonicalizeHost(domain_string, &ignored));
    203   if (cookie_domain.empty())
    204     return false;
    205   if (cookie_domain[0] != '.')
    206     cookie_domain = "." + cookie_domain;
    207 
    208   // Ensure |url| and |cookie_domain| have the same domain+registry.
    209   const std::string url_scheme(url.scheme());
    210   const std::string url_domain_and_registry(
    211       GetEffectiveDomain(url_scheme, url_host));
    212   if (url_domain_and_registry.empty())
    213     return false;  // IP addresses/intranet hosts can't set domain cookies.
    214   const std::string cookie_domain_and_registry(
    215       GetEffectiveDomain(url_scheme, cookie_domain));
    216   if (url_domain_and_registry != cookie_domain_and_registry)
    217     return false;  // Can't set a cookie on a different domain + registry.
    218 
    219   // Ensure |url_host| is |cookie_domain| or one of its subdomains.  Given that
    220   // we know the domain+registry are the same from the above checks, this is
    221   // basically a simple string suffix check.
    222   if ((url_host.length() < cookie_domain.length()) ?
    223       (cookie_domain != ("." + url_host)) :
    224       url_host.compare(url_host.length() - cookie_domain.length(),
    225                        cookie_domain.length(), cookie_domain))
    226     return false;
    227 
    228   *result = cookie_domain;
    229   return true;
    230 }
    231 
    232 // Determine the cookie domain to use for setting the specified cookie.
    233 bool GetCookieDomain(const GURL& url,
    234                      const CookieMonster::ParsedCookie& pc,
    235                      std::string* result) {
    236   std::string domain_string;
    237   if (pc.HasDomain())
    238     domain_string = pc.Domain();
    239   return GetCookieDomainWithString(url, domain_string, result);
    240 }
    241 
    242 std::string CanonPathWithString(const GURL& url,
    243                                 const std::string& path_string) {
    244   // The RFC says the path should be a prefix of the current URL path.
    245   // However, Mozilla allows you to set any path for compatibility with
    246   // broken websites.  We unfortunately will mimic this behavior.  We try
    247   // to be generous and accept cookies with an invalid path attribute, and
    248   // default the path to something reasonable.
    249 
    250   // The path was supplied in the cookie, we'll take it.
    251   if (!path_string.empty() && path_string[0] == '/')
    252     return path_string;
    253 
    254   // The path was not supplied in the cookie or invalid, we will default
    255   // to the current URL path.
    256   // """Defaults to the path of the request URL that generated the
    257   //    Set-Cookie response, up to, but not including, the
    258   //    right-most /."""
    259   // How would this work for a cookie on /?  We will include it then.
    260   const std::string& url_path = url.path();
    261 
    262   size_t idx = url_path.find_last_of('/');
    263 
    264   // The cookie path was invalid or a single '/'.
    265   if (idx == 0 || idx == std::string::npos)
    266     return std::string("/");
    267 
    268   // Return up to the rightmost '/'.
    269   return url_path.substr(0, idx);
    270 }
    271 
    272 std::string CanonPath(const GURL& url,
    273                       const CookieMonster::ParsedCookie& pc) {
    274   std::string path_string;
    275   if (pc.HasPath())
    276     path_string = pc.Path();
    277   return CanonPathWithString(url, path_string);
    278 }
    279 
    280 Time CanonExpirationInternal(const CookieMonster::ParsedCookie& pc,
    281                              const Time& current) {
    282   // First, try the Max-Age attribute.
    283   uint64 max_age = 0;
    284   if (pc.HasMaxAge() &&
    285 #ifdef COMPILER_MSVC
    286       sscanf_s(
    287 #else
    288       sscanf(
    289 #endif
    290              pc.MaxAge().c_str(), " %" PRIu64, &max_age) == 1) {
    291     return current + TimeDelta::FromSeconds(max_age);
    292   }
    293 
    294   // Try the Expires attribute.
    295   if (pc.HasExpires())
    296     return CookieMonster::ParseCookieTime(pc.Expires());
    297 
    298   // Invalid or no expiration, persistent cookie.
    299   return Time();
    300 }
    301 
    302 Time CanonExpiration(const CookieMonster::ParsedCookie& pc,
    303                      const Time& current,
    304                      const CookieOptions& options) {
    305   Time expiration_time = CanonExpirationInternal(pc, current);
    306 
    307   if (options.force_session()) {
    308     // Only override the expiry  adte if it's in the future. If the expiry date
    309     // is before the creation date, the cookie is supposed to be deleted.
    310     if (expiration_time.is_null() || expiration_time > current)
    311       return Time();
    312   }
    313 
    314   return expiration_time;
    315 }
    316 
    317 // Helper for GarbageCollection.  If |cookie_its->size() > num_max|, remove the
    318 // |num_max - num_purge| most recently accessed cookies from cookie_its.
    319 // (In other words, leave the entries that are candidates for
    320 // eviction in cookie_its.)  The cookies returned will be in order sorted by
    321 // access time, least recently accessed first.  The access time of the least
    322 // recently accessed entry not returned will be placed in
    323 // |*lra_removed| if that pointer is set.  FindLeastRecentlyAccessed
    324 // returns false if no manipulation is done (because the list size is less
    325 // than num_max), true otherwise.
    326 bool FindLeastRecentlyAccessed(
    327     size_t num_max,
    328     size_t num_purge,
    329     Time* lra_removed,
    330     std::vector<CookieMonster::CookieMap::iterator>* cookie_its) {
    331   DCHECK_LE(num_purge, num_max);
    332   if (cookie_its->size() > num_max) {
    333     VLOG(kVlogGarbageCollection)
    334         << "FindLeastRecentlyAccessed() Deep Garbage Collect.";
    335     num_purge += cookie_its->size() - num_max;
    336     DCHECK_GT(cookie_its->size(), num_purge);
    337 
    338     // Add 1 so that we can get the last time left in the store.
    339     std::partial_sort(cookie_its->begin(), cookie_its->begin() + num_purge + 1,
    340                       cookie_its->end(), LRUCookieSorter);
    341     *lra_removed =
    342         (*(cookie_its->begin() + num_purge))->second->LastAccessDate();
    343     cookie_its->erase(cookie_its->begin() + num_purge, cookie_its->end());
    344     return true;
    345   }
    346   return false;
    347 }
    348 
    349 // Mapping between DeletionCause and Delegate::ChangeCause; the mapping also
    350 // provides a boolean that specifies whether or not an OnCookieChanged
    351 // notification ought to be generated.
    352 typedef struct ChangeCausePair_struct {
    353   CookieMonster::Delegate::ChangeCause cause;
    354   bool notify;
    355 } ChangeCausePair;
    356 ChangeCausePair ChangeCauseMapping[] = {
    357   // DELETE_COOKIE_EXPLICIT
    358   { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, true },
    359   // DELETE_COOKIE_OVERWRITE
    360   { CookieMonster::Delegate::CHANGE_COOKIE_OVERWRITE, true },
    361   // DELETE_COOKIE_EXPIRED
    362   { CookieMonster::Delegate::CHANGE_COOKIE_EXPIRED, true },
    363   // DELETE_COOKIE_EVICTED
    364   { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true },
    365   // DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE
    366   { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false },
    367   // DELETE_COOKIE_DONT_RECORD
    368   { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false },
    369   // DELETE_COOKIE_EVICTED_DOMAIN
    370   { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true },
    371   // DELETE_COOKIE_EVICTED_GLOBAL
    372   { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true },
    373   // DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE
    374   { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true },
    375   // DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE
    376   { CookieMonster::Delegate::CHANGE_COOKIE_EVICTED, true },
    377   // DELETE_COOKIE_EXPIRED_OVERWRITE
    378   { CookieMonster::Delegate::CHANGE_COOKIE_EXPIRED_OVERWRITE, true },
    379   // DELETE_COOKIE_LAST_ENTRY
    380   { CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT, false }
    381 };
    382 
    383 }  // namespace
    384 
    385 // static
    386 bool CookieMonster::enable_file_scheme_ = false;
    387 
    388 CookieMonster::CookieMonster(PersistentCookieStore* store, Delegate* delegate)
    389     : initialized_(false),
    390       expiry_and_key_scheme_(expiry_and_key_default_),
    391       store_(store),
    392       last_access_threshold_(
    393           TimeDelta::FromSeconds(kDefaultAccessUpdateThresholdSeconds)),
    394       delegate_(delegate),
    395       last_statistic_record_time_(Time::Now()),
    396       keep_expired_cookies_(false) {
    397   InitializeHistograms();
    398   SetDefaultCookieableSchemes();
    399 }
    400 
    401 CookieMonster::CookieMonster(PersistentCookieStore* store,
    402                              Delegate* delegate,
    403                              int last_access_threshold_milliseconds)
    404     : initialized_(false),
    405       expiry_and_key_scheme_(expiry_and_key_default_),
    406       store_(store),
    407       last_access_threshold_(base::TimeDelta::FromMilliseconds(
    408           last_access_threshold_milliseconds)),
    409       delegate_(delegate),
    410       last_statistic_record_time_(base::Time::Now()),
    411       keep_expired_cookies_(false) {
    412   InitializeHistograms();
    413   SetDefaultCookieableSchemes();
    414 }
    415 
    416 // Parse a cookie expiration time.  We try to be lenient, but we need to
    417 // assume some order to distinguish the fields.  The basic rules:
    418 //  - The month name must be present and prefix the first 3 letters of the
    419 //    full month name (jan for January, jun for June).
    420 //  - If the year is <= 2 digits, it must occur after the day of month.
    421 //  - The time must be of the format hh:mm:ss.
    422 // An average cookie expiration will look something like this:
    423 //   Sat, 15-Apr-17 21:01:22 GMT
    424 Time CookieMonster::ParseCookieTime(const std::string& time_string) {
    425   static const char* kMonths[] = { "jan", "feb", "mar", "apr", "may", "jun",
    426                                    "jul", "aug", "sep", "oct", "nov", "dec" };
    427   static const int kMonthsLen = arraysize(kMonths);
    428   // We want to be pretty liberal, and support most non-ascii and non-digit
    429   // characters as a delimiter.  We can't treat : as a delimiter, because it
    430   // is the delimiter for hh:mm:ss, and we want to keep this field together.
    431   // We make sure to include - and +, since they could prefix numbers.
    432   // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes
    433   // will be preserved, and we will get them here.  So we make sure to include
    434   // quote characters, and also \ for anything that was internally escaped.
    435   static const char* kDelimiters = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~";
    436 
    437   Time::Exploded exploded = {0};
    438 
    439   StringTokenizer tokenizer(time_string, kDelimiters);
    440 
    441   bool found_day_of_month = false;
    442   bool found_month = false;
    443   bool found_time = false;
    444   bool found_year = false;
    445 
    446   while (tokenizer.GetNext()) {
    447     const std::string token = tokenizer.token();
    448     DCHECK(!token.empty());
    449     bool numerical = IsAsciiDigit(token[0]);
    450 
    451     // String field
    452     if (!numerical) {
    453       if (!found_month) {
    454         for (int i = 0; i < kMonthsLen; ++i) {
    455           // Match prefix, so we could match January, etc
    456           if (base::strncasecmp(token.c_str(), kMonths[i], 3) == 0) {
    457             exploded.month = i + 1;
    458             found_month = true;
    459             break;
    460           }
    461         }
    462       } else {
    463         // If we've gotten here, it means we've already found and parsed our
    464         // month, and we have another string, which we would expect to be the
    465         // the time zone name.  According to the RFC and my experiments with
    466         // how sites format their expirations, we don't have much of a reason
    467         // to support timezones.  We don't want to ever barf on user input,
    468         // but this DCHECK should pass for well-formed data.
    469         // DCHECK(token == "GMT");
    470       }
    471     // Numeric field w/ a colon
    472     } else if (token.find(':') != std::string::npos) {
    473       if (!found_time &&
    474 #ifdef COMPILER_MSVC
    475           sscanf_s(
    476 #else
    477           sscanf(
    478 #endif
    479                  token.c_str(), "%2u:%2u:%2u", &exploded.hour,
    480                  &exploded.minute, &exploded.second) == 3) {
    481         found_time = true;
    482       } else {
    483         // We should only ever encounter one time-like thing.  If we're here,
    484         // it means we've found a second, which shouldn't happen.  We keep
    485         // the first.  This check should be ok for well-formed input:
    486         // NOTREACHED();
    487       }
    488     // Numeric field
    489     } else {
    490       // Overflow with atoi() is unspecified, so we enforce a max length.
    491       if (!found_day_of_month && token.length() <= 2) {
    492         exploded.day_of_month = atoi(token.c_str());
    493         found_day_of_month = true;
    494       } else if (!found_year && token.length() <= 5) {
    495         exploded.year = atoi(token.c_str());
    496         found_year = true;
    497       } else {
    498         // If we're here, it means we've either found an extra numeric field,
    499         // or a numeric field which was too long.  For well-formed input, the
    500         // following check would be reasonable:
    501         // NOTREACHED();
    502       }
    503     }
    504   }
    505 
    506   if (!found_day_of_month || !found_month || !found_time || !found_year) {
    507     // We didn't find all of the fields we need.  For well-formed input, the
    508     // following check would be reasonable:
    509     // NOTREACHED() << "Cookie parse expiration failed: " << time_string;
    510     return Time();
    511   }
    512 
    513   // Normalize the year to expand abbreviated years to the full year.
    514   if (exploded.year >= 69 && exploded.year <= 99)
    515     exploded.year += 1900;
    516   if (exploded.year >= 0 && exploded.year <= 68)
    517     exploded.year += 2000;
    518 
    519   // If our values are within their correct ranges, we got our time.
    520   if (exploded.day_of_month >= 1 && exploded.day_of_month <= 31 &&
    521       exploded.month >= 1 && exploded.month <= 12 &&
    522       exploded.year >= 1601 && exploded.year <= 30827 &&
    523       exploded.hour <= 23 && exploded.minute <= 59 && exploded.second <= 59) {
    524     return Time::FromUTCExploded(exploded);
    525   }
    526 
    527   // One of our values was out of expected range.  For well-formed input,
    528   // the following check would be reasonable:
    529   // NOTREACHED() << "Cookie exploded expiration failed: " << time_string;
    530 
    531   return Time();
    532 }
    533 
    534 bool CookieMonster::DomainIsHostOnly(const std::string& domain_string) {
    535   return (domain_string.empty() || domain_string[0] != '.');
    536 }
    537 
    538 bool CookieMonster::SetCookieWithDetails(
    539     const GURL& url, const std::string& name, const std::string& value,
    540     const std::string& domain, const std::string& path,
    541     const base::Time& expiration_time, bool secure, bool http_only) {
    542   base::AutoLock autolock(lock_);
    543 
    544   if (!HasCookieableScheme(url))
    545     return false;
    546 
    547   InitIfNecessary();
    548 
    549   Time creation_time = CurrentTime();
    550   last_time_seen_ = creation_time;
    551 
    552   scoped_ptr<CanonicalCookie> cc;
    553   cc.reset(CanonicalCookie::Create(
    554       url, name, value, domain, path,
    555       creation_time, expiration_time,
    556       secure, http_only));
    557 
    558   if (!cc.get())
    559     return false;
    560 
    561   CookieOptions options;
    562   options.set_include_httponly();
    563   return SetCanonicalCookie(&cc, creation_time, options);
    564 }
    565 
    566 
    567 CookieList CookieMonster::GetAllCookies() {
    568   base::AutoLock autolock(lock_);
    569   InitIfNecessary();
    570 
    571   // This function is being called to scrape the cookie list for management UI
    572   // or similar.  We shouldn't show expired cookies in this list since it will
    573   // just be confusing to users, and this function is called rarely enough (and
    574   // is already slow enough) that it's OK to take the time to garbage collect
    575   // the expired cookies now.
    576   //
    577   // Note that this does not prune cookies to be below our limits (if we've
    578   // exceeded them) the way that calling GarbageCollect() would.
    579   GarbageCollectExpired(Time::Now(),
    580                         CookieMapItPair(cookies_.begin(), cookies_.end()),
    581                         NULL);
    582 
    583   // Copy the CanonicalCookie pointers from the map so that we can use the same
    584   // sorter as elsewhere, then copy the result out.
    585   std::vector<CanonicalCookie*> cookie_ptrs;
    586   cookie_ptrs.reserve(cookies_.size());
    587   for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end(); ++it)
    588     cookie_ptrs.push_back(it->second);
    589   std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
    590 
    591   CookieList cookie_list;
    592   cookie_list.reserve(cookie_ptrs.size());
    593   for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
    594        it != cookie_ptrs.end(); ++it)
    595     cookie_list.push_back(**it);
    596 
    597   return cookie_list;
    598 }
    599 
    600 CookieList CookieMonster::GetAllCookiesForURLWithOptions(
    601     const GURL& url,
    602     const CookieOptions& options) {
    603   base::AutoLock autolock(lock_);
    604   InitIfNecessary();
    605 
    606   std::vector<CanonicalCookie*> cookie_ptrs;
    607   FindCookiesForHostAndDomain(url, options, false, &cookie_ptrs);
    608   std::sort(cookie_ptrs.begin(), cookie_ptrs.end(), CookieSorter);
    609 
    610   CookieList cookies;
    611   for (std::vector<CanonicalCookie*>::const_iterator it = cookie_ptrs.begin();
    612        it != cookie_ptrs.end(); it++)
    613     cookies.push_back(**it);
    614 
    615   return cookies;
    616 }
    617 
    618 CookieList CookieMonster::GetAllCookiesForURL(const GURL& url) {
    619   CookieOptions options;
    620   options.set_include_httponly();
    621 
    622   return GetAllCookiesForURLWithOptions(url, options);
    623 }
    624 
    625 int CookieMonster::DeleteAll(bool sync_to_store) {
    626   base::AutoLock autolock(lock_);
    627   if (sync_to_store)
    628     InitIfNecessary();
    629 
    630   int num_deleted = 0;
    631   for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
    632     CookieMap::iterator curit = it;
    633     ++it;
    634     InternalDeleteCookie(curit, sync_to_store,
    635                          sync_to_store ? DELETE_COOKIE_EXPLICIT :
    636                              DELETE_COOKIE_DONT_RECORD /* Destruction. */);
    637     ++num_deleted;
    638   }
    639 
    640   return num_deleted;
    641 }
    642 
    643 int CookieMonster::DeleteAllCreatedBetween(const Time& delete_begin,
    644                                            const Time& delete_end,
    645                                            bool sync_to_store) {
    646   base::AutoLock autolock(lock_);
    647   InitIfNecessary();
    648 
    649   int num_deleted = 0;
    650   for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
    651     CookieMap::iterator curit = it;
    652     CanonicalCookie* cc = curit->second;
    653     ++it;
    654 
    655     if (cc->CreationDate() >= delete_begin &&
    656         (delete_end.is_null() || cc->CreationDate() < delete_end)) {
    657       InternalDeleteCookie(curit, sync_to_store, DELETE_COOKIE_EXPLICIT);
    658       ++num_deleted;
    659     }
    660   }
    661 
    662   return num_deleted;
    663 }
    664 
    665 int CookieMonster::DeleteAllCreatedAfter(const Time& delete_begin,
    666                                          bool sync_to_store) {
    667   return DeleteAllCreatedBetween(delete_begin, Time(), sync_to_store);
    668 }
    669 
    670 int CookieMonster::DeleteAllForHost(const GURL& url) {
    671   base::AutoLock autolock(lock_);
    672   InitIfNecessary();
    673 
    674   if (!HasCookieableScheme(url))
    675     return 0;
    676 
    677   const std::string scheme(url.scheme());
    678   const std::string host(url.host());
    679 
    680   // We store host cookies in the store by their canonical host name;
    681   // domain cookies are stored with a leading ".".  So this is a pretty
    682   // simple lookup and per-cookie delete.
    683   int num_deleted = 0;
    684   for (CookieMapItPair its = cookies_.equal_range(GetKey(host));
    685        its.first != its.second;) {
    686     CookieMap::iterator curit = its.first;
    687     ++its.first;
    688 
    689     const CanonicalCookie* const cc = curit->second;
    690 
    691     // Delete only on a match as a host cookie.
    692     if (cc->IsHostCookie() && cc->IsDomainMatch(scheme, host)) {
    693       num_deleted++;
    694 
    695       InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
    696     }
    697   }
    698   return num_deleted;
    699 }
    700 
    701 bool CookieMonster::DeleteCanonicalCookie(const CanonicalCookie& cookie) {
    702   base::AutoLock autolock(lock_);
    703   InitIfNecessary();
    704 
    705   for (CookieMapItPair its = cookies_.equal_range(GetKey(cookie.Domain()));
    706        its.first != its.second; ++its.first) {
    707     // The creation date acts as our unique index...
    708     if (its.first->second->CreationDate() == cookie.CreationDate()) {
    709       InternalDeleteCookie(its.first, true, DELETE_COOKIE_EXPLICIT);
    710       return true;
    711     }
    712   }
    713   return false;
    714 }
    715 
    716 void CookieMonster::SetCookieableSchemes(
    717     const char* schemes[], size_t num_schemes) {
    718   base::AutoLock autolock(lock_);
    719 
    720   // Cookieable Schemes must be set before first use of function.
    721   DCHECK(!initialized_);
    722 
    723   cookieable_schemes_.clear();
    724   cookieable_schemes_.insert(cookieable_schemes_.end(),
    725                              schemes, schemes + num_schemes);
    726 }
    727 
    728 void CookieMonster::SetExpiryAndKeyScheme(ExpiryAndKeyScheme key_scheme) {
    729   DCHECK(!initialized_);
    730   expiry_and_key_scheme_ = key_scheme;
    731 }
    732 
    733 void CookieMonster::SetKeepExpiredCookies() {
    734   keep_expired_cookies_ = true;
    735 }
    736 
    737 void CookieMonster::SetClearPersistentStoreOnExit(bool clear_local_store) {
    738   if (store_)
    739     store_->SetClearLocalStateOnExit(clear_local_store);
    740 }
    741 
    742 // static
    743 void CookieMonster::EnableFileScheme() {
    744   enable_file_scheme_ = true;
    745 }
    746 
    747 void CookieMonster::FlushStore(Task* completion_task) {
    748   base::AutoLock autolock(lock_);
    749   if (initialized_ && store_)
    750     store_->Flush(completion_task);
    751   else if (completion_task)
    752     MessageLoop::current()->PostTask(FROM_HERE, completion_task);
    753 }
    754 
    755 bool CookieMonster::SetCookieWithOptions(const GURL& url,
    756                                          const std::string& cookie_line,
    757                                          const CookieOptions& options) {
    758   base::AutoLock autolock(lock_);
    759 
    760   if (!HasCookieableScheme(url)) {
    761     return false;
    762   }
    763 
    764   InitIfNecessary();
    765 
    766   return SetCookieWithCreationTimeAndOptions(url, cookie_line, Time(), options);
    767 }
    768 
    769 std::string CookieMonster::GetCookiesWithOptions(const GURL& url,
    770                                                  const CookieOptions& options) {
    771   base::AutoLock autolock(lock_);
    772   InitIfNecessary();
    773 
    774   if (!HasCookieableScheme(url)) {
    775     return std::string();
    776   }
    777 
    778   TimeTicks start_time(TimeTicks::Now());
    779 
    780   // Get the cookies for this host and its domain(s).
    781   std::vector<CanonicalCookie*> cookies;
    782   FindCookiesForHostAndDomain(url, options, true, &cookies);
    783   std::sort(cookies.begin(), cookies.end(), CookieSorter);
    784 
    785   std::string cookie_line;
    786   for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
    787        it != cookies.end(); ++it) {
    788     if (it != cookies.begin())
    789       cookie_line += "; ";
    790     // In Mozilla if you set a cookie like AAAA, it will have an empty token
    791     // and a value of AAAA.  When it sends the cookie back, it will send AAAA,
    792     // so we need to avoid sending =AAAA for a blank token value.
    793     if (!(*it)->Name().empty())
    794       cookie_line += (*it)->Name() + "=";
    795     cookie_line += (*it)->Value();
    796   }
    797 
    798   histogram_time_get_->AddTime(TimeTicks::Now() - start_time);
    799 
    800   VLOG(kVlogGetCookies) << "GetCookies() result: " << cookie_line;
    801 
    802   return cookie_line;
    803 }
    804 
    805 void CookieMonster::DeleteCookie(const GURL& url,
    806                                  const std::string& cookie_name) {
    807   base::AutoLock autolock(lock_);
    808   InitIfNecessary();
    809 
    810   if (!HasCookieableScheme(url))
    811     return;
    812 
    813   CookieOptions options;
    814   options.set_include_httponly();
    815   // Get the cookies for this host and its domain(s).
    816   std::vector<CanonicalCookie*> cookies;
    817   FindCookiesForHostAndDomain(url, options, true, &cookies);
    818   std::set<CanonicalCookie*> matching_cookies;
    819 
    820   for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
    821        it != cookies.end(); ++it) {
    822     if ((*it)->Name() != cookie_name)
    823       continue;
    824     if (url.path().find((*it)->Path()))
    825       continue;
    826     matching_cookies.insert(*it);
    827   }
    828 
    829   for (CookieMap::iterator it = cookies_.begin(); it != cookies_.end();) {
    830     CookieMap::iterator curit = it;
    831     ++it;
    832     if (matching_cookies.find(curit->second) != matching_cookies.end()) {
    833       InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPLICIT);
    834     }
    835   }
    836 }
    837 
    838 CookieMonster* CookieMonster::GetCookieMonster() {
    839   return this;
    840 }
    841 
    842 CookieMonster::~CookieMonster() {
    843   DeleteAll(false);
    844 }
    845 
    846 bool CookieMonster::SetCookieWithCreationTime(const GURL& url,
    847                                               const std::string& cookie_line,
    848                                               const base::Time& creation_time) {
    849   base::AutoLock autolock(lock_);
    850 
    851   if (!HasCookieableScheme(url)) {
    852     return false;
    853   }
    854 
    855   InitIfNecessary();
    856   return SetCookieWithCreationTimeAndOptions(url, cookie_line, creation_time,
    857                                              CookieOptions());
    858 }
    859 
    860 void CookieMonster::InitStore() {
    861   DCHECK(store_) << "Store must exist to initialize";
    862 
    863   TimeTicks beginning_time(TimeTicks::Now());
    864 
    865   // Initialize the store and sync in any saved persistent cookies.  We don't
    866   // care if it's expired, insert it so it can be garbage collected, removed,
    867   // and sync'd.
    868   std::vector<CanonicalCookie*> cookies;
    869   // Reserve space for the maximum amount of cookies a database should have.
    870   // This prevents multiple vector growth / copies as we append cookies.
    871   cookies.reserve(kMaxCookies);
    872   store_->Load(&cookies);
    873 
    874   // Avoid ever letting cookies with duplicate creation times into the store;
    875   // that way we don't have to worry about what sections of code are safe
    876   // to call while it's in that state.
    877   std::set<int64> creation_times;
    878 
    879   // Presumably later than any access time in the store.
    880   Time earliest_access_time;
    881 
    882   for (std::vector<CanonicalCookie*>::const_iterator it = cookies.begin();
    883        it != cookies.end(); ++it) {
    884     int64 cookie_creation_time = (*it)->CreationDate().ToInternalValue();
    885 
    886     if (creation_times.insert(cookie_creation_time).second) {
    887       InternalInsertCookie(GetKey((*it)->Domain()), *it, false);
    888       const Time cookie_access_time((*it)->LastAccessDate());
    889       if (earliest_access_time.is_null() ||
    890           cookie_access_time < earliest_access_time)
    891         earliest_access_time = cookie_access_time;
    892     } else {
    893       LOG(ERROR) << base::StringPrintf("Found cookies with duplicate creation "
    894                                        "times in backing store: "
    895                                        "{name='%s', domain='%s', path='%s'}",
    896                                        (*it)->Name().c_str(),
    897                                        (*it)->Domain().c_str(),
    898                                        (*it)->Path().c_str());
    899       // We've been given ownership of the cookie and are throwing it
    900       // away; reclaim the space.
    901       delete (*it);
    902     }
    903   }
    904   earliest_access_time_= earliest_access_time;
    905 
    906   // After importing cookies from the PersistentCookieStore, verify that
    907   // none of our other constraints are violated.
    908   //
    909   // In particular, the backing store might have given us duplicate cookies.
    910   EnsureCookiesMapIsValid();
    911 
    912   histogram_time_load_->AddTime(TimeTicks::Now() - beginning_time);
    913 }
    914 
    915 void CookieMonster::EnsureCookiesMapIsValid() {
    916   lock_.AssertAcquired();
    917 
    918   int num_duplicates_trimmed = 0;
    919 
    920   // Iterate through all the of the cookies, grouped by host.
    921   CookieMap::iterator prev_range_end = cookies_.begin();
    922   while (prev_range_end != cookies_.end()) {
    923     CookieMap::iterator cur_range_begin = prev_range_end;
    924     const std::string key = cur_range_begin->first;  // Keep a copy.
    925     CookieMap::iterator cur_range_end = cookies_.upper_bound(key);
    926     prev_range_end = cur_range_end;
    927 
    928     // Ensure no equivalent cookies for this host.
    929     num_duplicates_trimmed +=
    930         TrimDuplicateCookiesForKey(key, cur_range_begin, cur_range_end);
    931   }
    932 
    933   // Record how many duplicates were found in the database.
    934   // See InitializeHistograms() for details.
    935   histogram_cookie_deletion_cause_->Add(num_duplicates_trimmed);
    936 }
    937 
    938 int CookieMonster::TrimDuplicateCookiesForKey(
    939     const std::string& key,
    940     CookieMap::iterator begin,
    941     CookieMap::iterator end) {
    942   lock_.AssertAcquired();
    943 
    944   // Set of cookies ordered by creation time.
    945   typedef std::set<CookieMap::iterator, OrderByCreationTimeDesc> CookieSet;
    946 
    947   // Helper map we populate to find the duplicates.
    948   typedef std::map<CookieSignature, CookieSet> EquivalenceMap;
    949   EquivalenceMap equivalent_cookies;
    950 
    951   // The number of duplicate cookies that have been found.
    952   int num_duplicates = 0;
    953 
    954   // Iterate through all of the cookies in our range, and insert them into
    955   // the equivalence map.
    956   for (CookieMap::iterator it = begin; it != end; ++it) {
    957     DCHECK_EQ(key, it->first);
    958     CanonicalCookie* cookie = it->second;
    959 
    960     CookieSignature signature(cookie->Name(), cookie->Domain(),
    961                               cookie->Path());
    962     CookieSet& set = equivalent_cookies[signature];
    963 
    964     // We found a duplicate!
    965     if (!set.empty())
    966       num_duplicates++;
    967 
    968     // We save the iterator into |cookies_| rather than the actual cookie
    969     // pointer, since we may need to delete it later.
    970     bool insert_success = set.insert(it).second;
    971     DCHECK(insert_success) <<
    972         "Duplicate creation times found in duplicate cookie name scan.";
    973   }
    974 
    975   // If there were no duplicates, we are done!
    976   if (num_duplicates == 0)
    977     return 0;
    978 
    979   // Make sure we find everything below that we did above.
    980   int num_duplicates_found = 0;
    981 
    982   // Otherwise, delete all the duplicate cookies, both from our in-memory store
    983   // and from the backing store.
    984   for (EquivalenceMap::iterator it = equivalent_cookies.begin();
    985        it != equivalent_cookies.end();
    986        ++it) {
    987     const CookieSignature& signature = it->first;
    988     CookieSet& dupes = it->second;
    989 
    990     if (dupes.size() <= 1)
    991       continue;  // This cookiename/path has no duplicates.
    992     num_duplicates_found += dupes.size() - 1;
    993 
    994     // Since |dups| is sorted by creation time (descending), the first cookie
    995     // is the most recent one, so we will keep it. The rest are duplicates.
    996     dupes.erase(dupes.begin());
    997 
    998     LOG(ERROR) << base::StringPrintf(
    999         "Found %d duplicate cookies for host='%s', "
   1000         "with {name='%s', domain='%s', path='%s'}",
   1001         static_cast<int>(dupes.size()),
   1002         key.c_str(),
   1003         signature.name.c_str(),
   1004         signature.domain.c_str(),
   1005         signature.path.c_str());
   1006 
   1007     // Remove all the cookies identified by |dupes|. It is valid to delete our
   1008     // list of iterators one at a time, since |cookies_| is a multimap (they
   1009     // don't invalidate existing iterators following deletion).
   1010     for (CookieSet::iterator dupes_it = dupes.begin();
   1011          dupes_it != dupes.end();
   1012          ++dupes_it) {
   1013       InternalDeleteCookie(*dupes_it, true /*sync_to_store*/,
   1014                            DELETE_COOKIE_DUPLICATE_IN_BACKING_STORE);
   1015     }
   1016   }
   1017   DCHECK_EQ(num_duplicates, num_duplicates_found);
   1018 
   1019   return num_duplicates;
   1020 }
   1021 
   1022 // Note: file must be the last scheme.
   1023 const char* CookieMonster::kDefaultCookieableSchemes[] =
   1024     { "http", "https", "file" };
   1025 const int CookieMonster::kDefaultCookieableSchemesCount =
   1026     arraysize(CookieMonster::kDefaultCookieableSchemes);
   1027 
   1028 void CookieMonster::SetDefaultCookieableSchemes() {
   1029   int num_schemes = enable_file_scheme_ ?
   1030       kDefaultCookieableSchemesCount : kDefaultCookieableSchemesCount - 1;
   1031   SetCookieableSchemes(kDefaultCookieableSchemes, num_schemes);
   1032 }
   1033 
   1034 
   1035 void CookieMonster::FindCookiesForHostAndDomain(
   1036     const GURL& url,
   1037     const CookieOptions& options,
   1038     bool update_access_time,
   1039     std::vector<CanonicalCookie*>* cookies) {
   1040   lock_.AssertAcquired();
   1041 
   1042   const Time current_time(CurrentTime());
   1043 
   1044   // Probe to save statistics relatively frequently.  We do it here rather
   1045   // than in the set path as many websites won't set cookies, and we
   1046   // want to collect statistics whenever the browser's being used.
   1047   RecordPeriodicStats(current_time);
   1048 
   1049   if (expiry_and_key_scheme_ == EKS_DISCARD_RECENT_AND_PURGE_DOMAIN) {
   1050     // Can just dispatch to FindCookiesForKey
   1051     const std::string key(GetKey(url.host()));
   1052     FindCookiesForKey(key, url, options, current_time,
   1053                       update_access_time, cookies);
   1054   } else {
   1055     // Need to probe for all domains that might have relevant
   1056     // cookies for us.
   1057 
   1058     // Query for the full host, For example: 'a.c.blah.com'.
   1059     std::string key(GetKey(url.host()));
   1060     FindCookiesForKey(key, url, options, current_time, update_access_time,
   1061                       cookies);
   1062 
   1063     // See if we can search for domain cookies, i.e. if the host has a TLD + 1.
   1064     const std::string domain(GetEffectiveDomain(url.scheme(), key));
   1065     if (domain.empty())
   1066       return;
   1067     DCHECK_LE(domain.length(), key.length());
   1068     DCHECK_EQ(0, key.compare(key.length() - domain.length(), domain.length(),
   1069                              domain));
   1070 
   1071     // Walk through the string and query at the dot points (GURL should have
   1072     // canonicalized the dots, so this should be safe).  Stop once we reach the
   1073     // domain + registry; we can't write cookies past this point, and with some
   1074     // registrars other domains can, in which case we don't want to read their
   1075     // cookies.
   1076     for (key = "." + key; key.length() > domain.length(); ) {
   1077       FindCookiesForKey(key, url, options, current_time, update_access_time,
   1078                         cookies);
   1079       const size_t next_dot = key.find('.', 1);  // Skip over leading dot.
   1080       key.erase(0, next_dot);
   1081     }
   1082   }
   1083 }
   1084 
   1085 void CookieMonster::FindCookiesForKey(
   1086     const std::string& key,
   1087     const GURL& url,
   1088     const CookieOptions& options,
   1089     const Time& current,
   1090     bool update_access_time,
   1091     std::vector<CanonicalCookie*>* cookies) {
   1092   lock_.AssertAcquired();
   1093 
   1094   const std::string scheme(url.scheme());
   1095   const std::string host(url.host());
   1096   bool secure = url.SchemeIsSecure();
   1097 
   1098   for (CookieMapItPair its = cookies_.equal_range(key);
   1099        its.first != its.second; ) {
   1100     CookieMap::iterator curit = its.first;
   1101     CanonicalCookie* cc = curit->second;
   1102     ++its.first;
   1103 
   1104     // If the cookie is expired, delete it.
   1105     if (cc->IsExpired(current) && !keep_expired_cookies_) {
   1106       InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
   1107       continue;
   1108     }
   1109 
   1110     // Filter out HttpOnly cookies, per options.
   1111     if (options.exclude_httponly() && cc->IsHttpOnly())
   1112       continue;
   1113 
   1114     // Filter out secure cookies unless we're https.
   1115     if (!secure && cc->IsSecure())
   1116       continue;
   1117 
   1118     // Filter out cookies that don't apply to this domain.
   1119     if (expiry_and_key_scheme_ == EKS_KEEP_RECENT_AND_PURGE_ETLDP1
   1120         && !cc->IsDomainMatch(scheme, host))
   1121       continue;
   1122 
   1123     if (!cc->IsOnPath(url.path()))
   1124       continue;
   1125 
   1126     // Add this cookie to the set of matching cookies.  Update the access
   1127     // time if we've been requested to do so.
   1128     if (update_access_time) {
   1129       InternalUpdateCookieAccessTime(cc, current);
   1130     }
   1131     cookies->push_back(cc);
   1132   }
   1133 }
   1134 
   1135 bool CookieMonster::DeleteAnyEquivalentCookie(const std::string& key,
   1136                                               const CanonicalCookie& ecc,
   1137                                               bool skip_httponly,
   1138                                               bool already_expired) {
   1139   lock_.AssertAcquired();
   1140 
   1141   bool found_equivalent_cookie = false;
   1142   bool skipped_httponly = false;
   1143   for (CookieMapItPair its = cookies_.equal_range(key);
   1144        its.first != its.second; ) {
   1145     CookieMap::iterator curit = its.first;
   1146     CanonicalCookie* cc = curit->second;
   1147     ++its.first;
   1148 
   1149     if (ecc.IsEquivalent(*cc)) {
   1150       // We should never have more than one equivalent cookie, since they should
   1151       // overwrite each other.
   1152       CHECK(!found_equivalent_cookie) <<
   1153           "Duplicate equivalent cookies found, cookie store is corrupted.";
   1154       if (skip_httponly && cc->IsHttpOnly()) {
   1155         skipped_httponly = true;
   1156       } else {
   1157         InternalDeleteCookie(curit, true, already_expired ?
   1158             DELETE_COOKIE_EXPIRED_OVERWRITE : DELETE_COOKIE_OVERWRITE);
   1159       }
   1160       found_equivalent_cookie = true;
   1161     }
   1162   }
   1163   return skipped_httponly;
   1164 }
   1165 
   1166 void CookieMonster::InternalInsertCookie(const std::string& key,
   1167                                          CanonicalCookie* cc,
   1168                                          bool sync_to_store) {
   1169   lock_.AssertAcquired();
   1170 
   1171   if (cc->IsPersistent() && store_ && sync_to_store)
   1172     store_->AddCookie(*cc);
   1173   cookies_.insert(CookieMap::value_type(key, cc));
   1174   if (delegate_.get()) {
   1175     delegate_->OnCookieChanged(
   1176         *cc, false, CookieMonster::Delegate::CHANGE_COOKIE_EXPLICIT);
   1177   }
   1178 }
   1179 
   1180 bool CookieMonster::SetCookieWithCreationTimeAndOptions(
   1181     const GURL& url,
   1182     const std::string& cookie_line,
   1183     const Time& creation_time_or_null,
   1184     const CookieOptions& options) {
   1185   lock_.AssertAcquired();
   1186 
   1187   VLOG(kVlogSetCookies) << "SetCookie() line: " << cookie_line;
   1188 
   1189   Time creation_time = creation_time_or_null;
   1190   if (creation_time.is_null()) {
   1191     creation_time = CurrentTime();
   1192     last_time_seen_ = creation_time;
   1193   }
   1194 
   1195   // Parse the cookie.
   1196   ParsedCookie pc(cookie_line);
   1197 
   1198   if (!pc.IsValid()) {
   1199     VLOG(kVlogSetCookies) << "WARNING: Couldn't parse cookie";
   1200     return false;
   1201   }
   1202 
   1203   if (options.exclude_httponly() && pc.IsHttpOnly()) {
   1204     VLOG(kVlogSetCookies) << "SetCookie() not setting httponly cookie";
   1205     return false;
   1206   }
   1207 
   1208   std::string cookie_domain;
   1209   if (!GetCookieDomain(url, pc, &cookie_domain)) {
   1210     return false;
   1211   }
   1212 
   1213   std::string cookie_path = CanonPath(url, pc);
   1214 
   1215   scoped_ptr<CanonicalCookie> cc;
   1216   Time cookie_expires = CanonExpiration(pc, creation_time, options);
   1217 
   1218   cc.reset(new CanonicalCookie(url, pc.Name(), pc.Value(), cookie_domain,
   1219                                cookie_path, creation_time, cookie_expires,
   1220                                creation_time, pc.IsSecure(), pc.IsHttpOnly(),
   1221                                !cookie_expires.is_null()));
   1222 
   1223   if (!cc.get()) {
   1224     VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie";
   1225     return false;
   1226   }
   1227   return SetCanonicalCookie(&cc, creation_time, options);
   1228 }
   1229 
   1230 bool CookieMonster::SetCanonicalCookie(scoped_ptr<CanonicalCookie>* cc,
   1231                                        const Time& creation_time,
   1232                                        const CookieOptions& options) {
   1233   const std::string key(GetKey((*cc)->Domain()));
   1234   bool already_expired = (*cc)->IsExpired(creation_time);
   1235   if (DeleteAnyEquivalentCookie(key, **cc, options.exclude_httponly(),
   1236                                 already_expired)) {
   1237     VLOG(kVlogSetCookies) << "SetCookie() not clobbering httponly cookie";
   1238     return false;
   1239   }
   1240 
   1241   VLOG(kVlogSetCookies) << "SetCookie() key: " << key << " cc: "
   1242                         << (*cc)->DebugString();
   1243 
   1244   // Realize that we might be setting an expired cookie, and the only point
   1245   // was to delete the cookie which we've already done.
   1246   if (!already_expired || keep_expired_cookies_) {
   1247     // See InitializeHistograms() for details.
   1248     if ((*cc)->DoesExpire()) {
   1249       histogram_expiration_duration_minutes_->Add(
   1250           ((*cc)->ExpiryDate() - creation_time).InMinutes());
   1251     }
   1252 
   1253     InternalInsertCookie(key, cc->release(), true);
   1254   }
   1255 
   1256   // We assume that hopefully setting a cookie will be less common than
   1257   // querying a cookie.  Since setting a cookie can put us over our limits,
   1258   // make sure that we garbage collect...  We can also make the assumption that
   1259   // if a cookie was set, in the common case it will be used soon after,
   1260   // and we will purge the expired cookies in GetCookies().
   1261   GarbageCollect(creation_time, key);
   1262 
   1263   return true;
   1264 }
   1265 
   1266 void CookieMonster::InternalUpdateCookieAccessTime(CanonicalCookie* cc,
   1267                                                    const Time& current) {
   1268   lock_.AssertAcquired();
   1269 
   1270   // Based off the Mozilla code.  When a cookie has been accessed recently,
   1271   // don't bother updating its access time again.  This reduces the number of
   1272   // updates we do during pageload, which in turn reduces the chance our storage
   1273   // backend will hit its batch thresholds and be forced to update.
   1274   if ((current - cc->LastAccessDate()) < last_access_threshold_)
   1275     return;
   1276 
   1277   // See InitializeHistograms() for details.
   1278   histogram_between_access_interval_minutes_->Add(
   1279       (current - cc->LastAccessDate()).InMinutes());
   1280 
   1281   cc->SetLastAccessDate(current);
   1282   if (cc->IsPersistent() && store_)
   1283     store_->UpdateCookieAccessTime(*cc);
   1284 }
   1285 
   1286 void CookieMonster::InternalDeleteCookie(CookieMap::iterator it,
   1287                                          bool sync_to_store,
   1288                                          DeletionCause deletion_cause) {
   1289   lock_.AssertAcquired();
   1290 
   1291   // Ideally, this would be asserted up where we define ChangeCauseMapping,
   1292   // but DeletionCause's visibility (or lack thereof) forces us to make
   1293   // this check here.
   1294   COMPILE_ASSERT(arraysize(ChangeCauseMapping) == DELETE_COOKIE_LAST_ENTRY + 1,
   1295                  ChangeCauseMapping_size_not_eq_DeletionCause_enum_size);
   1296 
   1297   // See InitializeHistograms() for details.
   1298   if (deletion_cause != DELETE_COOKIE_DONT_RECORD)
   1299     histogram_cookie_deletion_cause_->Add(deletion_cause);
   1300 
   1301   CanonicalCookie* cc = it->second;
   1302   VLOG(kVlogSetCookies) << "InternalDeleteCookie() cc: " << cc->DebugString();
   1303 
   1304   if (cc->IsPersistent() && store_ && sync_to_store)
   1305     store_->DeleteCookie(*cc);
   1306   if (delegate_.get()) {
   1307     ChangeCausePair mapping = ChangeCauseMapping[deletion_cause];
   1308 
   1309     if (mapping.notify)
   1310       delegate_->OnCookieChanged(*cc, true, mapping.cause);
   1311   }
   1312   cookies_.erase(it);
   1313   delete cc;
   1314 }
   1315 
   1316 // Domain expiry behavior is unchanged by key/expiry scheme (the
   1317 // meaning of the key is different, but that's not visible to this
   1318 // routine).  Global garbage collection is dependent on key/expiry
   1319 // scheme in that recently touched cookies are not saved if
   1320 // expiry_and_key_scheme_ == EKS_DISCARD_RECENT_AND_PURGE_DOMAIN.
   1321 int CookieMonster::GarbageCollect(const Time& current,
   1322                                   const std::string& key) {
   1323   lock_.AssertAcquired();
   1324 
   1325   int num_deleted = 0;
   1326 
   1327   // Collect garbage for this key.
   1328   if (cookies_.count(key) > kDomainMaxCookies) {
   1329     VLOG(kVlogGarbageCollection) << "GarbageCollect() key: " << key;
   1330 
   1331     std::vector<CookieMap::iterator> cookie_its;
   1332     num_deleted += GarbageCollectExpired(
   1333         current, cookies_.equal_range(key), &cookie_its);
   1334     base::Time oldest_removed;
   1335     if (FindLeastRecentlyAccessed(kDomainMaxCookies, kDomainPurgeCookies,
   1336                                   &oldest_removed, &cookie_its)) {
   1337       // Delete in two passes so we can figure out what we're nuking
   1338       // that would be kept at the global level.
   1339       int num_subject_to_global_purge =
   1340           GarbageCollectDeleteList(
   1341               current,
   1342               Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays),
   1343               DELETE_COOKIE_EVICTED_DOMAIN_PRE_SAFE,
   1344               cookie_its);
   1345       num_deleted += num_subject_to_global_purge;
   1346       // Correct because FindLeastRecentlyAccessed returns a sorted list.
   1347       cookie_its.erase(cookie_its.begin(),
   1348                        cookie_its.begin() + num_subject_to_global_purge);
   1349       num_deleted +=
   1350           GarbageCollectDeleteList(
   1351               current,
   1352               Time(),
   1353               DELETE_COOKIE_EVICTED_DOMAIN_POST_SAFE,
   1354               cookie_its);
   1355     }
   1356   }
   1357 
   1358   // Collect garbage for everything.  With firefox style we want to
   1359   // preserve cookies touched in kSafeFromGlobalPurgeDays, otherwise
   1360   // not.
   1361   if (cookies_.size() > kMaxCookies &&
   1362       (expiry_and_key_scheme_ == EKS_DISCARD_RECENT_AND_PURGE_DOMAIN ||
   1363        earliest_access_time_ <
   1364        Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays))) {
   1365     VLOG(kVlogGarbageCollection) << "GarbageCollect() everything";
   1366     std::vector<CookieMap::iterator> cookie_its;
   1367     base::Time oldest_left;
   1368     num_deleted += GarbageCollectExpired(
   1369         current, CookieMapItPair(cookies_.begin(), cookies_.end()),
   1370         &cookie_its);
   1371     if (FindLeastRecentlyAccessed(kMaxCookies, kPurgeCookies,
   1372                                   &oldest_left, &cookie_its)) {
   1373       Time oldest_safe_cookie(
   1374           expiry_and_key_scheme_ == EKS_KEEP_RECENT_AND_PURGE_ETLDP1 ?
   1375               (Time::Now() - TimeDelta::FromDays(kSafeFromGlobalPurgeDays)) :
   1376               Time());                  // Null time == ignore access time.
   1377       int num_evicted = GarbageCollectDeleteList(
   1378           current,
   1379           oldest_safe_cookie,
   1380           DELETE_COOKIE_EVICTED_GLOBAL,
   1381           cookie_its);
   1382 
   1383       // If no cookies were preserved by the time limit, the global last
   1384       // access is set to the value returned from FindLeastRecentlyAccessed.
   1385       // If the time limit preserved some cookies, we use the last access of
   1386       // the oldest preserved cookie.
   1387       if (num_evicted == static_cast<int>(cookie_its.size())) {
   1388         earliest_access_time_ = oldest_left;
   1389       } else {
   1390         earliest_access_time_ =
   1391             (*(cookie_its.begin() + num_evicted))->second->LastAccessDate();
   1392       }
   1393       num_deleted += num_evicted;
   1394     }
   1395   }
   1396 
   1397   return num_deleted;
   1398 }
   1399 
   1400 int CookieMonster::GarbageCollectExpired(
   1401     const Time& current,
   1402     const CookieMapItPair& itpair,
   1403     std::vector<CookieMap::iterator>* cookie_its) {
   1404   if (keep_expired_cookies_)
   1405     return 0;
   1406 
   1407   lock_.AssertAcquired();
   1408 
   1409   int num_deleted = 0;
   1410   for (CookieMap::iterator it = itpair.first, end = itpair.second; it != end;) {
   1411     CookieMap::iterator curit = it;
   1412     ++it;
   1413 
   1414     if (curit->second->IsExpired(current)) {
   1415       InternalDeleteCookie(curit, true, DELETE_COOKIE_EXPIRED);
   1416       ++num_deleted;
   1417     } else if (cookie_its) {
   1418       cookie_its->push_back(curit);
   1419     }
   1420   }
   1421 
   1422   return num_deleted;
   1423 }
   1424 
   1425 int CookieMonster::GarbageCollectDeleteList(
   1426     const Time& current,
   1427     const Time& keep_accessed_after,
   1428     DeletionCause cause,
   1429     std::vector<CookieMap::iterator>& cookie_its) {
   1430   int num_deleted = 0;
   1431   for (std::vector<CookieMap::iterator>::iterator it = cookie_its.begin();
   1432        it != cookie_its.end(); it++) {
   1433     if (keep_accessed_after.is_null() ||
   1434         (*it)->second->LastAccessDate() < keep_accessed_after) {
   1435       histogram_evicted_last_access_minutes_->Add(
   1436           (current - (*it)->second->LastAccessDate()).InMinutes());
   1437       InternalDeleteCookie((*it), true, cause);
   1438       num_deleted++;
   1439     }
   1440   }
   1441   return num_deleted;
   1442 }
   1443 
   1444 // A wrapper around RegistryControlledDomainService::GetDomainAndRegistry
   1445 // to make clear we're creating a key for our local map.  Here and
   1446 // in FindCookiesForHostAndDomain() are the only two places where
   1447 // we need to conditionalize based on key type.
   1448 //
   1449 // Note that this key algorithm explicitly ignores the scheme.  This is
   1450 // because when we're entering cookies into the map from the backing store,
   1451 // we in general won't have the scheme at that point.
   1452 // In practical terms, this means that file cookies will be stored
   1453 // in the map either by an empty string or by UNC name (and will be
   1454 // limited by kMaxCookiesPerHost), and extension cookies will be stored
   1455 // based on the single extension id, as the extension id won't have the
   1456 // form of a DNS host and hence GetKey() will return it unchanged.
   1457 //
   1458 // Arguably the right thing to do here is to make the key
   1459 // algorithm dependent on the scheme, and make sure that the scheme is
   1460 // available everywhere the key must be obtained (specfically at backing
   1461 // store load time).  This would require either changing the backing store
   1462 // database schema to include the scheme (far more trouble than it's worth), or
   1463 // separating out file cookies into their own CookieMonster instance and
   1464 // thus restricting each scheme to a single cookie monster (which might
   1465 // be worth it, but is still too much trouble to solve what is currently a
   1466 // non-problem).
   1467 std::string CookieMonster::GetKey(const std::string& domain) const {
   1468   if (expiry_and_key_scheme_ == EKS_DISCARD_RECENT_AND_PURGE_DOMAIN)
   1469     return domain;
   1470 
   1471   std::string effective_domain(
   1472       RegistryControlledDomainService::GetDomainAndRegistry(domain));
   1473   if (effective_domain.empty())
   1474     effective_domain = domain;
   1475 
   1476   if (!effective_domain.empty() && effective_domain[0] == '.')
   1477     return effective_domain.substr(1);
   1478   return effective_domain;
   1479 }
   1480 
   1481 bool CookieMonster::HasCookieableScheme(const GURL& url) {
   1482   lock_.AssertAcquired();
   1483 
   1484   // Make sure the request is on a cookie-able url scheme.
   1485   for (size_t i = 0; i < cookieable_schemes_.size(); ++i) {
   1486     // We matched a scheme.
   1487     if (url.SchemeIs(cookieable_schemes_[i].c_str())) {
   1488       // We've matched a supported scheme.
   1489       return true;
   1490     }
   1491   }
   1492 
   1493   // The scheme didn't match any in our whitelist.
   1494   VLOG(kVlogPerCookieMonster) << "WARNING: Unsupported cookie scheme: "
   1495                               << url.scheme();
   1496   return false;
   1497 }
   1498 
   1499 // Test to see if stats should be recorded, and record them if so.
   1500 // The goal here is to get sampling for the average browser-hour of
   1501 // activity.  We won't take samples when the web isn't being surfed,
   1502 // and when the web is being surfed, we'll take samples about every
   1503 // kRecordStatisticsIntervalSeconds.
   1504 // last_statistic_record_time_ is initialized to Now() rather than null
   1505 // in the constructor so that we won't take statistics right after
   1506 // startup, to avoid bias from browsers that are started but not used.
   1507 void CookieMonster::RecordPeriodicStats(const base::Time& current_time) {
   1508   const base::TimeDelta kRecordStatisticsIntervalTime(
   1509       base::TimeDelta::FromSeconds(kRecordStatisticsIntervalSeconds));
   1510 
   1511   // If we've taken statistics recently, return.
   1512   if (current_time - last_statistic_record_time_ <=
   1513       kRecordStatisticsIntervalTime) {
   1514     return;
   1515   }
   1516 
   1517   // See InitializeHistograms() for details.
   1518   histogram_count_->Add(cookies_.size());
   1519 
   1520   // More detailed statistics on cookie counts at different granularities.
   1521   TimeTicks beginning_of_time(TimeTicks::Now());
   1522 
   1523   for (CookieMap::const_iterator it_key = cookies_.begin();
   1524        it_key != cookies_.end(); ) {
   1525     const std::string& key(it_key->first);
   1526 
   1527     int key_count = 0;
   1528     typedef std::map<std::string, unsigned int> DomainMap;
   1529     DomainMap domain_map;
   1530     CookieMapItPair its_cookies = cookies_.equal_range(key);
   1531     while (its_cookies.first != its_cookies.second) {
   1532       key_count++;
   1533       const std::string& cookie_domain(its_cookies.first->second->Domain());
   1534       domain_map[cookie_domain]++;
   1535 
   1536       its_cookies.first++;
   1537     }
   1538     histogram_etldp1_count_->Add(key_count);
   1539     histogram_domain_per_etldp1_count_->Add(domain_map.size());
   1540     for (DomainMap::const_iterator domain_map_it = domain_map.begin();
   1541          domain_map_it != domain_map.end(); domain_map_it++)
   1542       histogram_domain_count_->Add(domain_map_it->second);
   1543 
   1544     it_key = its_cookies.second;
   1545   }
   1546 
   1547   VLOG(kVlogPeriodic)
   1548       << "Time for recording cookie stats (us): "
   1549       << (TimeTicks::Now() - beginning_of_time).InMicroseconds();
   1550 
   1551   last_statistic_record_time_ = current_time;
   1552 }
   1553 
   1554 // Initialize all histogram counter variables used in this class.
   1555 //
   1556 // Normal histogram usage involves using the macros defined in
   1557 // histogram.h, which automatically takes care of declaring these
   1558 // variables (as statics), initializing them, and accumulating into
   1559 // them, all from a single entry point.  Unfortunately, that solution
   1560 // doesn't work for the CookieMonster, as it's vulnerable to races between
   1561 // separate threads executing the same functions and hence initializing the
   1562 // same static variables.  There isn't a race danger in the histogram
   1563 // accumulation calls; they are written to be resilient to simultaneous
   1564 // calls from multiple threads.
   1565 //
   1566 // The solution taken here is to have per-CookieMonster instance
   1567 // variables that are constructed during CookieMonster construction.
   1568 // Note that these variables refer to the same underlying histogram,
   1569 // so we still race (but safely) with other CookieMonster instances
   1570 // for accumulation.
   1571 //
   1572 // To do this we've expanded out the individual histogram macros calls,
   1573 // with declarations of the variables in the class decl, initialization here
   1574 // (done from the class constructor) and direct calls to the accumulation
   1575 // methods where needed.  The specific histogram macro calls on which the
   1576 // initialization is based are included in comments below.
   1577 void CookieMonster::InitializeHistograms() {
   1578   // From UMA_HISTOGRAM_CUSTOM_COUNTS
   1579   histogram_expiration_duration_minutes_ = base::Histogram::FactoryGet(
   1580       "Cookie.ExpirationDurationMinutes",
   1581       1, kMinutesInTenYears, 50,
   1582       base::Histogram::kUmaTargetedHistogramFlag);
   1583   histogram_between_access_interval_minutes_ = base::Histogram::FactoryGet(
   1584       "Cookie.BetweenAccessIntervalMinutes",
   1585       1, kMinutesInTenYears, 50,
   1586       base::Histogram::kUmaTargetedHistogramFlag);
   1587   histogram_evicted_last_access_minutes_ = base::Histogram::FactoryGet(
   1588       "Cookie.EvictedLastAccessMinutes",
   1589       1, kMinutesInTenYears, 50,
   1590       base::Histogram::kUmaTargetedHistogramFlag);
   1591   histogram_count_ = base::Histogram::FactoryGet(
   1592       "Cookie.Count", 1, 4000, 50,
   1593       base::Histogram::kUmaTargetedHistogramFlag);
   1594   histogram_domain_count_ = base::Histogram::FactoryGet(
   1595       "Cookie.DomainCount", 1, 4000, 50,
   1596       base::Histogram::kUmaTargetedHistogramFlag);
   1597   histogram_etldp1_count_ = base::Histogram::FactoryGet(
   1598       "Cookie.Etldp1Count", 1, 4000, 50,
   1599       base::Histogram::kUmaTargetedHistogramFlag);
   1600   histogram_domain_per_etldp1_count_ = base::Histogram::FactoryGet(
   1601       "Cookie.DomainPerEtldp1Count", 1, 4000, 50,
   1602       base::Histogram::kUmaTargetedHistogramFlag);
   1603 
   1604   // From UMA_HISTOGRAM_COUNTS_10000 & UMA_HISTOGRAM_CUSTOM_COUNTS
   1605   histogram_number_duplicate_db_cookies_ = base::Histogram::FactoryGet(
   1606       "Net.NumDuplicateCookiesInDb", 1, 10000, 50,
   1607       base::Histogram::kUmaTargetedHistogramFlag);
   1608 
   1609   // From UMA_HISTOGRAM_ENUMERATION
   1610   histogram_cookie_deletion_cause_ = base::LinearHistogram::FactoryGet(
   1611       "Cookie.DeletionCause", 1,
   1612       DELETE_COOKIE_LAST_ENTRY - 1, DELETE_COOKIE_LAST_ENTRY,
   1613       base::Histogram::kUmaTargetedHistogramFlag);
   1614 
   1615   // From UMA_HISTOGRAM_{CUSTOM_,}TIMES
   1616   histogram_time_get_ = base::Histogram::FactoryTimeGet("Cookie.TimeGet",
   1617       base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
   1618       50, base::Histogram::kUmaTargetedHistogramFlag);
   1619   histogram_time_load_ = base::Histogram::FactoryTimeGet("Cookie.TimeLoad",
   1620       base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromMinutes(1),
   1621       50, base::Histogram::kUmaTargetedHistogramFlag);
   1622 }
   1623 
   1624 
   1625 // The system resolution is not high enough, so we can have multiple
   1626 // set cookies that result in the same system time.  When this happens, we
   1627 // increment by one Time unit.  Let's hope computers don't get too fast.
   1628 Time CookieMonster::CurrentTime() {
   1629   return std::max(Time::Now(),
   1630       Time::FromInternalValue(last_time_seen_.ToInternalValue() + 1));
   1631 }
   1632 
   1633 CookieMonster::ParsedCookie::ParsedCookie(const std::string& cookie_line)
   1634     : is_valid_(false),
   1635       path_index_(0),
   1636       domain_index_(0),
   1637       expires_index_(0),
   1638       maxage_index_(0),
   1639       secure_index_(0),
   1640       httponly_index_(0) {
   1641 
   1642   if (cookie_line.size() > kMaxCookieSize) {
   1643     VLOG(1) << "Not parsing cookie, too large: " << cookie_line.size();
   1644     return;
   1645   }
   1646 
   1647   ParseTokenValuePairs(cookie_line);
   1648   if (!pairs_.empty()) {
   1649     is_valid_ = true;
   1650     SetupAttributes();
   1651   }
   1652 }
   1653 
   1654 CookieMonster::ParsedCookie::~ParsedCookie() {
   1655 }
   1656 
   1657 // Returns true if |c| occurs in |chars|
   1658 // TODO maybe make this take an iterator, could check for end also?
   1659 static inline bool CharIsA(const char c, const char* chars) {
   1660   return strchr(chars, c) != NULL;
   1661 }
   1662 // Seek the iterator to the first occurrence of a character in |chars|.
   1663 // Returns true if it hit the end, false otherwise.
   1664 static inline bool SeekTo(std::string::const_iterator* it,
   1665                           const std::string::const_iterator& end,
   1666                           const char* chars) {
   1667   for (; *it != end && !CharIsA(**it, chars); ++(*it)) {}
   1668   return *it == end;
   1669 }
   1670 // Seek the iterator to the first occurrence of a character not in |chars|.
   1671 // Returns true if it hit the end, false otherwise.
   1672 static inline bool SeekPast(std::string::const_iterator* it,
   1673                             const std::string::const_iterator& end,
   1674                             const char* chars) {
   1675   for (; *it != end && CharIsA(**it, chars); ++(*it)) {}
   1676   return *it == end;
   1677 }
   1678 static inline bool SeekBackPast(std::string::const_iterator* it,
   1679                                 const std::string::const_iterator& end,
   1680                                 const char* chars) {
   1681   for (; *it != end && CharIsA(**it, chars); --(*it)) {}
   1682   return *it == end;
   1683 }
   1684 
   1685 const char CookieMonster::ParsedCookie::kTerminator[] = "\n\r\0";
   1686 const int CookieMonster::ParsedCookie::kTerminatorLen =
   1687     sizeof(kTerminator) - 1;
   1688 const char CookieMonster::ParsedCookie::kWhitespace[] = " \t";
   1689 const char CookieMonster::ParsedCookie::kValueSeparator[] = ";";
   1690 const char CookieMonster::ParsedCookie::kTokenSeparator[] = ";=";
   1691 
   1692 // Create a cookie-line for the cookie.  For debugging only!
   1693 // If we want to use this for something more than debugging, we
   1694 // should rewrite it better...
   1695 std::string CookieMonster::ParsedCookie::DebugString() const {
   1696   std::string out;
   1697   for (PairList::const_iterator it = pairs_.begin();
   1698        it != pairs_.end(); ++it) {
   1699     out.append(it->first);
   1700     out.append("=");
   1701     out.append(it->second);
   1702     out.append("; ");
   1703   }
   1704   return out;
   1705 }
   1706 
   1707 std::string::const_iterator CookieMonster::ParsedCookie::FindFirstTerminator(
   1708     const std::string& s) {
   1709   std::string::const_iterator end = s.end();
   1710   size_t term_pos =
   1711       s.find_first_of(std::string(kTerminator, kTerminatorLen));
   1712   if (term_pos != std::string::npos) {
   1713     // We found a character we should treat as an end of string.
   1714     end = s.begin() + term_pos;
   1715   }
   1716   return end;
   1717 }
   1718 
   1719 bool CookieMonster::ParsedCookie::ParseToken(
   1720     std::string::const_iterator* it,
   1721     const std::string::const_iterator& end,
   1722     std::string::const_iterator* token_start,
   1723     std::string::const_iterator* token_end) {
   1724   DCHECK(it && token_start && token_end);
   1725   std::string::const_iterator token_real_end;
   1726 
   1727   // Seek past any whitespace before the "token" (the name).
   1728   // token_start should point at the first character in the token
   1729   if (SeekPast(it, end, kWhitespace))
   1730     return false;  // No token, whitespace or empty.
   1731   *token_start = *it;
   1732 
   1733   // Seek over the token, to the token separator.
   1734   // token_real_end should point at the token separator, i.e. '='.
   1735   // If it == end after the seek, we probably have a token-value.
   1736   SeekTo(it, end, kTokenSeparator);
   1737   token_real_end = *it;
   1738 
   1739   // Ignore any whitespace between the token and the token separator.
   1740   // token_end should point after the last interesting token character,
   1741   // pointing at either whitespace, or at '=' (and equal to token_real_end).
   1742   if (*it != *token_start) {  // We could have an empty token name.
   1743     --(*it);  // Go back before the token separator.
   1744     // Skip over any whitespace to the first non-whitespace character.
   1745     SeekBackPast(it, *token_start, kWhitespace);
   1746     // Point after it.
   1747     ++(*it);
   1748   }
   1749   *token_end = *it;
   1750 
   1751   // Seek us back to the end of the token.
   1752   *it = token_real_end;
   1753   return true;
   1754 }
   1755 
   1756 void CookieMonster::ParsedCookie::ParseValue(
   1757     std::string::const_iterator* it,
   1758     const std::string::const_iterator& end,
   1759     std::string::const_iterator* value_start,
   1760     std::string::const_iterator* value_end) {
   1761   DCHECK(it && value_start && value_end);
   1762 
   1763   // Seek past any whitespace that might in-between the token and value.
   1764   SeekPast(it, end, kWhitespace);
   1765   // value_start should point at the first character of the value.
   1766   *value_start = *it;
   1767 
   1768 #ifdef ANDROID
   1769   // It is unclear exactly how quoted string values should be handled.
   1770   // Major browsers do different things, for example, Firefox and Safari support
   1771   // semicolons embedded in a quoted value, while IE does not.  Looking at
   1772   // the specs, RFC 2109 and 2965 allow for a quoted-string as the value.
   1773   // However, these specs were apparently written after browsers had
   1774   // implemented cookies, and they seem very distant from the reality of
   1775   // what is actually implemented and used on the web.  The original spec
   1776   // from Netscape is possibly what is closest to the cookies used today.
   1777   // This spec didn't have explicit support for double quoted strings, and
   1778   // states that ; is not allowed as part of a value.
   1779 
   1780   // The spec disallows control characters and separators in the unquoted value,
   1781   // but we allow all of these, other than the value separator ';'.
   1782 #ifdef ALLOW_QUOTED_COOKIE_VALUES
   1783   // When a value is quoted, the spec states that any text (other than a double
   1784   // quote character, but including an escaped double quote character) is
   1785   // treated as an opaque part of the value. The spec allows for exactly one
   1786   // such quoted string for the value, but we allow multiple such strings,
   1787   // possibly with intermediate separators. This matches our policy of allowing
   1788   // separators in the unquoted value. This matches the behaviour of Safari, but
   1789   // not that of FF.
   1790   bool isInQuotedString = false;
   1791   for (; *it != end && (isInQuotedString || !CharIsA(**it, kValueSeparator)); ++(*it)) {
   1792     // Inside a quoted string, a backslash esacpes the next character, which can
   1793     // be any character and should be ignored.
   1794     if (isInQuotedString && **it == '\\') {
   1795       ++(*it);
   1796       // If this backslash is the last character, we just take what we have.
   1797       if (*it == end)
   1798         break;
   1799       continue;
   1800     }
   1801 
   1802     if (**it == '\"')
   1803       isInQuotedString = !isInQuotedString;
   1804   }
   1805 #else
   1806   // Just look for ';' to terminate ('=' allowed).
   1807   // We can hit the end, maybe they didn't terminate.
   1808   SeekTo(it, end, kValueSeparator);
   1809 #endif
   1810 #endif // ANDROID
   1811 
   1812   // Will be pointed at the ; seperator or the end.
   1813   *value_end = *it;
   1814 
   1815   // Ignore any unwanted whitespace after the value.
   1816   if (*value_end != *value_start) {  // Could have an empty value
   1817     --(*value_end);
   1818     SeekBackPast(value_end, *value_start, kWhitespace);
   1819     ++(*value_end);
   1820   }
   1821 }
   1822 
   1823 std::string CookieMonster::ParsedCookie::ParseTokenString(
   1824     const std::string& token) {
   1825   std::string::const_iterator it = token.begin();
   1826   std::string::const_iterator end = FindFirstTerminator(token);
   1827 
   1828   std::string::const_iterator token_start, token_end;
   1829   if (ParseToken(&it, end, &token_start, &token_end))
   1830     return std::string(token_start, token_end);
   1831   return std::string();
   1832 }
   1833 
   1834 std::string CookieMonster::ParsedCookie::ParseValueString(
   1835     const std::string& value) {
   1836   std::string::const_iterator it = value.begin();
   1837   std::string::const_iterator end = FindFirstTerminator(value);
   1838 
   1839   std::string::const_iterator value_start, value_end;
   1840   ParseValue(&it, end, &value_start, &value_end);
   1841   return std::string(value_start, value_end);
   1842 }
   1843 
   1844 // Parse all token/value pairs and populate pairs_.
   1845 void CookieMonster::ParsedCookie::ParseTokenValuePairs(
   1846     const std::string& cookie_line) {
   1847   pairs_.clear();
   1848 
   1849   // Ok, here we go.  We should be expecting to be starting somewhere
   1850   // before the cookie line, not including any header name...
   1851   std::string::const_iterator start = cookie_line.begin();
   1852   std::string::const_iterator it = start;
   1853 
   1854   // TODO Make sure we're stripping \r\n in the network code.  Then we
   1855   // can log any unexpected terminators.
   1856   std::string::const_iterator end = FindFirstTerminator(cookie_line);
   1857 
   1858   for (int pair_num = 0; pair_num < kMaxPairs && it != end; ++pair_num) {
   1859     TokenValuePair pair;
   1860 
   1861     std::string::const_iterator token_start, token_end;
   1862     if (!ParseToken(&it, end, &token_start, &token_end))
   1863       break;
   1864 
   1865     if (it == end || *it != '=') {
   1866       // We have a token-value, we didn't have any token name.
   1867       if (pair_num == 0) {
   1868         // For the first time around, we want to treat single values
   1869         // as a value with an empty name. (Mozilla bug 169091).
   1870         // IE seems to also have this behavior, ex "AAA", and "AAA=10" will
   1871         // set 2 different cookies, and setting "BBB" will then replace "AAA".
   1872         pair.first = "";
   1873         // Rewind to the beginning of what we thought was the token name,
   1874         // and let it get parsed as a value.
   1875         it = token_start;
   1876       } else {
   1877         // Any not-first attribute we want to treat a value as a
   1878         // name with an empty value...  This is so something like
   1879         // "secure;" will get parsed as a Token name, and not a value.
   1880         pair.first = std::string(token_start, token_end);
   1881       }
   1882     } else {
   1883       // We have a TOKEN=VALUE.
   1884       pair.first = std::string(token_start, token_end);
   1885       ++it;  // Skip past the '='.
   1886     }
   1887 
   1888     // OK, now try to parse a value.
   1889     std::string::const_iterator value_start, value_end;
   1890     ParseValue(&it, end, &value_start, &value_end);
   1891     // OK, we're finished with a Token/Value.
   1892     pair.second = std::string(value_start, value_end);
   1893 
   1894     // From RFC2109: "Attributes (names) (attr) are case-insensitive."
   1895     if (pair_num != 0)
   1896       StringToLowerASCII(&pair.first);
   1897     pairs_.push_back(pair);
   1898 
   1899     // We've processed a token/value pair, we're either at the end of
   1900     // the string or a ValueSeparator like ';', which we want to skip.
   1901     if (it != end)
   1902       ++it;
   1903   }
   1904 }
   1905 
   1906 void CookieMonster::ParsedCookie::SetupAttributes() {
   1907   static const char kPathTokenName[]      = "path";
   1908   static const char kDomainTokenName[]    = "domain";
   1909   static const char kExpiresTokenName[]   = "expires";
   1910   static const char kMaxAgeTokenName[]    = "max-age";
   1911   static const char kSecureTokenName[]    = "secure";
   1912   static const char kHttpOnlyTokenName[]  = "httponly";
   1913 
   1914   // We skip over the first token/value, the user supplied one.
   1915   for (size_t i = 1; i < pairs_.size(); ++i) {
   1916     if (pairs_[i].first == kPathTokenName) {
   1917       path_index_ = i;
   1918     } else if (pairs_[i].first == kDomainTokenName) {
   1919       domain_index_ = i;
   1920     } else if (pairs_[i].first == kExpiresTokenName) {
   1921       expires_index_ = i;
   1922     } else if (pairs_[i].first == kMaxAgeTokenName) {
   1923       maxage_index_ = i;
   1924     } else if (pairs_[i].first == kSecureTokenName) {
   1925       secure_index_ = i;
   1926     } else if (pairs_[i].first == kHttpOnlyTokenName) {
   1927       httponly_index_ = i;
   1928     } else {
   1929       /* some attribute we don't know or don't care about. */
   1930     }
   1931   }
   1932 }
   1933 
   1934 CookieMonster::CanonicalCookie::CanonicalCookie()
   1935     : secure_(false),
   1936       httponly_(false),
   1937       has_expires_(false) {
   1938 }
   1939 
   1940 CookieMonster::CanonicalCookie::CanonicalCookie(const GURL& url,
   1941                                                 const std::string& name,
   1942                                                 const std::string& value,
   1943                                                 const std::string& domain,
   1944                                                 const std::string& path,
   1945                                                 const base::Time& creation,
   1946                                                 const base::Time& expiration,
   1947                                                 const base::Time& last_access,
   1948                                                 bool secure,
   1949                                                 bool httponly,
   1950                                                 bool has_expires)
   1951     : source_(GetCookieSourceFromURL(url)),
   1952       name_(name),
   1953       value_(value),
   1954       domain_(domain),
   1955       path_(path),
   1956       creation_date_(creation),
   1957       expiry_date_(expiration),
   1958       last_access_date_(last_access),
   1959       secure_(secure),
   1960       httponly_(httponly),
   1961       has_expires_(has_expires) {
   1962 }
   1963 
   1964 CookieMonster::CanonicalCookie::CanonicalCookie(const GURL& url,
   1965                                                 const ParsedCookie& pc)
   1966     : source_(GetCookieSourceFromURL(url)),
   1967       name_(pc.Name()),
   1968       value_(pc.Value()),
   1969       path_(CanonPath(url, pc)),
   1970       creation_date_(Time::Now()),
   1971       last_access_date_(Time()),
   1972       secure_(pc.IsSecure()),
   1973       httponly_(pc.IsHttpOnly()),
   1974       has_expires_(pc.HasExpires()) {
   1975   if (has_expires_)
   1976     expiry_date_ = CanonExpiration(pc, creation_date_, CookieOptions());
   1977 
   1978   // Do the best we can with the domain.
   1979   std::string cookie_domain;
   1980   std::string domain_string;
   1981   if (pc.HasDomain()) {
   1982     domain_string = pc.Domain();
   1983   }
   1984   bool result
   1985       = GetCookieDomainWithString(url, domain_string,
   1986                                   &cookie_domain);
   1987   // Caller is responsible for passing in good arguments.
   1988   DCHECK(result);
   1989   domain_ = cookie_domain;
   1990 }
   1991 
   1992 CookieMonster::CanonicalCookie::~CanonicalCookie() {
   1993 }
   1994 
   1995 std::string CookieMonster::CanonicalCookie::GetCookieSourceFromURL(
   1996     const GURL& url) {
   1997   if (url.SchemeIsFile())
   1998     return url.spec();
   1999 
   2000   url_canon::Replacements<char> replacements;
   2001   replacements.ClearPort();
   2002   if (url.SchemeIsSecure())
   2003     replacements.SetScheme("http", url_parse::Component(0, 4));
   2004 
   2005   return url.GetOrigin().ReplaceComponents(replacements).spec();
   2006 }
   2007 
   2008 CookieMonster::CanonicalCookie* CookieMonster::CanonicalCookie::Create(
   2009       const GURL& url,
   2010       const std::string& name,
   2011       const std::string& value,
   2012       const std::string& domain,
   2013       const std::string& path,
   2014       const base::Time& creation,
   2015       const base::Time& expiration,
   2016       bool secure,
   2017       bool http_only) {
   2018   // Expect valid attribute tokens and values, as defined by the ParsedCookie
   2019   // logic, otherwise don't create the cookie.
   2020   std::string parsed_name = ParsedCookie::ParseTokenString(name);
   2021   if (parsed_name != name)
   2022     return NULL;
   2023   std::string parsed_value = ParsedCookie::ParseValueString(value);
   2024   if (parsed_value != value)
   2025     return NULL;
   2026 
   2027   std::string parsed_domain = ParsedCookie::ParseValueString(domain);
   2028   if (parsed_domain != domain)
   2029     return NULL;
   2030   std::string cookie_domain;
   2031   if (!GetCookieDomainWithString(url, parsed_domain, &cookie_domain))
   2032     return NULL;
   2033 
   2034   std::string parsed_path = ParsedCookie::ParseValueString(path);
   2035   if (parsed_path != path)
   2036     return NULL;
   2037 
   2038   std::string cookie_path = CanonPathWithString(url, parsed_path);
   2039   // Expect that the path was either not specified (empty), or is valid.
   2040   if (!parsed_path.empty() && cookie_path != parsed_path)
   2041     return NULL;
   2042   // Canonicalize path again to make sure it escapes characters as needed.
   2043   url_parse::Component path_component(0, cookie_path.length());
   2044   url_canon::RawCanonOutputT<char> canon_path;
   2045   url_parse::Component canon_path_component;
   2046   url_canon::CanonicalizePath(cookie_path.data(), path_component,
   2047                               &canon_path, &canon_path_component);
   2048   cookie_path = std::string(canon_path.data() + canon_path_component.begin,
   2049                             canon_path_component.len);
   2050 
   2051   return new CanonicalCookie(url, parsed_name, parsed_value, cookie_domain,
   2052                              cookie_path, creation, expiration, creation,
   2053                              secure, http_only, !expiration.is_null());
   2054 }
   2055 
   2056 bool CookieMonster::CanonicalCookie::IsOnPath(
   2057     const std::string& url_path) const {
   2058 
   2059   // A zero length would be unsafe for our trailing '/' checks, and
   2060   // would also make no sense for our prefix match.  The code that
   2061   // creates a CanonicalCookie should make sure the path is never zero length,
   2062   // but we double check anyway.
   2063   if (path_.empty())
   2064     return false;
   2065 
   2066   // The Mozilla code broke it into 3 cases, if it's strings lengths
   2067   // are less than, equal, or greater.  I think this is simpler:
   2068 
   2069   // Make sure the cookie path is a prefix of the url path.  If the
   2070   // url path is shorter than the cookie path, then the cookie path
   2071   // can't be a prefix.
   2072   if (url_path.find(path_) != 0)
   2073     return false;
   2074 
   2075   // Now we know that url_path is >= cookie_path, and that cookie_path
   2076   // is a prefix of url_path.  If they are the are the same length then
   2077   // they are identical, otherwise we need an additional check:
   2078 
   2079   // In order to avoid in correctly matching a cookie path of /blah
   2080   // with a request path of '/blahblah/', we need to make sure that either
   2081   // the cookie path ends in a trailing '/', or that we prefix up to a '/'
   2082   // in the url path.  Since we know that the url path length is greater
   2083   // than the cookie path length, it's safe to index one byte past.
   2084   if (path_.length() != url_path.length() &&
   2085       path_[path_.length() - 1] != '/' &&
   2086       url_path[path_.length()] != '/')
   2087     return false;
   2088 
   2089   return true;
   2090 }
   2091 
   2092 bool CookieMonster::CanonicalCookie::IsDomainMatch(
   2093     const std::string& scheme,
   2094     const std::string& host) const {
   2095   // Can domain match in two ways; as a domain cookie (where the cookie
   2096   // domain begins with ".") or as a host cookie (where it doesn't).
   2097 
   2098   // Some consumers of the CookieMonster expect to set cookies on
   2099   // URLs like http://.strange.url.  To retrieve cookies in this instance,
   2100   // we allow matching as a host cookie even when the domain_ starts with
   2101   // a period.
   2102   if (host == domain_)
   2103     return true;
   2104 
   2105   // Domain cookie must have an initial ".".  To match, it must be
   2106   // equal to url's host with initial period removed, or a suffix of
   2107   // it.
   2108 
   2109   // Arguably this should only apply to "http" or "https" cookies, but
   2110   // extension cookie tests currently use the funtionality, and if we
   2111   // ever decide to implement that it should be done by preventing
   2112   // such cookies from being set.
   2113   if (domain_.empty() || domain_[0] != '.')
   2114     return false;
   2115 
   2116   // The host with a "." prefixed.
   2117   if (domain_.compare(1, std::string::npos, host) == 0)
   2118     return true;
   2119 
   2120   // A pure suffix of the host (ok since we know the domain already
   2121   // starts with a ".")
   2122   return (host.length() > domain_.length() &&
   2123           host.compare(host.length() - domain_.length(),
   2124                        domain_.length(), domain_) == 0);
   2125 }
   2126 
   2127 std::string CookieMonster::CanonicalCookie::DebugString() const {
   2128   return base::StringPrintf(
   2129       "name: %s value: %s domain: %s path: %s creation: %"
   2130       PRId64,
   2131       name_.c_str(), value_.c_str(),
   2132       domain_.c_str(), path_.c_str(),
   2133       static_cast<int64>(creation_date_.ToTimeT()));
   2134 }
   2135 
   2136 }  // namespace
   2137