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