I'm bringing this over from a discussion on IRC with nothingmuch. All up-to-date as of yesterday (fresh install on new machine).
I set a flag in the session that adjusts how long cookies persist. Then override this method in my application: sub calculate_session_cookie_expires { my $c = shift; return $c->session->{remember_me} ? $c->session_expires : $c->NEXT::calculate_session_cookie_expires; } If I wait a while when the session expires (but the cookie hasn't expired yet) I get this behavior: 1) session expired. 2) request comes in with expired session id in the cookie. 3) session/cookie cleared 4) new session created 5) cookie set in headers 6) session data cleared. 7) session data requested -- but session data already clear 8) so, create new session id 9) write session to store, but using new session id, not one set in cookie header. Here's a Cat application to duplicate (which I've been able to do on two machines). The trick to make it fail is to have an invalid cookie. You can generate a few requests and see that the same cookie is sent each time. Then edit your browser's cookie to make it invalid (change a single digit). Then reload /bar and watch how a new cookie is generated each time. (Note: If the cookie is an invalid *format* you get: [error] Caught exception in Foo->bar "Tried to set invalid session ID '7xxx0da4dfba9790d232f9dfc479ecc23bc0c2d83db' at /usr/local/share/perl/5.8.8/Catalyst/Action.pm line 47" which is another problem. Seems like should just ignore it and set a new cookie.) package Foo; use strict; use warnings; use Catalyst::Runtime; use Catalyst ( 'Session', 'Session::State::Cookie', 'Session::Store::FastMmap', 'Cache::FastMmap', ); __PACKAGE__->config( name => 'Foo' ); __PACKAGE__->setup; __PACKAGE__->config->{session} = { cookie_expires => 0, # Session cookie expires => 604800, cookie_name => 'my_cookie', }; sub bar : Local { my ( $self, $c ) = @_; $c->session->{stuff} = 'keep this'; $c->res->body('in bar'); } sub calculate_session_cookie_expires { my $c = shift; warn ">>>>>App::calculate_session_cookie_expires\n"; my $x = $c->session->{foo}; # force a reload of the session. return $c->NEXT::calculate_session_cookie_expires; } sub finalize_body { my $c = shift; warn join( "\n", '','------ finalize_body -----------------', $c->req->path, 'Request:', $c->req->headers->as_string, 'Response:', $c->res->headers->as_string, ); return $c->NEXT::finalize_body( @_ ); } 1; Here's an annotated dump of a single request in the session code. Note also how many sessions are created. Request Cookie: my_cookie=810906f7a29c3f46f8b61dcf564f426c5209b254 # Now try and fetch the expired session: Session::_load_session: get_session_id returned: 810906f7a29c3f46f8b61dcf564f426c5209b254 Store::get_session_data: fetched [expires:810906f7a29c3f46f8b61dcf564f426c5209b254]: [undef] Session::_load_session_expires: expires = 0 810906f7a29c3f46f8b61dcf564f426c5209b254. # Session is expired so purge it: calling delete_session()<< State::Cookie::update_session_cookie: setting cookie { expires => 0, value => "810906f7a29c3f46f8b61dcf564f426c5209b254", } Session::_clear_session_instance_data >> Session::_load_session_expires: after calling delete_session # And create a new session: Session::session(): creating session Session::generate_session_id = 6d30ea44e84f658ae647f249bd7237e8a117740b # Now my overridden calculate_session_cookie_expires() is called: >>>>> App::calculate_session_cookie_expires # Which triggers a session fetch, but there is no session data yet: Store::get_session_data: fetched [expires:6d30ea44e84f658ae647f249bd7237e8a117740b]: [undef] Session::_load_session_expires: expires = 0 6d30ea44e84f658ae647f249bd7237e8a117740b. # So it's considered expired and deletes the session again: calling delete_session()<< State::Cookie::update_session_cookie: setting cookie { expires => 0, value => "6d30ea44e84f658ae647f249bd7237e8a117740b" } Session::_clear_session_instance_data >> Session::_load_session_expires: after calling delete_session # And yet another session is created and the cookie is set: Session::session(): creating session Session::generate_session_id = 4cc5a1526a6958df043edfcd77de025ece5e6334 # But it's the previous session id: State::Cookie::update_session_cookie: setting cookie { expires => undef, value => "6d30ea44e84f658ae647f249bd7237e8a117740b", } Session::prepare_action start for path: login # And when the data is finally stored it's using the latest session id, but not the same one used for the cookie: Store::store_session_data: setting [session:4cc5a1526a6958df043edfcd77de025ece5e6334] [HASH(0x9d937e8)] Store::store_session_data: setting [expires:4cc5a1526a6958df043edfcd77de025ece5e6334] [1184906823] ------- Finalize body ------- # And here's the cookie in the response headers. Matches the last update_session_cookie() but not the session written to the store. Set-Cookie: my_cookie=6d30ea44e84f658ae647f249bd7237e8a117740b; path=/ -- Bill Moseley [EMAIL PROTECTED] _______________________________________________ List: Catalyst@lists.rawmode.org Listinfo: http://lists.rawmode.org/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.rawmode.org/ Dev site: http://dev.catalyst.perl.org/