Checking in changes prior to tagging of version 0.09_02. Changelog diff is:
[catagits/Web-Session.git] / lib / Plack / Middleware / Session.pm
index 03f8798..8d9a3ee 100644 (file)
@@ -2,12 +2,9 @@ package Plack::Middleware::Session;
 use strict;
 use warnings;
 
-our $VERSION   = '0.01';
+our $VERSION   = '0.09_02';
 our $AUTHORITY = 'cpan:STEVAN';
 
-use Plack::Session;
-use Plack::Request;
-use Plack::Response;
 use Plack::Util;
 use Scalar::Util;
 
@@ -16,15 +13,12 @@ use parent 'Plack::Middleware';
 use Plack::Util::Accessor qw(
     state
     store
-    session_class
 );
 
 sub prepare_app {
     my $self = shift;
 
-    $self->session_class( 'Plack::Session' ) unless $self->session_class;
-    $self->state( 'Cookie' )                 unless $self->state;
-
+    $self->state( 'Cookie' ) unless $self->state;
     $self->state( $self->inflate_backend('Plack::Session::State', $self->state) );
     $self->store( $self->inflate_backend('Plack::Session::Store', $self->store) );
 }
@@ -45,18 +39,69 @@ sub call {
     my $self = shift;
     my $env  = shift;
 
-    $env->{'plack.session'} = $self->session_class->new(
-        state   => $self->state,
-        store   => $self->store,
-        request => Plack::Request->new( $env )
-    );
+    my($id, $session) = $self->get_session($env);
+    if ($id && $session) {
+        $env->{'psgix.session'} = $session;
+    } else {
+        $id = $self->generate_id($env);
+        $env->{'psgix.session'} = {};
+    }
+
+    $env->{'psgix.session.options'} = { id => $id };
 
     my $res = $self->app->($env);
-    $self->response_cb($res, sub {
-        my $res = Plack::Response->new(@{$_[0]});
-        $env->{'plack.session'}->finalize( $res );
-        @{$_[0]} = @{$res->finalize};
-    });
+    $self->response_cb($res, sub { $self->finalize($env, $_[0]) });
+}
+
+sub get_session {
+    my($self, $env) = @_;
+
+    my $id = $self->state->extract($env)   or return;
+    my $session = $self->store->fetch($id) or return;
+
+    return ($id, $session);
+}
+
+sub generate_id {
+    my($self, $env) = @_;
+    $self->state->generate($env);
+}
+
+sub commit {
+    my($self, $env) = @_;
+
+    my $session = $env->{'psgix.session'};
+    my $options = $env->{'psgix.session.options'};
+
+    if ($options->{expire}) {
+        $self->store->remove($options->{id});
+    } else {
+        $self->store->store($options->{id}, $session);
+    }
+}
+
+sub finalize {
+    my($self, $env, $res) = @_;
+
+    my $session = $env->{'psgix.session'};
+    my $options = $env->{'psgix.session.options'};
+
+    $self->commit($env) unless $options->{no_store};
+    if ($options->{expire}) {
+        $self->expire_session($options->{id}, $res, $env);
+    } else {
+        $self->save_state($options->{id}, $res, $env);
+    }
+}
+
+sub expire_session {
+    my($self, $id, $res, $env) = @_;
+    $self->state->expire_session_id($id, $res, $env->{'psgix.session.options'});
+}
+
+sub save_state {
+    my($self, $id, $res, $env) = @_;
+    $self->state->finalize($id, $res, $env->{'psgix.session.options'});
 }
 
 1;
@@ -74,7 +119,13 @@ Plack::Middleware::Session - Middleware for session management
   use Plack::Builder;
 
   my $app = sub {
-      return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Hello Foo' ] ];
+      my $env = shift;
+      my $session = $env->{'psgix.session'};
+      return [
+          200,
+          [ 'Content-Type' => 'text/plain' ],
+          [ "Hello, you've been here for ", $session->{counter}++, "th time!" ],
+      ];
   };
 
   builder {
@@ -96,6 +147,13 @@ default it will use cookies to keep session state and store data in
 memory. This distribution also comes with other state and store
 solutions. See perldoc for these backends how to use them.
 
+It should be noted that we store the current session as a hash
+reference in the C<psgix.session> key inside the C<$env> where you can
+access it as needed.
+
+B<NOTE:> As of version 0.04 the session is stored in C<psgix.session>
+instead of C<plack.session>.
+
 =head2 State
 
 =over 4
@@ -162,12 +220,6 @@ is only suitable for development (or single process servers). For a
 more robust solution see L<Plack::Session::Store::File> or
 L<Plack::Session::Store::Cache>.
 
-=item I<session_class>
-
-This can be used to override the actual session class. It currently
-defaults to L<Plack::Session> but you can substitute any class which
-implements the same interface.
-
 =back
 
 =head1 BUGS
@@ -184,7 +236,7 @@ Stevan Little E<lt>stevan.little@iinteractive.comE<gt>
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright 2009 Infinity Interactive, Inc.
+Copyright 2009, 2010 Infinity Interactive, Inc.
 
 L<http://www.iinteractive.com>