| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // Portions of this code based on Mozilla: | 5 // Portions of this code based on Mozilla: |
| 6 // (netwerk/cookie/src/nsCookieService.cpp) | 6 // (netwerk/cookie/src/nsCookieService.cpp) |
| 7 /* ***** BEGIN LICENSE BLOCK ***** | 7 /* ***** BEGIN LICENSE BLOCK ***** |
| 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | 8 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
| 9 * | 9 * |
| 10 * The contents of this file are subject to the Mozilla Public License Version | 10 * The contents of this file are subject to the Mozilla Public License Version |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 #include "base/logging.h" | 54 #include "base/logging.h" |
| 55 #include "base/memory/scoped_ptr.h" | 55 #include "base/memory/scoped_ptr.h" |
| 56 #include "base/message_loop.h" | 56 #include "base/message_loop.h" |
| 57 #include "base/message_loop_proxy.h" | 57 #include "base/message_loop_proxy.h" |
| 58 #include "base/metrics/histogram.h" | 58 #include "base/metrics/histogram.h" |
| 59 #include "base/string_tokenizer.h" | 59 #include "base/string_tokenizer.h" |
| 60 #include "base/string_util.h" | 60 #include "base/string_util.h" |
| 61 #include "base/stringprintf.h" | 61 #include "base/stringprintf.h" |
| 62 #include "googleurl/src/gurl.h" | 62 #include "googleurl/src/gurl.h" |
| 63 #include "googleurl/src/url_canon.h" | 63 #include "googleurl/src/url_canon.h" |
| 64 #include "net/cookies/canonical_cookie.h" |
| 64 #include "net/cookies/cookie_util.h" | 65 #include "net/cookies/cookie_util.h" |
| 65 #include "net/cookies/parsed_cookie.h" | 66 #include "net/cookies/parsed_cookie.h" |
| 66 #include "net/base/registry_controlled_domain.h" | 67 #include "net/base/registry_controlled_domain.h" |
| 67 | 68 |
| 68 using base::Time; | 69 using base::Time; |
| 69 using base::TimeDelta; | 70 using base::TimeDelta; |
| 70 using base::TimeTicks; | 71 using base::TimeTicks; |
| 71 | 72 |
| 72 // In steady state, most cookie requests can be satisfied by the in memory | 73 // In steady state, most cookie requests can be satisfied by the in memory |
| 73 // cookie monster store. However, if a request comes in during the initial | 74 // cookie monster store. However, if a request comes in during the initial |
| (...skipping 22 matching lines...) Expand all Loading... |
| 96 // See comments at declaration of these variables in cookie_monster.h | 97 // See comments at declaration of these variables in cookie_monster.h |
| 97 // for details. | 98 // for details. |
| 98 const size_t CookieMonster::kDomainMaxCookies = 180; | 99 const size_t CookieMonster::kDomainMaxCookies = 180; |
| 99 const size_t CookieMonster::kDomainPurgeCookies = 30; | 100 const size_t CookieMonster::kDomainPurgeCookies = 30; |
| 100 const size_t CookieMonster::kMaxCookies = 3300; | 101 const size_t CookieMonster::kMaxCookies = 3300; |
| 101 const size_t CookieMonster::kPurgeCookies = 300; | 102 const size_t CookieMonster::kPurgeCookies = 300; |
| 102 const int CookieMonster::kSafeFromGlobalPurgeDays = 30; | 103 const int CookieMonster::kSafeFromGlobalPurgeDays = 30; |
| 103 | 104 |
| 104 namespace { | 105 namespace { |
| 105 | 106 |
| 106 typedef std::vector<CookieMonster::CanonicalCookie*> CanonicalCookieVector; | 107 typedef std::vector<CanonicalCookie*> CanonicalCookieVector; |
| 107 | 108 |
| 108 // Default minimum delay after updating a cookie's LastAccessDate before we | 109 // Default minimum delay after updating a cookie's LastAccessDate before we |
| 109 // will update it again. | 110 // will update it again. |
| 110 const int kDefaultAccessUpdateThresholdSeconds = 60; | 111 const int kDefaultAccessUpdateThresholdSeconds = 60; |
| 111 | 112 |
| 112 // Comparator to sort cookies from highest creation date to lowest | 113 // Comparator to sort cookies from highest creation date to lowest |
| 113 // creation date. | 114 // creation date. |
| 114 struct OrderByCreationTimeDesc { | 115 struct OrderByCreationTimeDesc { |
| 115 bool operator()(const CookieMonster::CookieMap::iterator& a, | 116 bool operator()(const CookieMonster::CookieMap::iterator& a, |
| 116 const CookieMonster::CookieMap::iterator& b) const { | 117 const CookieMonster::CookieMap::iterator& b) const { |
| 117 return a->second->CreationDate() > b->second->CreationDate(); | 118 return a->second->CreationDate() > b->second->CreationDate(); |
| 118 } | 119 } |
| 119 }; | 120 }; |
| 120 | 121 |
| 121 // Constants for use in VLOG | 122 // Constants for use in VLOG |
| 122 const int kVlogPerCookieMonster = 1; | 123 const int kVlogPerCookieMonster = 1; |
| 123 const int kVlogPeriodic = 3; | 124 const int kVlogPeriodic = 3; |
| 124 const int kVlogGarbageCollection = 5; | 125 const int kVlogGarbageCollection = 5; |
| 125 const int kVlogSetCookies = 7; | 126 const int kVlogSetCookies = 7; |
| 126 const int kVlogGetCookies = 9; | 127 const int kVlogGetCookies = 9; |
| 127 | 128 |
| 128 #if defined(ENABLE_PERSISTENT_SESSION_COOKIES) | 129 #if defined(ENABLE_PERSISTENT_SESSION_COOKIES) |
| 129 const int kPersistentSessionCookieExpiryInDays = 14; | 130 const int kPersistentSessionCookieExpiryInDays = 14; |
| 130 #endif | 131 #endif |
| 131 | 132 |
| 132 // Mozilla sorts on the path length (longest first), and then it | 133 // Mozilla sorts on the path length (longest first), and then it |
| 133 // sorts by creation time (oldest first). | 134 // sorts by creation time (oldest first). |
| 134 // The RFC says the sort order for the domain attribute is undefined. | 135 // The RFC says the sort order for the domain attribute is undefined. |
| 135 bool CookieSorter(CookieMonster::CanonicalCookie* cc1, | 136 bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) { |
| 136 CookieMonster::CanonicalCookie* cc2) { | |
| 137 if (cc1->Path().length() == cc2->Path().length()) | 137 if (cc1->Path().length() == cc2->Path().length()) |
| 138 return cc1->CreationDate() < cc2->CreationDate(); | 138 return cc1->CreationDate() < cc2->CreationDate(); |
| 139 return cc1->Path().length() > cc2->Path().length(); | 139 return cc1->Path().length() > cc2->Path().length(); |
| 140 } | 140 } |
| 141 | 141 |
| 142 bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1, | 142 bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1, |
| 143 const CookieMonster::CookieMap::iterator& it2) { | 143 const CookieMonster::CookieMap::iterator& it2) { |
| 144 // Cookies accessed less recently should be deleted first. | 144 // Cookies accessed less recently should be deleted first. |
| 145 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) | 145 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) |
| 146 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); | 146 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 // Determine the cookie domain to use for setting the specified cookie. | 192 // Determine the cookie domain to use for setting the specified cookie. |
| 193 bool GetCookieDomain(const GURL& url, | 193 bool GetCookieDomain(const GURL& url, |
| 194 const ParsedCookie& pc, | 194 const ParsedCookie& pc, |
| 195 std::string* result) { | 195 std::string* result) { |
| 196 std::string domain_string; | 196 std::string domain_string; |
| 197 if (pc.HasDomain()) | 197 if (pc.HasDomain()) |
| 198 domain_string = pc.Domain(); | 198 domain_string = pc.Domain(); |
| 199 return cookie_util::GetCookieDomainWithString(url, domain_string, result); | 199 return cookie_util::GetCookieDomainWithString(url, domain_string, result); |
| 200 } | 200 } |
| 201 | 201 |
| 202 std::string CanonPathWithString(const GURL& url, | |
| 203 const std::string& path_string) { | |
| 204 // The RFC says the path should be a prefix of the current URL path. | |
| 205 // However, Mozilla allows you to set any path for compatibility with | |
| 206 // broken websites. We unfortunately will mimic this behavior. We try | |
| 207 // to be generous and accept cookies with an invalid path attribute, and | |
| 208 // default the path to something reasonable. | |
| 209 | |
| 210 // The path was supplied in the cookie, we'll take it. | |
| 211 if (!path_string.empty() && path_string[0] == '/') | |
| 212 return path_string; | |
| 213 | |
| 214 // The path was not supplied in the cookie or invalid, we will default | |
| 215 // to the current URL path. | |
| 216 // """Defaults to the path of the request URL that generated the | |
| 217 // Set-Cookie response, up to, but not including, the | |
| 218 // right-most /.""" | |
| 219 // How would this work for a cookie on /? We will include it then. | |
| 220 const std::string& url_path = url.path(); | |
| 221 | |
| 222 size_t idx = url_path.find_last_of('/'); | |
| 223 | |
| 224 // The cookie path was invalid or a single '/'. | |
| 225 if (idx == 0 || idx == std::string::npos) | |
| 226 return std::string("/"); | |
| 227 | |
| 228 // Return up to the rightmost '/'. | |
| 229 return url_path.substr(0, idx); | |
| 230 } | |
| 231 | |
| 232 std::string CanonPath(const GURL& url, const ParsedCookie& pc) { | |
| 233 std::string path_string; | |
| 234 if (pc.HasPath()) | |
| 235 path_string = pc.Path(); | |
| 236 return CanonPathWithString(url, path_string); | |
| 237 } | |
| 238 | |
| 239 Time CanonExpiration(const ParsedCookie& pc, | |
| 240 const Time& current, | |
| 241 const Time& server_time) { | |
| 242 // First, try the Max-Age attribute. | |
| 243 uint64 max_age = 0; | |
| 244 if (pc.HasMaxAge() && | |
| 245 #ifdef COMPILER_MSVC | |
| 246 sscanf_s( | |
| 247 #else | |
| 248 sscanf( | |
| 249 #endif | |
| 250 pc.MaxAge().c_str(), " %" PRIu64, &max_age) == 1) { | |
| 251 return current + TimeDelta::FromSeconds(max_age); | |
| 252 } | |
| 253 | |
| 254 // Try the Expires attribute. | |
| 255 if (pc.HasExpires()) { | |
| 256 // Adjust for clock skew between server and host. | |
| 257 return current + (CookieMonster::ParseCookieTime(pc.Expires()) - | |
| 258 server_time); | |
| 259 } | |
| 260 | |
| 261 // Invalid or no expiration, persistent cookie. | |
| 262 return Time(); | |
| 263 } | |
| 264 | |
| 265 // Helper for GarbageCollection. If |cookie_its->size() > num_max|, remove the | 202 // Helper for GarbageCollection. If |cookie_its->size() > num_max|, remove the |
| 266 // |num_max - num_purge| most recently accessed cookies from cookie_its. | 203 // |num_max - num_purge| most recently accessed cookies from cookie_its. |
| 267 // (In other words, leave the entries that are candidates for | 204 // (In other words, leave the entries that are candidates for |
| 268 // eviction in cookie_its.) The cookies returned will be in order sorted by | 205 // eviction in cookie_its.) The cookies returned will be in order sorted by |
| 269 // access time, least recently accessed first. The access time of the least | 206 // access time, least recently accessed first. The access time of the least |
| 270 // recently accessed entry not returned will be placed in | 207 // recently accessed entry not returned will be placed in |
| 271 // |*lra_removed| if that pointer is set. FindLeastRecentlyAccessed | 208 // |*lra_removed| if that pointer is set. FindLeastRecentlyAccessed |
| 272 // returns false if no manipulation is done (because the list size is less | 209 // returns false if no manipulation is done (because the list size is less |
| 273 // than num_max), true otherwise. | 210 // than num_max), true otherwise. |
| 274 bool FindLeastRecentlyAccessed( | 211 bool FindLeastRecentlyAccessed( |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 cookie_line += (*it)->Name() + "="; | 278 cookie_line += (*it)->Name() + "="; |
| 342 cookie_line += (*it)->Value(); | 279 cookie_line += (*it)->Value(); |
| 343 } | 280 } |
| 344 return cookie_line; | 281 return cookie_line; |
| 345 } | 282 } |
| 346 | 283 |
| 347 void BuildCookieInfoList(const CanonicalCookieVector& cookies, | 284 void BuildCookieInfoList(const CanonicalCookieVector& cookies, |
| 348 std::vector<CookieStore::CookieInfo>* cookie_infos) { | 285 std::vector<CookieStore::CookieInfo>* cookie_infos) { |
| 349 for (CanonicalCookieVector::const_iterator it = cookies.begin(); | 286 for (CanonicalCookieVector::const_iterator it = cookies.begin(); |
| 350 it != cookies.end(); ++it) { | 287 it != cookies.end(); ++it) { |
| 351 const CookieMonster::CanonicalCookie* cookie = *it; | 288 const CanonicalCookie* cookie = *it; |
| 352 CookieStore::CookieInfo cookie_info; | 289 CookieStore::CookieInfo cookie_info; |
| 353 | 290 |
| 354 cookie_info.name = cookie->Name(); | 291 cookie_info.name = cookie->Name(); |
| 355 cookie_info.creation_date = cookie->CreationDate(); | 292 cookie_info.creation_date = cookie->CreationDate(); |
| 356 cookie_info.mac_key = cookie->MACKey(); | 293 cookie_info.mac_key = cookie->MACKey(); |
| 357 cookie_info.mac_algorithm = cookie->MACAlgorithm(); | 294 cookie_info.mac_algorithm = cookie->MACAlgorithm(); |
| 358 | 295 |
| 359 cookie_infos->push_back(cookie_info); | 296 cookie_infos->push_back(cookie_info); |
| 360 } | 297 } |
| 361 } | 298 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 388 last_access_threshold_(base::TimeDelta::FromMilliseconds( | 325 last_access_threshold_(base::TimeDelta::FromMilliseconds( |
| 389 last_access_threshold_milliseconds)), | 326 last_access_threshold_milliseconds)), |
| 390 delegate_(delegate), | 327 delegate_(delegate), |
| 391 last_statistic_record_time_(base::Time::Now()), | 328 last_statistic_record_time_(base::Time::Now()), |
| 392 keep_expired_cookies_(false), | 329 keep_expired_cookies_(false), |
| 393 persist_session_cookies_(false) { | 330 persist_session_cookies_(false) { |
| 394 InitializeHistograms(); | 331 InitializeHistograms(); |
| 395 SetDefaultCookieableSchemes(); | 332 SetDefaultCookieableSchemes(); |
| 396 } | 333 } |
| 397 | 334 |
| 398 // Parse a cookie expiration time. We try to be lenient, but we need to | |
| 399 // assume some order to distinguish the fields. The basic rules: | |
| 400 // - The month name must be present and prefix the first 3 letters of the | |
| 401 // full month name (jan for January, jun for June). | |
| 402 // - If the year is <= 2 digits, it must occur after the day of month. | |
| 403 // - The time must be of the format hh:mm:ss. | |
| 404 // An average cookie expiration will look something like this: | |
| 405 // Sat, 15-Apr-17 21:01:22 GMT | |
| 406 Time CookieMonster::ParseCookieTime(const std::string& time_string) { | |
| 407 static const char* kMonths[] = { "jan", "feb", "mar", "apr", "may", "jun", | |
| 408 "jul", "aug", "sep", "oct", "nov", "dec" }; | |
| 409 static const int kMonthsLen = arraysize(kMonths); | |
| 410 // We want to be pretty liberal, and support most non-ascii and non-digit | |
| 411 // characters as a delimiter. We can't treat : as a delimiter, because it | |
| 412 // is the delimiter for hh:mm:ss, and we want to keep this field together. | |
| 413 // We make sure to include - and +, since they could prefix numbers. | |
| 414 // If the cookie attribute came in in quotes (ex expires="XXX"), the quotes | |
| 415 // will be preserved, and we will get them here. So we make sure to include | |
| 416 // quote characters, and also \ for anything that was internally escaped. | |
| 417 static const char* kDelimiters = "\t !\"#$%&'()*+,-./;<=>?@[\\]^_`{|}~"; | |
| 418 | |
| 419 Time::Exploded exploded = {0}; | |
| 420 | |
| 421 StringTokenizer tokenizer(time_string, kDelimiters); | |
| 422 | |
| 423 bool found_day_of_month = false; | |
| 424 bool found_month = false; | |
| 425 bool found_time = false; | |
| 426 bool found_year = false; | |
| 427 | |
| 428 while (tokenizer.GetNext()) { | |
| 429 const std::string token = tokenizer.token(); | |
| 430 DCHECK(!token.empty()); | |
| 431 bool numerical = IsAsciiDigit(token[0]); | |
| 432 | |
| 433 // String field | |
| 434 if (!numerical) { | |
| 435 if (!found_month) { | |
| 436 for (int i = 0; i < kMonthsLen; ++i) { | |
| 437 // Match prefix, so we could match January, etc | |
| 438 if (base::strncasecmp(token.c_str(), kMonths[i], 3) == 0) { | |
| 439 exploded.month = i + 1; | |
| 440 found_month = true; | |
| 441 break; | |
| 442 } | |
| 443 } | |
| 444 } else { | |
| 445 // If we've gotten here, it means we've already found and parsed our | |
| 446 // month, and we have another string, which we would expect to be the | |
| 447 // the time zone name. According to the RFC and my experiments with | |
| 448 // how sites format their expirations, we don't have much of a reason | |
| 449 // to support timezones. We don't want to ever barf on user input, | |
| 450 // but this DCHECK should pass for well-formed data. | |
| 451 // DCHECK(token == "GMT"); | |
| 452 } | |
| 453 // Numeric field w/ a colon | |
| 454 } else if (token.find(':') != std::string::npos) { | |
| 455 if (!found_time && | |
| 456 #ifdef COMPILER_MSVC | |
| 457 sscanf_s( | |
| 458 #else | |
| 459 sscanf( | |
| 460 #endif | |
| 461 token.c_str(), "%2u:%2u:%2u", &exploded.hour, | |
| 462 &exploded.minute, &exploded.second) == 3) { | |
| 463 found_time = true; | |
| 464 } else { | |
| 465 // We should only ever encounter one time-like thing. If we're here, | |
| 466 // it means we've found a second, which shouldn't happen. We keep | |
| 467 // the first. This check should be ok for well-formed input: | |
| 468 // NOTREACHED(); | |
| 469 } | |
| 470 // Numeric field | |
| 471 } else { | |
| 472 // Overflow with atoi() is unspecified, so we enforce a max length. | |
| 473 if (!found_day_of_month && token.length() <= 2) { | |
| 474 exploded.day_of_month = atoi(token.c_str()); | |
| 475 found_day_of_month = true; | |
| 476 } else if (!found_year && token.length() <= 5) { | |
| 477 exploded.year = atoi(token.c_str()); | |
| 478 found_year = true; | |
| 479 } else { | |
| 480 // If we're here, it means we've either found an extra numeric field, | |
| 481 // or a numeric field which was too long. For well-formed input, the | |
| 482 // following check would be reasonable: | |
| 483 // NOTREACHED(); | |
| 484 } | |
| 485 } | |
| 486 } | |
| 487 | |
| 488 if (!found_day_of_month || !found_month || !found_time || !found_year) { | |
| 489 // We didn't find all of the fields we need. For well-formed input, the | |
| 490 // following check would be reasonable: | |
| 491 // NOTREACHED() << "Cookie parse expiration failed: " << time_string; | |
| 492 return Time(); | |
| 493 } | |
| 494 | |
| 495 // Normalize the year to expand abbreviated years to the full year. | |
| 496 if (exploded.year >= 69 && exploded.year <= 99) | |
| 497 exploded.year += 1900; | |
| 498 if (exploded.year >= 0 && exploded.year <= 68) | |
| 499 exploded.year += 2000; | |
| 500 | |
| 501 // If our values are within their correct ranges, we got our time. | |
| 502 if (exploded.day_of_month >= 1 && exploded.day_of_month <= 31 && | |
| 503 exploded.month >= 1 && exploded.month <= 12 && | |
| 504 exploded.year >= 1601 && exploded.year <= 30827 && | |
| 505 exploded.hour <= 23 && exploded.minute <= 59 && exploded.second <= 59) { | |
| 506 return Time::FromUTCExploded(exploded); | |
| 507 } | |
| 508 | |
| 509 // One of our values was out of expected range. For well-formed input, | |
| 510 // the following check would be reasonable: | |
| 511 // NOTREACHED() << "Cookie exploded expiration failed: " << time_string; | |
| 512 | |
| 513 return Time(); | |
| 514 } | |
| 515 | 335 |
| 516 // Task classes for queueing the coming request. | 336 // Task classes for queueing the coming request. |
| 517 | 337 |
| 518 class CookieMonster::CookieMonsterTask | 338 class CookieMonster::CookieMonsterTask |
| 519 : public base::RefCountedThreadSafe<CookieMonsterTask> { | 339 : public base::RefCountedThreadSafe<CookieMonsterTask> { |
| 520 public: | 340 public: |
| 521 // Runs the task and invokes the client callback on the thread that | 341 // Runs the task and invokes the client callback on the thread that |
| 522 // originally constructed the task. | 342 // originally constructed the task. |
| 523 virtual void Run() = 0; | 343 virtual void Run() = 0; |
| 524 | 344 |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 791 base::Unretained(&callback_), num_deleted)); | 611 base::Unretained(&callback_), num_deleted)); |
| 792 } | 612 } |
| 793 } | 613 } |
| 794 | 614 |
| 795 // Task class for DeleteCanonicalCookie call. | 615 // Task class for DeleteCanonicalCookie call. |
| 796 class CookieMonster::DeleteCanonicalCookieTask | 616 class CookieMonster::DeleteCanonicalCookieTask |
| 797 : public CookieMonster::CookieMonsterTask { | 617 : public CookieMonster::CookieMonsterTask { |
| 798 public: | 618 public: |
| 799 DeleteCanonicalCookieTask( | 619 DeleteCanonicalCookieTask( |
| 800 CookieMonster* cookie_monster, | 620 CookieMonster* cookie_monster, |
| 801 const CookieMonster::CanonicalCookie& cookie, | 621 const CanonicalCookie& cookie, |
| 802 const CookieMonster::DeleteCookieCallback& callback) | 622 const CookieMonster::DeleteCookieCallback& callback) |
| 803 : CookieMonsterTask(cookie_monster), | 623 : CookieMonsterTask(cookie_monster), |
| 804 cookie_(cookie), | 624 cookie_(cookie), |
| 805 callback_(callback) { | 625 callback_(callback) { |
| 806 } | 626 } |
| 807 | 627 |
| 808 // CookieMonster::CookieMonsterTask: | 628 // CookieMonster::CookieMonsterTask: |
| 809 virtual void Run() OVERRIDE; | 629 virtual void Run() OVERRIDE; |
| 810 | 630 |
| 811 protected: | 631 protected: |
| 812 virtual ~DeleteCanonicalCookieTask() {} | 632 virtual ~DeleteCanonicalCookieTask() {} |
| 813 | 633 |
| 814 private: | 634 private: |
| 815 CookieMonster::CanonicalCookie cookie_; | 635 CanonicalCookie cookie_; |
| 816 CookieMonster::DeleteCookieCallback callback_; | 636 CookieMonster::DeleteCookieCallback callback_; |
| 817 | 637 |
| 818 DISALLOW_COPY_AND_ASSIGN(DeleteCanonicalCookieTask); | 638 DISALLOW_COPY_AND_ASSIGN(DeleteCanonicalCookieTask); |
| 819 }; | 639 }; |
| 820 | 640 |
| 821 void CookieMonster::DeleteCanonicalCookieTask::Run() { | 641 void CookieMonster::DeleteCanonicalCookieTask::Run() { |
| 822 bool result = this->cookie_monster()->DeleteCanonicalCookie(cookie_); | 642 bool result = this->cookie_monster()->DeleteCanonicalCookie(cookie_); |
| 823 if (!callback_.is_null()) { | 643 if (!callback_.is_null()) { |
| 824 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCookieCallback::Run, | 644 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCookieCallback::Run, |
| 825 base::Unretained(&callback_), result)); | 645 base::Unretained(&callback_), result)); |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1204 CookieOptions options; | 1024 CookieOptions options; |
| 1205 options.set_include_httponly(); | 1025 options.set_include_httponly(); |
| 1206 return SetCanonicalCookie(&cc, creation_time, options); | 1026 return SetCanonicalCookie(&cc, creation_time, options); |
| 1207 } | 1027 } |
| 1208 | 1028 |
| 1209 bool CookieMonster::InitializeFrom(const CookieList& list) { | 1029 bool CookieMonster::InitializeFrom(const CookieList& list) { |
| 1210 base::AutoLock autolock(lock_); | 1030 base::AutoLock autolock(lock_); |
| 1211 InitIfNecessary(); | 1031 InitIfNecessary(); |
| 1212 for (net::CookieList::const_iterator iter = list.begin(); | 1032 for (net::CookieList::const_iterator iter = list.begin(); |
| 1213 iter != list.end(); ++iter) { | 1033 iter != list.end(); ++iter) { |
| 1214 scoped_ptr<net::CookieMonster::CanonicalCookie> cookie; | 1034 scoped_ptr<CanonicalCookie> cookie(new CanonicalCookie(*iter)); |
| 1215 cookie.reset(new net::CookieMonster::CanonicalCookie(*iter)); | |
| 1216 net::CookieOptions options; | 1035 net::CookieOptions options; |
| 1217 options.set_include_httponly(); | 1036 options.set_include_httponly(); |
| 1218 if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), | 1037 if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), options)) |
| 1219 options)) { | |
| 1220 return false; | 1038 return false; |
| 1221 } | |
| 1222 } | 1039 } |
| 1223 return true; | 1040 return true; |
| 1224 } | 1041 } |
| 1225 | 1042 |
| 1226 CookieList CookieMonster::GetAllCookies() { | 1043 CookieList CookieMonster::GetAllCookies() { |
| 1227 base::AutoLock autolock(lock_); | 1044 base::AutoLock autolock(lock_); |
| 1228 | 1045 |
| 1229 // This function is being called to scrape the cookie list for management UI | 1046 // This function is being called to scrape the cookie list for management UI |
| 1230 // or similar. We shouldn't show expired cookies in this list since it will | 1047 // or similar. We shouldn't show expired cookies in this list since it will |
| 1231 // just be confusing to users, and this function is called rarely enough (and | 1048 // just be confusing to users, and this function is called rarely enough (and |
| (...skipping 678 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1910 if (options.exclude_httponly() && pc.IsHttpOnly()) { | 1727 if (options.exclude_httponly() && pc.IsHttpOnly()) { |
| 1911 VLOG(kVlogSetCookies) << "SetCookie() not setting httponly cookie"; | 1728 VLOG(kVlogSetCookies) << "SetCookie() not setting httponly cookie"; |
| 1912 return false; | 1729 return false; |
| 1913 } | 1730 } |
| 1914 | 1731 |
| 1915 std::string cookie_domain; | 1732 std::string cookie_domain; |
| 1916 if (!GetCookieDomain(url, pc, &cookie_domain)) { | 1733 if (!GetCookieDomain(url, pc, &cookie_domain)) { |
| 1917 return false; | 1734 return false; |
| 1918 } | 1735 } |
| 1919 | 1736 |
| 1920 std::string cookie_path = CanonPath(url, pc); | 1737 std::string cookie_path = CanonicalCookie::CanonPath(url, pc); |
| 1921 std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string(); | 1738 std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string(); |
| 1922 std::string mac_algorithm = pc.HasMACAlgorithm() ? | 1739 std::string mac_algorithm = pc.HasMACAlgorithm() ? |
| 1923 pc.MACAlgorithm() : std::string(); | 1740 pc.MACAlgorithm() : std::string(); |
| 1924 | 1741 |
| 1925 scoped_ptr<CanonicalCookie> cc; | 1742 scoped_ptr<CanonicalCookie> cc; |
| 1926 Time cookie_expires = CanonExpiration(pc, creation_time, server_time); | 1743 Time cookie_expires = |
| 1744 CanonicalCookie::CanonExpiration(pc, creation_time, server_time); |
| 1927 | 1745 |
| 1928 cc.reset(new CanonicalCookie(url, pc.Name(), pc.Value(), cookie_domain, | 1746 cc.reset(new CanonicalCookie(url, pc.Name(), pc.Value(), cookie_domain, |
| 1929 cookie_path, mac_key, mac_algorithm, | 1747 cookie_path, mac_key, mac_algorithm, |
| 1930 creation_time, cookie_expires, | 1748 creation_time, cookie_expires, |
| 1931 creation_time, pc.IsSecure(), pc.IsHttpOnly())); | 1749 creation_time, pc.IsSecure(), pc.IsHttpOnly())); |
| 1932 | 1750 |
| 1933 if (!cc.get()) { | 1751 if (!cc.get()) { |
| 1934 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie"; | 1752 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie"; |
| 1935 return false; | 1753 return false; |
| 1936 } | 1754 } |
| (...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2337 | 2155 |
| 2338 | 2156 |
| 2339 // The system resolution is not high enough, so we can have multiple | 2157 // The system resolution is not high enough, so we can have multiple |
| 2340 // set cookies that result in the same system time. When this happens, we | 2158 // set cookies that result in the same system time. When this happens, we |
| 2341 // increment by one Time unit. Let's hope computers don't get too fast. | 2159 // increment by one Time unit. Let's hope computers don't get too fast. |
| 2342 Time CookieMonster::CurrentTime() { | 2160 Time CookieMonster::CurrentTime() { |
| 2343 return std::max(Time::Now(), | 2161 return std::max(Time::Now(), |
| 2344 Time::FromInternalValue(last_time_seen_.ToInternalValue() + 1)); | 2162 Time::FromInternalValue(last_time_seen_.ToInternalValue() + 1)); |
| 2345 } | 2163 } |
| 2346 | 2164 |
| 2347 CookieMonster::CanonicalCookie::CanonicalCookie() | |
| 2348 : secure_(false), | |
| 2349 httponly_(false) { | |
| 2350 SetSessionCookieExpiryTime(); | |
| 2351 } | |
| 2352 | |
| 2353 CookieMonster::CanonicalCookie::CanonicalCookie( | |
| 2354 const GURL& url, const std::string& name, const std::string& value, | |
| 2355 const std::string& domain, const std::string& path, | |
| 2356 const std::string& mac_key, const std::string& mac_algorithm, | |
| 2357 const base::Time& creation, const base::Time& expiration, | |
| 2358 const base::Time& last_access, bool secure, bool httponly) | |
| 2359 : source_(GetCookieSourceFromURL(url)), | |
| 2360 name_(name), | |
| 2361 value_(value), | |
| 2362 domain_(domain), | |
| 2363 path_(path), | |
| 2364 mac_key_(mac_key), | |
| 2365 mac_algorithm_(mac_algorithm), | |
| 2366 creation_date_(creation), | |
| 2367 expiry_date_(expiration), | |
| 2368 last_access_date_(last_access), | |
| 2369 secure_(secure), | |
| 2370 httponly_(httponly) { | |
| 2371 if (expiration.is_null()) | |
| 2372 SetSessionCookieExpiryTime(); | |
| 2373 } | |
| 2374 | |
| 2375 CookieMonster::CanonicalCookie::CanonicalCookie(const GURL& url, | |
| 2376 const ParsedCookie& pc) | |
| 2377 : source_(GetCookieSourceFromURL(url)), | |
| 2378 name_(pc.Name()), | |
| 2379 value_(pc.Value()), | |
| 2380 path_(CanonPath(url, pc)), | |
| 2381 mac_key_(pc.MACKey()), | |
| 2382 mac_algorithm_(pc.MACAlgorithm()), | |
| 2383 creation_date_(Time::Now()), | |
| 2384 last_access_date_(Time()), | |
| 2385 secure_(pc.IsSecure()), | |
| 2386 httponly_(pc.IsHttpOnly()) { | |
| 2387 if (pc.HasExpires()) | |
| 2388 expiry_date_ = CanonExpiration(pc, creation_date_, creation_date_); | |
| 2389 else | |
| 2390 SetSessionCookieExpiryTime(); | |
| 2391 | |
| 2392 // Do the best we can with the domain. | |
| 2393 std::string cookie_domain; | |
| 2394 std::string domain_string; | |
| 2395 if (pc.HasDomain()) { | |
| 2396 domain_string = pc.Domain(); | |
| 2397 } | |
| 2398 bool result | |
| 2399 = cookie_util::GetCookieDomainWithString(url, domain_string, | |
| 2400 &cookie_domain); | |
| 2401 // Caller is responsible for passing in good arguments. | |
| 2402 DCHECK(result); | |
| 2403 domain_ = cookie_domain; | |
| 2404 } | |
| 2405 | |
| 2406 CookieMonster::CanonicalCookie::~CanonicalCookie() { | |
| 2407 } | |
| 2408 | |
| 2409 std::string CookieMonster::CanonicalCookie::GetCookieSourceFromURL( | |
| 2410 const GURL& url) { | |
| 2411 if (url.SchemeIsFile()) | |
| 2412 return url.spec(); | |
| 2413 | |
| 2414 url_canon::Replacements<char> replacements; | |
| 2415 replacements.ClearPort(); | |
| 2416 if (url.SchemeIsSecure()) | |
| 2417 replacements.SetScheme("http", url_parse::Component(0, 4)); | |
| 2418 | |
| 2419 return url.GetOrigin().ReplaceComponents(replacements).spec(); | |
| 2420 } | |
| 2421 | |
| 2422 void CookieMonster::CanonicalCookie::SetSessionCookieExpiryTime() { | |
| 2423 #if defined(ENABLE_PERSISTENT_SESSION_COOKIES) | |
| 2424 // Mobile apps can sometimes be shut down without any warning, so the session | |
| 2425 // cookie has to be persistent and given a default expiration time. | |
| 2426 expiry_date_ = base::Time::Now() + | |
| 2427 base::TimeDelta::FromDays(kPersistentSessionCookieExpiryInDays); | |
| 2428 #endif | |
| 2429 } | |
| 2430 | |
| 2431 CookieMonster::CanonicalCookie* CookieMonster::CanonicalCookie::Create( | |
| 2432 const GURL& url, | |
| 2433 const ParsedCookie& pc) { | |
| 2434 if (!pc.IsValid()) { | |
| 2435 return NULL; | |
| 2436 } | |
| 2437 | |
| 2438 std::string domain_string; | |
| 2439 if (!GetCookieDomain(url, pc, &domain_string)) { | |
| 2440 return NULL; | |
| 2441 } | |
| 2442 std::string path_string = CanonPath(url, pc); | |
| 2443 std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string(); | |
| 2444 std::string mac_algorithm = pc.HasMACAlgorithm() ? | |
| 2445 pc.MACAlgorithm() : std::string(); | |
| 2446 Time creation_time = Time::Now(); | |
| 2447 Time expiration_time; | |
| 2448 if (pc.HasExpires()) | |
| 2449 expiration_time = net::CookieMonster::ParseCookieTime(pc.Expires()); | |
| 2450 | |
| 2451 return (Create(url, pc.Name(), pc.Value(), domain_string, path_string, | |
| 2452 mac_key, mac_algorithm, creation_time, expiration_time, | |
| 2453 pc.IsSecure(), pc.IsHttpOnly())); | |
| 2454 } | |
| 2455 | |
| 2456 CookieMonster::CanonicalCookie* CookieMonster::CanonicalCookie::Create( | |
| 2457 const GURL& url, | |
| 2458 const std::string& name, | |
| 2459 const std::string& value, | |
| 2460 const std::string& domain, | |
| 2461 const std::string& path, | |
| 2462 const std::string& mac_key, | |
| 2463 const std::string& mac_algorithm, | |
| 2464 const base::Time& creation, | |
| 2465 const base::Time& expiration, | |
| 2466 bool secure, | |
| 2467 bool http_only) { | |
| 2468 // Expect valid attribute tokens and values, as defined by the ParsedCookie | |
| 2469 // logic, otherwise don't create the cookie. | |
| 2470 std::string parsed_name = ParsedCookie::ParseTokenString(name); | |
| 2471 if (parsed_name != name) | |
| 2472 return NULL; | |
| 2473 std::string parsed_value = ParsedCookie::ParseValueString(value); | |
| 2474 if (parsed_value != value) | |
| 2475 return NULL; | |
| 2476 | |
| 2477 std::string parsed_domain = ParsedCookie::ParseValueString(domain); | |
| 2478 if (parsed_domain != domain) | |
| 2479 return NULL; | |
| 2480 std::string cookie_domain; | |
| 2481 if (!cookie_util::GetCookieDomainWithString(url, parsed_domain, | |
| 2482 &cookie_domain)) { | |
| 2483 return NULL; | |
| 2484 } | |
| 2485 | |
| 2486 std::string parsed_path = ParsedCookie::ParseValueString(path); | |
| 2487 if (parsed_path != path) | |
| 2488 return NULL; | |
| 2489 | |
| 2490 std::string cookie_path = CanonPathWithString(url, parsed_path); | |
| 2491 // Expect that the path was either not specified (empty), or is valid. | |
| 2492 if (!parsed_path.empty() && cookie_path != parsed_path) | |
| 2493 return NULL; | |
| 2494 // Canonicalize path again to make sure it escapes characters as needed. | |
| 2495 url_parse::Component path_component(0, cookie_path.length()); | |
| 2496 url_canon::RawCanonOutputT<char> canon_path; | |
| 2497 url_parse::Component canon_path_component; | |
| 2498 url_canon::CanonicalizePath(cookie_path.data(), path_component, | |
| 2499 &canon_path, &canon_path_component); | |
| 2500 cookie_path = std::string(canon_path.data() + canon_path_component.begin, | |
| 2501 canon_path_component.len); | |
| 2502 | |
| 2503 return new CanonicalCookie(url, parsed_name, parsed_value, cookie_domain, | |
| 2504 cookie_path, mac_key, mac_algorithm, creation, | |
| 2505 expiration, creation, secure, http_only); | |
| 2506 } | |
| 2507 | |
| 2508 bool CookieMonster::CanonicalCookie::IsOnPath( | |
| 2509 const std::string& url_path) const { | |
| 2510 | |
| 2511 // A zero length would be unsafe for our trailing '/' checks, and | |
| 2512 // would also make no sense for our prefix match. The code that | |
| 2513 // creates a CanonicalCookie should make sure the path is never zero length, | |
| 2514 // but we double check anyway. | |
| 2515 if (path_.empty()) | |
| 2516 return false; | |
| 2517 | |
| 2518 // The Mozilla code broke this into three cases, based on if the cookie path | |
| 2519 // was longer, the same length, or shorter than the length of the url path. | |
| 2520 // I think the approach below is simpler. | |
| 2521 | |
| 2522 // Make sure the cookie path is a prefix of the url path. If the | |
| 2523 // url path is shorter than the cookie path, then the cookie path | |
| 2524 // can't be a prefix. | |
| 2525 if (url_path.find(path_) != 0) | |
| 2526 return false; | |
| 2527 | |
| 2528 // Now we know that url_path is >= cookie_path, and that cookie_path | |
| 2529 // is a prefix of url_path. If they are the are the same length then | |
| 2530 // they are identical, otherwise we need an additional check: | |
| 2531 | |
| 2532 // In order to avoid in correctly matching a cookie path of /blah | |
| 2533 // with a request path of '/blahblah/', we need to make sure that either | |
| 2534 // the cookie path ends in a trailing '/', or that we prefix up to a '/' | |
| 2535 // in the url path. Since we know that the url path length is greater | |
| 2536 // than the cookie path length, it's safe to index one byte past. | |
| 2537 if (path_.length() != url_path.length() && | |
| 2538 path_[path_.length() - 1] != '/' && | |
| 2539 url_path[path_.length()] != '/') | |
| 2540 return false; | |
| 2541 | |
| 2542 return true; | |
| 2543 } | |
| 2544 | |
| 2545 bool CookieMonster::CanonicalCookie::IsDomainMatch( | |
| 2546 const std::string& scheme, | |
| 2547 const std::string& host) const { | |
| 2548 // Can domain match in two ways; as a domain cookie (where the cookie | |
| 2549 // domain begins with ".") or as a host cookie (where it doesn't). | |
| 2550 | |
| 2551 // Some consumers of the CookieMonster expect to set cookies on | |
| 2552 // URLs like http://.strange.url. To retrieve cookies in this instance, | |
| 2553 // we allow matching as a host cookie even when the domain_ starts with | |
| 2554 // a period. | |
| 2555 if (host == domain_) | |
| 2556 return true; | |
| 2557 | |
| 2558 // Domain cookie must have an initial ".". To match, it must be | |
| 2559 // equal to url's host with initial period removed, or a suffix of | |
| 2560 // it. | |
| 2561 | |
| 2562 // Arguably this should only apply to "http" or "https" cookies, but | |
| 2563 // extension cookie tests currently use the funtionality, and if we | |
| 2564 // ever decide to implement that it should be done by preventing | |
| 2565 // such cookies from being set. | |
| 2566 if (domain_.empty() || domain_[0] != '.') | |
| 2567 return false; | |
| 2568 | |
| 2569 // The host with a "." prefixed. | |
| 2570 if (domain_.compare(1, std::string::npos, host) == 0) | |
| 2571 return true; | |
| 2572 | |
| 2573 // A pure suffix of the host (ok since we know the domain already | |
| 2574 // starts with a ".") | |
| 2575 return (host.length() > domain_.length() && | |
| 2576 host.compare(host.length() - domain_.length(), | |
| 2577 domain_.length(), domain_) == 0); | |
| 2578 } | |
| 2579 | |
| 2580 std::string CookieMonster::CanonicalCookie::DebugString() const { | |
| 2581 return base::StringPrintf( | |
| 2582 "name: %s value: %s domain: %s path: %s creation: %" | |
| 2583 PRId64, | |
| 2584 name_.c_str(), value_.c_str(), | |
| 2585 domain_.c_str(), path_.c_str(), | |
| 2586 static_cast<int64>(creation_date_.ToTimeT())); | |
| 2587 } | |
| 2588 | |
| 2589 } // namespace | 2165 } // namespace |
| OLD | NEW |