Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: net/cookies/cookie_monster.cc

Issue 10785017: Move CanonicalCookie into separate files (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed comments Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 * ***** END LICENSE BLOCK ***** */ 43 * ***** END LICENSE BLOCK ***** */
44 44
45 #include "net/cookies/cookie_monster.h" 45 #include "net/cookies/cookie_monster.h"
46 46
47 #include <algorithm> 47 #include <algorithm>
48 #include <set> 48 #include <set>
49 49
50 #include "base/basictypes.h" 50 #include "base/basictypes.h"
51 #include "base/bind.h" 51 #include "base/bind.h"
52 #include "base/callback.h" 52 #include "base/callback.h"
53 #include "base/format_macros.h"
54 #include "base/logging.h" 53 #include "base/logging.h"
55 #include "base/memory/scoped_ptr.h" 54 #include "base/memory/scoped_ptr.h"
56 #include "base/message_loop.h" 55 #include "base/message_loop.h"
57 #include "base/message_loop_proxy.h" 56 #include "base/message_loop_proxy.h"
58 #include "base/metrics/histogram.h" 57 #include "base/metrics/histogram.h"
59 #include "base/string_tokenizer.h"
60 #include "base/string_util.h" 58 #include "base/string_util.h"
61 #include "base/stringprintf.h" 59 #include "base/stringprintf.h"
62 #include "googleurl/src/gurl.h" 60 #include "googleurl/src/gurl.h"
63 #include "googleurl/src/url_canon.h" 61 #include "net/cookies/canonical_cookie.h"
64 #include "net/cookies/cookie_util.h" 62 #include "net/cookies/cookie_util.h"
65 #include "net/cookies/parsed_cookie.h" 63 #include "net/cookies/parsed_cookie.h"
66 #include "net/base/registry_controlled_domain.h" 64 #include "net/base/registry_controlled_domain.h"
67 65
68 using base::Time; 66 using base::Time;
69 using base::TimeDelta; 67 using base::TimeDelta;
70 using base::TimeTicks; 68 using base::TimeTicks;
71 69
72 // In steady state, most cookie requests can be satisfied by the in memory 70 // 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 71 // cookie monster store. However, if a request comes in during the initial
(...skipping 22 matching lines...) Expand all
96 // See comments at declaration of these variables in cookie_monster.h 94 // See comments at declaration of these variables in cookie_monster.h
97 // for details. 95 // for details.
98 const size_t CookieMonster::kDomainMaxCookies = 180; 96 const size_t CookieMonster::kDomainMaxCookies = 180;
99 const size_t CookieMonster::kDomainPurgeCookies = 30; 97 const size_t CookieMonster::kDomainPurgeCookies = 30;
100 const size_t CookieMonster::kMaxCookies = 3300; 98 const size_t CookieMonster::kMaxCookies = 3300;
101 const size_t CookieMonster::kPurgeCookies = 300; 99 const size_t CookieMonster::kPurgeCookies = 300;
102 const int CookieMonster::kSafeFromGlobalPurgeDays = 30; 100 const int CookieMonster::kSafeFromGlobalPurgeDays = 30;
103 101
104 namespace { 102 namespace {
105 103
106 typedef std::vector<CookieMonster::CanonicalCookie*> CanonicalCookieVector; 104 typedef std::vector<CanonicalCookie*> CanonicalCookieVector;
107 105
108 // Default minimum delay after updating a cookie's LastAccessDate before we 106 // Default minimum delay after updating a cookie's LastAccessDate before we
109 // will update it again. 107 // will update it again.
110 const int kDefaultAccessUpdateThresholdSeconds = 60; 108 const int kDefaultAccessUpdateThresholdSeconds = 60;
111 109
112 // Comparator to sort cookies from highest creation date to lowest 110 // Comparator to sort cookies from highest creation date to lowest
113 // creation date. 111 // creation date.
114 struct OrderByCreationTimeDesc { 112 struct OrderByCreationTimeDesc {
115 bool operator()(const CookieMonster::CookieMap::iterator& a, 113 bool operator()(const CookieMonster::CookieMap::iterator& a,
116 const CookieMonster::CookieMap::iterator& b) const { 114 const CookieMonster::CookieMap::iterator& b) const {
117 return a->second->CreationDate() > b->second->CreationDate(); 115 return a->second->CreationDate() > b->second->CreationDate();
118 } 116 }
119 }; 117 };
120 118
121 // Constants for use in VLOG 119 // Constants for use in VLOG
122 const int kVlogPerCookieMonster = 1; 120 const int kVlogPerCookieMonster = 1;
123 const int kVlogPeriodic = 3; 121 const int kVlogPeriodic = 3;
124 const int kVlogGarbageCollection = 5; 122 const int kVlogGarbageCollection = 5;
125 const int kVlogSetCookies = 7; 123 const int kVlogSetCookies = 7;
126 const int kVlogGetCookies = 9; 124 const int kVlogGetCookies = 9;
127 125
128 #if defined(ENABLE_PERSISTENT_SESSION_COOKIES) 126 #if defined(ENABLE_PERSISTENT_SESSION_COOKIES)
129 const int kPersistentSessionCookieExpiryInDays = 14; 127 const int kPersistentSessionCookieExpiryInDays = 14;
130 #endif 128 #endif
131 129
132 // Mozilla sorts on the path length (longest first), and then it 130 // Mozilla sorts on the path length (longest first), and then it
133 // sorts by creation time (oldest first). 131 // sorts by creation time (oldest first).
134 // The RFC says the sort order for the domain attribute is undefined. 132 // The RFC says the sort order for the domain attribute is undefined.
135 bool CookieSorter(CookieMonster::CanonicalCookie* cc1, 133 bool CookieSorter(CanonicalCookie* cc1, CanonicalCookie* cc2) {
136 CookieMonster::CanonicalCookie* cc2) {
137 if (cc1->Path().length() == cc2->Path().length()) 134 if (cc1->Path().length() == cc2->Path().length())
138 return cc1->CreationDate() < cc2->CreationDate(); 135 return cc1->CreationDate() < cc2->CreationDate();
139 return cc1->Path().length() > cc2->Path().length(); 136 return cc1->Path().length() > cc2->Path().length();
140 } 137 }
141 138
142 bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1, 139 bool LRUCookieSorter(const CookieMonster::CookieMap::iterator& it1,
143 const CookieMonster::CookieMap::iterator& it2) { 140 const CookieMonster::CookieMap::iterator& it2) {
144 // Cookies accessed less recently should be deleted first. 141 // Cookies accessed less recently should be deleted first.
145 if (it1->second->LastAccessDate() != it2->second->LastAccessDate()) 142 if (it1->second->LastAccessDate() != it2->second->LastAccessDate())
146 return it1->second->LastAccessDate() < it2->second->LastAccessDate(); 143 return it1->second->LastAccessDate() < it2->second->LastAccessDate();
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 // Determine the cookie domain to use for setting the specified cookie. 189 // Determine the cookie domain to use for setting the specified cookie.
193 bool GetCookieDomain(const GURL& url, 190 bool GetCookieDomain(const GURL& url,
194 const ParsedCookie& pc, 191 const ParsedCookie& pc,
195 std::string* result) { 192 std::string* result) {
196 std::string domain_string; 193 std::string domain_string;
197 if (pc.HasDomain()) 194 if (pc.HasDomain())
198 domain_string = pc.Domain(); 195 domain_string = pc.Domain();
199 return cookie_util::GetCookieDomainWithString(url, domain_string, result); 196 return cookie_util::GetCookieDomainWithString(url, domain_string, result);
200 } 197 }
201 198
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 199 // Helper for GarbageCollection. If |cookie_its->size() > num_max|, remove the
266 // |num_max - num_purge| most recently accessed cookies from cookie_its. 200 // |num_max - num_purge| most recently accessed cookies from cookie_its.
267 // (In other words, leave the entries that are candidates for 201 // (In other words, leave the entries that are candidates for
268 // eviction in cookie_its.) The cookies returned will be in order sorted by 202 // 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 203 // access time, least recently accessed first. The access time of the least
270 // recently accessed entry not returned will be placed in 204 // recently accessed entry not returned will be placed in
271 // |*lra_removed| if that pointer is set. FindLeastRecentlyAccessed 205 // |*lra_removed| if that pointer is set. FindLeastRecentlyAccessed
272 // returns false if no manipulation is done (because the list size is less 206 // returns false if no manipulation is done (because the list size is less
273 // than num_max), true otherwise. 207 // than num_max), true otherwise.
274 bool FindLeastRecentlyAccessed( 208 bool FindLeastRecentlyAccessed(
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 cookie_line += (*it)->Name() + "="; 275 cookie_line += (*it)->Name() + "=";
342 cookie_line += (*it)->Value(); 276 cookie_line += (*it)->Value();
343 } 277 }
344 return cookie_line; 278 return cookie_line;
345 } 279 }
346 280
347 void BuildCookieInfoList(const CanonicalCookieVector& cookies, 281 void BuildCookieInfoList(const CanonicalCookieVector& cookies,
348 std::vector<CookieStore::CookieInfo>* cookie_infos) { 282 std::vector<CookieStore::CookieInfo>* cookie_infos) {
349 for (CanonicalCookieVector::const_iterator it = cookies.begin(); 283 for (CanonicalCookieVector::const_iterator it = cookies.begin();
350 it != cookies.end(); ++it) { 284 it != cookies.end(); ++it) {
351 const CookieMonster::CanonicalCookie* cookie = *it; 285 const CanonicalCookie* cookie = *it;
352 CookieStore::CookieInfo cookie_info; 286 CookieStore::CookieInfo cookie_info;
353 287
354 cookie_info.name = cookie->Name(); 288 cookie_info.name = cookie->Name();
355 cookie_info.creation_date = cookie->CreationDate(); 289 cookie_info.creation_date = cookie->CreationDate();
356 cookie_info.mac_key = cookie->MACKey(); 290 cookie_info.mac_key = cookie->MACKey();
357 cookie_info.mac_algorithm = cookie->MACAlgorithm(); 291 cookie_info.mac_algorithm = cookie->MACAlgorithm();
358 292
359 cookie_infos->push_back(cookie_info); 293 cookie_infos->push_back(cookie_info);
360 } 294 }
361 } 295 }
(...skipping 26 matching lines...) Expand all
388 last_access_threshold_(base::TimeDelta::FromMilliseconds( 322 last_access_threshold_(base::TimeDelta::FromMilliseconds(
389 last_access_threshold_milliseconds)), 323 last_access_threshold_milliseconds)),
390 delegate_(delegate), 324 delegate_(delegate),
391 last_statistic_record_time_(base::Time::Now()), 325 last_statistic_record_time_(base::Time::Now()),
392 keep_expired_cookies_(false), 326 keep_expired_cookies_(false),
393 persist_session_cookies_(false) { 327 persist_session_cookies_(false) {
394 InitializeHistograms(); 328 InitializeHistograms();
395 SetDefaultCookieableSchemes(); 329 SetDefaultCookieableSchemes();
396 } 330 }
397 331
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 332
516 // Task classes for queueing the coming request. 333 // Task classes for queueing the coming request.
517 334
518 class CookieMonster::CookieMonsterTask 335 class CookieMonster::CookieMonsterTask
519 : public base::RefCountedThreadSafe<CookieMonsterTask> { 336 : public base::RefCountedThreadSafe<CookieMonsterTask> {
520 public: 337 public:
521 // Runs the task and invokes the client callback on the thread that 338 // Runs the task and invokes the client callback on the thread that
522 // originally constructed the task. 339 // originally constructed the task.
523 virtual void Run() = 0; 340 virtual void Run() = 0;
524 341
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 base::Unretained(&callback_), num_deleted)); 608 base::Unretained(&callback_), num_deleted));
792 } 609 }
793 } 610 }
794 611
795 // Task class for DeleteCanonicalCookie call. 612 // Task class for DeleteCanonicalCookie call.
796 class CookieMonster::DeleteCanonicalCookieTask 613 class CookieMonster::DeleteCanonicalCookieTask
797 : public CookieMonster::CookieMonsterTask { 614 : public CookieMonster::CookieMonsterTask {
798 public: 615 public:
799 DeleteCanonicalCookieTask( 616 DeleteCanonicalCookieTask(
800 CookieMonster* cookie_monster, 617 CookieMonster* cookie_monster,
801 const CookieMonster::CanonicalCookie& cookie, 618 const CanonicalCookie& cookie,
802 const CookieMonster::DeleteCookieCallback& callback) 619 const CookieMonster::DeleteCookieCallback& callback)
803 : CookieMonsterTask(cookie_monster), 620 : CookieMonsterTask(cookie_monster),
804 cookie_(cookie), 621 cookie_(cookie),
805 callback_(callback) { 622 callback_(callback) {
806 } 623 }
807 624
808 // CookieMonster::CookieMonsterTask: 625 // CookieMonster::CookieMonsterTask:
809 virtual void Run() OVERRIDE; 626 virtual void Run() OVERRIDE;
810 627
811 protected: 628 protected:
812 virtual ~DeleteCanonicalCookieTask() {} 629 virtual ~DeleteCanonicalCookieTask() {}
813 630
814 private: 631 private:
815 CookieMonster::CanonicalCookie cookie_; 632 CanonicalCookie cookie_;
816 CookieMonster::DeleteCookieCallback callback_; 633 CookieMonster::DeleteCookieCallback callback_;
817 634
818 DISALLOW_COPY_AND_ASSIGN(DeleteCanonicalCookieTask); 635 DISALLOW_COPY_AND_ASSIGN(DeleteCanonicalCookieTask);
819 }; 636 };
820 637
821 void CookieMonster::DeleteCanonicalCookieTask::Run() { 638 void CookieMonster::DeleteCanonicalCookieTask::Run() {
822 bool result = this->cookie_monster()->DeleteCanonicalCookie(cookie_); 639 bool result = this->cookie_monster()->DeleteCanonicalCookie(cookie_);
823 if (!callback_.is_null()) { 640 if (!callback_.is_null()) {
824 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCookieCallback::Run, 641 this->InvokeCallback(base::Bind(&CookieMonster::DeleteCookieCallback::Run,
825 base::Unretained(&callback_), result)); 642 base::Unretained(&callback_), result));
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after
1204 CookieOptions options; 1021 CookieOptions options;
1205 options.set_include_httponly(); 1022 options.set_include_httponly();
1206 return SetCanonicalCookie(&cc, creation_time, options); 1023 return SetCanonicalCookie(&cc, creation_time, options);
1207 } 1024 }
1208 1025
1209 bool CookieMonster::InitializeFrom(const CookieList& list) { 1026 bool CookieMonster::InitializeFrom(const CookieList& list) {
1210 base::AutoLock autolock(lock_); 1027 base::AutoLock autolock(lock_);
1211 InitIfNecessary(); 1028 InitIfNecessary();
1212 for (net::CookieList::const_iterator iter = list.begin(); 1029 for (net::CookieList::const_iterator iter = list.begin();
1213 iter != list.end(); ++iter) { 1030 iter != list.end(); ++iter) {
1214 scoped_ptr<net::CookieMonster::CanonicalCookie> cookie; 1031 scoped_ptr<CanonicalCookie> cookie(new CanonicalCookie(*iter));
1215 cookie.reset(new net::CookieMonster::CanonicalCookie(*iter));
1216 net::CookieOptions options; 1032 net::CookieOptions options;
1217 options.set_include_httponly(); 1033 options.set_include_httponly();
1218 if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), 1034 if (!SetCanonicalCookie(&cookie, cookie->CreationDate(), options))
1219 options)) {
1220 return false; 1035 return false;
1221 }
1222 } 1036 }
1223 return true; 1037 return true;
1224 } 1038 }
1225 1039
1226 CookieList CookieMonster::GetAllCookies() { 1040 CookieList CookieMonster::GetAllCookies() {
1227 base::AutoLock autolock(lock_); 1041 base::AutoLock autolock(lock_);
1228 1042
1229 // This function is being called to scrape the cookie list for management UI 1043 // 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 1044 // 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 1045 // 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
1910 if (options.exclude_httponly() && pc.IsHttpOnly()) { 1724 if (options.exclude_httponly() && pc.IsHttpOnly()) {
1911 VLOG(kVlogSetCookies) << "SetCookie() not setting httponly cookie"; 1725 VLOG(kVlogSetCookies) << "SetCookie() not setting httponly cookie";
1912 return false; 1726 return false;
1913 } 1727 }
1914 1728
1915 std::string cookie_domain; 1729 std::string cookie_domain;
1916 if (!GetCookieDomain(url, pc, &cookie_domain)) { 1730 if (!GetCookieDomain(url, pc, &cookie_domain)) {
1917 return false; 1731 return false;
1918 } 1732 }
1919 1733
1920 std::string cookie_path = CanonPath(url, pc); 1734 std::string cookie_path = CanonicalCookie::CanonPath(url, pc);
1921 std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string(); 1735 std::string mac_key = pc.HasMACKey() ? pc.MACKey() : std::string();
1922 std::string mac_algorithm = pc.HasMACAlgorithm() ? 1736 std::string mac_algorithm = pc.HasMACAlgorithm() ?
1923 pc.MACAlgorithm() : std::string(); 1737 pc.MACAlgorithm() : std::string();
1924 1738
1925 scoped_ptr<CanonicalCookie> cc; 1739 scoped_ptr<CanonicalCookie> cc;
1926 Time cookie_expires = CanonExpiration(pc, creation_time, server_time); 1740 Time cookie_expires =
1741 CanonicalCookie::CanonExpiration(pc, creation_time, server_time);
1927 1742
1928 cc.reset(new CanonicalCookie(url, pc.Name(), pc.Value(), cookie_domain, 1743 cc.reset(new CanonicalCookie(url, pc.Name(), pc.Value(), cookie_domain,
1929 cookie_path, mac_key, mac_algorithm, 1744 cookie_path, mac_key, mac_algorithm,
1930 creation_time, cookie_expires, 1745 creation_time, cookie_expires,
1931 creation_time, pc.IsSecure(), pc.IsHttpOnly())); 1746 creation_time, pc.IsSecure(), pc.IsHttpOnly()));
1932 1747
1933 if (!cc.get()) { 1748 if (!cc.get()) {
1934 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie"; 1749 VLOG(kVlogSetCookies) << "WARNING: Failed to allocate CanonicalCookie";
1935 return false; 1750 return false;
1936 } 1751 }
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after
2337 2152
2338 2153
2339 // The system resolution is not high enough, so we can have multiple 2154 // 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 2155 // 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. 2156 // increment by one Time unit. Let's hope computers don't get too fast.
2342 Time CookieMonster::CurrentTime() { 2157 Time CookieMonster::CurrentTime() {
2343 return std::max(Time::Now(), 2158 return std::max(Time::Now(),
2344 Time::FromInternalValue(last_time_seen_.ToInternalValue() + 1)); 2159 Time::FromInternalValue(last_time_seen_.ToInternalValue() + 1));
2345 } 2160 }
2346 2161
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 2162 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698