File Coverage

blib/lib/Apache2/ASP/SessionStateManager.pm
Criterion Covered Total %
statement 33 132 25.0
branch 0 14 0.0
condition 0 4 0.0
subroutine 11 23 47.8
pod 1 11 9.0
total 45 184 24.4


line stmt bran cond sub pod time code
1            
2             package Apache2::ASP::SessionStateManager;
3            
4 23     23   127 use strict;
  23         30  
  23         587  
5 23     23   82 use warnings 'all';
  23         30  
  23         631  
6 23     23   80 use base 'Ima::DBI';
  23         30  
  23         11064  
7 23     23   393336 use Digest::MD5 'md5_hex';
  23         44  
  23         1338  
8 23     23   110 use Storable qw( freeze thaw );
  23         38  
  23         1459  
9 23     23   106 use HTTP::Date qw( time2iso str2time );
  23         33  
  23         1070  
10 23     23   103 use Scalar::Util 'weaken';
  23         32  
  23         5527  
11            
12            
13             #==============================================================================
14             sub new
15             {
16 0     0 0   my ($class, %args) = @_;
17            
18 0           my $s = bless {}, $class;
19 0           my $conn = $s->context->config->data_connections->session;
20            
21 0           local $^W = 0;
22 0           __PACKAGE__->set_db('Main',
23             $conn->dsn,
24             $conn->username,
25             $conn->password
26             );
27            
28             # Prepare our Session:
29 0 0         if( my $id = $s->parse_session_id() )
30             {
31 0 0         if( $s->verify_session_id( $id ) )
32             {
33 0           $s->{SessionID} = $id;
34 0           return $s->retrieve( $id );
35             }
36             else
37             {
38 0           $s->{SessionID} = $s->new_session_id();
39 0           $s->write_session_cookie();
40 0           return $s->create( $s->{SessionID} );
41             }# end if()
42             }
43             else
44             {
45 0           $s->{SessionID} = $s->new_session_id();
46 0           $s->write_session_cookie();
47 0           return $s->create( $s->{SessionID} );
48             }# end if()
49             }# end new()
50              
51              
52             #==============================================================================
53             sub context
54             {
55 0     0 0   $Apache2::ASP::HTTPContext::ClassName->current;
56             }# end context()
57            
58            
59             #==============================================================================
60             sub parse_session_id
61             {
62 0     0 0   my ($s) = @_;
63            
64 0           my $cookiename = $s->context->config->data_connections->session->cookie_name;
65              
66 23     23   119 no warnings 'uninitialized';
  23         38  
  23         6200  
67 0 0         if( my ($id) = $ENV{HTTP_COOKIE} =~ m/\b$cookiename\=([a-f0-9]+)\b/ )
    0          
68             {
69 0           return $id;
70             }
71             elsif( ($id) = $s->context->r->headers_in->{Cookie} =~ m/\b$cookiename\=([a-f0-9]+)\b/ )
72             {
73 0           return $id;
74             }
75             else
76             {
77 0           return;
78             }# end if()
79             }# end parse_session_id()
80            
81            
82             #==============================================================================
83             # Returns true if the session exists and has not timed out:
84             sub verify_session_id
85             {
86 0     0 0   my ($s, $id) = @_;
87              
88 0           my $range_start = time() - ( $s->context->config->data_connections->session->session_timeout * 60 );
89 0           local $s->db_Main->{AutoCommit} = 1;
90 0           my $sth = $s->db_Main->prepare_cached(<<"");
91             SELECT COUNT(*)
92             FROM asp_sessions
93             WHERE session_id = ?
94             AND modified_on BETWEEN ? AND ?
95              
96 0           $sth->execute( $id, time2iso($range_start), time2iso() );
97 0           my ($active) = $sth->fetchrow();
98 0           $sth->finish();
99            
100 0           return $active;
101             }# end verify_session_id()
102            
103            
104             #==============================================================================
105             sub create
106             {
107 0     0 0   my ($s, $id) = @_;
108            
109 0           local $s->db_Main->{AutoCommit} = 1;
110 0           my $sth = $s->db_Main->prepare_cached(<<"");
111             INSERT INTO asp_sessions (
112             session_id,
113             session_data,
114             created_on,
115             modified_on
116             )
117             VALUES (
118             ?, ?, ?, ?
119             )
120            
121 0           my $now = time2iso();
122            
123 23     23   120 no warnings 'uninitialized';
  23         44  
  23         6122  
124             $s->{__signature} = md5_hex(
125             join ":",
126 0           map { "$_:$s->{$_}" }
127 0           grep { $_ ne '__signature' } sort keys(%$s)
  0            
128             );
129            
130 0           my %clone = %$s;
131            
132 0           $sth->execute(
133             $id,
134             freeze( \%clone ),
135             $now,
136             $now,
137             );
138 0           $sth->finish();
139            
140 0           return $s->retrieve( $id );
141             }# end create()
142            
143            
144             #==============================================================================
145             sub retrieve
146             {
147 0     0 0   my ($s, $id) = @_;
148            
149 0           local $s->db_Main->{AutoCommit} = 1;
150 0           my $sth = $s->db_Main->prepare_cached(<<"");
151             SELECT session_data, modified_on
152             FROM asp_sessions
153             WHERE session_id = ?
154              
155 0           my $now = time2iso();
156 0           $sth->execute( $id );
157 0           my ($data, $modified_on) = $sth->fetchrow;
158 0   0       $data = thaw($data) || { SessionID => $id };
159 0           $sth->finish();
160              
161 0 0         if( time() - str2time($modified_on) >= ( $s->context->config->data_connections->session->session_timeout * 59 ) )
162             {
163 0           local $s->db_Main->{AutoCommit} = 1;
164 0           my $sth = $s->db_Main->prepare_cached(<<"");
165             UPDATE asp_sessions SET
166             modified_on = ?
167             WHERE session_id = ?
168              
169 0           $sth->execute( time2iso(), $id );
170 0           $sth->finish();
171             }# end if()
172            
173 0           undef(%$s);
174 0           $s = bless $data, ref($s);
175 0           weaken($s);
176            
177 23     23   119 no warnings 'uninitialized';
  23         37  
  23         3372  
178            
179 0           my @keys = sort keys(%$s);
180            
181             my $sig = md5_hex(
182             join ":",
183 0           map { "$_:$s->{$_}" }
184 0           grep { $_ ne '__signature' } @keys
  0            
185             );
186            
187 0           $s->{__signature} = $sig;
188            
189 0           return $s;
190             }# end retrieve()
191            
192            
193             #==============================================================================
194             sub save
195             {
196 0     0 1   my ($s) = @_;
197            
198 23     23   112 no warnings 'uninitialized';
  23         35  
  23         11120  
199             return if $s->{__signature} eq md5_hex(
200 0           join ":", map { "$_:$s->{$_}" }
201 0 0         grep { $_ ne '__signature' } sort keys(%$s)
  0            
202             );
203             $s->{__signature} = md5_hex(
204             join ":",
205 0           map { "$_:$s->{$_}" }
206 0           grep { $_ ne '__signature' } sort keys(%$s)
  0            
207             );
208            
209 0           local $s->db_Main->{AutoCommit} = 1;
210 0           my $sth = $s->db_Main->prepare_cached(<<"");
211             UPDATE asp_sessions SET
212             session_data = ?,
213             modified_on = ?
214             WHERE session_id = ?
215            
216 0           my %clone = %$s;
217 0           my $data = freeze( \%clone );
218 0           $sth->execute( $data, time2iso(), $s->{SessionID} );
219 0           $sth->finish();
220            
221 0           1;
222             }# end save()
223            
224            
225             #=========================================================================
226             sub reset
227             {
228 0     0 0   my ($s) = @_;
229            
230             # Remove everything *but* our important parts:
231 0           my %saves = map { $_ => 1 } qw/ SessionID /;
  0            
232 0           delete( $s->{$_} ) foreach grep { ! $saves{$_} } keys(%$s);
  0            
233 0           $s->save;
234             }# end reset()
235            
236            
237             #==============================================================================
238             sub new_session_id
239             {
240 0     0 0   my $s = shift;
241 0           md5_hex( $s->context->config->web->application_name . rand() );
242             }# end new_session_id()
243            
244            
245             #==============================================================================
246             sub write_session_cookie
247             {
248 0     0 0   my $s = shift;
249            
250 0           my $state = $s->context->config->data_connections->session;
251 0           my $cookiename = $state->cookie_name;
252 0           $s->context->response->AddHeader(
253             'Set-Cookie' => "$cookiename=$s->{SessionID}; path=/;" #; domain=" . $state->cookie_domain
254             );
255            
256             # If we weren't given an HTTP cookie value, set it here.
257             # This prevents subsequent calls to 'parse_session_id()' to fail:
258 0   0       $ENV{HTTP_COOKIE} ||= '';
259 0 0         if( $ENV{HTTP_COOKIE} !~ m/\b$cookiename\=.*?\b/ )
260             {
261 0           my @cookies = split /;/, $ENV{HTTP_COOKIE};
262 0           push @cookies, "$cookiename=$s->{SessionID}";
263 0           $ENV{HTTP_COOKIE} = join ';', @cookies;
264             }# end if()
265            
266 0           1;
267             }# end write_session_cookie()
268            
269            
270             #==============================================================================
271             sub dbh
272             {
273 0     0 0   my $s = shift;
274 0           return $s->db_Main;
275             }# end dbh()
276            
277            
278             #==============================================================================
279             sub DESTROY
280             {
281 0     0     my $s = shift;
282            
283 0           delete($s->{$_}) foreach keys(%$s);
284             }# end DESTROY()
285            
286             1;# return true:
287            
288             __END__