X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FCatalyst%2FPlugin%2FSession.pm;h=0aae81797d327f46556a3a4e293495bbf1f50943;hb=fa0221108e7d61b2fccb3fc7449edaec165933d7;hp=2549f66c19630d6656a2e99e820cf9c75c5b55f6;hpb=064c3709e9bb8f435964fe9bf06b169db710e40d;p=catagits%2FCatalyst-Plugin-Session.git diff --git a/lib/Catalyst/Plugin/Session.pm b/lib/Catalyst/Plugin/Session.pm index 2549f66..0aae817 100644 --- a/lib/Catalyst/Plugin/Session.pm +++ b/lib/Catalyst/Plugin/Session.pm @@ -13,7 +13,8 @@ use Carp; use namespace::clean -except => 'meta'; -our $VERSION = '0.26'; +our $VERSION = '0.34'; +$VERSION = eval $VERSION; my @session_data_accessors; # used in delete_session @@ -101,8 +102,10 @@ sub prepare_action { sub finalize_headers { my $c = shift; - # fix cookie before we send headers - $c->_save_session_expires; + # Force extension of session_expires before finalizing headers, so a possible cookie will be + # up to date. First call to session_expires will extend the expiry, subsequent calls will + # just return the previously extended value. + $c->session_expires; return $c->maybe::next::method(@_); } @@ -123,6 +126,7 @@ sub finalize_session { $c->maybe::next::method(@_); + $c->_save_session_expires; $c->_save_session_id; $c->_save_session; $c->_save_flash; @@ -224,6 +228,7 @@ sub _load_session { no warnings 'uninitialized'; # ne __address if ( $c->_session_plugin_config->{verify_address} + && exists $session_data->{__address} && $session_data->{__address} ne $c->request->address ) { $c->log->warn( @@ -354,19 +359,39 @@ sub session_expires { sub extend_session_expires { my ( $c, $expires ) = @_; - $c->_extended_session_expires( my $updated = $c->calculate_extended_session_expires( $expires ) ); + $c->_extended_session_expires( my $updated = $c->calculate_initial_session_expires( $expires ) ); $c->extend_session_id( $c->sessionid, $updated ); return $updated; } -sub calculate_initial_session_expires { +sub change_session_expires { + my ( $c, $expires ) = @_; + + $expires ||= 0; + my $sid = $c->sessionid; + my $time_exp = time() + $expires; + $c->store_session_data( "expires:$sid" => $time_exp ); +} + +sub initial_session_expires { my $c = shift; return ( time() + $c->_session_plugin_config->{expires} ); } +sub calculate_initial_session_expires { + my $c = shift; + + my $initial_expires = $c->initial_session_expires; + my $stored_session_expires = 0; + if ( my $sid = $c->sessionid ) { + $stored_session_expires = $c->get_session_data("expires:$sid") || 0; + } + return ( $initial_expires > $stored_session_expires ) ? $initial_expires : $stored_session_expires; +} + sub calculate_extended_session_expires { my ( $c, $prev ) = @_; - $c->calculate_initial_session_expires; + return ( time() + $prev ); } sub reset_session_expires { @@ -374,6 +399,11 @@ sub reset_session_expires { my $exp = $c->calculate_initial_session_expires; $c->_session_expires( $exp ); + # + # since we're setting _session_expires directly, make load_session_expires + # actually use that value. + # + $c->_tried_loading_session_expires(1); $c->_extended_session_expires( $exp ); $exp; } @@ -424,10 +454,21 @@ sub validate_session_id { sub session { my $c = shift; - $c->_session || $c->_load_session || do { + my $session = $c->_session || $c->_load_session || do { $c->create_session_id_if_needed; $c->initialize_session_data; }; + + if (@_) { + my $new_values = @_ > 1 ? { @_ } : $_[0]; + croak('session takes a hash or hashref') unless ref $new_values; + + for my $key (keys %$new_values) { + $session->{$key} = $new_values->{$key}; + } + } + + $session; } sub keep_flash { @@ -561,7 +602,7 @@ sub dump_these { ( $c->maybe::next::method(), - $c->sessionid + $c->_sessionid ? ( [ "Session ID" => $c->sessionid ], [ Session => $c->session ], ) : () ); @@ -677,18 +718,19 @@ requests. This method will automatically create a new session and session ID if none exists. -=item session_expires +You can also set session keys by passing a list of key/value pairs or a +hashref. -=item session_expires $reset + $c->session->{foo} = "bar"; # This works. + $c->session(one => 1, two => 2); # And this. + $c->session({ answer => 42 }); # And this. + +=item session_expires This method returns the time when the current session will expire, or 0 if there is no current session. If there is a session and it already expired, it will delete the session and return 0 as well. -If the C<$reset> parameter is true, and there is a session ID the expiry time -will be reset to the current time plus the time to live (see -L). This is used when creating a new session. - =item flash This is like Ruby on Rails' flash data structure. Think of it as a stash that @@ -699,6 +741,15 @@ $c->flash (thus allowing multiple redirections), and the policy is to delete all the keys which haven't changed since the flash data was loaded at the end of every request. +Note that use of the flash is an easy way to get data across requests, but +it's also strongly disrecommended, due it it being inherently plagued with +race conditions. This means that it's unlikely to work well if your +users have multiple tabs open at once, or if your site does a lot of AJAX +requests. + +L is the recommended alternative solution, +as this doesn't suffer from these issues. + sub moose : Local { my ( $self, $c ) = @_; @@ -764,7 +815,8 @@ expiry time for the whole session). For example: - __PACKAGE__->config('Plugin::Session' => { expires => 1000000000000 }); # forever + __PACKAGE__->config('Plugin::Session' => { expires => 10000000000 }); # "forever" + (NB If this number is too large, Y2K38 breakage could result.) # later @@ -800,6 +852,14 @@ you should call change_session_id in your login controller like this: ... } +=item change_session_expires $expires + +You can change the session expiration time for this session; + + $c->change_session_expires( 4000 ); + +Note that this only works to set the session longer than the config setting. + =back =head1 INTERNAL METHODS @@ -928,6 +988,9 @@ dumped objects if session ID is defined. =item extend_session_expires +Note: this is *not* used to give an individual user a longer session. See +'change_session_expires'. + =item extend_session_id =item get_session_id @@ -1081,11 +1144,8 @@ changes by request a =back -If this is a concern in your application, a soon-to-be-developed locking -solution is the only safe way to go. This will have a bigger overhead. - -For applications where any given user is only making one request at a time this -plugin should be safe enough. +For applications where any given user's session is only making one request +at a time this plugin should be safe enough. =head1 AUTHORS @@ -1103,8 +1163,16 @@ Sergio Salvi kmx C +Florian Ragwitz (rafl) C + +Kent Fredric (kentnl) + And countless other contributers from #catalyst. Thanks guys! +=head1 Contributors + +Devin Austin (dhoss) + =head1 COPYRIGHT & LICENSE Copyright (c) 2005 the aforementioned authors. All rights