File Coverage

blib/lib/HTTP/Session.pm
Criterion Covered Total %
statement 109 111 98.2
branch 24 28 85.7
condition 12 15 80.0
subroutine 25 25 100.0
pod 10 10 100.0
total 180 189 95.2


line stmt bran cond sub pod time code
1             package HTTP::Session;
2 26     26   2592636 use strict;
  26         61  
  26         1041  
3 26     26   249 use warnings;
  26         51  
  26         1519  
4 26     26   150 use base qw/Class::Accessor::Fast/;
  26         45  
  26         13659  
5 26     26   81110 use 5.00800;
  26         115  
6             our $VERSION = '0.53';
7 26     26   171 use Carp ();
  26         49  
  26         484  
8 26     26   119 use Scalar::Util ();
  26         51  
  26         574  
9 26     26   13932 use Module::Runtime ();
  26         51766  
  26         965  
10 26     26   12312 use HTTP::Session::Finalized;
  26         73  
  26         1120  
11 26     26   11517 use HTTP::Session::Expired;
  26         88  
  26         28911  
12              
13             __PACKAGE__->mk_ro_accessors(qw/store request sid_length save_modified_session_only/);
14             __PACKAGE__->mk_accessors(qw/session_id _data is_changed is_fresh state/);
15              
16             sub new {
17 72     72 1 395165 my $class = shift;
18 72 50       478 my %args = ref($_[0]) ? %{$_[0]} : @_;
  0         0  
19             # check required parameters
20 72         238 for my $key (qw/store state request/) {
21 214 100       1128 Carp::croak "missing parameter $key" unless $args{$key};
22             }
23             # set default values
24 71   50     524 $args{_data} ||= {};
25 71   100     381 $args{save_modified_session_only} ||= 0;
26 71   50     404 $args{is_changed} ||= 0;
27 71   50     369 $args{is_fresh} ||= 0;
28 71   100     413 $args{sid_length} ||= 32;
29 71   100     386 $args{id} ||= 'HTTP::Session::ID::SHA1';
30 71         501 my $self = bless {%args}, $class;
31 71         389 $self->_load_session();
32 71 50       827 Carp::croak "[BUG] we have bug" unless $self->{request};
33 71         548 $self;
34             }
35              
36             sub _load_session {
37 71     71   136 my $self = shift;
38              
39 71         2634 my $session_id = $self->state->get_session_id($self->request);
40 71 100       6700 if ( $session_id ) {
41 44         1398 my $data = $self->store->select($session_id);
42 44 100       514 if ($data) {
43 35         955 $self->session_id( $session_id );
44 35         1150 $self->_data($data);
45             } else {
46 9 100       222 if ($self->state->permissive) {
47 2         126 $self->session_id( $session_id );
48 2         89 $self->is_fresh(1);
49             } else {
50             # session was expired? or session fixation?
51             # regen session id.
52 7         238 $self->session_id( $self->_generate_session_id() );
53 7         199 $self->is_fresh(1);
54             }
55             }
56             } else {
57             # no sid; generate it
58 27         126 $self->session_id( $self->_generate_session_id() );
59 27         1566 $self->is_fresh(1);
60             }
61             }
62              
63             sub _generate_session_id {
64 40     40   125 my $self = shift;
65 40 50       260 Module::Runtime::require_module($self->{id}) or die $@;
66 40         2206 $self->{id}->generate_id($self->sid_length);
67             }
68              
69             sub response_filter {
70 29     29 1 16095 my ($self, $response) = @_;
71 29 100       336 Carp::croak "missing response" unless ref $response;
72              
73 28         983 $self->state->response_filter($self->session_id, $response);
74             }
75              
76             sub finalize {
77 71     71 1 234 my ($self, ) = @_;
78              
79 71 100       2557 if ($self->is_fresh) {
80 37 100 100     1170 if ($self->is_changed || !$self->save_modified_session_only) {
81 36         2113 $self->store->insert( $self->session_id, $self->_data );
82             }
83             } else {
84 34 100       1118 if ($self->is_changed) {
85 2         63 $self->store->update( $self->session_id, $self->_data );
86             }
87             }
88              
89 71         2374 delete $self->{$_} for keys %$self;
90 71         2684 bless $self, 'HTTP::Session::Finalized';
91             }
92              
93             sub DESTROY {
94 66     66   69737 my $self = shift;
95              
96 66 50       318 if ($self->{store}) {
97 66         238 $self->finalize();
98             } else {
99             # this case happen at global destruction?
100 0         0 Carp::carp "you should call HTTP::Session->finalize method manually";
101             }
102             }
103              
104             sub keys {
105 1     1 1 780 my $self = shift;
106 1         3 return keys %{ $self->_data };
  1         37  
107             }
108              
109             sub get {
110 24     24 1 8733 my ($self, $key) = @_;
111 24         674 $self->_data->{$key};
112             }
113              
114             sub set {
115 15     15 1 4462 my ($self, $key, $val) = @_;
116 15         433 $self->is_changed(1);
117 15         424 $self->_data->{$key} = $val;
118             }
119              
120             sub remove {
121 3     3 1 908 my ( $self, $key ) = @_;
122 3         72 $self->is_changed(1);
123 3         70 delete $self->_data->{$key};
124             }
125              
126             sub as_hashref {
127 3     3 1 1353 my $self = shift;
128 3         22 return { %{ $self->_data } }; # shallow copy
  3         102  
129             }
130              
131             sub expire {
132 2     2 1 44 my $self = shift;
133 2         53 $self->store->delete($self->session_id);
134              
135             # XXX tricky bit to unlock
136 2         22 delete $self->{$_} for qw(is_fresh is_changed);
137 2         10 $self->DESTROY;
138              
139             # rebless to null class
140 2         10 bless $self, 'HTTP::Session::Expired';
141             }
142              
143             sub regenerate_session_id {
144 3     3 1 3168 my ($self, $delete_old) = @_;
145 3         6 $self->_data( { %{ $self->_data } } );
  3         70  
146              
147 3 100       34 if ($delete_old) {
148 1         21 my $oldsid = $self->session_id;
149 1         23 $self->store->delete($oldsid);
150             }
151 3         13 my $session_id = $self->_generate_session_id();
152 3         65 $self->session_id( $session_id );
153 3         63 $self->is_fresh(1);
154             }
155              
156             BEGIN {
157 26     26   250 no strict 'refs';
  26         174  
  26         3723  
158 26     26   198 for my $meth (qw/redirect_filter header_filter html_filter/) {
159 78         1507 *{__PACKAGE__ . '::' . $meth} = sub {
160 6     6   3539 my ($self, $stuff) = @_;
161 6 100       190 if ($self->state->can($meth)) {
162 4         192 $self->state->$meth($self->session_id, $stuff);
163             } else {
164 2         45 $stuff;
165             }
166 78         368 };
167             }
168             }
169              
170             1;
171             __END__