2014-12-04 13 views
7

Sto tentando di utilizzare le NSURLSessions temporanee per fornire una gestione dei cookie separata per diverse attività all'interno della mia app. Queste attività non sono direttamente collegate a un'interfaccia utente. Problema: qualunque cosa io faccia, la cookieAcceptPolicy dell'effettuario NSHTTPCookieStorage rimane NSHTTPCookieAcceptPolicyNever.Come impostare cookieAcceptPolicy per NSURLSession temporaneo

Ecco il mio codice:

// 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]; 

L'uscita dal NSLog è sempre:

Ephemeral <NSHTTPCookieStorage cookies count:0> 
1 

dove 1 è il valore per NSHTTPCookieAcceptPolicyNever (previsto 0 per NSHTTPCookieAcceptPolicyAlways). Le intestazioni nella risposta sono lì.

Cosa posso fare per ricordare a NSHTTPCookieStorage i miei cookie mentre la sessione è attiva? Non ho bisogno e non voglio alcuna persistenza. Voglio solo tenere i cookie in memoria in modo che vengano riutilizzati per ulteriori richieste nella stessa sessione.

risposta

2

Sembra che le sessioni effimere non memorizzino mai i cookie. eskimo1 says on the devforums:

ISTR che le configurazioni di sessione effimere non funzionano il modo in cui le persone si aspettano basano sulla documentazione. Non sono mai riuscito a vedere in dettaglio ma sembra che tu abbia. Si dovrebbe presentare un bug su questo; l'implementazione e la documentazione sono chiaramente fuori di sincronizzazione, quindi è necessario ripararne uno.

1

Sembra che l'effimeroSessionConfiguration di iOS9 funzioni come previsto. Su iOS8, tuttavia, sembra che la memorizzazione dei cookie non restituisca mai per la sua politica e non possa essere ripristinata. L'implementazione sembra essere no-storage nonostante il nome della classe privata, anziché solo la memoria.

Per iOS8, sono stato in grado di sostituire un'implementazione rudimentale e sembra funzionare (almeno nel simulatore con test della luce). L'implementazione dei nuovi metodi che accettano oggetti task era essenziale.

#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, i.e. 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 

Dovrebbe essere possibile testare sessionConfiguration.HTTPCookieStorage.cookieAcceptPolicy == NSHTTPCookieAcceptPolicyNever dopo aver creato la sessione effimera per vedere se il HTTPCookieStorage deve essere sostituito con un'istanza della classe di cui sopra (non dovrebbe bisogno sul iOS9). Probabilmente ci sono alcuni bug ... Ho solo bisogno di questo per una demo e ha funzionato abbastanza bene per quello. Ma non dovrebbero essere troppo difficili da risolvere se qualcuno dovesse venire fuori.