How to set cookieAcceptPolicy for ephemeral NSURLSession

I am trying to use ephemeral NSURLSessions to provide separate cookie handling for several tasks in my application. These tasks are not directly related to the user interface. Problem: no matter what I do, the cookieAcceptPolicy of the ephemeral NSHTTPCookieStorage remains NSHTTPCookieAcceptPolicyNever .

Here is my code:

// use a pure in-memory configuration with its own private cache, cookie, and credential store __block NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; // do anything to accept all cookies config.HTTPShouldSetCookies = YES; config.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways; config.HTTPCookieStorage.cookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways; __block NSURLSession* session = [NSURLSession sessionWithConfiguration:config]; NSURLSessionDataTask* task = [session dataTaskWithURL:[NSURL URLWithString:@"https://test.cgmlife.com/Catalogs"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPCookieStorage* cookies = session.configuration.HTTPCookieStorage; NSLog(@"%@", cookies); NSLog(@"%lu", cookies.cookieAcceptPolicy); }]; [task resume]; 

Exiting NSLog is always:

 Ephemeral <NSHTTPCookieStorage cookies count:0> 1 

where 1 is the value for NSHTTPCookieAcceptPolicyNever (expected 0 for NSHTTPCookieAcceptPolicyAlways). There are headers in the answer.

What can I do to make NSHTTPCookieStorage remember my cookies while the session is alive? I do not need and do not want perseverance. I just want to keep cookies in memory so that they can be reused for subsequent requests in the same session.

+7
cookies nsurlsession
source share
2 answers

Ephemeral sessions do not seem to store cookies. eskimo1 says about devforums :

ISTR that ephemeral session configurations do not work like this, people calculate based on documentation. I never went looking at this in detail, but it looks like you have it. You must file a mistake about this; the implementation and documentation are clearly synchronized, so one of them needs to be fixed.

+2
source share

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.

+1
source share

All Articles