line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package CGI::Session::Driver::layered; |
2
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
13362
|
use strict; |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
218
|
|
4
|
6
|
|
|
6
|
|
31
|
use warnings; |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
248
|
|
5
|
6
|
|
|
6
|
|
39
|
use base qw(CGI::Session::Driver); |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
5592
|
|
6
|
|
|
|
|
|
|
|
7
|
6
|
|
|
6
|
|
10650
|
use Time::HiRes qw(time); |
|
6
|
|
|
|
|
17401
|
|
|
6
|
|
|
|
|
31
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $VERSION = '0.8'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 NAME |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
CGI::Session::Driver::layered - Use multiple layered drivers |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=head1 SYNOPSIS |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
use CGI::Session; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
my $session = CGI::Session->new("driver:layered", $sessionId, { Layers => [ |
20
|
|
|
|
|
|
|
{ |
21
|
|
|
|
|
|
|
Driver => 'file', |
22
|
|
|
|
|
|
|
Directory => '/tmp/foo', |
23
|
|
|
|
|
|
|
}, |
24
|
|
|
|
|
|
|
{ |
25
|
|
|
|
|
|
|
Driver => 'postgresql' |
26
|
|
|
|
|
|
|
table => 'websessions', |
27
|
|
|
|
|
|
|
handle => $dbh |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
]}); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=head1 DESCRIPTION |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
CGI::Session::Driver::Layered provides a interface for using multple drivers |
34
|
|
|
|
|
|
|
to store sessions. Each session is stored in all the configured drivers. When |
35
|
|
|
|
|
|
|
fetching a session, the driver with the most recent copy of the session is used. |
36
|
|
|
|
|
|
|
The drivers are searched in the order they were configured. |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 OPTIONS |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
Unlike most drivers for CGI::Session, this driver requires options to |
41
|
|
|
|
|
|
|
function. The driver args must has a layers field, which is an array ref of |
42
|
|
|
|
|
|
|
hash references. Each hash reference should contain the driver name under |
43
|
|
|
|
|
|
|
the key C, and the rest of the arguments for that driver. The order |
44
|
|
|
|
|
|
|
of the layers argument is the order that the layer will check during a |
45
|
|
|
|
|
|
|
retrieve. |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=cut |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
sub init { |
50
|
24
|
|
|
24
|
1
|
882903
|
my $self = shift; |
51
|
|
|
|
|
|
|
|
52
|
24
|
|
|
|
|
134
|
my $ret = $self->SUPER::init(@_); |
53
|
|
|
|
|
|
|
|
54
|
24
|
|
|
|
|
148
|
$self->{drivers} = []; |
55
|
|
|
|
|
|
|
|
56
|
24
|
|
|
|
|
49
|
foreach my $layer (@{$self->{Layers}}) { |
|
24
|
|
|
|
|
83
|
|
57
|
|
|
|
|
|
|
# make a local copy of the driver, so we can delete it from the args |
58
|
|
|
|
|
|
|
# we pass to Driver->new() |
59
|
47
|
|
|
|
|
139
|
local $layer->{Driver} = $layer->{Driver}; |
60
|
|
|
|
|
|
|
|
61
|
47
|
|
50
|
|
|
184
|
my $driver = delete $layer->{Driver} || return $self->set_error("A layer was missing a driver."); |
62
|
|
|
|
|
|
|
|
63
|
47
|
|
|
|
|
4934
|
require "CGI/Session/Driver/$driver.pm"; |
64
|
|
|
|
|
|
|
|
65
|
47
|
|
|
|
|
12205
|
my $obj = eval { "CGI::Session::Driver::$driver"->new($layer) }; |
|
47
|
|
|
|
|
345
|
|
66
|
47
|
100
|
|
|
|
2161
|
push(@{$self->{drivers}}, $obj) if $obj; |
|
46
|
|
|
|
|
203
|
|
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
24
|
50
|
|
|
|
250
|
if (@{$self->{drivers}} == 0) { |
|
24
|
|
|
|
|
96
|
|
70
|
0
|
|
|
|
|
0
|
return $self->set_error("Could not load any of the layers.") |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
24
|
|
|
|
|
67
|
return $self; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub store { |
78
|
14
|
|
|
14
|
1
|
4753
|
my ($self, $sid, $datastr) = @_; |
79
|
|
|
|
|
|
|
|
80
|
14
|
|
|
|
|
151
|
$datastr = time . ':' . $datastr; |
81
|
|
|
|
|
|
|
|
82
|
14
|
|
|
|
|
84
|
my $ret = 1; |
83
|
|
|
|
|
|
|
|
84
|
14
|
|
|
|
|
23
|
foreach my $driver (@{$self->{drivers}}) { |
|
14
|
|
|
|
|
38
|
|
85
|
27
|
50
|
|
|
|
3803
|
eval { $driver->store($sid, $datastr) } || do { $ret = 0 }; |
|
27
|
|
|
|
|
220
|
|
|
0
|
|
|
|
|
0
|
|
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
14
|
50
|
|
|
|
2960
|
return $ret if $ret; |
89
|
0
|
|
|
|
|
0
|
return; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub retrieve { |
93
|
10
|
|
|
10
|
1
|
119
|
my ($self, $sid) = @_; |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# atime at 0, data at 1 |
96
|
10
|
|
|
|
|
28
|
my $latest = [0, '']; |
97
|
|
|
|
|
|
|
|
98
|
10
|
|
|
|
|
22
|
foreach my $driver (@{$self->{drivers}}) { |
|
10
|
|
|
|
|
29
|
|
99
|
19
|
|
|
|
|
24
|
my $str = eval { $driver->retrieve($sid) }; |
|
19
|
|
|
|
|
76
|
|
100
|
19
|
100
|
|
|
|
2144
|
if ($str) { |
101
|
11
|
|
|
|
|
46
|
my ($atime, $data) = split(m/:/, $str, 2); |
102
|
|
|
|
|
|
|
|
103
|
11
|
100
|
|
|
|
85
|
if ($atime > $latest->[0]) { |
104
|
10
|
|
|
|
|
44
|
$latest = [$atime, $data]; |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
10
|
|
|
|
|
44
|
return $latest->[1]; |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub remove { |
113
|
0
|
|
|
0
|
1
|
0
|
my ($self, $sid) = @_; |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
0
|
my $ret = 1; |
116
|
|
|
|
|
|
|
|
117
|
0
|
|
|
|
|
0
|
foreach my $driver (@{$self->{drivers}}) { |
|
0
|
|
|
|
|
0
|
|
118
|
0
|
|
|
|
|
0
|
my $ret = eval { |
119
|
0
|
|
|
|
|
0
|
$driver->remove($sid); |
120
|
|
|
|
|
|
|
}; |
121
|
0
|
0
|
0
|
|
|
0
|
if ($@ || !$ret) { |
122
|
0
|
|
|
|
|
0
|
$ret = 0; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
0
|
return $ret; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub traverse { |
130
|
1
|
|
|
1
|
1
|
46
|
my ($self, $coderef) = @_; |
131
|
|
|
|
|
|
|
# execute $coderef for each session id passing session id as the first and the only |
132
|
|
|
|
|
|
|
# argument |
133
|
|
|
|
|
|
|
|
134
|
1
|
|
|
|
|
3
|
my %seen; |
135
|
|
|
|
|
|
|
# make closure over the coderef and our seen hash, this will make sure that |
136
|
|
|
|
|
|
|
# we visit each session exactly once. |
137
|
|
|
|
|
|
|
my $visitor = sub { |
138
|
20
|
|
|
20
|
|
4716
|
my ($sid) = @_; |
139
|
|
|
|
|
|
|
|
140
|
20
|
100
|
|
|
|
97
|
return if $seen{$sid}++; |
141
|
|
|
|
|
|
|
|
142
|
10
|
|
|
|
|
22
|
$coderef->($sid); |
143
|
1
|
|
|
|
|
6
|
}; |
144
|
|
|
|
|
|
|
|
145
|
1
|
|
|
|
|
2
|
my $ok = 1; |
146
|
|
|
|
|
|
|
|
147
|
1
|
|
|
|
|
3
|
foreach my $driver (@{$self->{drivers}}) { |
|
1
|
|
|
|
|
5
|
|
148
|
2
|
|
33
|
|
|
8
|
$ok &&= eval { |
149
|
2
|
|
|
|
|
11
|
$driver->traverse($visitor); |
150
|
2
|
|
|
|
|
503
|
1; |
151
|
|
|
|
|
|
|
}; |
152
|
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
1
|
50
|
|
|
|
6
|
if (!$ok) { |
155
|
0
|
|
|
|
|
0
|
return $self->set_error($@); |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
1
|
|
|
|
|
9
|
return 1; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub _drivers { |
163
|
2
|
|
|
2
|
|
21
|
return @{shift->{drivers}}; |
|
2
|
|
|
|
|
9
|
|
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
sub errstr { |
168
|
1
|
|
|
1
|
1
|
39
|
my ($self) = @_; |
169
|
|
|
|
|
|
|
|
170
|
1
|
|
|
|
|
3
|
return join("\n", map { "[ $_ ]" } grep { length } map { $_->errstr } @{$self->{drivers}}); |
|
2
|
|
|
|
|
11
|
|
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
18
|
|
|
1
|
|
|
|
|
2
|
|
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=head1 COPYRIGHT |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
Copyright (C) 2009 Liquidweb Inc. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head1 AUTHOR |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Chris Reinhardt |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=head1 SEE ALSO |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
L, L |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=cut |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
1; |