Checking in changes prior to tagging of version 0.12.
[catagits/Web-Session.git] / lib / Plack / Middleware / Session.pm
CommitLineData
bd992981 1package Plack::Middleware::Session;
2use strict;
3use warnings;
4
89d240fa 5our $VERSION = '0.12';
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});
4ff41723 78 } else {
79 $self->store->store($options->{id}, $session);
80 }
81}
82
83sub finalize {
92edbddf 84 my($self, $env, $res) = @_;
dc556d28 85
7518e927 86 my $session = $env->{'psgix.session'};
87 my $options = $env->{'psgix.session.options'};
4ff41723 88
7518e927 89 $self->commit($env) unless $options->{no_store};
98b27b31 90 if ($options->{expire}) {
92edbddf 91 $self->expire_session($options->{id}, $res, $env);
4ff41723 92 } else {
92edbddf 93 $self->save_state($options->{id}, $res, $env);
4ff41723 94 }
95}
96
dc556d28 97sub expire_session {
7518e927 98 my($self, $id, $res, $env) = @_;
99 $self->state->expire_session_id($id, $res, $env->{'psgix.session.options'});
dc556d28 100}
101
102sub save_state {
7518e927 103 my($self, $id, $res, $env) = @_;
104 $self->state->finalize($id, $res, $env->{'psgix.session.options'});
dc556d28 105}
106
bd992981 1071;
108
109__END__
ac4892f4 110
111=pod
112
113=head1 NAME
114
115Plack::Middleware::Session - Middleware for session management
116
117=head1 SYNOPSIS
118
3d92cf47 119 use Plack::Builder;
ac4892f4 120
3d92cf47 121 my $app = sub {
536da026 122 my $env = shift;
4ff41723 123 my $session = $env->{'psgix.session'};
536da026 124 return [
125 200,
126 [ 'Content-Type' => 'text/plain' ],
4ff41723 127 [ "Hello, you've been here for ", $session->{counter}++, "th time!" ],
536da026 128 ];
3d92cf47 129 };
130
131 builder {
132 enable 'Session';
133 $app;
134 };
135
ad80e445 136 # Or, use the File store backend (great if you use multiprocess server)
137 # For more options, see perldoc Plack::Session::Store::File
138 builder {
139 enable 'Session', store => 'File';
140 $app;
141 };
142
ac4892f4 143=head1 DESCRIPTION
144
3d92cf47 145This is a Plack Middleware component for session management. By
ad80e445 146default it will use cookies to keep session state and store data in
147memory. This distribution also comes with other state and store
148solutions. See perldoc for these backends how to use them.
3d92cf47 149
4ff41723 150It should be noted that we store the current session as a hash
151reference in the C<psgix.session> key inside the C<$env> where you can
152access it as needed.
153
154B<NOTE:> As of version 0.04 the session is stored in C<psgix.session>
155instead of C<plack.session>.
b84f31d0 156
3d92cf47 157=head2 State
158
159=over 4
160
161=item L<Plack::Session::State>
162
163This will maintain session state by passing the session through
164the request params. It does not do this automatically though,
165you are responsible for passing the session param.
166
167=item L<Plack::Session::State::Cookie>
168
169This will maintain session state using browser cookies.
170
171=back
172
173=head2 Store
174
175=over 4
176
177=item L<Plack::Session::Store>
178
179This is your basic in-memory session data store. It is volatile storage
180and not recommended for multiprocessing environments. However it is
181very useful for development and testing.
182
183=item L<Plack::Session::Store::File>
184
185This will persist session data in a file. By default it uses
186L<Storable> but it can be configured to have a custom serializer and
187deserializer.
188
20ede533 189=item L<Plack::Session::Store::Cache>
3d92cf47 190
20ede533 191This will persist session data using the L<Cache> interface.
3d92cf47 192
193=item L<Plack::Session::Store::Null>
194
195Sometimes you don't care about storing session data, in that case
196you can use this noop module.
197
198=back
199
30cc0a71 200=head1 OPTIONS
201
eb14af1e 202The following are options that can be passed to this module.
30cc0a71 203
204=over 4
205
206=item I<state>
207
208This is expected to be an instance of L<Plack::Session::State> or an
209object that implements the same interface. If no option is provided
210the default L<Plack::Session::State::Cookie> will be used.
211
212=item I<store>
213
214This is expected to be an instance of L<Plack::Session::Store> or an
215object that implements the same interface. If no option is provided
216the default L<Plack::Session::Store> will be used.
217
218It should be noted that this default is an in-memory volatile store
219is only suitable for development (or single process servers). For a
220more robust solution see L<Plack::Session::Store::File> or
221L<Plack::Session::Store::Cache>.
222
30cc0a71 223=back
224
ac4892f4 225=head1 BUGS
226
227All complex software has bugs lurking in it, and this module is no
228exception. If you find a bug please either email me, or add the bug
229to cpan-RT.
230
231=head1 AUTHOR
232
233Tatsuhiko Miyagawa
234
235Stevan Little E<lt>stevan.little@iinteractive.comE<gt>
236
237=head1 COPYRIGHT AND LICENSE
238
000c696e 239Copyright 2009, 2010 Infinity Interactive, Inc.
ac4892f4 240
241L<http://www.iinteractive.com>
242
243This library is free software; you can redistribute it and/or modify
244it under the same terms as Perl itself.
245
246=cut
247
248