blob: 6fa47eab1cc6be3fdede00db33229a87ade7537d [file] [log] [blame]
droger3e8d98b2015-03-18 15:29:531// Copyright 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.
4
Mohammad Refaat6a4276492017-09-08 00:18:525#import "ios/net/cookies/cookie_store_ios.h"
droger3e8d98b2015-03-18 15:29:536
7#import <Foundation/Foundation.h>
avi571943672015-12-22 02:12:498#include <stddef.h>
droger3e8d98b2015-03-18 15:29:539
10#include "base/bind.h"
11#include "base/files/file_path.h"
12#include "base/files/file_util.h"
droger3e8d98b2015-03-18 15:29:5313#include "base/location.h"
14#include "base/logging.h"
15#include "base/mac/foundation_util.h"
avi571943672015-12-22 02:12:4916#include "base/macros.h"
droger3e8d98b2015-03-18 15:29:5317#include "base/memory/weak_ptr.h"
asvitkinef1899e32017-01-27 16:30:2918#include "base/metrics/histogram_macros.h"
droger3e8d98b2015-03-18 15:29:5319#include "base/observer_list.h"
20#include "base/sequenced_task_runner.h"
droger3e8d98b2015-03-18 15:29:5321#include "base/strings/sys_string_conversions.h"
22#include "base/task_runner_util.h"
23#include "base/threading/thread_restrictions.h"
gab3d426fa62016-05-11 18:13:3324#include "base/threading/thread_task_runner_handle.h"
rdsmitha6ce4442017-06-21 17:11:0525#include "base/time/time.h"
droger3e8d98b2015-03-18 15:29:5326#include "ios/net/cookies/cookie_store_ios_client.h"
Mohammad Refaat6a4276492017-09-08 00:18:5227#import "ios/net/cookies/ns_http_system_cookie_store.h"
28#import "ios/net/cookies/system_cookie_util.h"
Scott Violetd9ec3a6d2018-03-27 03:08:5629#include "ios/net/ios_net_buildflags.h"
droger3e8d98b2015-03-18 15:29:5330#import "net/base/mac/url_conversions.h"
31#include "net/cookies/cookie_util.h"
ellyjones98a0b9202015-09-04 17:22:2432#include "net/cookies/parsed_cookie.h"
Helen Li4e4cb0d2018-08-21 14:50:4733#include "net/log/net_log.h"
droger3e8d98b2015-03-18 15:29:5334#include "url/gurl.h"
35
stkhapugind335d772016-11-16 16:48:4536#if !defined(__has_feature) || !__has_feature(objc_arc)
37#error "This file requires ARC support."
38#endif
39
droger3e8d98b2015-03-18 15:29:5340namespace net {
41
Chris Mumfordd8ed9f82018-05-01 15:43:1342using CookieDeletionInfo = CookieDeletionInfo;
Chris Mumford800caa62018-04-20 19:34:4443
droger3e8d98b2015-03-18 15:29:5344namespace {
45
droger3e8d98b2015-03-18 15:29:5346#pragma mark NotificationTrampoline
47
48// NotificationTrampoline dispatches cookie notifications to all the existing
49// CookieStoreIOS.
50class NotificationTrampoline {
51 public:
52 static NotificationTrampoline* GetInstance();
53
54 void AddObserver(CookieNotificationObserver* obs);
55 void RemoveObserver(CookieNotificationObserver* obs);
56
57 // Notify the observers.
58 void NotifyCookiesChanged();
droger3e8d98b2015-03-18 15:29:5359
60 private:
61 NotificationTrampoline();
62 ~NotificationTrampoline();
63
Trent Apteda250ec3ab2018-08-19 08:52:1964 base::ObserverList<CookieNotificationObserver>::Unchecked observer_list_;
droger3e8d98b2015-03-18 15:29:5365
66 DISALLOW_COPY_AND_ASSIGN(NotificationTrampoline);
67
68 static NotificationTrampoline* g_notification_trampoline;
69};
70
71#pragma mark NotificationTrampoline implementation
72
73NotificationTrampoline* NotificationTrampoline::GetInstance() {
74 if (!g_notification_trampoline)
75 g_notification_trampoline = new NotificationTrampoline;
76 return g_notification_trampoline;
77}
78
79void NotificationTrampoline::AddObserver(CookieNotificationObserver* obs) {
80 observer_list_.AddObserver(obs);
81}
82
83void NotificationTrampoline::RemoveObserver(CookieNotificationObserver* obs) {
84 observer_list_.RemoveObserver(obs);
85}
86
87void NotificationTrampoline::NotifyCookiesChanged() {
ericwilligersff4feda2016-10-18 00:33:4488 for (auto& observer : observer_list_)
89 observer.OnSystemCookiesChanged();
droger3e8d98b2015-03-18 15:29:5390}
91
droger3e8d98b2015-03-18 15:29:5392NotificationTrampoline::NotificationTrampoline() {
93}
94
95NotificationTrampoline::~NotificationTrampoline() {
96}
97
98// Global instance of NotificationTrampoline.
99NotificationTrampoline* NotificationTrampoline::g_notification_trampoline =
100 nullptr;
101
102#pragma mark Utility functions
103
Mohammad Refaat41032802017-10-06 04:15:57104// Returns an empty closure if |callback| is null callback or binds the
Aaron Tagliaboschi29764f52019-02-21 17:19:59105// callback to |status|.
Mohammad Refaat41032802017-10-06 04:15:57106base::OnceClosure BindSetCookiesCallback(
107 CookieStoreIOS::SetCookiesCallback* callback,
Aaron Tagliaboschi29764f52019-02-21 17:19:59108 net::CanonicalCookie::CookieInclusionStatus status) {
Mohammad Refaat41032802017-10-06 04:15:57109 base::OnceClosure set_callback;
110 if (!callback->is_null()) {
Aaron Tagliaboschi29764f52019-02-21 17:19:59111 set_callback = base::BindOnce(std::move(*callback), status);
Mohammad Refaat41032802017-10-06 04:15:57112 }
113 return set_callback;
114}
115
droger3e8d98b2015-03-18 15:29:53116// Adds cookies in |cookies| with name |name| to |filtered|.
Lily Chenf068a762019-08-21 21:10:50117void OnlyCookiesWithName(const net::CookieStatusList& cookies,
droger3e8d98b2015-03-18 15:29:53118 const std::string& name,
119 net::CookieList* filtered) {
Lily Chenf068a762019-08-21 21:10:50120 for (const auto& cookie_with_status : cookies) {
121 if (cookie_with_status.cookie.Name() == name)
122 filtered->push_back(cookie_with_status.cookie);
droger3e8d98b2015-03-18 15:29:53123 }
124}
125
droger3e8d98b2015-03-18 15:29:53126} // namespace
127
128#pragma mark -
Victor Costan14f47c12018-03-01 08:02:24129
Sergey Kuznetsov0edf1612018-10-12 14:29:05130#pragma mark CookieStoreIOS::Subscription
131
132CookieStoreIOS::Subscription::Subscription(
133 std::unique_ptr<CookieChangeCallbackList::Subscription> subscription)
134 : subscription_(std::move(subscription)) {
135 DCHECK(subscription_);
136}
137
138CookieStoreIOS::Subscription::~Subscription() {
139 if (!subscription_) {
140 // |CookieStoreIOS| already destroyed - bail out.
141 return;
142 }
143
144 // |CookieStoreIOS| is alive - unsubscribe.
145 RemoveFromList();
146}
147
148void CookieStoreIOS::Subscription::ResetSubscription() {
149 subscription_.reset();
150}
151
152#pragma mark -
153
Victor Costan14f47c12018-03-01 08:02:24154#pragma mark CookieStoreIOS::CookieChangeDispatcherIOS
155
156CookieStoreIOS::CookieChangeDispatcherIOS::CookieChangeDispatcherIOS(
157 CookieStoreIOS* cookie_store)
158 : cookie_store_(cookie_store) {
159 DCHECK(cookie_store);
160}
161
162CookieStoreIOS::CookieChangeDispatcherIOS::~CookieChangeDispatcherIOS() =
163 default;
164
165std::unique_ptr<CookieChangeSubscription>
166CookieStoreIOS::CookieChangeDispatcherIOS::AddCallbackForCookie(
167 const GURL& gurl,
168 const std::string& name,
169 CookieChangeCallback callback) {
170 return cookie_store_->AddCallbackForCookie(gurl, name, std::move(callback));
171}
172
173std::unique_ptr<CookieChangeSubscription>
Victor Costan2a1891672018-03-02 06:01:53174CookieStoreIOS::CookieChangeDispatcherIOS::AddCallbackForUrl(
175 const GURL& gurl,
176 CookieChangeCallback callback) {
177 // Implement when needed by iOS consumers.
178 NOTIMPLEMENTED();
179 return nullptr;
180}
181
182std::unique_ptr<CookieChangeSubscription>
Victor Costan14f47c12018-03-01 08:02:24183CookieStoreIOS::CookieChangeDispatcherIOS::AddCallbackForAllChanges(
184 CookieChangeCallback callback) {
185 // Implement when needed by iOS consumers.
186 NOTIMPLEMENTED();
187 return nullptr;
188}
189
droger3e8d98b2015-03-18 15:29:53190#pragma mark CookieStoreIOS
191
Mohammad Refaat6a4276492017-09-08 00:18:52192CookieStoreIOS::CookieStoreIOS(
Helen Li4e4cb0d2018-08-21 14:50:47193 std::unique_ptr<SystemCookieStore> system_cookie_store,
194 NetLog* net_log)
Mohammad Refaat6a4276492017-09-08 00:18:52195 : CookieStoreIOS(/*persistent_store=*/nullptr,
Helen Li4e4cb0d2018-08-21 14:50:47196 std::move(system_cookie_store),
197 net_log) {}
Mohammad Refaat6a4276492017-09-08 00:18:52198
Helen Li4e4cb0d2018-08-21 14:50:47199CookieStoreIOS::CookieStoreIOS(NSHTTPCookieStorage* ns_cookie_store,
200 NetLog* net_log)
201 : CookieStoreIOS(std::make_unique<NSHTTPSystemCookieStore>(ns_cookie_store),
202 net_log) {}
shreyasv1ae3c3a32015-11-03 20:13:12203
mmenke606c59c2016-03-07 18:20:55204CookieStoreIOS::~CookieStoreIOS() {
205 NotificationTrampoline::GetInstance()->RemoveObserver(this);
Sergey Kuznetsov0edf1612018-10-12 14:29:05206
207 // Reset subscriptions.
208 for (auto* node = all_subscriptions_.head(); node != all_subscriptions_.end();
209 node = node->next()) {
210 node->value()->ResetSubscription();
211 }
mmenke606c59c2016-03-07 18:20:55212}
213
droger3e8d98b2015-03-18 15:29:53214// static
droger3e8d98b2015-03-18 15:29:53215void CookieStoreIOS::NotifySystemCookiesChanged() {
216 NotificationTrampoline::GetInstance()->NotifyCookiesChanged();
217}
218
droger3e8d98b2015-03-18 15:29:53219void CookieStoreIOS::SetMetricsEnabled() {
220 static CookieStoreIOS* g_cookie_store_with_metrics = nullptr;
221 DCHECK(!g_cookie_store_with_metrics || g_cookie_store_with_metrics == this)
222 << "Only one cookie store may use metrics.";
223 g_cookie_store_with_metrics = this;
224 metrics_enabled_ = true;
225}
226
227#pragma mark -
228#pragma mark CookieStore methods
229
rdsmitha6ce4442017-06-21 17:11:05230void CookieStoreIOS::SetCanonicalCookieAsync(
231 std::unique_ptr<net::CanonicalCookie> cookie,
Maks Orlovich44525ce2019-02-25 14:17:58232 std::string source_scheme,
Maks Orlovichfdbc8be2019-03-18 18:34:52233 const net::CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54234 SetCookiesCallback callback) {
Victor Costanfb17d1a2018-02-23 03:42:26235 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
236
237 // If cookies are not allowed, a CookieStoreIOS subclass should be used
238 // instead.
239 DCHECK(SystemCookiesAllowed());
240
rdsmitha6ce4442017-06-21 17:11:05241 DCHECK(cookie->IsCanonical());
242 // The exclude_httponly() option would only be used by a javascript
243 // engine.
Maks Orlovichfdbc8be2019-03-18 18:34:52244 DCHECK(!options.exclude_httponly());
rdsmitha6ce4442017-06-21 17:11:05245
Maks Orlovich44525ce2019-02-25 14:17:58246 bool secure_source =
247 GURL::SchemeIsCryptographic(base::ToLowerASCII(source_scheme));
248
rdsmitha6ce4442017-06-21 17:11:05249 if (cookie->IsSecure() && !secure_source) {
250 if (!callback.is_null())
Lily Chenf53dfbcd2019-08-30 01:42:10251 std::move(callback).Run(net::CanonicalCookie::CookieInclusionStatus(
252 net::CanonicalCookie::CookieInclusionStatus::EXCLUDE_SECURE_ONLY));
rdsmitha6ce4442017-06-21 17:11:05253 return;
254 }
255
256 NSHTTPCookie* ns_cookie = SystemCookieFromCanonicalCookie(*cookie.get());
257
258 if (ns_cookie != nil) {
Aaron Tagliaboschi29764f52019-02-21 17:19:59259 system_store_->SetCookieAsync(
260 ns_cookie, &cookie->CreationDate(),
Lily Chenf53dfbcd2019-08-30 01:42:10261 BindSetCookiesCallback(&callback,
262 net::CanonicalCookie::CookieInclusionStatus()));
rdsmitha6ce4442017-06-21 17:11:05263 return;
264 }
265
266 if (!callback.is_null())
Lily Chenf53dfbcd2019-08-30 01:42:10267 std::move(callback).Run(net::CanonicalCookie::CookieInclusionStatus(
268 net::CanonicalCookie::CookieInclusionStatus::EXCLUDE_FAILURE_TO_STORE));
rdsmitha6ce4442017-06-21 17:11:05269}
270
mkwstc611e6d2016-02-23 15:45:55271void CookieStoreIOS::GetCookieListWithOptionsAsync(
droger3e8d98b2015-03-18 15:29:53272 const GURL& url,
mkwstc611e6d2016-02-23 15:45:55273 const net::CookieOptions& options,
rdsmith7ac81712017-06-22 17:09:54274 GetCookieListCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42275 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Victor Costanfb17d1a2018-02-23 03:42:26276
277 // If cookies are not allowed, a CookieStoreIOS subclass should be used
278 // instead.
279 DCHECK(SystemCookiesAllowed());
maksim.sisovfdd9f092017-01-30 10:41:42280
281 // TODO(mkwst): If/when iOS supports Same-Site cookies, we'll need to pass
282 // options in here as well. https://crbug.com/459154
Mohammad Refaat41032802017-10-06 04:15:57283 system_store_->GetCookiesForURLAsync(
284 url,
285 base::BindOnce(&CookieStoreIOS::RunGetCookieListCallbackOnSystemCookies,
286 weak_factory_.GetWeakPtr(), base::Passed(&callback)));
droger3e8d98b2015-03-18 15:29:53287}
288
Lily Chenf068a762019-08-21 21:10:50289void CookieStoreIOS::GetAllCookiesAsync(GetAllCookiesCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42290 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
mmenke9fa44f2d2016-01-22 23:36:39291
Victor Costanfb17d1a2018-02-23 03:42:26292 // If cookies are not allowed, a CookieStoreIOS subclass should be used
293 // instead.
294 DCHECK(SystemCookiesAllowed());
295
Mohammad Refaat41032802017-10-06 04:15:57296 // TODO(crbug.com/459154): If/when iOS supports Same-Site cookies, we'll need
297 // to pass options in here as well.
298 system_store_->GetAllCookiesAsync(
Lily Chenf068a762019-08-21 21:10:50299 base::BindOnce(&CookieStoreIOS::RunGetAllCookiesCallbackOnSystemCookies,
Mohammad Refaat41032802017-10-06 04:15:57300 weak_factory_.GetWeakPtr(), base::Passed(&callback)));
mmenke9fa44f2d2016-01-22 23:36:39301}
302
rdsmith7ac81712017-06-22 17:09:54303void CookieStoreIOS::DeleteCanonicalCookieAsync(const CanonicalCookie& cookie,
304 DeleteCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42305 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
mmenke24379d52016-02-05 23:50:17306
Victor Costanfb17d1a2018-02-23 03:42:26307 // If cookies are not allowed, a CookieStoreIOS subclass should be used
308 // instead.
309 DCHECK(SystemCookiesAllowed());
310
Maks Orlovichf58b8da2019-02-11 17:12:45311 DeleteCookiesMatchingPredicateAsync(base::BindRepeating(
312 [](const net::CanonicalCookie& target,
313 const net::CanonicalCookie& cc) {
314 return cc.IsEquivalent(target) &&
315 cc.Value() == target.Value();
316 },
317 cookie),
318 std::move(callback));
mmenke24379d52016-02-05 23:50:17319}
320
Chris Mumford800caa62018-04-20 19:34:44321void CookieStoreIOS::DeleteAllCreatedInTimeRangeAsync(
Chris Mumfordd8ed9f82018-05-01 15:43:13322 const CookieDeletionInfo::TimeRange& creation_range,
rdsmith7ac81712017-06-22 17:09:54323 DeleteCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42324 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53325
Victor Costanfb17d1a2018-02-23 03:42:26326 // If cookies are not allowed, a CookieStoreIOS subclass should be used
327 // instead.
328 DCHECK(SystemCookiesAllowed());
329
330 if (metrics_enabled())
droger3e8d98b2015-03-18 15:29:53331 ResetCookieCountMetrics();
332
Chris Mumford800caa62018-04-20 19:34:44333 CookieDeletionInfo delete_info(creation_range.start(), creation_range.end());
334 DeleteCookiesMatchingInfoAsync(std::move(delete_info), std::move(callback));
droger3e8d98b2015-03-18 15:29:53335}
336
Chris Mumfordd8ed9f82018-05-01 15:43:13337void CookieStoreIOS::DeleteAllMatchingInfoAsync(CookieDeletionInfo delete_info,
338 DeleteCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42339 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53340
Victor Costanfb17d1a2018-02-23 03:42:26341 // If cookies are not allowed, a CookieStoreIOS subclass should be used
342 // instead.
343 DCHECK(SystemCookiesAllowed());
344
345 if (metrics_enabled())
droger3e8d98b2015-03-18 15:29:53346 ResetCookieCountMetrics();
347
Chris Mumford800caa62018-04-20 19:34:44348 DeleteCookiesMatchingInfoAsync(std::move(delete_info), std::move(callback));
droger3e8d98b2015-03-18 15:29:53349}
350
rdsmith7ac81712017-06-22 17:09:54351void CookieStoreIOS::DeleteSessionCookiesAsync(DeleteCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42352 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53353
Victor Costanfb17d1a2018-02-23 03:42:26354 // If cookies are not allowed, a CookieStoreIOS subclass should be used
355 // instead.
356 DCHECK(SystemCookiesAllowed());
357
358 if (metrics_enabled())
droger3e8d98b2015-03-18 15:29:53359 ResetCookieCountMetrics();
360
Chris Mumford800caa62018-04-20 19:34:44361 CookieDeletionInfo delete_info;
362 delete_info.session_control =
363 CookieDeletionInfo::SessionControl::SESSION_COOKIES;
364 DeleteCookiesMatchingInfoAsync(std::move(delete_info), std::move(callback));
droger3e8d98b2015-03-18 15:29:53365}
366
rdsmith7ac81712017-06-22 17:09:54367void CookieStoreIOS::FlushStore(base::OnceClosure closure) {
Victor Costanb805fba2018-02-21 13:49:42368 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
mmenke96f3bab2016-01-22 17:34:02369
370 if (SystemCookiesAllowed()) {
371 // If cookies are disabled, the system store is empty, and the cookies are
372 // stashed on disk. Do not delete the cookies on the disk in this case.
Mohammad Refaat41032802017-10-06 04:15:57373 system_store_->GetAllCookiesAsync(
374 base ::BindOnce(&CookieStoreIOS::FlushStoreFromCookies,
375 weak_factory_.GetWeakPtr(), std::move(closure)));
376 return;
mmenke96f3bab2016-01-22 17:34:02377 }
Mohammad Refaat41032802017-10-06 04:15:57378
Victor Costanfb17d1a2018-02-23 03:42:26379 // This code path is used by a CookieStoreIOS subclass, which shares this
380 // implementation.
rdsmith7ac81712017-06-22 17:09:54381 cookie_monster_->FlushStore(std::move(closure));
mmenke96f3bab2016-01-22 17:34:02382 flush_closure_.Cancel();
383}
384
droger3e8d98b2015-03-18 15:29:53385#pragma mark -
maksim.sisovfdd9f092017-01-30 10:41:42386#pragma mark Protected methods
droger3e8d98b2015-03-18 15:29:53387
eugenebut2cbccb72016-12-30 16:27:52388CookieStoreIOS::CookieStoreIOS(
389 net::CookieMonster::PersistentCookieStore* persistent_store,
Helen Li4e4cb0d2018-08-21 14:50:47390 std::unique_ptr<SystemCookieStore> system_store,
391 NetLog* net_log)
392 : cookie_monster_(new net::CookieMonster(persistent_store,
Helen Li4e4cb0d2018-08-21 14:50:47393 net_log)),
Mohammad Refaat6a4276492017-09-08 00:18:52394 system_store_(std::move(system_store)),
eugenebut2cbccb72016-12-30 16:27:52395 metrics_enabled_(false),
eugenebut2cbccb72016-12-30 16:27:52396 cookie_cache_(new CookieCache()),
Victor Costan14f47c12018-03-01 08:02:24397 change_dispatcher_(this),
eugenebut2cbccb72016-12-30 16:27:52398 weak_factory_(this) {
Mohammad Refaat6a4276492017-09-08 00:18:52399 DCHECK(system_store_);
eugenebut2cbccb72016-12-30 16:27:52400
401 NotificationTrampoline::GetInstance()->AddObserver(this);
402
403 cookie_monster_->SetPersistSessionCookies(true);
404 cookie_monster_->SetForceKeepSessionState();
405}
406
Victor Costanfb17d1a2018-02-23 03:42:26407void CookieStoreIOS::FlushStoreFromCookies(base::OnceClosure closure,
408 NSArray<NSHTTPCookie*>* cookies) {
409 WriteToCookieMonster(cookies);
410 cookie_monster_->FlushStore(std::move(closure));
411 flush_closure_.Cancel();
412}
413
maksim.sisovfdd9f092017-01-30 10:41:42414CookieStoreIOS::SetCookiesCallback CookieStoreIOS::WrapSetCallback(
rdsmith7ac81712017-06-22 17:09:54415 SetCookiesCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42416 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
rdsmith7ac81712017-06-22 17:09:54417 return base::BindOnce(&CookieStoreIOS::UpdateCachesAfterSet,
418 weak_factory_.GetWeakPtr(), std::move(callback));
maksim.sisovfdd9f092017-01-30 10:41:42419}
420
421CookieStoreIOS::DeleteCallback CookieStoreIOS::WrapDeleteCallback(
rdsmith7ac81712017-06-22 17:09:54422 DeleteCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42423 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
rdsmith7ac81712017-06-22 17:09:54424 return base::BindOnce(&CookieStoreIOS::UpdateCachesAfterDelete,
425 weak_factory_.GetWeakPtr(), std::move(callback));
maksim.sisovfdd9f092017-01-30 10:41:42426}
427
rdsmith7ac81712017-06-22 17:09:54428base::OnceClosure CookieStoreIOS::WrapClosure(base::OnceClosure callback) {
Victor Costanb805fba2018-02-21 13:49:42429 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
rdsmith7ac81712017-06-22 17:09:54430 return base::BindOnce(&CookieStoreIOS::UpdateCachesAfterClosure,
431 weak_factory_.GetWeakPtr(), std::move(callback));
maksim.sisovfdd9f092017-01-30 10:41:42432}
433
434#pragma mark -
435#pragma mark Private methods
436
droger3e8d98b2015-03-18 15:29:53437bool CookieStoreIOS::SystemCookiesAllowed() {
Victor Costanb805fba2018-02-21 13:49:42438 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Mohammad Refaat6a4276492017-09-08 00:18:52439 return system_store_->GetCookieAcceptPolicy() !=
440 NSHTTPCookieAcceptPolicyNever;
droger3e8d98b2015-03-18 15:29:53441}
442
droger3e8d98b2015-03-18 15:29:53443void CookieStoreIOS::WriteToCookieMonster(NSArray* system_cookies) {
Victor Costanb805fba2018-02-21 13:49:42444 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53445 // Copy the cookies from the global cookie store to |cookie_monster_|.
446 // Unlike the system store, CookieMonster requires unique creation times.
447 net::CookieList cookie_list;
448 NSUInteger cookie_count = [system_cookies count];
449 cookie_list.reserve(cookie_count);
450 for (NSHTTPCookie* cookie in system_cookies) {
451 cookie_list.push_back(CanonicalCookieFromSystemCookie(
Mohammad Refaat41032802017-10-06 04:15:57452 cookie, system_store_->GetCookieCreationTime(cookie)));
droger3e8d98b2015-03-18 15:29:53453 }
454 cookie_monster_->SetAllCookiesAsync(cookie_list, SetCookiesCallback());
455
456 // Update metrics.
457 if (metrics_enabled_)
458 UMA_HISTOGRAM_COUNTS_10000("CookieIOS.CookieWrittenCount", cookie_count);
459}
460
Chris Mumford800caa62018-04-20 19:34:44461void CookieStoreIOS::DeleteCookiesMatchingInfoAsync(
Maks Orlovichf58b8da2019-02-11 17:12:45462 net::CookieDeletionInfo delete_info,
463 DeleteCallback callback) {
464 DeleteCookiesMatchingPredicateAsync(
465 base::BindRepeating(
466 [](const CookieDeletionInfo& delete_info,
467 const net::CanonicalCookie& cc) {
468 return delete_info.Matches(cc);
469 },
470 std::move(delete_info)),
471 std::move(callback));
472}
473
474void CookieStoreIOS::DeleteCookiesMatchingPredicateAsync(
475 const base::RepeatingCallback<bool(const net::CanonicalCookie&)>& predicate,
Chris Mumford800caa62018-04-20 19:34:44476 DeleteCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42477 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Mohammad Refaat41032802017-10-06 04:15:57478 __block DeleteCallback shared_callback = std::move(callback);
Maks Orlovichf58b8da2019-02-11 17:12:45479 __block base::RepeatingCallback<bool(const net::CanonicalCookie&)>
480 shared_predicate = predicate;
Mohammad Refaat41032802017-10-06 04:15:57481 base::WeakPtr<SystemCookieStore> weak_system_store =
482 system_store_->GetWeakPtr();
483 system_store_->GetAllCookiesAsync(
Sylvain Defresnea44edf42018-06-05 15:08:34484 base::BindOnce(^(NSArray<NSHTTPCookie*>* cookies) {
Mohammad Refaat2e6de022018-05-29 20:36:44485 if (!weak_system_store) {
486 if (!shared_callback.is_null())
487 std::move(shared_callback).Run(0);
488 return;
489 }
Mohammad Refaat41032802017-10-06 04:15:57490 int to_delete_count = 0;
491 for (NSHTTPCookie* cookie in cookies) {
Chris Mumford800caa62018-04-20 19:34:44492 base::Time creation_time =
493 weak_system_store->GetCookieCreationTime(cookie);
494 CanonicalCookie cc =
495 CanonicalCookieFromSystemCookie(cookie, creation_time);
Maks Orlovichf58b8da2019-02-11 17:12:45496 if (shared_predicate.Run(cc)) {
Mohammad Refaat41032802017-10-06 04:15:57497 weak_system_store->DeleteCookieAsync(
498 cookie, SystemCookieStore::SystemCookieCallback());
499 to_delete_count++;
500 }
501 }
droger3e8d98b2015-03-18 15:29:53502
Mohammad Refaat41032802017-10-06 04:15:57503 if (!shared_callback.is_null())
504 std::move(shared_callback).Run(to_delete_count);
505 }));
droger3e8d98b2015-03-18 15:29:53506}
507
508void CookieStoreIOS::OnSystemCookiesChanged() {
Victor Costanb805fba2018-02-21 13:49:42509 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53510
droger3e8d98b2015-03-18 15:29:53511 for (const auto& hook_map_entry : hook_map_) {
512 std::pair<GURL, std::string> key = hook_map_entry.first;
Mohammad Refaat41032802017-10-06 04:15:57513 UpdateCacheForCookieFromSystem(key.first, key.second,
514 /*run_callbacks=*/true);
droger3e8d98b2015-03-18 15:29:53515 }
516
517 // Do not schedule a flush if one is already scheduled.
518 if (!flush_closure_.IsCancelled())
519 return;
520
mmenke96f3bab2016-01-22 17:34:02521 flush_closure_.Reset(base::Bind(&CookieStoreIOS::FlushStore,
mmenke606c59c2016-03-07 18:20:55522 weak_factory_.GetWeakPtr(), base::Closure()));
skyostilc2740982015-06-05 19:15:31523 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
eugenebut8a37ce252017-01-10 14:13:13524 FROM_HERE, flush_closure_.callback(), base::TimeDelta::FromSeconds(10));
droger3e8d98b2015-03-18 15:29:53525}
526
Victor Costan14f47c12018-03-01 08:02:24527CookieChangeDispatcher& CookieStoreIOS::GetChangeDispatcher() {
528 return change_dispatcher_;
529}
530
Nate Fischerc6fb6cf2019-03-27 00:39:49531void CookieStoreIOS::SetCookieableSchemes(
532 const std::vector<std::string>& schemes,
533 SetCookieableSchemesCallback callback) {
534 // Not supported on iOS.
535 std::move(callback).Run(false);
536}
537
Victor Costan14f47c12018-03-01 08:02:24538std::unique_ptr<CookieChangeSubscription> CookieStoreIOS::AddCallbackForCookie(
539 const GURL& gurl,
540 const std::string& name,
541 CookieChangeCallback callback) {
Victor Costanb805fba2018-02-21 13:49:42542 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53543
544 // Prefill cookie cache with all pertinent cookies for |url| if needed.
545 std::pair<GURL, std::string> key(gurl, name);
546 if (hook_map_.count(key) == 0) {
Mohammad Refaat41032802017-10-06 04:15:57547 UpdateCacheForCookieFromSystem(gurl, name, /*run_callbacks=*/false);
Victor Costan14f47c12018-03-01 08:02:24548 hook_map_[key] = std::make_unique<CookieChangeCallbackList>();
droger3e8d98b2015-03-18 15:29:53549 }
550
551 DCHECK(hook_map_.find(key) != hook_map_.end());
Sergey Kuznetsov0edf1612018-10-12 14:29:05552 auto subscription =
553 std::make_unique<Subscription>(hook_map_[key]->Add(std::move(callback)));
554 all_subscriptions_.Append(subscription.get());
555
556 return subscription;
nharper5babb5e62016-03-09 18:58:07557}
558
Mohammad Refaat41032802017-10-06 04:15:57559void CookieStoreIOS::UpdateCacheForCookieFromSystem(
droger3e8d98b2015-03-18 15:29:53560 const GURL& gurl,
Mohammad Refaat41032802017-10-06 04:15:57561 const std::string& cookie_name,
562 bool run_callbacks) {
Victor Costanb805fba2018-02-21 13:49:42563 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Mohammad Refaat41032802017-10-06 04:15:57564 system_store_->GetCookiesForURLAsync(
565 gurl, base::BindOnce(&CookieStoreIOS::UpdateCacheForCookies,
566 weak_factory_.GetWeakPtr(), gurl, cookie_name,
567 run_callbacks));
568}
569
570void CookieStoreIOS::UpdateCacheForCookies(const GURL& gurl,
571 const std::string& cookie_name,
572 bool run_callbacks,
573 NSArray<NSHTTPCookie*>* nscookies) {
574 std::vector<net::CanonicalCookie> cookies;
575 std::vector<net::CanonicalCookie> out_removed_cookies;
576 std::vector<net::CanonicalCookie> out_added_cookies;
577 for (NSHTTPCookie* nscookie in nscookies) {
578 if (base::SysNSStringToUTF8(nscookie.name) == cookie_name) {
579 net::CanonicalCookie canonical_cookie = CanonicalCookieFromSystemCookie(
580 nscookie, system_store_->GetCookieCreationTime(nscookie));
581 cookies.push_back(canonical_cookie);
582 }
583 }
584
585 bool changes = cookie_cache_->Update(
586 gurl, cookie_name, cookies, &out_removed_cookies, &out_added_cookies);
587 if (run_callbacks && changes) {
588 RunCallbacksForCookies(gurl, cookie_name, out_removed_cookies,
Victor Costan14f47c12018-03-01 08:02:24589 net::CookieChangeCause::UNKNOWN_DELETION);
Mohammad Refaat41032802017-10-06 04:15:57590 RunCallbacksForCookies(gurl, cookie_name, out_added_cookies,
Victor Costan14f47c12018-03-01 08:02:24591 net::CookieChangeCause::INSERTED);
Mohammad Refaat41032802017-10-06 04:15:57592 }
droger3e8d98b2015-03-18 15:29:53593}
594
595void CookieStoreIOS::RunCallbacksForCookies(
596 const GURL& url,
597 const std::string& name,
598 const std::vector<net::CanonicalCookie>& cookies,
Victor Costan14f47c12018-03-01 08:02:24599 net::CookieChangeCause cause) {
Victor Costanb805fba2018-02-21 13:49:42600 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53601 if (cookies.empty())
602 return;
603
604 std::pair<GURL, std::string> key(url, name);
Victor Costan14f47c12018-03-01 08:02:24605 CookieChangeCallbackList* callbacks = hook_map_[key].get();
droger3e8d98b2015-03-18 15:29:53606 for (const auto& cookie : cookies) {
607 DCHECK_EQ(name, cookie.Name());
Lily Chen19cced422019-10-17 21:45:55608 // TODO(crbug.com/978172): Support CookieAccessSemantics values on iOS and
609 // use it to check IncludeForRequestURL before notifying?
610 callbacks->Notify(net::CookieChangeInfo(
611 cookie, net::CookieAccessSemantics::UNKNOWN, cause));
droger3e8d98b2015-03-18 15:29:53612 }
613}
614
Aaron Tagliaboschia4c64b52019-01-25 03:28:49615void CookieStoreIOS::GotCookieListFor(
616 const std::pair<GURL, std::string> key,
Lily Chenf068a762019-08-21 21:10:50617 const net::CookieStatusList& cookies,
Aaron Tagliaboschia4c64b52019-01-25 03:28:49618 const net::CookieStatusList& excluded_cookies) {
Victor Costanb805fba2018-02-21 13:49:42619 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53620
621 net::CookieList filtered;
622 OnlyCookiesWithName(cookies, key.second, &filtered);
623 std::vector<net::CanonicalCookie> removed_cookies;
624 std::vector<net::CanonicalCookie> added_cookies;
625 if (cookie_cache_->Update(key.first, key.second, filtered, &removed_cookies,
626 &added_cookies)) {
nharper352933e2016-09-30 18:24:57627 RunCallbacksForCookies(key.first, key.second, removed_cookies,
Victor Costan14f47c12018-03-01 08:02:24628 net::CookieChangeCause::UNKNOWN_DELETION);
nharper352933e2016-09-30 18:24:57629 RunCallbacksForCookies(key.first, key.second, added_cookies,
Victor Costan14f47c12018-03-01 08:02:24630 net::CookieChangeCause::INSERTED);
droger3e8d98b2015-03-18 15:29:53631 }
632}
633
droger3e8d98b2015-03-18 15:29:53634void CookieStoreIOS::UpdateCachesFromCookieMonster() {
Victor Costanb805fba2018-02-21 13:49:42635 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53636 for (const auto& hook_map_entry : hook_map_) {
637 std::pair<GURL, std::string> key = hook_map_entry.first;
rdsmith7ac81712017-06-22 17:09:54638 GetCookieListCallback callback = base::BindOnce(
mmenke606c59c2016-03-07 18:20:55639 &CookieStoreIOS::GotCookieListFor, weak_factory_.GetWeakPtr(), key);
Lily Chenf2dc5f02019-08-12 19:43:11640 cookie_monster_->GetCookieListWithOptionsAsync(
641 key.first, net::CookieOptions::MakeAllInclusive(), std::move(callback));
droger3e8d98b2015-03-18 15:29:53642 }
643}
644
Aaron Tagliaboschi29764f52019-02-21 17:19:59645void CookieStoreIOS::UpdateCachesAfterSet(
646 SetCookiesCallback callback,
647 net::CanonicalCookie::CookieInclusionStatus status) {
Victor Costanb805fba2018-02-21 13:49:42648 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
Lily Chenf53dfbcd2019-08-30 01:42:10649 if (status.IsInclude())
droger3e8d98b2015-03-18 15:29:53650 UpdateCachesFromCookieMonster();
droger4c3ea112016-02-22 19:19:33651 if (!callback.is_null())
Aaron Tagliaboschi29764f52019-02-21 17:19:59652 std::move(callback).Run(status);
droger3e8d98b2015-03-18 15:29:53653}
654
rdsmith7ac81712017-06-22 17:09:54655void CookieStoreIOS::UpdateCachesAfterDelete(DeleteCallback callback,
rdsmitha5beda162017-07-08 13:55:42656 uint32_t num_deleted) {
Victor Costanb805fba2018-02-21 13:49:42657 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53658 UpdateCachesFromCookieMonster();
droger4c3ea112016-02-22 19:19:33659 if (!callback.is_null())
rdsmith7ac81712017-06-22 17:09:54660 std::move(callback).Run(num_deleted);
droger3e8d98b2015-03-18 15:29:53661}
662
rdsmith7ac81712017-06-22 17:09:54663void CookieStoreIOS::UpdateCachesAfterClosure(base::OnceClosure callback) {
Victor Costanb805fba2018-02-21 13:49:42664 DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
droger3e8d98b2015-03-18 15:29:53665 UpdateCachesFromCookieMonster();
droger4c3ea112016-02-22 19:19:33666 if (!callback.is_null())
rdsmith7ac81712017-06-22 17:09:54667 std::move(callback).Run();
droger3e8d98b2015-03-18 15:29:53668}
669
mmenke9fa44f2d2016-01-22 23:36:39670net::CookieList
671CookieStoreIOS::CanonicalCookieListFromSystemCookies(NSArray* cookies) {
672 net::CookieList cookie_list;
673 cookie_list.reserve([cookies count]);
674 for (NSHTTPCookie* cookie in cookies) {
Mohammad Refaat41032802017-10-06 04:15:57675 base::Time created = system_store_->GetCookieCreationTime(cookie);
mmenke9fa44f2d2016-01-22 23:36:39676 cookie_list.push_back(CanonicalCookieFromSystemCookie(cookie, created));
677 }
678 return cookie_list;
679}
680
Lily Chenf068a762019-08-21 21:10:50681net::CookieStatusList
682CookieStoreIOS::CanonicalCookieWithStatusListFromSystemCookies(
683 NSArray* cookies) {
684 net::CookieStatusList cookie_list;
685 cookie_list.reserve([cookies count]);
686 for (NSHTTPCookie* cookie in cookies) {
687 base::Time created = system_store_->GetCookieCreationTime(cookie);
Lily Chenf53dfbcd2019-08-30 01:42:10688 cookie_list.push_back({CanonicalCookieFromSystemCookie(cookie, created),
689 net::CanonicalCookie::CookieInclusionStatus()});
Lily Chenf068a762019-08-21 21:10:50690 }
691 return cookie_list;
692}
693
Mohammad Refaat41032802017-10-06 04:15:57694void CookieStoreIOS::RunGetCookieListCallbackOnSystemCookies(
695 CookieStoreIOS::GetCookieListCallback callback,
696 NSArray<NSHTTPCookie*>* cookies) {
697 if (!callback.is_null()) {
Aaron Tagliaboschia4c64b52019-01-25 03:28:49698 net::CookieStatusList excluded_cookies;
Lily Chenf068a762019-08-21 21:10:50699 std::move(callback).Run(
700 CanonicalCookieWithStatusListFromSystemCookies(cookies),
701 excluded_cookies);
702 }
703}
704
705void CookieStoreIOS::RunGetAllCookiesCallbackOnSystemCookies(
706 CookieStoreIOS::GetAllCookiesCallback callback,
707 NSArray<NSHTTPCookie*>* cookies) {
708 if (!callback.is_null()) {
709 std::move(callback).Run(CanonicalCookieListFromSystemCookies(cookies));
Mohammad Refaat41032802017-10-06 04:15:57710 }
711}
712
droger3e8d98b2015-03-18 15:29:53713} // namespace net