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
3 // found in the LICENSE file.
5 #include "ios/net/cookies/cookie_creation_time_manager.h"
7 #include <Foundation/Foundation.h>
9 #include "base/logging.h"
10 #include "base/strings/sys_string_conversions.h"
11 #include "base/time/time.h"
13 // Key holding the creation-time in NSHTTPCookie properties.
14 // This key is undocumented, and its value has type NSNumber.
15 NSString* const kHTTPCookieCreated = @"Created";
19 // Gets the creation date of a NSHTTPCookie, reading a undocumented property.
20 base::Time GetCreationTimeFromObject(NSHTTPCookie* cookie) {
21 // The "Created" key is not documented.
22 // Return a null time if the key is missing.
23 id created = [[cookie properties] objectForKey:kHTTPCookieCreated];
24 DCHECK(created && [created isKindOfClass:[NSNumber class]]);
25 if (!created || ![created isKindOfClass:[NSNumber class]])
27 // created is the time from January 1st, 2001 in seconds.
28 CFAbsoluteTime absolute_time = [(NSNumber*)created doubleValue];
29 // If the cookie has been created using |-initWithProperties:|, the creation
30 // date property is (incorrectly) set to 1.0. Treat that as an invalid time.
31 if (absolute_time < 2.0)
33 return base::Time::FromCFAbsoluteTime(absolute_time);
36 // Gets a string that can be used as a unique identifier for |cookie|.
37 std::string GetCookieUniqueID(NSHTTPCookie* cookie) {
38 return base::SysNSStringToUTF8([cookie name]) + ";" +
39 base::SysNSStringToUTF8([cookie domain]) + ";" +
40 base::SysNSStringToUTF8([cookie path]);
47 CookieCreationTimeManager::CookieCreationTimeManager() {
50 CookieCreationTimeManager::~CookieCreationTimeManager() {
53 void CookieCreationTimeManager::SetCreationTime(
55 const base::Time& creation_time) {
56 DCHECK(thread_checker_.CalledOnValidThread());
57 DCHECK(unique_times_.find(creation_time) == unique_times_.end());
59 // If the cookie overrides an existing cookie, remove its creation time.
60 auto it = creation_times_.find(GetCookieUniqueID(cookie));
61 if (it != creation_times_.end()) {
62 size_t erased = unique_times_.erase(it->second);
63 DCHECK_EQ(1u, erased);
66 unique_times_.insert(creation_time);
67 creation_times_[GetCookieUniqueID(cookie)] = creation_time;
70 base::Time CookieCreationTimeManager::MakeUniqueCreationTime(
71 const base::Time& creation_time) {
72 DCHECK(thread_checker_.CalledOnValidThread());
73 auto it = unique_times_.find(creation_time);
75 if (it == unique_times_.end())
78 // If the time already exist, increment until we find a time available.
79 // |unique_times_| is sorted according to time, so we can traverse it from
81 base::Time time = creation_time;
85 time = base::Time::FromInternalValue(time.ToInternalValue() + 1);
86 } while (it != unique_times_.end() && *it == time);
91 base::Time CookieCreationTimeManager::GetCreationTime(NSHTTPCookie* cookie) {
92 DCHECK(thread_checker_.CalledOnValidThread());
93 base::hash_map<std::string, base::Time>::iterator it =
94 creation_times_.find(GetCookieUniqueID(cookie));
95 if (it != creation_times_.end())
98 base::Time native_creation_time = GetCreationTimeFromObject(cookie);
99 native_creation_time = MakeUniqueCreationTime(native_creation_time);
100 SetCreationTime(cookie, native_creation_time);
101 return native_creation_time;
104 void CookieCreationTimeManager::DeleteCreationTime(NSHTTPCookie* cookie) {
105 DCHECK(thread_checker_.CalledOnValidThread());
106 auto it = creation_times_.find(GetCookieUniqueID(cookie));
107 if (it != creation_times_.end()) {
108 size_t erased = unique_times_.erase(it->second);
109 DCHECK_EQ(1u, erased);
110 creation_times_.erase(it);
114 void CookieCreationTimeManager::Clear() {
115 DCHECK(thread_checker_.CalledOnValidThread());
116 creation_times_.clear();
117 unique_times_.clear();