Make psgix.session a hash reference and plack.session an (optional)
[catagits/Web-Session.git] / lib / Plack / Middleware / Session.pm
CommitLineData
bd992981 1package Plack::Middleware::Session;
2use strict;
3use warnings;
4
000c696e 5our $VERSION = '0.03';
30cc0a71 6our $AUTHORITY = 'cpan:STEVAN';
7
bd992981 8use Plack::Request;
9use Plack::Response;
ad80e445 10use Plack::Util;
11use Scalar::Util;
bd992981 12
13use parent 'Plack::Middleware';
14
d6af4aa8 15use Plack::Util::Accessor qw(
16 state
17 store
18 session_class
19);
bd992981 20
fe1bfe7d 21sub prepare_app {
22 my $self = shift;
fe1bfe7d 23
4ff41723 24 $self->state( 'Cookie' ) unless $self->state;
ad80e445 25 $self->state( $self->inflate_backend('Plack::Session::State', $self->state) );
26 $self->store( $self->inflate_backend('Plack::Session::Store', $self->store) );
4ff41723 27
28 Plack::Util::load_class($self->session_class) if $self->session_class;
ad80e445 29}
30
31sub inflate_backend {
32 my($self, $prefix, $backend) = @_;
33
34 return $backend if defined $backend && Scalar::Util::blessed $backend;
35
36 my @class;
37 push @class, $backend if defined $backend; # undef means the root class
38 push @class, $prefix;
39
40 Plack::Util::load_class(@class)->new();
fe1bfe7d 41}
42
bd992981 43sub call {
44 my $self = shift;
45 my $env = shift;
46
4ff41723 47 my $request = Plack::Request->new($env);
48
49 my($id, $session);
50 if ($id = $self->state->extract($request) and
51 $session = $self->store->fetch($id)) {
52 $env->{'psgix.session'} = $session;
53 } else {
54 $id = $self->state->generate($request);
55 $env->{'psgix.session'} = {};
56 }
57
58 $env->{'psgix.session.options'} = { id => $id };
4a0cb5a0 59
4ff41723 60 if ($self->session_class) {
61 $env->{'plack.session'} = $self->session_class->new(
62 manager => $self,
63 _data => $env->{'psgix.session'},
64 options => $env->{'psgix.session.options'},
65 );
66 }
bd992981 67
fe1bfe7d 68 my $res = $self->app->($env);
69 $self->response_cb($res, sub {
70 my $res = Plack::Response->new(@{$_[0]});
4ff41723 71 $self->finalize($env, $res);
b2504d01 72 $res = $res->finalize;
73 $_[0]->[0] = $res->[0];
74 $_[0]->[1] = $res->[1];
fe1bfe7d 75 });
bd992981 76}
77
4ff41723 78sub commit {
79 my($self, $session, $options) = @_;
80 if ($options->{expire}) {
81 $self->store->cleanup($options->{id});
82 } else {
83 $self->store->store($options->{id}, $session);
84 }
85}
86
87sub finalize {
88 my($self, $env, $response) = @_;
89
90 $self->commit($env->{'psgix.session'}, $env->{'psgix.session.options'});
91 if ($env->{'psgix.session.options'}->{expire}) {
92 $self->state->expire_session_id($env->{'psgix.session.options'}->{id}, $response);
93 } else {
94 $self->state->finalize($env->{'psgix.session.options'}->{id}, $response, $env->{'psgix.session.options'});
95 }
96}
97
bd992981 981;
99
100__END__
ac4892f4 101
102=pod
103
104=head1 NAME
105
106Plack::Middleware::Session - Middleware for session management
107
108=head1 SYNOPSIS
109
3d92cf47 110 use Plack::Builder;
ac4892f4 111
3d92cf47 112 my $app = sub {
536da026 113 my $env = shift;
4ff41723 114 my $session = $env->{'psgix.session'};
536da026 115 return [
116 200,
117 [ 'Content-Type' => 'text/plain' ],
4ff41723 118 [ "Hello, you've been here for ", $session->{counter}++, "th time!" ],
536da026 119 ];
3d92cf47 120 };
121
122 builder {
123 enable 'Session';
124 $app;
125 };
126
ad80e445 127 # Or, use the File store backend (great if you use multiprocess server)
128 # For more options, see perldoc Plack::Session::Store::File
129 builder {
130 enable 'Session', store => 'File';
131 $app;
132 };
133
ac4892f4 134=head1 DESCRIPTION
135
3d92cf47 136This is a Plack Middleware component for session management. By
ad80e445 137default it will use cookies to keep session state and store data in
138memory. This distribution also comes with other state and store
139solutions. See perldoc for these backends how to use them.
3d92cf47 140
4ff41723 141It should be noted that we store the current session as a hash
142reference in the C<psgix.session> key inside the C<$env> where you can
143access it as needed.
144
145B<NOTE:> As of version 0.04 the session is stored in C<psgix.session>
146instead of C<plack.session>.
b84f31d0 147
4ff41723 148Also, if you set I<session_class> option (see below), we create a
149session object out of the hash reference in C<plack.session>.
536da026 150
3d92cf47 151=head2 State
152
153=over 4
154
155=item L<Plack::Session::State>
156
157This will maintain session state by passing the session through
158the request params. It does not do this automatically though,
159you are responsible for passing the session param.
160
161=item L<Plack::Session::State::Cookie>
162
163This will maintain session state using browser cookies.
164
165=back
166
167=head2 Store
168
169=over 4
170
171=item L<Plack::Session::Store>
172
173This is your basic in-memory session data store. It is volatile storage
174and not recommended for multiprocessing environments. However it is
175very useful for development and testing.
176
177=item L<Plack::Session::Store::File>
178
179This will persist session data in a file. By default it uses
180L<Storable> but it can be configured to have a custom serializer and
181deserializer.
182
20ede533 183=item L<Plack::Session::Store::Cache>
3d92cf47 184
20ede533 185This will persist session data using the L<Cache> interface.
3d92cf47 186
187=item L<Plack::Session::Store::Null>
188
189Sometimes you don't care about storing session data, in that case
190you can use this noop module.
191
192=back
193
30cc0a71 194=head1 OPTIONS
195
196The following are options that can be passed to this mdoule.
197
198=over 4
199
200=item I<state>
201
202This is expected to be an instance of L<Plack::Session::State> or an
203object that implements the same interface. If no option is provided
204the default L<Plack::Session::State::Cookie> will be used.
205
206=item I<store>
207
208This is expected to be an instance of L<Plack::Session::Store> or an
209object that implements the same interface. If no option is provided
210the default L<Plack::Session::Store> will be used.
211
212It should be noted that this default is an in-memory volatile store
213is only suitable for development (or single process servers). For a
214more robust solution see L<Plack::Session::Store::File> or
215L<Plack::Session::Store::Cache>.
216
217=item I<session_class>
218
4ff41723 219This can be used to create an actual session object in
220C<plack.session> environment. Defaults to none, which means the
221session object is not created but you can set C<Plack::Session> to
222create an object for you.
30cc0a71 223
224=back
225
ac4892f4 226=head1 BUGS
227
228All complex software has bugs lurking in it, and this module is no
229exception. If you find a bug please either email me, or add the bug
230to cpan-RT.
231
232=head1 AUTHOR
233
234Tatsuhiko Miyagawa
235
236Stevan Little E<lt>stevan.little@iinteractive.comE<gt>
237
238=head1 COPYRIGHT AND LICENSE
239
000c696e 240Copyright 2009, 2010 Infinity Interactive, Inc.
ac4892f4 241
242L<http://www.iinteractive.com>
243
244This library is free software; you can redistribute it and/or modify
245it under the same terms as Perl itself.
246
247=cut
248
249