2 * Copyright (C) 2015-2018 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #import "NetworkStorageSession.h"
30 #import "CookieRequestHeaderFieldProxy.h"
31 #import "CookieStorageObserver.h"
32 #import "CookiesStrategy.h"
33 #import "SameSiteInfo.h"
35 #import <pal/spi/cf/CFNetworkSPI.h>
36 #import <wtf/BlockObjCExceptions.h>
37 #import <wtf/Optional.h>
38 #import <wtf/ProcessPrivilege.h>
39 #import <wtf/text/StringBuilder.h>
45 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
46 @interface NSHTTPCookieStorage (Staging)
47 - (void)_getCookiesForURL:(NSURL *)url mainDocumentURL:(NSURL *)mainDocumentURL partition:(NSString *)partition policyProperties:(NSDictionary*)props completionHandler:(void (^)(NSArray *))completionHandler;
48 - (void)_setCookies:(NSArray *)cookies forURL:(NSURL *)URL mainDocumentURL:(NSURL *)mainDocumentURL policyProperties:(NSDictionary*) props;
54 void NetworkStorageSession::setCookie(const Cookie& cookie)
56 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
58 BEGIN_BLOCK_OBJC_EXCEPTIONS;
59 [nsCookieStorage() setCookie:(NSHTTPCookie *)cookie];
60 END_BLOCK_OBJC_EXCEPTIONS;
63 void NetworkStorageSession::setCookies(const Vector<Cookie>& cookies, const URL& url, const URL& mainDocumentURL)
65 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
67 RetainPtr<NSMutableArray> nsCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:cookies.size()]);
68 for (const auto& cookie : cookies)
69 [nsCookies addObject:(NSHTTPCookie *)cookie];
71 BEGIN_BLOCK_OBJC_EXCEPTIONS;
72 [nsCookieStorage() setCookies:nsCookies.get() forURL:(NSURL *)url mainDocumentURL:(NSURL *)mainDocumentURL];
73 END_BLOCK_OBJC_EXCEPTIONS;
76 void NetworkStorageSession::deleteCookie(const Cookie& cookie)
78 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
79 [nsCookieStorage() deleteCookie:(NSHTTPCookie *)cookie];
82 static Vector<Cookie> nsCookiesToCookieVector(NSArray<NSHTTPCookie *> *nsCookies)
84 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
86 Vector<Cookie> cookies;
87 cookies.reserveInitialCapacity(nsCookies.count);
88 for (NSHTTPCookie *nsCookie in nsCookies)
89 cookies.uncheckedAppend(nsCookie);
94 Vector<Cookie> NetworkStorageSession::getAllCookies()
96 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
97 return nsCookiesToCookieVector(nsCookieStorage().cookies);
100 Vector<Cookie> NetworkStorageSession::getCookies(const URL& url)
102 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
103 return nsCookiesToCookieVector([nsCookieStorage() cookiesForURL:(NSURL *)url]);
106 void NetworkStorageSession::flushCookieStore()
108 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
109 [nsCookieStorage() _saveCookies];
112 NSHTTPCookieStorage *NetworkStorageSession::nsCookieStorage() const
114 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
115 auto cfCookieStorage = cookieStorage();
116 if (!cfCookieStorage || [NSHTTPCookieStorage sharedHTTPCookieStorage]._cookieStorage == cfCookieStorage)
117 return [NSHTTPCookieStorage sharedHTTPCookieStorage];
119 return [[[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cfCookieStorage.get()] autorelease];
122 CookieStorageObserver& NetworkStorageSession::cookieStorageObserver() const
124 if (!m_cookieStorageObserver)
125 m_cookieStorageObserver = CookieStorageObserver::create(nsCookieStorage());
127 return *m_cookieStorageObserver;
130 CFURLStorageSessionRef createPrivateStorageSession(CFStringRef identifier)
132 const void* sessionPropertyKeys[] = { _kCFURLStorageSessionIsPrivate };
133 const void* sessionPropertyValues[] = { kCFBooleanTrue };
134 auto sessionProperties = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, sessionPropertyKeys, sessionPropertyValues, sizeof(sessionPropertyKeys) / sizeof(*sessionPropertyKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
135 auto storageSession = adoptCF(_CFURLStorageSessionCreate(kCFAllocatorDefault, identifier, sessionProperties.get()));
140 // The private storage session should have the same properties as the default storage session,
141 // with the exception that it should be in-memory only storage.
143 // FIXME 9199649: If any of the storages do not exist, do no use the storage session.
144 // This could occur if there is an issue figuring out where to place a storage on disk (e.g. the
145 // sandbox does not allow CFNetwork access).
147 auto cache = adoptCF(_CFURLStorageSessionCopyCache(kCFAllocatorDefault, storageSession.get()));
151 CFURLCacheSetDiskCapacity(cache.get(), 0); // Setting disk cache size should not be necessary once <rdar://problem/12656814> is fixed.
152 CFURLCacheSetMemoryCapacity(cache.get(), [[NSURLCache sharedURLCache] memoryCapacity]);
154 if (!NetworkStorageSession::processMayUseCookieAPI())
155 return storageSession.leakRef();
157 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
159 auto cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get()));
163 // FIXME: Use _CFHTTPCookieStorageGetDefault when USE(CFNETWORK) is defined in WebKit for consistency.
164 CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage.get(), [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy]);
166 return storageSession.leakRef();
169 static NSArray *httpCookies(CFHTTPCookieStorageRef cookieStorage)
171 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
173 return [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
175 auto cookies = adoptCF(CFHTTPCookieStorageCopyCookies(cookieStorage));
176 return [NSHTTPCookie _cf2nsCookies:cookies.get()];
179 static void deleteHTTPCookie(CFHTTPCookieStorageRef cookieStorage, NSHTTPCookie *cookie)
181 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
182 if (!cookieStorage) {
183 [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
187 CFHTTPCookieStorageDeleteCookie(cookieStorage, [cookie _GetInternalCFHTTPCookie]);
190 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
191 static RetainPtr<NSDictionary> policyProperties(const SameSiteInfo& sameSiteInfo, NSURL *url)
193 static NSURL *emptyURL = [[NSURL alloc] initWithString:@""];
194 NSDictionary *policyProperties = @{
195 @"_kCFHTTPCookiePolicyPropertySiteForCookies": sameSiteInfo.isSameSite ? url : emptyURL,
196 @"_kCFHTTPCookiePolicyPropertyIsTopLevelNavigation": [NSNumber numberWithBool:sameSiteInfo.isTopSite],
198 return policyProperties;
202 static NSArray *cookiesForURL(NSHTTPCookieStorage *storage, NSURL *url, NSURL *mainDocumentURL, const std::optional<SameSiteInfo>& sameSiteInfo, NSString *partition = nullptr)
204 // The _getCookiesForURL: method calls the completionHandler synchronously. We use std::optional<> to ensure this invariant.
205 std::optional<RetainPtr<NSArray *>> cookiesPtr;
206 auto completionHandler = [&cookiesPtr] (NSArray *cookies) {
207 cookiesPtr = retainPtr(cookies);
209 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
210 if ([storage respondsToSelector:@selector(_getCookiesForURL:mainDocumentURL:partition:policyProperties:completionHandler:)])
211 [storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL partition:partition policyProperties:sameSiteInfo ? policyProperties(sameSiteInfo.value(), url).get() : nullptr completionHandler:completionHandler];
213 [storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL partition:partition completionHandler:completionHandler];
215 [storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL partition:partition completionHandler:completionHandler];
216 UNUSED_PARAM(sameSiteInfo);
218 ASSERT(!!cookiesPtr);
219 return cookiesPtr->autorelease();
222 static void setHTTPCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSArray *cookies, NSURL *url, NSURL *mainDocumentURL, const SameSiteInfo& sameSiteInfo)
224 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
225 if (!cookieStorage) {
226 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
227 if ([NSHTTPCookieStorage instancesRespondToSelector:@selector(_setCookies:forURL:mainDocumentURL:policyProperties:)])
228 [[NSHTTPCookieStorage sharedHTTPCookieStorage] _setCookies:cookies forURL:url mainDocumentURL:mainDocumentURL policyProperties:policyProperties(sameSiteInfo, url).get()];
231 [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:url mainDocumentURL:mainDocumentURL];
234 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
235 if ([NSHTTPCookieStorage instancesRespondToSelector:@selector(_setCookies:forURL:mainDocumentURL:policyProperties:)]) {
236 // FIXME: Stop creating a new NSHTTPCookieStorage object each time we want to query the cookie jar.
237 // NetworkStorageSession could instead keep a NSHTTPCookieStorage object for us.
238 RetainPtr<NSHTTPCookieStorage> nsCookieStorage = adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorage]);
239 [nsCookieStorage _setCookies:cookies forURL:url mainDocumentURL:mainDocumentURL policyProperties:policyProperties(sameSiteInfo, url).get()];
242 auto cfCookies = adoptCF([NSHTTPCookie _ns2cfCookies:cookies]);
243 CFHTTPCookieStorageSetCookies(cookieStorage, cfCookies.get(), [url _cfurl], [mainDocumentURL _cfurl]);
244 #if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
247 UNUSED_PARAM(sameSiteInfo);
251 static NSArray *httpCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSURL *firstParty, const std::optional<SameSiteInfo>& sameSiteInfo, NSURL *url)
253 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
255 cookieStorage = _CFHTTPCookieStorageGetDefault(kCFAllocatorDefault);
257 // FIXME: Stop creating a new NSHTTPCookieStorage object each time we want to query the cookie jar.
258 // NetworkStorageSession could instead keep a NSHTTPCookieStorage object for us.
259 RetainPtr<NSHTTPCookieStorage> nsCookieStorage = adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorage]);
260 return cookiesForURL(nsCookieStorage.get(), url, firstParty, sameSiteInfo);
263 static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies)
265 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
266 NSUInteger count = [unfilteredCookies count];
267 RetainPtr<NSMutableArray> filteredCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:count]);
269 const NSTimeInterval secondsPerWeek = 7 * 24 * 60 * 60;
270 for (NSUInteger i = 0; i < count; ++i) {
271 NSHTTPCookie *cookie = (NSHTTPCookie *)[unfilteredCookies objectAtIndex:i];
273 // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
274 // which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent
275 // that, but we also need to avoid sending cookies that were previously stored, and
276 // there's no harm to doing this check because such a cookie is never valid.
277 if (![[cookie name] length])
280 if ([cookie isHTTPOnly])
283 // Cap lifetime of persistent, client-side cookies to a week.
284 if (![cookie isSessionOnly]) {
285 if (!cookie.expiresDate || cookie.expiresDate.timeIntervalSinceNow > secondsPerWeek) {
286 RetainPtr<NSMutableDictionary<NSHTTPCookiePropertyKey, id>> properties = adoptNS([[cookie properties] mutableCopy]);
287 RetainPtr<NSDate> dateInAWeek = adoptNS([[NSDate alloc] initWithTimeIntervalSinceNow:secondsPerWeek]);
288 [properties setObject:dateInAWeek.get() forKey:NSHTTPCookieExpires];
289 cookie = [NSHTTPCookie cookieWithProperties:properties.get()];
293 [filteredCookies.get() addObject:cookie];
296 return filteredCookies;
299 static NSArray *cookiesForURL(const NetworkStorageSession& session, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID)
301 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
302 if (session.shouldBlockCookies(firstParty, url, frameID, pageID))
305 UNUSED_PARAM(frameID);
306 UNUSED_PARAM(pageID);
308 return httpCookiesForURL(session.cookieStorage().get(), firstParty, sameSiteInfo, url);
311 enum IncludeHTTPOnlyOrNot { DoNotIncludeHTTPOnly, IncludeHTTPOnly };
312 static std::pair<String, bool> cookiesForSession(const NetworkStorageSession& session, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeHTTPOnlyOrNot includeHTTPOnly, IncludeSecureCookies includeSecureCookies)
314 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
316 BEGIN_BLOCK_OBJC_EXCEPTIONS;
318 NSArray *cookies = cookiesForURL(session, firstParty, sameSiteInfo, url, frameID, pageID);
319 if (![cookies count])
320 return { String(), false }; // Return a null string, not an empty one that StringBuilder would create below.
322 StringBuilder cookiesBuilder;
323 bool didAccessSecureCookies = false;
324 for (NSHTTPCookie *cookie in cookies) {
325 if (![[cookie name] length])
328 if (!includeHTTPOnly && [cookie isHTTPOnly])
331 if ([cookie isSecure]) {
332 didAccessSecureCookies = true;
333 if (includeSecureCookies == IncludeSecureCookies::No)
337 if (!cookiesBuilder.isEmpty())
338 cookiesBuilder.appendLiteral("; ");
340 cookiesBuilder.append([cookie name]);
341 cookiesBuilder.append('=');
342 cookiesBuilder.append([cookie value]);
344 return { cookiesBuilder.toString(), didAccessSecureCookies };
346 END_BLOCK_OBJC_EXCEPTIONS;
347 return { String(), false };
350 static void deleteAllHTTPCookies(CFHTTPCookieStorageRef cookieStorage)
352 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
354 if (!cookieStorage) {
355 NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
356 NSArray *cookies = [cookieStorage cookies];
360 for (NSHTTPCookie *cookie in cookies)
361 [cookieStorage deleteCookie:cookie];
365 CFHTTPCookieStorageDeleteAllCookies(cookieStorage);
368 std::pair<String, bool> NetworkStorageSession::cookiesForDOM(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies) const
370 return cookiesForSession(*this, firstParty, sameSiteInfo, url, frameID, pageID, DoNotIncludeHTTPOnly, includeSecureCookies);
373 std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, IncludeSecureCookies includeSecureCookies) const
375 return cookiesForSession(*this, firstParty, sameSiteInfo, url, frameID, pageID, IncludeHTTPOnly, includeSecureCookies);
378 std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(const CookieRequestHeaderFieldProxy& headerFieldProxy) const
380 return cookiesForSession(*this, headerFieldProxy.firstParty, headerFieldProxy.sameSiteInfo, headerFieldProxy.url, headerFieldProxy.frameID, headerFieldProxy.pageID, IncludeHTTPOnly, headerFieldProxy.includeSecureCookies);
383 void NetworkStorageSession::setCookiesFromDOM(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, const String& cookieStr) const
385 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
387 BEGIN_BLOCK_OBJC_EXCEPTIONS;
389 // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
390 // which would be sent as "Cookie: =".
391 if (cookieStr.isEmpty())
394 // <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034>
395 // cookiesWithResponseHeaderFields doesn't parse cookies without a value
396 String cookieString = cookieStr.contains('=') ? cookieStr : cookieStr + "=";
398 NSURL *cookieURL = url;
399 NSDictionary *headerFields = [NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"];
402 NSArray *unfilteredCookies = [NSHTTPCookie _parsedCookiesWithResponseHeaderFields:headerFields forURL:cookieURL];
404 NSArray *unfilteredCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headerFields forURL:cookieURL];
407 RetainPtr<NSArray> filteredCookies = filterCookies(unfilteredCookies);
408 ASSERT([filteredCookies.get() count] <= 1);
410 #if HAVE(CFNETWORK_STORAGE_PARTITIONING)
411 if (shouldBlockCookies(firstParty, url, frameID, pageID))
414 UNUSED_PARAM(frameID);
415 UNUSED_PARAM(pageID);
418 setHTTPCookiesForURL(cookieStorage().get(), filteredCookies.get(), cookieURL, firstParty, sameSiteInfo);
420 END_BLOCK_OBJC_EXCEPTIONS;
423 static NSHTTPCookieAcceptPolicy httpCookieAcceptPolicy(CFHTTPCookieStorageRef cookieStorage)
425 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
428 return [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy];
430 return static_cast<NSHTTPCookieAcceptPolicy>(CFHTTPCookieStorageGetCookieAcceptPolicy(cookieStorage));
433 bool NetworkStorageSession::cookiesEnabled() const
435 BEGIN_BLOCK_OBJC_EXCEPTIONS;
437 NSHTTPCookieAcceptPolicy cookieAcceptPolicy = httpCookieAcceptPolicy(cookieStorage().get());
438 return cookieAcceptPolicy == NSHTTPCookieAcceptPolicyAlways || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain;
440 END_BLOCK_OBJC_EXCEPTIONS;
444 bool NetworkStorageSession::getRawCookies(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, std::optional<uint64_t> frameID, std::optional<uint64_t> pageID, Vector<Cookie>& rawCookies) const
447 BEGIN_BLOCK_OBJC_EXCEPTIONS;
449 NSArray *cookies = cookiesForURL(*this, firstParty, sameSiteInfo, url, frameID, pageID);
450 NSUInteger count = [cookies count];
451 rawCookies.reserveCapacity(count);
452 for (NSUInteger i = 0; i < count; ++i) {
453 NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
454 rawCookies.uncheckedAppend({ cookie });
457 END_BLOCK_OBJC_EXCEPTIONS;
461 void NetworkStorageSession::deleteCookie(const URL& url, const String& cookieName) const
463 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
465 BEGIN_BLOCK_OBJC_EXCEPTIONS;
467 RetainPtr<CFHTTPCookieStorageRef> cookieStorage = this->cookieStorage();
468 NSArray *cookies = httpCookiesForURL(cookieStorage.get(), nil, std::nullopt, url);
470 NSString *cookieNameString = cookieName;
472 NSUInteger count = [cookies count];
473 for (NSUInteger i = 0; i < count; ++i) {
474 NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
475 if ([[cookie name] isEqualToString:cookieNameString])
476 deleteHTTPCookie(cookieStorage.get(), cookie);
479 END_BLOCK_OBJC_EXCEPTIONS;
482 void NetworkStorageSession::getHostnamesWithCookies(HashSet<String>& hostnames)
484 BEGIN_BLOCK_OBJC_EXCEPTIONS;
486 NSArray *cookies = httpCookies(cookieStorage().get());
488 for (NSHTTPCookie* cookie in cookies)
489 hostnames.add([cookie domain]);
491 END_BLOCK_OBJC_EXCEPTIONS;
494 void NetworkStorageSession::deleteAllCookies()
496 deleteAllHTTPCookies(cookieStorage().get());
499 void NetworkStorageSession::deleteCookiesForHostnames(const Vector<String>& hostnames)
501 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
503 BEGIN_BLOCK_OBJC_EXCEPTIONS;
505 RetainPtr<CFHTTPCookieStorageRef> cookieStorage = this->cookieStorage();
506 NSArray *cookies = httpCookies(cookieStorage.get());
510 HashMap<String, Vector<RetainPtr<NSHTTPCookie>>> cookiesByDomain;
511 for (NSHTTPCookie* cookie in cookies) {
512 auto& cookies = cookiesByDomain.add(cookie.domain, Vector<RetainPtr<NSHTTPCookie>>()).iterator->value;
513 cookies.append(cookie);
516 for (const auto& hostname : hostnames) {
517 auto it = cookiesByDomain.find(hostname);
518 if (it == cookiesByDomain.end())
521 for (auto& cookie : it->value)
522 deleteHTTPCookie(cookieStorage.get(), cookie.get());
525 [nsCookieStorage() _saveCookies];
527 END_BLOCK_OBJC_EXCEPTIONS;
530 void NetworkStorageSession::deleteAllCookiesModifiedSince(WallTime timePoint)
532 ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
534 if (![NSHTTPCookieStorage instancesRespondToSelector:@selector(removeCookiesSinceDate:)])
537 NSTimeInterval timeInterval = timePoint.secondsSinceEpoch().seconds();
538 NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
540 auto *storage = nsCookieStorage();
542 [storage removeCookiesSinceDate:date];
543 [storage _saveCookies];
546 } // namespace WebCore