Shared instance of NSHTTPCookieStorage does not persist cookies
Asked Answered
F

4

18

I'm developing an application where the server hands me a cookie to identify the user.

My successive requests need to have that cookie to have the response that the user expects. What I can't understand is how and when the shared instance of NSHTTPCookieStorage loses its cookies.

The first solution I used is to archive and save the cookies from my server to user defaults on application terminations then clear existing ones from my server on application launch and reset the ones I stored. Through the developing process I didn't encounter problems as the sessions for debugging are very short and didn't usually need to put the app in background.

During beta testing, troubles started. The hack I came with is to save the cookies not only on application termination but also after the API calls that hand me back these cookies. And to load the saved cookies not only on app launch but also when the app returns to foreground.

How come the NSHTTPCookieStorage share instance gets rid of these cookies and what's the best practice to deal with it as it's a vital part of my app and I can't trust such a hacked solution if not backed up by more experienced developers.

Thank you in advance for your answers

EDIT: Here are the methods to save/read/clear the cookies

-(void)saveStoredCookies
{
    NSURL *httpUrl = @"http://myServer.com";
    NSURL *httpsUrl = @"https://myServer.com";

    NSArray *httpCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:httpUrl];
    NSData *httpCookiesData = [NSKeyedArchiver archivedDataWithRootObject:httpCookies];
    [[NSUserDefaults standardUserDefaults] setObject:httpCookiesData forKey:@"savedHttpCookies"];

    NSArray *httpsCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:httpsUrl];
    NSData *httpsCookiesData = [NSKeyedArchiver archivedDataWithRootObject:httpsCookies];
    [[NSUserDefaults standardUserDefaults] setObject:httpsCookiesData forKey:@"savedHttpsCookies"];

    [[NSUserDefaults standardUserDefaults] synchronize];
}

-(void)readStoredCookies
{
    //clear, read and install stored cookies
    NSURL *httpUrl = @"http://myServer.com";
    NSURL *httpsUrl = @"https://myServer.com";

    NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:httpUrl];
    for (NSHTTPCookie *cookie in cookies) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    }
    cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:httpsUrl];
    for (NSHTTPCookie *cookie in cookies) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    }

    NSData *httpCookiesData = [[NSUserDefaults standardUserDefaults] objectForKey:@"savedHttpCookies"];
    if([httpCookiesData length]) {
        NSArray *savedCookies = [NSKeyedUnarchiver unarchiveObjectWithData:httpCookiesData];
        for (NSHTTPCookie *cookie in savedCookies) {
            [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
        }       
    }
    NSData *httpsCookiesData = [[NSUserDefaults standardUserDefaults] objectForKey:@"savedHttpsCookies"];
    if([httpsCookiesData length]) {
        NSArray *savedCookies = [NSKeyedUnarchiver unarchiveObjectWithData:httpsCookiesData];
        for (NSHTTPCookie *cookie in savedCookies) {
            [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];
        }       
    }
}

-(void)clearStoredCookies
{
    NSURL *httpUrl = @"http://myServer.com";
    NSURL *httpsUrl = @"https://myServer.com";
    NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:httpUrl];
    for (NSHTTPCookie *cookie in cookies) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    }
    cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:httpsUrl];
    for (NSHTTPCookie *cookie in cookies) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:cookie];
    }
}
Flynt answered 19/7, 2012 at 23:22 Comment(2)
Please update with the code you are using to pull the cookies out of cookie storage upon a new request. your description is not sufficient.Diakinesis
You didnt see a problem because you werent loading the cookies from storage between new sessions during testing.Diakinesis
F
0

Solved !

After some simple debugging I found out that the problem was with the url I was using in cookiesForURL:. I simply started using cookies property and now it works fine.

Flynt answered 2/10, 2012 at 14:12 Comment(2)
Sorry but I don't have access to the code anymore. It's from 4 years ago.Flynt
@Flynt i need help for thisStyx
W
23

NSHttpCookieStorage loses its cookies because you didn't set the expiration time for cookies. Setting expiration time is necessary otherwise your cookies will lose when your app exits.

Here is a quick look how I stored my cookies during app exit and launch,

NSMutableDictionary *cookieProperties = [NSMutableDictionary dictionary];
[cookieProperties setObject:name forKey:NSHTTPCookieName];
[cookieProperties setObject:strValue forKey:NSHTTPCookieValue];
[cookieProperties setObject:@"myserver.com" forKey:NSHTTPCookieDomain];    // Without http://
[cookieProperties setObject:@"myserver.com" forKey:NSHTTPCookieOriginURL]; // Without http://
[cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];

// set expiration to one month from now or any future NSDate of your choice
// this makes the cookie sessionless and it will persist across web sessions and app launches
/// if you want the cookie to be destroyed when your app exits, don't set this
[cookieProperties setObject:[[NSDate date] dateByAddingTimeInterval:2629743] forKey:NSHTTPCookieExpires];

NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];

Hope this helps.

Washedup answered 10/8, 2012 at 4:15 Comment(1)
I awarded your answer the bounty though it's not a solution for me but it let me discover things that I missed in my code (with the URL I used I didn't store any cookies). I'm on vacation now and with my surf lessons I get back home too exhausted to touch my code. I'll edit my question when I'll change something.Flynt
G
7

Is this the simulator? And using rolling cookies?

In the simulator, cookies don't really persist as they should, because they're shared with desktop Safari. As the cookies roll over, one eventually overwrites the other.

This isn't a problem on the device itself, where each app has its own cookie store. (And, truth be told, I haven't noticed it happening yet in Mountain Lion.)

Garden answered 11/8, 2012 at 4:6 Comment(3)
Thank you! Saved me from going insane trying to find out why cookies weren't persisting on the simulator.Wandie
Oh my god are you serious?...Lalalalage
Probably not true by now (that was 2016), but I switched to handling cookies myself and haven't had cause to revisit it.Garden
D
1

humayun might be right -

However you should not be writing cookies to NSUserDefaults -

The whole point of the sharedHTTPCookieStorage is you read them from there.

NSArray *httpCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:httpUrl];

You should not even be able to write those cookies to NSUserDefaults for security reasons. But maybe you can. Either way its probable that the timeout wasnt set as humayun mentioned.

Either way please refactor your code and dont try to store cookies in user prefs.

Diakinesis answered 10/8, 2012 at 15:12 Comment(1)
But the problem is that they don't persist in the sharedHTTPCookieStorage. I've checked the expiration date when handed from the server and it's well set (doesn't expire before a long time)Flynt
F
0

Solved !

After some simple debugging I found out that the problem was with the url I was using in cookiesForURL:. I simply started using cookies property and now it works fine.

Flynt answered 2/10, 2012 at 14:12 Comment(2)
Sorry but I don't have access to the code anymore. It's from 4 years ago.Flynt
@Flynt i need help for thisStyx

© 2022 - 2024 — McMap. All rights reserved.