1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cookies/cookie_monster_store_test.h"
6
7 #include "base/functional/bind.h"
8 #include "base/location.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/task/single_thread_task_runner.h"
11 #include "base/time/time.h"
12 #include "net/cookies/cookie_constants.h"
13 #include "net/cookies/cookie_util.h"
14 #include "net/cookies/parsed_cookie.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "url/gurl.h"
17
18 namespace net {
19
CookieStoreCommand(Type type,CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback,const std::string & key)20 CookieStoreCommand::CookieStoreCommand(
21 Type type,
22 CookieMonster::PersistentCookieStore::LoadedCallback loaded_callback,
23 const std::string& key)
24 : type(type), loaded_callback(std::move(loaded_callback)), key(key) {}
25
CookieStoreCommand(Type type,const CanonicalCookie & cookie)26 CookieStoreCommand::CookieStoreCommand(Type type, const CanonicalCookie& cookie)
27 : type(type), cookie(cookie) {}
28
29 CookieStoreCommand::CookieStoreCommand(CookieStoreCommand&& other) = default;
30 CookieStoreCommand::~CookieStoreCommand() = default;
31
32 MockPersistentCookieStore::MockPersistentCookieStore() = default;
33
SetLoadExpectation(bool return_value,std::vector<std::unique_ptr<CanonicalCookie>> result)34 void MockPersistentCookieStore::SetLoadExpectation(
35 bool return_value,
36 std::vector<std::unique_ptr<CanonicalCookie>> result) {
37 load_return_value_ = return_value;
38 load_result_.swap(result);
39 }
40
Load(LoadedCallback loaded_callback,const NetLogWithSource &)41 void MockPersistentCookieStore::Load(LoadedCallback loaded_callback,
42 const NetLogWithSource& /* net_log */) {
43 if (store_load_commands_) {
44 commands_.push_back(CookieStoreCommand(CookieStoreCommand::LOAD,
45 std::move(loaded_callback), ""));
46 return;
47 }
48 std::vector<std::unique_ptr<CanonicalCookie>> out_cookies;
49 if (load_return_value_) {
50 out_cookies.swap(load_result_);
51 loaded_ = true;
52 }
53 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
54 FROM_HERE,
55 base::BindOnce(std::move(loaded_callback), std::move(out_cookies)));
56 }
57
LoadCookiesForKey(const std::string & key,LoadedCallback loaded_callback)58 void MockPersistentCookieStore::LoadCookiesForKey(
59 const std::string& key,
60 LoadedCallback loaded_callback) {
61 if (store_load_commands_) {
62 commands_.push_back(
63 CookieStoreCommand(CookieStoreCommand::LOAD_COOKIES_FOR_KEY,
64 std::move(loaded_callback), key));
65 return;
66 }
67 if (!loaded_) {
68 Load(std::move(loaded_callback), NetLogWithSource());
69 } else {
70 std::vector<std::unique_ptr<CanonicalCookie>> empty_cookies;
71 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
72 FROM_HERE,
73 base::BindOnce(std::move(loaded_callback), std::move(empty_cookies)));
74 }
75 }
76
AddCookie(const CanonicalCookie & cookie)77 void MockPersistentCookieStore::AddCookie(const CanonicalCookie& cookie) {
78 commands_.push_back(CookieStoreCommand(CookieStoreCommand::ADD, cookie));
79 }
80
UpdateCookieAccessTime(const CanonicalCookie & cookie)81 void MockPersistentCookieStore::UpdateCookieAccessTime(
82 const CanonicalCookie& cookie) {
83 }
84
DeleteCookie(const CanonicalCookie & cookie)85 void MockPersistentCookieStore::DeleteCookie(const CanonicalCookie& cookie) {
86 commands_.push_back(CookieStoreCommand(CookieStoreCommand::REMOVE, cookie));
87 }
88
SetForceKeepSessionState()89 void MockPersistentCookieStore::SetForceKeepSessionState() {}
90
SetBeforeCommitCallback(base::RepeatingClosure callback)91 void MockPersistentCookieStore::SetBeforeCommitCallback(
92 base::RepeatingClosure callback) {}
93
Flush(base::OnceClosure callback)94 void MockPersistentCookieStore::Flush(base::OnceClosure callback) {
95 if (!callback.is_null())
96 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
97 FROM_HERE, std::move(callback));
98 }
99
100 MockPersistentCookieStore::~MockPersistentCookieStore() = default;
101
BuildCanonicalCookie(const GURL & url,const std::string & cookie_line,const base::Time & creation_time)102 std::unique_ptr<CanonicalCookie> BuildCanonicalCookie(
103 const GURL& url,
104 const std::string& cookie_line,
105 const base::Time& creation_time) {
106 // Parse the cookie line.
107 ParsedCookie pc(cookie_line);
108 EXPECT_TRUE(pc.IsValid());
109
110 // This helper is simplistic in interpreting a parsed cookie, in order to
111 // avoid duplicated CookieMonster's CanonPath() and CanonExpiration()
112 // functions. Would be nice to export them, and re-use here.
113 EXPECT_FALSE(pc.HasMaxAge());
114 EXPECT_TRUE(pc.HasPath());
115 base::Time cookie_expires =
116 pc.HasExpires() ? cookie_util::ParseCookieExpirationTime(pc.Expires())
117 : base::Time();
118 std::string cookie_path = pc.Path();
119
120 return CanonicalCookie::CreateUnsafeCookieForTesting(
121 pc.Name(), pc.Value(), "." + url.host(), cookie_path, creation_time,
122 cookie_expires, base::Time(), base::Time(), pc.IsSecure(),
123 pc.IsHttpOnly(), pc.SameSite(), pc.Priority());
124 }
125
AddCookieToList(const GURL & url,const std::string & cookie_line,const base::Time & creation_time,std::vector<std::unique_ptr<CanonicalCookie>> * out_list)126 void AddCookieToList(const GURL& url,
127 const std::string& cookie_line,
128 const base::Time& creation_time,
129 std::vector<std::unique_ptr<CanonicalCookie>>* out_list) {
130 std::unique_ptr<CanonicalCookie> cookie(
131 BuildCanonicalCookie(url, cookie_line, creation_time));
132
133 out_list->push_back(std::move(cookie));
134 }
135
136 MockSimplePersistentCookieStore::MockSimplePersistentCookieStore() = default;
137
Load(LoadedCallback loaded_callback,const NetLogWithSource &)138 void MockSimplePersistentCookieStore::Load(
139 LoadedCallback loaded_callback,
140 const NetLogWithSource& /* net_log */) {
141 std::vector<std::unique_ptr<CanonicalCookie>> out_cookies;
142
143 for (const auto& cookie_map_it : cookies_) {
144 out_cookies.push_back(
145 std::make_unique<CanonicalCookie>(cookie_map_it.second));
146 }
147
148 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
149 FROM_HERE,
150 base::BindOnce(std::move(loaded_callback), std::move(out_cookies)));
151 loaded_ = true;
152 }
153
LoadCookiesForKey(const std::string & key,LoadedCallback loaded_callback)154 void MockSimplePersistentCookieStore::LoadCookiesForKey(
155 const std::string& key,
156 LoadedCallback loaded_callback) {
157 if (!loaded_) {
158 Load(std::move(loaded_callback), NetLogWithSource());
159 } else {
160 std::vector<std::unique_ptr<CanonicalCookie>> empty_cookies;
161 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
162 FROM_HERE,
163 base::BindOnce(std::move(loaded_callback), std::move(empty_cookies)));
164 }
165 }
166
AddCookie(const CanonicalCookie & cookie)167 void MockSimplePersistentCookieStore::AddCookie(const CanonicalCookie& cookie) {
168 const auto& key = cookie.UniqueKey();
169 EXPECT_TRUE(cookies_.find(key) == cookies_.end());
170 cookies_[key] = cookie;
171 }
172
UpdateCookieAccessTime(const CanonicalCookie & cookie)173 void MockSimplePersistentCookieStore::UpdateCookieAccessTime(
174 const CanonicalCookie& cookie) {
175 const auto& key = cookie.UniqueKey();
176 ASSERT_TRUE(cookies_.find(key) != cookies_.end());
177 cookies_[key].SetLastAccessDate(base::Time::Now());
178 }
179
DeleteCookie(const CanonicalCookie & cookie)180 void MockSimplePersistentCookieStore::DeleteCookie(
181 const CanonicalCookie& cookie) {
182 const auto& key = cookie.UniqueKey();
183 auto it = cookies_.find(key);
184 ASSERT_TRUE(it != cookies_.end());
185 cookies_.erase(it);
186 }
187
SetForceKeepSessionState()188 void MockSimplePersistentCookieStore::SetForceKeepSessionState() {}
189
SetBeforeCommitCallback(base::RepeatingClosure callback)190 void MockSimplePersistentCookieStore::SetBeforeCommitCallback(
191 base::RepeatingClosure callback) {}
192
Flush(base::OnceClosure callback)193 void MockSimplePersistentCookieStore::Flush(base::OnceClosure callback) {
194 if (!callback.is_null())
195 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
196 FROM_HERE, std::move(callback));
197 }
198
CreateMonsterFromStoreForGC(int num_secure_cookies,int num_old_secure_cookies,int num_non_secure_cookies,int num_old_non_secure_cookies,int days_old)199 std::unique_ptr<CookieMonster> CreateMonsterFromStoreForGC(
200 int num_secure_cookies,
201 int num_old_secure_cookies,
202 int num_non_secure_cookies,
203 int num_old_non_secure_cookies,
204 int days_old) {
205 base::Time current(base::Time::Now());
206 base::Time past_creation(base::Time::Now() - base::Days(100));
207 auto store = base::MakeRefCounted<MockSimplePersistentCookieStore>();
208 int total_cookies = num_secure_cookies + num_non_secure_cookies;
209 int base = 0;
210 // Must expire to be persistent
211 for (int i = 0; i < total_cookies; i++) {
212 int num_old_cookies;
213 bool secure;
214 if (i < num_secure_cookies) {
215 num_old_cookies = num_old_secure_cookies;
216 secure = true;
217 } else {
218 base = num_secure_cookies;
219 num_old_cookies = num_old_non_secure_cookies;
220 secure = false;
221 }
222 base::Time creation_time = past_creation + base::Microseconds(i);
223 base::Time expiration_time = current + base::Days(30);
224 base::Time last_access_time = ((i - base) < num_old_cookies)
225 ? current - base::Days(days_old)
226 : current;
227
228 // The URL must be HTTPS since |secure| can be true or false, and because
229 // strict secure cookies are enforced, the cookie will fail to be created if
230 // |secure| is true but the URL is an insecure scheme.
231 std::unique_ptr<CanonicalCookie> cc =
232 CanonicalCookie::CreateUnsafeCookieForTesting(
233 "a", "1", base::StringPrintf("h%05d.izzle", i), "/path",
234 creation_time, expiration_time, base::Time(), base::Time(), secure,
235 false, CookieSameSite::NO_RESTRICTION, COOKIE_PRIORITY_DEFAULT);
236 cc->SetLastAccessDate(last_access_time);
237 store->AddCookie(*cc);
238 }
239
240 return std::make_unique<CookieMonster>(store.get(), /*net_log=*/nullptr);
241 }
242
243 MockSimplePersistentCookieStore::~MockSimplePersistentCookieStore() = default;
244
245 } // namespace net
246