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