Version requirement bump
[catagits/Catalyst-Plugin-Session-State-Cookie.git] / lib / Catalyst / Plugin / Session / State / Cookie.pm
CommitLineData
1a776a0c 1package Catalyst::Plugin::Session::State::Cookie;
ea139a65 2use base qw/Catalyst::Plugin::Session::State Class::Accessor::Fast/;
bf2bce67 3
4use strict;
1a776a0c 5use warnings;
bf2bce67 6
45c96680 7use MRO::Compat;
74586782 8use Catalyst::Utils ();
bf2bce67 9
602b9593 10our $VERSION = "0.11";
ea139a65 11
12BEGIN { __PACKAGE__->mk_accessors(qw/_deleted_session_id/) }
81eb8ebf 13
5e50008f 14sub setup_session {
20e33791 15 my $c = shift;
5e50008f 16
45c96680 17 $c->maybe::next::method(@_);
2bde9162 18
7022ec4c 19 $c->config->{session}{cookie_name}
20 ||= Catalyst::Utils::appprefix($c) . '_session';
5e50008f 21}
22
0ff18b66 23sub extend_session_id {
24 my ( $c, $sid, $expires ) = @_;
1a776a0c 25
2bde9162 26 if ( my $cookie = $c->get_session_cookie ) {
0ff18b66 27 $c->update_session_cookie( $c->make_session_cookie( $sid ) );
58730edc 28 }
db1cda22 29
45c96680 30 $c->maybe::next::method( $sid, $expires );
2bde9162 31}
32
33sub set_session_id {
34 my ( $c, $sid ) = @_;
35
36 $c->update_session_cookie( $c->make_session_cookie( $sid ) );
37
45c96680 38 return $c->maybe::next::method($sid);
db1cda22 39}
40
41sub update_session_cookie {
58730edc 42 my ( $c, $updated ) = @_;
8bdcbb46 43
44 unless ( $c->cookie_is_rejecting( $updated ) ) {
45 my $cookie_name = $c->config->{session}{cookie_name};
46 $c->response->cookies->{$cookie_name} = $updated;
47 }
48}
49
50sub cookie_is_rejecting {
51 my ( $c, $cookie ) = @_;
52
53 if ( $cookie->{path} ) {
91e4fe2d 54 return 1 if index '/'.$c->request->path, $cookie->{path};
8bdcbb46 55 }
56
57 return 0;
db1cda22 58}
5e50008f 59
db1cda22 60sub make_session_cookie {
2bde9162 61 my ( $c, $sid, %attrs ) = @_;
58730edc 62
63 my $cfg = $c->config->{session};
64 my $cookie = {
2bde9162 65 value => $sid,
58730edc 66 ( $cfg->{cookie_domain} ? ( domain => $cfg->{cookie_domain} ) : () ),
8bdcbb46 67 ( $cfg->{cookie_path} ? ( path => $cfg->{cookie_path} ) : () ),
df55e818 68 %attrs,
58730edc 69 };
70
2bde9162 71 unless ( exists $cookie->{expires} ) {
72 $cookie->{expires} = $c->calculate_session_cookie_expires();
73 }
1e986fd5 74
d2cf2047 75 #beware: we have to accept also the old syntax "cookie_secure = true"
76 my $sec = $cfg->{cookie_secure} || 0; # default = 0 (not set)
77 $cookie->{secure} = 1 unless ( ($sec==0) || ($sec==2) );
78 $cookie->{secure} = 1 if ( ($sec==2) && $c->req->secure );
79
80 my $hto = $cookie->{httponly} || 1; # default = 1 (set httponly)
81 $cookie->{httponly} = 1 unless ($hto==0);
fc4b9d6d 82
1e986fd5 83 return $cookie;
84}
85
2bde9162 86sub calc_expiry { # compat
87 my $c = shift;
45c96680 88 $c->maybe::next::method( @_ ) || $c->calculate_session_cookie_expires( @_ );
2bde9162 89}
90
91sub calculate_session_cookie_expires {
92 my $c = shift;
93 my $cfg = $c->config->{session};
94
45c96680 95 my $value = $c->maybe::next::method(@_);
1e986fd5 96 return $value if $value;
2bde9162 97
58730edc 98 if ( exists $cfg->{cookie_expires} ) {
7022ec4c 99 if ( $cfg->{cookie_expires} > 0 ) {
1e986fd5 100 return time() + $cfg->{cookie_expires};
7022ec4c 101 }
102 else {
1e986fd5 103 return undef;
7022ec4c 104 }
58730edc 105 }
106 else {
2bde9162 107 return $c->session_expires;
58730edc 108 }
bf2bce67 109}
110
2bde9162 111sub get_session_cookie {
bf2bce67 112 my $c = shift;
1a776a0c 113
20e33791 114 my $cookie_name = $c->config->{session}{cookie_name};
5e50008f 115
2bde9162 116 return $c->request->cookies->{$cookie_name};
117}
118
119sub get_session_id {
120 my $c = shift;
121
ea139a65 122 if ( !$c->_deleted_session_id and my $cookie = $c->get_session_cookie ) {
bf2bce67 123 my $sid = $cookie->value;
bf2bce67 124 $c->log->debug(qq/Found sessionid "$sid" in cookie/) if $c->debug;
2bde9162 125 return $sid if $sid;
bf2bce67 126 }
bf2bce67 127
45c96680 128 $c->maybe::next::method(@_);
2bde9162 129}
130
131sub delete_session_id {
df55e818 132 my ( $c, $sid ) = @_;
ea139a65 133
134 $c->_deleted_session_id(1); # to prevent get_session_id from returning it
df55e818 135
136 $c->update_session_cookie( $c->make_session_cookie( $sid, expires => 0 ) );
137
45c96680 138 $c->maybe::next::method($sid);
bf2bce67 139}
140
1a776a0c 141__PACKAGE__
57dbf608 142
1a776a0c 143__END__
bf2bce67 144
1a776a0c 145=pod
b2f8df5e 146
1a776a0c 147=head1 NAME
bf2bce67 148
75d3560d 149Catalyst::Plugin::Session::State::Cookie - Maintain session IDs using cookies.
bf2bce67 150
1a776a0c 151=head1 SYNOPSIS
bf2bce67 152
20e33791 153 use Catalyst qw/Session Session::State::Cookie Session::Store::Foo/;
bf2bce67 154
1a776a0c 155=head1 DESCRIPTION
bf2bce67 156
1a776a0c 157In order for L<Catalyst::Plugin::Session> to work the session ID needs to be
158stored on the client, and the session data needs to be stored on the server.
bf2bce67 159
1a776a0c 160This plugin stores the session ID on the client using the cookie mechanism.
57dbf608 161
724a6173 162=head1 METHODS
163
164=over 4
165
166=item make_session_cookie
167
168Returns a hash reference with the default values for new cookies.
169
170=item update_session_cookie $hash_ref
171
172Sets the cookie based on C<cookie_name> in the response object.
173
2cfb85de 174=item calc_expiry
175
176=item calculate_session_cookie_expires
177
178=item cookie_is_rejecting
179
180=item delete_session_id
181
182=item extend_session_id
183
184=item get_session_cookie
185
186=item get_session_id
187
188=item set_session_id
189
724a6173 190=back
191
1a776a0c 192=head1 EXTENDED METHODS
58c05d1a 193
57dbf608 194=over 4
195
1a776a0c 196=item prepare_cookies
57dbf608 197
1a776a0c 198Will restore if an appropriate cookie is found.
58c05d1a 199
d52e5079 200=item finalize_cookies
58c05d1a 201
1536d9aa 202Will set a cookie called C<session> if it doesn't exist or if its value is not
19c2baa1 203the current session id.
204
205=item setup_session
206
1536d9aa 207Will set the C<cookie_name> parameter to its default value if it isn't set.
58c05d1a 208
57dbf608 209=back
58c05d1a 210
5e50008f 211=head1 CONFIGURATION
212
213=over 4
214
215=item cookie_name
216
ae33e13f 217The name of the cookie to store (defaults to C<Catalyst::Utils::apprefix($c) . '_session'>).
5e50008f 218
41b4b15c 219=item cookie_domain
220
221The name of the domain to store in the cookie (defaults to current host)
222
7022ec4c 223=item cookie_expires
224
225Number of seconds from now you want to elapse before cookie will expire.
226Set to 0 to create a session cookie, ie one which will die when the
227user's browser is shut down.
228
fc4b9d6d 229=item cookie_secure
230
d2cf2047 231If this attribute B<set to 0> the cookie will not have the secure flag.
232
233If this attribute B<set to 1> (or true for backward compatibility) - the cookie
234send by the server to the client will got the secure flag that tells the browser
235to send this cookies back to the server only via HTTPS.
236
237If this attribute B<set to 2> then the cookie will got the secure flag only if
238the request that caused cookie generation was sent over https (this option is
239not good if you are mixing https and http in you application).
240
241Default vaule is 0.
242
243=item cookie_httponly
244
245If this attribute B<set to 0>, the cookie will not have HTTPOnly flag.
246
247If this attribute B<set to 1>, the cookie will got HTTPOnly flag that should
248prevent client side Javascript accessing the cookie value - this makes some
249sort of session hijacking attacks significantly harder. Unfortunately not all
250browsers support this flag (MSIE 6 SP1+, Firefox 3.0.0.6+, Opera 9.5+); if
251a browser is not aware of HTTPOnly the flag will be ignored.
252
253Default value is 1.
254
255Note1: Many peole are confused by the name "HTTPOnly" - it B<does not mean>
256that this cookie works only over HTTP and not over HTTPS.
257
258Note2: This paramater requires Catalyst::Runtime 5.80005 otherwise is skipped.
fc4b9d6d 259
8bdcbb46 260=item cookie_path
261
262The path of the request url where cookie should be baked.
263
5e50008f 264=back
265
d6bdceb5 266For example, you could stick this in MyApp.pm:
267
268 __PACKAGE__->config( session => {
269 cookie_domain => '.mydomain.com',
270 });
271
724a6173 272=head1 CAVEATS
db1cda22 273
274Sessions have to be created before the first write to be saved. For example:
275
276 sub action : Local {
277 my ( $self, $c ) = @_;
278 $c->res->write("foo");
279 $c->session( ... );
280 ...
281 }
282
283Will cause a session ID to not be set, because by the time a session is
284actually created the headers have already been sent to the client.
285
bf2bce67 286=head1 SEE ALSO
287
1a776a0c 288L<Catalyst>, L<Catalyst::Plugin::Session>.
bf2bce67 289
47f47da5 290=head1 AUTHORS
bf2bce67 291
8ae6d944 292Yuval Kogman E<lt>nothingmuch@woobling.orgE<gt>
293
294=head1 CONTRIBUTORS
295
47f47da5 296This module is derived from L<Catalyst::Plugin::Session::FastMmap> code, and
297has been heavily modified since.
298
d6bdceb5 299 Andrew Ford
300 Andy Grundman
301 Christian Hansen
302 Marcus Ramberg
303 Jonathan Rockway E<lt>jrockway@cpan.orgE<gt>
304 Sebastian Riedel
bf2bce67 305
306=head1 COPYRIGHT
307
bfeb5ca0 308This program is free software, you can redistribute it and/or modify it
309under the same terms as Perl itself.
bf2bce67 310
311=cut
312
3131;