It seems that iOS9 ephemeralSessionConfiguration works as expected. On iOS8, it looks like the cookie store returns Never for its policy, and it cannot be reset. The implementation does not seem to be a repository, despite the name of a private class, and not just memory.
For iOS8, I was able to replace the elementary implementation, although it seems to work (at least in a simulator with easy testing). The implementation of new methods that occupy task objects is important.
#import <Foundation/Foundation.h> @interface MemoryCookieStorage : NSHTTPCookieStorage @property (nonatomic, strong) NSMutableArray *internalCookies; @property (atomic, assign) NSHTTPCookieAcceptPolicy policy; @end @implementation MemoryCookieStorage - (id)init { if (self = [super init]) { _internalCookies = [NSMutableArray new]; _policy = NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain; } return self; } - (NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { return self.policy; } - (void)setCookieAcceptPolicy:(NSHTTPCookieAcceptPolicy)cookieAcceptPolicy { self.policy = cookieAcceptPolicy; } - (NSUInteger)_indexOfCookie:(NSHTTPCookie *)target { return [_internalCookies indexOfObjectPassingTest:^BOOL(NSHTTPCookie *cookie, NSUInteger idx, BOOL *stop) { return ([target.name caseInsensitiveCompare:cookie.name] == NSOrderedSame && [target.domain caseInsensitiveCompare:cookie.domain] == NSOrderedSame && (target.path == cookie.path || [target.path isEqual:cookie.path])); }]; } - (void)setCookie:(NSHTTPCookie *)cookie { if (self.cookieAcceptPolicy != NSHTTPCookieAcceptPolicyNever) { @synchronized(_internalCookies) { NSInteger idx = [self _indexOfCookie:cookie]; if (idx == NSNotFound) [_internalCookies addObject:cookie]; else [_internalCookies replaceObjectAtIndex:idx withObject:cookie]; } } } - (void)deleteCookie:(NSHTTPCookie *)cookie { @synchronized(_internalCookies) { NSInteger idx = [self _indexOfCookie:cookie]; if (idx != NSNotFound) [_internalCookies removeObjectAtIndex:idx]; } } - (NSArray *)cookies { @synchronized(_internalCookies) { return [_internalCookies copy]; } } static BOOL HasCaseSuffix(NSString *string, NSString *suffix) { return [string rangeOfString:suffix options:NSCaseInsensitiveSearch|NSAnchoredSearch|NSBackwardsSearch].length > 0; } static BOOL IsDomainOK(NSString *cookieDomain, NSString *host) { return ([cookieDomain caseInsensitiveCompare:host] == NSOrderedSame || ([cookieDomain hasPrefix:@"."] && HasCaseSuffix(host, cookieDomain)) || (cookieDomain && HasCaseSuffix(host, [@"." stringByAppendingString:cookieDomain]))); } - (NSArray *)cookiesForURL:(NSURL *)URL { NSMutableArray *array = [NSMutableArray new]; NSString *host = URL.host; NSString *path = URL.path; @synchronized(_internalCookies) { for (NSHTTPCookie *cookie in _internalCookies) { if (!IsDomainOK(cookie.domain, host)) continue; BOOL pathOK = cookie.path.length == 0 || [cookie.path isEqual:@"/"] || [path hasPrefix:cookie.path]; if (!pathOK) continue; if (cookie.isSecure && [URL.scheme caseInsensitiveCompare:@"https"] != NSOrderedSame) continue; if ([cookie.expiresDate timeIntervalSinceNow] > 0) continue; [array addObject:cookie]; } } array = (id)[array sortedArrayUsingComparator:^NSComparisonResult(NSHTTPCookie *c1, NSHTTPCookie *c2) { /* More specific cookies, ie matching the longest portion of the path, come first */ NSInteger path1 = c1.path.length; NSInteger path2 = c2.path.length; if (path1 > path2) return NSOrderedAscending; if (path2 > path1) return NSOrderedDescending; return [c1.name caseInsensitiveCompare:c2.name]; }]; return array; } - (NSArray *)sortedCookiesUsingDescriptors:(NSArray *)sortOrder { return [[self cookies] sortedArrayUsingDescriptors:sortOrder]; } - (void)getCookiesForTask:(NSURLSessionTask *)task completionHandler:(void (^) (NSArray *taskCookies))completionHandler { NSArray *urlCookies = [self cookiesForURL:task.currentRequest.URL]; completionHandler(urlCookies); } - (void)setCookies:(NSArray *)newCookies forURL:(NSURL *)URL mainDocumentURL:(NSURL *)mainDocumentURL { NSString *host = mainDocumentURL.host; for (NSHTTPCookie *cookie in newCookies) { switch (self.cookieAcceptPolicy) { case NSHTTPCookieAcceptPolicyAlways: [self setCookie:cookie]; break; case NSHTTPCookieAcceptPolicyNever: break; case NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain: if (IsDomainOK(cookie.domain, host)) [self setCookie:cookie]; break; } } } - (void)storeCookies:(NSArray *)taskCookies forTask:(NSURLSessionTask *)task { NSURL *mainURL = task.currentRequest.mainDocumentURL ?: task.originalRequest.mainDocumentURL ?: task.originalRequest.URL; [self setCookies:taskCookies forURL:task.currentRequest.URL mainDocumentURL:mainURL]; } @end
After creating an ephemeral session, you should check sessionConfiguration.HTTPCookieStorage.cookieAcceptPolicy == NSHTTPCookieAcceptPolicyNever to check if HTTPCookieStorage should be replaced with an instance of the above class (it should not need it in iOS9). There are probably some mistakes ... I just needed this for a demonstration, and for this it worked quite well. But they should not be too difficult to fix if they come.
Carl Lindberg
source share