refactoring chiba++ commit so we only extract session id once
[catagits/Web-Session.git] / lib / Plack / Session / State.pm
1 package Plack::Session::State;
2 use strict;
3 use warnings;
4
5 use Digest::SHA1 ();
6
7 use Plack::Util::Accessor qw[
8     session_key
9     sid_generator
10     sid_validator
11 ];
12
13 sub new {
14     my ($class, %params) = @_;
15
16     $params{'_expired'}      ||= +{};
17     $params{'session_key'}   ||= 'plack_session';
18     $params{'sid_generator'} ||= sub {
19         Digest::SHA1::sha1_hex(rand() . $$ . {} . time)
20     };
21     $params{'sid_validator'} ||= qr/\A[0-9a-f]{40}\Z/;
22
23     bless { %params } => $class;
24 }
25
26 sub expire_session_id {
27     my ($self, $id) = @_;
28     $self->{'_expired'}->{ $id }++;
29 }
30
31 sub is_session_expired {
32     my ($self, $id) = @_;
33     exists $self->{'_expired'}->{ $id }
34 }
35
36 sub check_expired {
37     my ($self, $id) = @_;
38     return if $self->is_session_expired( $id );
39     return $id;
40 }
41
42 sub validate_session_id {
43     my ($self, $id) = @_;
44     $id =~ $self->sid_validator;
45 }
46
47 sub get_session_id {
48     my ($self, $request) = @_;
49     $self->extract( $request )
50         ||
51     $self->generate( $request )
52 }
53
54 sub get_session_id_from_request {
55     my ($self, $request) = @_;
56     $request->param( $self->session_key );
57 }
58
59 sub extract {
60     my ($self, $request) = @_;
61
62     my $id = $self->get_session_id_from_request( $request );
63     return unless defined $id;
64
65     $self->validate_session_id( $id )
66         &&
67     $self->check_expired( $id );
68 }
69
70 sub generate {
71     my $self = shift;
72     $self->sid_generator->( @_ );
73 }
74
75
76 sub finalize {
77     my ($self, $id, $response) = @_;
78     ();
79 }
80
81 1;
82
83 __END__
84
85 =pod
86
87 =head1 NAME
88
89 Plack::Session::State - Basic parameter-based session state
90
91 =head1 SYNOPSIS
92
93   use Plack::Builder;
94   use Plack::Middleware::Session;
95   use Plack::Session::State;
96
97   my $app = sub {
98       return [ 200, [ 'Content-Type' => 'text/plain' ], [ 'Hello Foo' ] ];
99   };
100
101   builder {
102       enable 'Session',
103           state => Plack::Session::State->new;
104       $app;
105   };
106
107 =head1 DESCRIPTION
108
109 This will maintain session state by passing the session through
110 the request params. It does not do this automatically though,
111 you are responsible for passing the session param.
112
113 This should be considered the state "base" class (although
114 subclassing is not a requirement) and defines the spec for
115 all B<Plack::Session::State::*> modules. You will only
116 need to override a couple methods if you do subclass. See
117 L<Plack::Session::State::Cookie> for an example of this.
118
119 =head1 METHODS
120
121 =over 4
122
123 =item B<new ( %params )>
124
125 The C<%params> can include I<session_key>, I<sid_generator> and I<sid_checker>
126 however in both cases a default will be provided for you.
127
128 =item B<session_key>
129
130 This is the name of the session key, it default to 'plack_session'.
131
132 =item B<sid_generator>
133
134 This is a CODE ref used to generate unique session ids, by default
135 it will generate a SHA1 using fairly sufficient entropy. If you are
136 concerned or interested, just read the source.
137
138 =item B<sid_validator>
139
140 This is a regex used to validate requested session id.
141
142 =back
143
144 =head2 Session ID Managment
145
146 =over 4
147
148 =item B<get_session_id ( $request )>
149
150 Given a C<$request> this will first attempt to extract the session,
151 if the is expired or does not exist, it will then generate a new
152 session. The C<$request> is expected to be a L<Plack::Request> instance
153 or an object with an equivalent interface.
154
155 =item B<get_session_id_from_request ( $request )>
156
157 This is the method used to extract the session id from a C<$request>.
158 Subclasses will often only need to override this method and the
159 C<finalize> method.
160
161 =item B<validate_session_id ( $session_id )>
162
163 This will use the C<sid_validator> regex and confirm that the
164 C<$session_id> is valid.
165
166 =item B<extract ( $request )>
167
168 This will attempt to extract the session from a C<$request> by looking
169 for the C<session_key> in the C<$request> params. It will then check to
170 see if the session has expired and return the session id if it is not.
171 The C<$request> is expected to be a L<Plack::Request> instance or an
172 object with an equivalent interface.
173
174 =item B<generate ( $request )>
175
176 This will generate a new session id using the C<sid_generator> callback.
177 The C<$request> argument is not used by this method but is there for
178 use by subclasses. The C<$request> is expected to be a L<Plack::Request>
179 instance or an object with an equivalent interface.
180
181 =item B<finalize ( $session_id, $response )>
182
183 Given a C<$session_id> and a C<$response> this will perform any
184 finalization nessecary to preserve state. This method is called by
185 the L<Plack::Session> C<finalize> method. The C<$response> is expected
186 to be a L<Plack::Response> instance or an object with an equivalent
187 interface.
188
189 =back
190
191 =head2 Session Expiration Handling
192
193 =over 4
194
195 =item B<expire_session_id ( $id )>
196
197 This will mark the session for C<$id> as expired. This method is called
198 by the L<Plack::Session> C<expire> method.
199
200 =item B<is_session_expired ( $id )>
201
202 This will check to see if the session C<$id> has been marked as
203 expired.
204
205 =item B<check_expired ( $id )>
206
207 Given an session C<$id> this will return C<undef> if the session is
208 expired or return the C<$id> if it is not.
209
210 =back
211
212 =head1 BUGS
213
214 All complex software has bugs lurking in it, and this module is no
215 exception. If you find a bug please either email me, or add the bug
216 to cpan-RT.
217
218 =head1 AUTHOR
219
220 Stevan Little E<lt>stevan.little@iinteractive.comE<gt>
221
222 =head1 COPYRIGHT AND LICENSE
223
224 Copyright 2009 Infinity Interactive, Inc.
225
226 L<http://www.iinteractive.com>
227
228 This library is free software; you can redistribute it and/or modify
229 it under the same terms as Perl itself.
230
231 =cut
232
233