blob: ddca2c63cce30a6c2ce003db77984c219887b47d [file] [log] [blame]
/*
* Copyright (C) 2015-2018 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "NetworkStorageSession.h"
#import "Cookie.h"
#import "CookieRequestHeaderFieldProxy.h"
#import "CookieStorageObserver.h"
#import "SameSiteInfo.h"
#import <pal/spi/cf/CFNetworkSPI.h>
#import <wtf/BlockObjCExceptions.h>
#import <wtf/Optional.h>
#import <wtf/ProcessPrivilege.h>
#import <wtf/URL.h>
#import <wtf/text/StringBuilder.h>
@interface NSURL ()
- (CFURLRef)_cfurl;
@end
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
@interface NSHTTPCookieStorage (Staging)
- (void)_getCookiesForURL:(NSURL *)url mainDocumentURL:(NSURL *)mainDocumentURL partition:(NSString *)partition policyProperties:(NSDictionary*)props completionHandler:(void (^)(NSArray *))completionHandler;
- (void)_setCookies:(NSArray *)cookies forURL:(NSURL *)URL mainDocumentURL:(NSURL *)mainDocumentURL policyProperties:(NSDictionary*) props;
@end
#endif
namespace WebCore {
void NetworkStorageSession::setCookie(const Cookie& cookie)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
BEGIN_BLOCK_OBJC_EXCEPTIONS;
[nsCookieStorage() setCookie:(NSHTTPCookie *)cookie];
END_BLOCK_OBJC_EXCEPTIONS;
}
void NetworkStorageSession::setCookies(const Vector<Cookie>& cookies, const URL& url, const URL& mainDocumentURL)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
RetainPtr<NSMutableArray> nsCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:cookies.size()]);
for (const auto& cookie : cookies)
[nsCookies addObject:(NSHTTPCookie *)cookie];
BEGIN_BLOCK_OBJC_EXCEPTIONS;
[nsCookieStorage() setCookies:nsCookies.get() forURL:(NSURL *)url mainDocumentURL:(NSURL *)mainDocumentURL];
END_BLOCK_OBJC_EXCEPTIONS;
}
void NetworkStorageSession::deleteCookie(const Cookie& cookie)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
[nsCookieStorage() deleteCookie:(NSHTTPCookie *)cookie];
}
static Vector<Cookie> nsCookiesToCookieVector(NSArray<NSHTTPCookie *> *nsCookies)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
Vector<Cookie> cookies;
cookies.reserveInitialCapacity(nsCookies.count);
for (NSHTTPCookie *nsCookie in nsCookies)
cookies.uncheckedAppend(nsCookie);
return cookies;
}
Vector<Cookie> NetworkStorageSession::getAllCookies()
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
return nsCookiesToCookieVector(nsCookieStorage().cookies);
}
Vector<Cookie> NetworkStorageSession::getCookies(const URL& url)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
return nsCookiesToCookieVector([nsCookieStorage() cookiesForURL:(NSURL *)url]);
}
void NetworkStorageSession::hasCookies(const RegistrableDomain& domain, CompletionHandler<void(bool)>&& completionHandler) const
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
for (NSHTTPCookie *nsCookie in nsCookieStorage().cookies) {
if (RegistrableDomain::uncheckedCreateFromHost(nsCookie.domain) == domain) {
completionHandler(true);
return;
}
}
completionHandler(false);
}
void NetworkStorageSession::flushCookieStore()
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
[nsCookieStorage() _saveCookies];
}
NSHTTPCookieStorage *NetworkStorageSession::nsCookieStorage() const
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
auto cfCookieStorage = cookieStorage();
if (!cfCookieStorage || [NSHTTPCookieStorage sharedHTTPCookieStorage]._cookieStorage == cfCookieStorage)
return [NSHTTPCookieStorage sharedHTTPCookieStorage];
return [[[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cfCookieStorage.get()] autorelease];
}
CookieStorageObserver& NetworkStorageSession::cookieStorageObserver() const
{
if (!m_cookieStorageObserver)
m_cookieStorageObserver = makeUnique<CookieStorageObserver>(nsCookieStorage());
return *m_cookieStorageObserver;
}
CFURLStorageSessionRef createPrivateStorageSession(CFStringRef identifier)
{
const void* sessionPropertyKeys[] = { _kCFURLStorageSessionIsPrivate };
const void* sessionPropertyValues[] = { kCFBooleanTrue };
auto sessionProperties = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, sessionPropertyKeys, sessionPropertyValues, sizeof(sessionPropertyKeys) / sizeof(*sessionPropertyKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
auto storageSession = adoptCF(_CFURLStorageSessionCreate(kCFAllocatorDefault, identifier, sessionProperties.get()));
if (!storageSession)
return nullptr;
// The private storage session should have the same properties as the default storage session,
// with the exception that it should be in-memory only storage.
// FIXME 9199649: If any of the storages do not exist, do no use the storage session.
// This could occur if there is an issue figuring out where to place a storage on disk (e.g. the
// sandbox does not allow CFNetwork access).
auto cache = adoptCF(_CFURLStorageSessionCopyCache(kCFAllocatorDefault, storageSession.get()));
if (!cache)
return nullptr;
CFURLCacheSetDiskCapacity(cache.get(), 0); // Setting disk cache size should not be necessary once <rdar://problem/12656814> is fixed.
CFURLCacheSetMemoryCapacity(cache.get(), [[NSURLCache sharedURLCache] memoryCapacity]);
if (!NetworkStorageSession::processMayUseCookieAPI())
return storageSession.leakRef();
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
auto cookieStorage = adoptCF(_CFURLStorageSessionCopyCookieStorage(kCFAllocatorDefault, storageSession.get()));
if (!cookieStorage)
return nullptr;
// FIXME: Use _CFHTTPCookieStorageGetDefault when USE(CFNETWORK) is defined in WebKit for consistency.
CFHTTPCookieStorageSetCookieAcceptPolicy(cookieStorage.get(), [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy]);
return storageSession.leakRef();
}
static NSArray *httpCookies(CFHTTPCookieStorageRef cookieStorage)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
if (!cookieStorage)
return [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
auto cookies = adoptCF(CFHTTPCookieStorageCopyCookies(cookieStorage));
return [NSHTTPCookie _cf2nsCookies:cookies.get()];
}
static void deleteHTTPCookie(CFHTTPCookieStorageRef cookieStorage, NSHTTPCookie *cookie)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
if (!cookieStorage) {
[[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
return;
}
CFHTTPCookieStorageDeleteCookie(cookieStorage, [cookie _GetInternalCFHTTPCookie]);
}
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
static RetainPtr<NSDictionary> policyProperties(const SameSiteInfo& sameSiteInfo, NSURL *url)
{
static NSURL *emptyURL = [[NSURL alloc] initWithString:@""];
NSDictionary *policyProperties = @{
@"_kCFHTTPCookiePolicyPropertySiteForCookies": sameSiteInfo.isSameSite ? url : emptyURL,
@"_kCFHTTPCookiePolicyPropertyIsTopLevelNavigation": [NSNumber numberWithBool:sameSiteInfo.isTopSite],
};
return policyProperties;
}
#endif
static NSArray *cookiesForURL(NSHTTPCookieStorage *storage, NSURL *url, NSURL *mainDocumentURL, const Optional<SameSiteInfo>& sameSiteInfo, NSString *partition = nullptr)
{
// The _getCookiesForURL: method calls the completionHandler synchronously. We use Optional<> to ensure this invariant.
Optional<RetainPtr<NSArray>> cookiesPtr;
auto completionHandler = [&cookiesPtr] (NSArray *cookies) {
cookiesPtr = retainPtr(cookies);
};
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
if ([storage respondsToSelector:@selector(_getCookiesForURL:mainDocumentURL:partition:policyProperties:completionHandler:)])
[storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL partition:partition policyProperties:sameSiteInfo ? policyProperties(sameSiteInfo.value(), url).get() : nullptr completionHandler:completionHandler];
else
[storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL partition:partition completionHandler:completionHandler];
#else
[storage _getCookiesForURL:url mainDocumentURL:mainDocumentURL partition:partition completionHandler:completionHandler];
UNUSED_PARAM(sameSiteInfo);
#endif
ASSERT(!!cookiesPtr);
return cookiesPtr->autorelease();
}
static void setHTTPCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSArray *cookies, NSURL *url, NSURL *mainDocumentURL, const SameSiteInfo& sameSiteInfo)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
if (!cookieStorage) {
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
if ([NSHTTPCookieStorage instancesRespondToSelector:@selector(_setCookies:forURL:mainDocumentURL:policyProperties:)])
[[NSHTTPCookieStorage sharedHTTPCookieStorage] _setCookies:cookies forURL:url mainDocumentURL:mainDocumentURL policyProperties:policyProperties(sameSiteInfo, url).get()];
else
#endif
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:url mainDocumentURL:mainDocumentURL];
return;
}
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
if ([NSHTTPCookieStorage instancesRespondToSelector:@selector(_setCookies:forURL:mainDocumentURL:policyProperties:)]) {
// FIXME: Stop creating a new NSHTTPCookieStorage object each time we want to query the cookie jar.
// NetworkStorageSession could instead keep a NSHTTPCookieStorage object for us.
RetainPtr<NSHTTPCookieStorage> nsCookieStorage = adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorage]);
[nsCookieStorage _setCookies:cookies forURL:url mainDocumentURL:mainDocumentURL policyProperties:policyProperties(sameSiteInfo, url).get()];
} else {
#endif
auto cfCookies = adoptCF([NSHTTPCookie _ns2cfCookies:cookies]);
CFHTTPCookieStorageSetCookies(cookieStorage, cfCookies.get(), [url _cfurl], [mainDocumentURL _cfurl]);
#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400) || (PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000)
}
#else
UNUSED_PARAM(sameSiteInfo);
#endif
}
static NSArray *httpCookiesForURL(CFHTTPCookieStorageRef cookieStorage, NSURL *firstParty, const Optional<SameSiteInfo>& sameSiteInfo, NSURL *url)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
if (!cookieStorage)
cookieStorage = _CFHTTPCookieStorageGetDefault(kCFAllocatorDefault);
// FIXME: Stop creating a new NSHTTPCookieStorage object each time we want to query the cookie jar.
// NetworkStorageSession could instead keep a NSHTTPCookieStorage object for us.
RetainPtr<NSHTTPCookieStorage> nsCookieStorage = adoptNS([[NSHTTPCookieStorage alloc] _initWithCFHTTPCookieStorage:cookieStorage]);
return cookiesForURL(nsCookieStorage.get(), url, firstParty, sameSiteInfo);
}
static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies, Optional<Seconds> cappedLifetime)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
NSUInteger count = [unfilteredCookies count];
RetainPtr<NSMutableArray> filteredCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:count]);
for (NSUInteger i = 0; i < count; ++i) {
NSHTTPCookie *cookie = (NSHTTPCookie *)[unfilteredCookies objectAtIndex:i];
// <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
// which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent
// that, but we also need to avoid sending cookies that were previously stored, and
// there's no harm to doing this check because such a cookie is never valid.
if (![[cookie name] length])
continue;
if ([cookie isHTTPOnly])
continue;
// Cap lifetime of persistent, client-side cookies to a week.
if (cappedLifetime && ![cookie isSessionOnly]) {
if (!cookie.expiresDate || cookie.expiresDate.timeIntervalSinceNow > cappedLifetime->seconds()) {
RetainPtr<NSMutableDictionary<NSHTTPCookiePropertyKey, id>> properties = adoptNS([[cookie properties] mutableCopy]);
RetainPtr<NSDate> dateInAWeek = adoptNS([[NSDate alloc] initWithTimeIntervalSinceNow:cappedLifetime->seconds()]);
[properties setObject:dateInAWeek.get() forKey:NSHTTPCookieExpires];
cookie = [NSHTTPCookie cookieWithProperties:properties.get()];
}
}
[filteredCookies.get() addObject:cookie];
}
return filteredCookies;
}
static NSArray *cookiesForURL(const NetworkStorageSession& session, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID)
{
#if ENABLE(RESOURCE_LOAD_STATISTICS)
if (session.shouldBlockCookies(firstParty, url, frameID, pageID))
return nil;
#else
UNUSED_PARAM(frameID);
UNUSED_PARAM(pageID);
#endif
return httpCookiesForURL(session.cookieStorage().get(), firstParty, sameSiteInfo, url);
}
enum IncludeHTTPOnlyOrNot { DoNotIncludeHTTPOnly, IncludeHTTPOnly };
static std::pair<String, bool> cookiesForSession(const NetworkStorageSession& session, const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, IncludeHTTPOnlyOrNot includeHTTPOnly, IncludeSecureCookies includeSecureCookies)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
BEGIN_BLOCK_OBJC_EXCEPTIONS;
NSArray *cookies = cookiesForURL(session, firstParty, sameSiteInfo, url, frameID, pageID);
if (![cookies count])
return { String(), false }; // Return a null string, not an empty one that StringBuilder would create below.
StringBuilder cookiesBuilder;
bool didAccessSecureCookies = false;
for (NSHTTPCookie *cookie in cookies) {
if (![[cookie name] length])
continue;
if (!includeHTTPOnly && [cookie isHTTPOnly])
continue;
if ([cookie isSecure]) {
didAccessSecureCookies = true;
if (includeSecureCookies == IncludeSecureCookies::No)
continue;
}
if (!cookiesBuilder.isEmpty())
cookiesBuilder.appendLiteral("; ");
cookiesBuilder.append([cookie name]);
cookiesBuilder.append('=');
cookiesBuilder.append([cookie value]);
}
return { cookiesBuilder.toString(), didAccessSecureCookies };
END_BLOCK_OBJC_EXCEPTIONS;
return { String(), false };
}
static void deleteAllHTTPCookies(CFHTTPCookieStorageRef cookieStorage)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
if (!cookieStorage) {
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookies];
if (!cookies)
return;
for (NSHTTPCookie *cookie in cookies)
[cookieStorage deleteCookie:cookie];
return;
}
CFHTTPCookieStorageDeleteAllCookies(cookieStorage);
}
std::pair<String, bool> NetworkStorageSession::cookiesForDOM(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, IncludeSecureCookies includeSecureCookies) const
{
return cookiesForSession(*this, firstParty, sameSiteInfo, url, frameID, pageID, DoNotIncludeHTTPOnly, includeSecureCookies);
}
std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, IncludeSecureCookies includeSecureCookies) const
{
return cookiesForSession(*this, firstParty, sameSiteInfo, url, frameID, pageID, IncludeHTTPOnly, includeSecureCookies);
}
std::pair<String, bool> NetworkStorageSession::cookieRequestHeaderFieldValue(const CookieRequestHeaderFieldProxy& headerFieldProxy) const
{
return cookiesForSession(*this, headerFieldProxy.firstParty, headerFieldProxy.sameSiteInfo, headerFieldProxy.url, headerFieldProxy.frameID, headerFieldProxy.pageID, IncludeHTTPOnly, headerFieldProxy.includeSecureCookies);
}
void NetworkStorageSession::setCookiesFromDOM(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, const String& cookieStr) const
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
BEGIN_BLOCK_OBJC_EXCEPTIONS;
// <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
// which would be sent as "Cookie: =".
if (cookieStr.isEmpty())
return;
// <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034>
// cookiesWithResponseHeaderFields doesn't parse cookies without a value
String cookieString = cookieStr.contains('=') ? cookieStr : cookieStr + "=";
NSURL *cookieURL = url;
NSDictionary *headerFields = [NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"];
#if PLATFORM(MAC)
NSArray *unfilteredCookies = [NSHTTPCookie _parsedCookiesWithResponseHeaderFields:headerFields forURL:cookieURL];
#else
NSArray *unfilteredCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headerFields forURL:cookieURL];
#endif
#if ENABLE(RESOURCE_LOAD_STATISTICS)
RetainPtr<NSArray> filteredCookies = filterCookies(unfilteredCookies, clientSideCookieCap(RegistrableDomain { firstParty }, pageID));
#else
RetainPtr<NSArray> filteredCookies = filterCookies(unfilteredCookies, WTF::nullopt);
#endif
ASSERT([filteredCookies.get() count] <= 1);
#if ENABLE(RESOURCE_LOAD_STATISTICS)
if (shouldBlockCookies(firstParty, url, frameID, pageID))
return;
#else
UNUSED_PARAM(frameID);
UNUSED_PARAM(pageID);
#endif
setHTTPCookiesForURL(cookieStorage().get(), filteredCookies.get(), cookieURL, firstParty, sameSiteInfo);
END_BLOCK_OBJC_EXCEPTIONS;
}
static NSHTTPCookieAcceptPolicy httpCookieAcceptPolicy(CFHTTPCookieStorageRef cookieStorage)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
if (!cookieStorage)
return [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy];
return static_cast<NSHTTPCookieAcceptPolicy>(CFHTTPCookieStorageGetCookieAcceptPolicy(cookieStorage));
}
bool NetworkStorageSession::cookiesEnabled() const
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;
NSHTTPCookieAcceptPolicy cookieAcceptPolicy = httpCookieAcceptPolicy(cookieStorage().get());
return cookieAcceptPolicy == NSHTTPCookieAcceptPolicyAlways || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain;
END_BLOCK_OBJC_EXCEPTIONS;
return false;
}
bool NetworkStorageSession::getRawCookies(const URL& firstParty, const SameSiteInfo& sameSiteInfo, const URL& url, Optional<FrameIdentifier> frameID, Optional<PageIdentifier> pageID, Vector<Cookie>& rawCookies) const
{
rawCookies.clear();
BEGIN_BLOCK_OBJC_EXCEPTIONS;
NSArray *cookies = cookiesForURL(*this, firstParty, sameSiteInfo, url, frameID, pageID);
NSUInteger count = [cookies count];
rawCookies.reserveCapacity(count);
for (NSUInteger i = 0; i < count; ++i) {
NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
rawCookies.uncheckedAppend({ cookie });
}
END_BLOCK_OBJC_EXCEPTIONS;
return true;
}
void NetworkStorageSession::deleteCookie(const URL& url, const String& cookieName) const
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
BEGIN_BLOCK_OBJC_EXCEPTIONS;
RetainPtr<CFHTTPCookieStorageRef> cookieStorage = this->cookieStorage();
NSArray *cookies = httpCookiesForURL(cookieStorage.get(), nil, WTF::nullopt, url);
NSString *cookieNameString = cookieName;
NSUInteger count = [cookies count];
for (NSUInteger i = 0; i < count; ++i) {
NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
if ([[cookie name] isEqualToString:cookieNameString])
deleteHTTPCookie(cookieStorage.get(), cookie);
}
END_BLOCK_OBJC_EXCEPTIONS;
}
void NetworkStorageSession::getHostnamesWithCookies(HashSet<String>& hostnames)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;
NSArray *cookies = httpCookies(cookieStorage().get());
for (NSHTTPCookie* cookie in cookies) {
if (NSString *domain = [cookie domain])
hostnames.add(domain);
else
ASSERT_NOT_REACHED();
}
END_BLOCK_OBJC_EXCEPTIONS;
}
void NetworkStorageSession::deleteAllCookies()
{
deleteAllHTTPCookies(cookieStorage().get());
}
void NetworkStorageSession::deleteCookiesForHostnames(const Vector<String>& hostnames)
{
deleteCookiesForHostnames(hostnames, IncludeHttpOnlyCookies::Yes);
}
void NetworkStorageSession::deleteCookiesForHostnames(const Vector<String>& hostnames, IncludeHttpOnlyCookies includeHttpOnlyCookies)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
BEGIN_BLOCK_OBJC_EXCEPTIONS;
RetainPtr<CFHTTPCookieStorageRef> cookieStorage = this->cookieStorage();
NSArray *cookies = httpCookies(cookieStorage.get());
if (!cookies)
return;
HashMap<String, Vector<RetainPtr<NSHTTPCookie>>> cookiesByDomain;
for (NSHTTPCookie *cookie in cookies) {
if (!cookie.domain || (includeHttpOnlyCookies == IncludeHttpOnlyCookies::No && cookie.isHTTPOnly))
continue;
cookiesByDomain.ensure(cookie.domain, [] {
return Vector<RetainPtr<NSHTTPCookie>>();
}).iterator->value.append(cookie);
}
for (const auto& hostname : hostnames) {
auto it = cookiesByDomain.find(hostname);
if (it == cookiesByDomain.end())
continue;
for (auto& cookie : it->value)
deleteHTTPCookie(cookieStorage.get(), cookie.get());
}
[nsCookieStorage() _saveCookies];
END_BLOCK_OBJC_EXCEPTIONS;
}
void NetworkStorageSession::deleteAllCookiesModifiedSince(WallTime timePoint)
{
ASSERT(hasProcessPrivilege(ProcessPrivilege::CanAccessRawCookies));
if (![NSHTTPCookieStorage instancesRespondToSelector:@selector(removeCookiesSinceDate:)])
return;
NSTimeInterval timeInterval = timePoint.secondsSinceEpoch().seconds();
NSDate *date = [NSDate dateWithTimeIntervalSince1970:timeInterval];
auto *storage = nsCookieStorage();
[storage removeCookiesSinceDate:date];
[storage _saveCookies];
}
} // namespace WebCore