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