1

May be this is a dumb question, but I want to store cookies for same url but different for usernames. How can this be achieved using NSHTTPCookieStorage ? This is how I store cookies from response.

        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;

        NSDictionary *headerFields = [httpResponse allHeaderFields];


        NSArray* cookies = [NSHTTPCookie
                            cookiesWithResponseHeaderFields:headerFields
                            forURL:[NSURL URLWithString:@""]];

        for (NSHTTPCookie *cookie in cookies) {
            [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
        }

       NSString *urlString = ...;

        [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:[NSURL URLWithString:urlString] mainDocumentURL:nil];
Deepak Sharma
  • 5,577
  • 7
  • 55
  • 131
  • i would suggest is to store a single cookie in a JSON Format. You can add security if you want to on the stored information. – Akhilesh Sharma Jun 02 '16 at 16:26
  • So you mean I should avoid NSHTTPCookieStorage ? How about extending the URL that's associated with the cookie, any harm in doing that ? – Deepak Sharma Jun 02 '16 at 16:31
  • It depends you will need more processing to get the relevant data out of it. If you have a JSON object its easy to render in iOS using JSON serialization process which will convert the relevant data to NSDictionary. if you are using URL it might run out of space as the max you have is 1024 characters. – Akhilesh Sharma Jun 02 '16 at 16:45
  • it depends how you have your architecture setup if you wanna use the NSHTTPCookieStorage – Akhilesh Sharma Jun 02 '16 at 16:46
  • I updated the code in the question. I understand if I use httpcookiestorage, then cookies will automatically get appended in any future requests, which is an advantage, – Deepak Sharma Jun 02 '16 at 17:29

3 Answers3

2

If I understand you correctly, you want to have separate sets of cookies for different users. If so, then you should:

  1. Create your own custom cookie storage class (probably just a dictionary with the base URL as the key and an array of cookies as the value) and store cookies there in addition to using the sharedHTTPCookieStorage object.

  2. When you change users, wipe the shared cookie storage and copy the cookies from the new user's cookie jar (or selectively remove every cookie created by that user from the shared jar).

If I misunderstood you and you want to store one particular cookie outside of the shared cookie storage for some reason:

  1. Create an NSURLSession object based on a configuration with a nil cookie jar (disabling automatic cookie storage).

  2. Store the cookies into a cookie jar like you're doing above (which may or may not be the shared cookie jar), but leave out the ones you want to avoid storing.

  3. Write a method to adds the cookies from that cookie jar to an NSURLRequest object.

  4. Always remember to call that method on your URL request objects before you create tasks with them.

This all assumes NSURLSession, of course. I don't think there's a way to control cookie storage with NSURLConnection. All cookies get stored in the cookie jar, period, AFAIK.

dgatwood
  • 10,129
  • 1
  • 28
  • 49
  • I think it is ok to create separate NSHTTPCookieStorage for each user and then swap sharedCookieStorage with the appropriate user. – Deepak Sharma Jun 06 '16 at 06:38
  • But how do I create a separate NSHTTPCookieStorage ? I think all API allows is to access sharedHTTPCookieStorage. – Deepak Sharma Jun 06 '16 at 06:42
  • ``[[NSHTTPCookieStorage alloc] init]`` – dgatwood Jun 06 '16 at 19:46
  • From the docs - "NSHTTPCookieStorage implements a singleton object (shared instance) that manages storage of cookies" – Deepak Sharma Jun 07 '16 at 06:42
  • Also from this answer it looks impossible to do what you suggest - http://stackoverflow.com/questions/27132606/multiple-nshttpcookiestorage-in-the-same-app – Deepak Sharma Jun 07 '16 at 06:45
  • Ouch. Yeah, it looks like the public version of that API is actually broken. WebKit does this, but it creates a CFHTTPCookieStorage object using a private API call first, and then uses another private API call to initialize the NSHTTPCookieStorage object. Blech. – dgatwood Jun 07 '16 at 07:32
  • 1
    So in that case, you'd have to store it in your own data structure. Odd. I could have sworn they fixed that years ago. – dgatwood Jun 07 '16 at 07:33
  • In iOS 9 / macOS 10.11 there is a new method `+sharedCookieStorageForGroupContainerIdentifier:`, which claims to return a cookie store that's specific to the identifier string you pass in. I haven't tried using it yet (my code still has to support older OS's) but it sounds like it would solve your problem. – Jens Alfke Jun 29 '16 at 21:58
1

You can have separate cookie stores (i.e. multiple users) for the same URL using the sharedCookieStorage(forGroupContainerIdentifier:).

You can obtain a common cookie storage by using that method and use it in a URLSession.

Example:

NSHTTPCookieStorage for same URL but different users

let configuration = URLSessionConfiguration.default.copy() as! URLSessionConfiguration
configuration.httpCookieStorage = HTTPCookieStorage.sharedCookieStorage(forGroupContainerIdentifier: UUID().uuidString)
configuration.httpCookieStorage?.cookieAcceptPolicy = .always
let sessionForCurrentUser = URLSession(configuration: configuration)
let task = sessionForCurrentUser.dataTask(with: URL(string: "https://foo.com/feature")!)
// ...

So, if you want to support multiple users, then create a common group identifier for each user.

In case the app starts with a guest user, then you need to "upgrade" the cookies storage when the user signs in. Something like:

// Upgrade from Guest user to Paid user
let guestCookieStorage = HTTPCookieStorage.sharedCookieStorage(forGroupContainerIdentifier: guestId)
let userCookieStorage = HTTPCookieStorage.sharedCookieStorage(forGroupContainerIdentifier: user.uniqueIdentifier)
for cookie in guestCookieStorage.cookies ?? [] {
    userCookieStorage.setCookie(cookie)
}
ricardopereira
  • 11,118
  • 5
  • 63
  • 81
0
@interface NSHTTPCookieStorage (ApplePrivateHeader)
-(id)_initWithIdentifier:(id)arg1 private:(BOOL)arg2;
@end

@interface User()
@property (nonatomic, strong) NSHTTPCookieStorage *myHTTPCookieStorage;
@end

@implementation User

-(instancetype)init
{
    self = [super init];
    if (self) {
         //the [NSHTTPCookieStorage init] will generate a instance with no inner `NSHTTPCookieStorageInternal`, so.
        _myHTTPCookieStorage = [[NSHTTPCookieStorage alloc] _initWithIdentifier: @"user_id_xxx" private:0];
        _myHTTPCookieStorage.cookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
    }
    return self;
}

-(void)httpTask{
    NSURLSessionConfiguration *c =[NSURLSessionConfiguration ephemeralSessionConfiguration];

    c.HTTPCookieStorage = _myHTTPCookieStorage;

    [[[NSURLSession sessionWithConfiguration: c] dataTaskWithRequest:request completionHandler:nil] resume];
}


// load from file
-(void)(id)initWithCoder:(NSCoder *)aDecoder{
    NSArray<NSHTTPCookie*> *cookies = [aDecoder decodeObjectForKey:@"cookies"];

    for (NSHTTPCookie *cookie in cookies) {
        [_myHTTPCookieStorage setCookie: cookie];
    }
}

//save to file
- (void)encodeWithCoder:(NSCoder *)aCoder
    [aCoder encodeObject:_myHTTPCookieStorage.cookies forKey: @"cookies"];
}


@end
liaogang
  • 508
  • 3
  • 16