line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#line 1 |
2
|
|
|
|
|
|
|
package CGI::Application::Plugin::Session; |
3
|
4
|
|
|
4
|
|
5695
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
use CGI::Session (); |
5
|
|
|
|
|
|
|
use File::Spec (); |
6
|
|
|
|
|
|
|
use CGI::Application 3.21; |
7
|
|
|
|
|
|
|
use Carp qw(croak); |
8
|
|
|
|
|
|
|
use Scalar::Util (); |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
use strict; |
11
|
|
|
|
|
|
|
use vars qw($VERSION @EXPORT); |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
require Exporter; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
@EXPORT = qw( |
16
|
|
|
|
|
|
|
session |
17
|
|
|
|
|
|
|
session_config |
18
|
|
|
|
|
|
|
session_cookie |
19
|
|
|
|
|
|
|
session_delete |
20
|
|
|
|
|
|
|
); |
21
|
|
|
|
|
|
|
sub import { goto &Exporter::import } |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
$VERSION = '1.02'; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub session { |
26
|
|
|
|
|
|
|
my $self = shift; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
if (!$self->{__CAP__SESSION_OBJ}) { |
29
|
|
|
|
|
|
|
# define the config hash if it doesn't exist to save some checks later |
30
|
|
|
|
|
|
|
$self->{__CAP__SESSION_CONFIG} = {} unless $self->{__CAP__SESSION_CONFIG}; |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
# gather parameters for the CGI::Session module from the user, |
33
|
|
|
|
|
|
|
# or use some sane defaults |
34
|
|
|
|
|
|
|
my @params = ($self->{__CAP__SESSION_CONFIG}->{CGI_SESSION_OPTIONS}) ? |
35
|
|
|
|
|
|
|
@{ $self->{__CAP__SESSION_CONFIG}->{CGI_SESSION_OPTIONS} } : |
36
|
|
|
|
|
|
|
('driver:File', $self->query, {Directory=>File::Spec->tmpdir}); |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# CGI::Session only works properly with CGI.pm so extract the sid manually if |
40
|
|
|
|
|
|
|
# another module is being used |
41
|
|
|
|
|
|
|
if (Scalar::Util::blessed($params[1]) && ! $params[1]->isa('CGI')) { |
42
|
|
|
|
|
|
|
my $sid = $params[1]->cookie(CGI::Session->name) || $params[1]->param(CGI::Session->name); |
43
|
|
|
|
|
|
|
$params[1] = $sid; |
44
|
|
|
|
|
|
|
} |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# create CGI::Session object or die with an error |
47
|
|
|
|
|
|
|
$self->{__CAP__SESSION_OBJ} = CGI::Session->new(@params); |
48
|
|
|
|
|
|
|
if (! $self->{__CAP__SESSION_OBJ} ) { |
49
|
|
|
|
|
|
|
my $errstr = CGI::Session->errstr || 'Unknown'; |
50
|
|
|
|
|
|
|
croak "Failed to Create CGI::Session object :: Reason: $errstr"; |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Set the default expiry if requested and if this is a new session |
54
|
|
|
|
|
|
|
if ($self->{__CAP__SESSION_CONFIG}->{DEFAULT_EXPIRY} && $self->{__CAP__SESSION_OBJ}->is_new) { |
55
|
|
|
|
|
|
|
$self->{__CAP__SESSION_OBJ}->expire($self->{__CAP__SESSION_CONFIG}->{DEFAULT_EXPIRY}); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
# add the cookie to the outgoing headers under the following conditions |
59
|
|
|
|
|
|
|
# if the cookie doesn't exist, |
60
|
|
|
|
|
|
|
# or if the session ID doesn't match what is in the current cookie, |
61
|
|
|
|
|
|
|
# or if the session has an expiry set on it |
62
|
|
|
|
|
|
|
# but don't send it if SEND_COOKIE is set to 0 |
63
|
|
|
|
|
|
|
if (!defined $self->{__CAP__SESSION_CONFIG}->{SEND_COOKIE} || $self->{__CAP__SESSION_CONFIG}->{SEND_COOKIE}) { |
64
|
|
|
|
|
|
|
my $cid = $self->query->cookie(CGI::Session->name); |
65
|
|
|
|
|
|
|
if (!$cid || $cid ne $self->{__CAP__SESSION_OBJ}->id || $self->{__CAP__SESSION_OBJ}->expire()) { |
66
|
|
|
|
|
|
|
session_cookie($self); |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
return $self->{__CAP__SESSION_OBJ}; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub session_config { |
75
|
|
|
|
|
|
|
my $self = shift; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
if (@_) { |
78
|
|
|
|
|
|
|
die "Calling session_config after the session has already been created" if (defined $self->{__CAP__SESSION_OBJ}); |
79
|
|
|
|
|
|
|
my $props; |
80
|
|
|
|
|
|
|
if (ref($_[0]) eq 'HASH') { |
81
|
|
|
|
|
|
|
my $rthash = %{$_[0]}; |
82
|
|
|
|
|
|
|
$props = $self->_cap_hash($_[0]); |
83
|
|
|
|
|
|
|
} else { |
84
|
|
|
|
|
|
|
$props = $self->_cap_hash({ @_ }); |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# Check for CGI_SESSION_OPTIONS |
88
|
|
|
|
|
|
|
if ($props->{CGI_SESSION_OPTIONS}) { |
89
|
|
|
|
|
|
|
die "session_config error: parameter CGI_SESSION_OPTIONS is not an array reference" if ref $props->{CGI_SESSION_OPTIONS} ne 'ARRAY'; |
90
|
|
|
|
|
|
|
$self->{__CAP__SESSION_CONFIG}->{CGI_SESSION_OPTIONS} = delete $props->{CGI_SESSION_OPTIONS}; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
# Check for COOKIE_PARAMS |
94
|
|
|
|
|
|
|
if ($props->{COOKIE_PARAMS}) { |
95
|
|
|
|
|
|
|
die "session_config error: parameter COOKIE_PARAMS is not a hash reference" if ref $props->{COOKIE_PARAMS} ne 'HASH'; |
96
|
|
|
|
|
|
|
$self->{__CAP__SESSION_CONFIG}->{COOKIE_PARAMS} = delete $props->{COOKIE_PARAMS}; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# Check for SEND_COOKIE |
100
|
|
|
|
|
|
|
if (defined $props->{SEND_COOKIE}) { |
101
|
|
|
|
|
|
|
$self->{__CAP__SESSION_CONFIG}->{SEND_COOKIE} = (delete $props->{SEND_COOKIE}) ? 1 : 0; |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# Check for DEFAULT_EXPIRY |
105
|
|
|
|
|
|
|
if (defined $props->{DEFAULT_EXPIRY}) { |
106
|
|
|
|
|
|
|
$self->{__CAP__SESSION_CONFIG}->{DEFAULT_EXPIRY} = delete $props->{DEFAULT_EXPIRY}; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# If there are still entries left in $props then they are invalid |
110
|
|
|
|
|
|
|
die "Invalid option(s) (".join(', ', keys %$props).") passed to session_config" if %$props; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
$self->{__CAP__SESSION_CONFIG}; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
sub session_cookie { |
117
|
|
|
|
|
|
|
my $self = shift; |
118
|
|
|
|
|
|
|
my %options = @_; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# merge in any parameters set by config_session |
121
|
|
|
|
|
|
|
if ($self->{__CAP__SESSION_CONFIG}->{COOKIE_PARAMS}) { |
122
|
|
|
|
|
|
|
%options = (%{ $self->{__CAP__SESSION_CONFIG}->{COOKIE_PARAMS} }, %options); |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
if (!$self->{__CAP__SESSION_OBJ}) { |
126
|
|
|
|
|
|
|
# The session object has not been created yet, so make sure we at least call it once |
127
|
|
|
|
|
|
|
my $tmp = $self->session; |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
$options{'-name'} ||= CGI::Session->name; |
131
|
|
|
|
|
|
|
$options{'-value'} ||= $self->session->id; |
132
|
|
|
|
|
|
|
if(defined($self->session->expires()) && !defined($options{'-expires'})) { |
133
|
|
|
|
|
|
|
$options{'-expires'} = _build_exp_time( $self->session->expires() ); |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
my $cookie = $self->query->cookie(%options); |
136
|
|
|
|
|
|
|
$self->header_add(-cookie => [$cookie]); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub _build_exp_time { |
140
|
|
|
|
|
|
|
my $secs_until_expiry = shift; |
141
|
|
|
|
|
|
|
return unless defined $secs_until_expiry; |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
# Add a plus sign unless the number is negative |
144
|
|
|
|
|
|
|
my $prefix = ($secs_until_expiry >= 0) ? '+' : ''; |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# Add an 's' for "seconds". |
147
|
|
|
|
|
|
|
return $prefix.$secs_until_expiry.'s'; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub session_delete { |
151
|
|
|
|
|
|
|
my $self = shift; |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
if ( my $session = $self->session ) { |
154
|
|
|
|
|
|
|
$session->delete; |
155
|
|
|
|
|
|
|
if ( $self->{'__CAP__SESSION_CONFIG'}->{'SEND_COOKIE'} ) { |
156
|
|
|
|
|
|
|
my %options; |
157
|
|
|
|
|
|
|
if ( $self->{'__CAP__SESSION_CONFIG'}->{'COOKIE_PARAMS'} ) { |
158
|
|
|
|
|
|
|
%options = ( %{ $self->{'__CAP__SESSION_CONFIG'}->{'COOKIE_PARAMS'} }, %options ); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
$options{'name'} ||= CGI::Session->name; |
161
|
|
|
|
|
|
|
$options{'value'} = ''; |
162
|
|
|
|
|
|
|
$options{'-expires'} = '-1d'; |
163
|
|
|
|
|
|
|
my $newcookie = $self->query->cookie(%options); |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# See if a session cookie has already been set (this will happen if |
166
|
|
|
|
|
|
|
# this is a new session). We keep all existing cookies except the |
167
|
|
|
|
|
|
|
# session cookie, which we replace with the timed out session |
168
|
|
|
|
|
|
|
# cookie |
169
|
|
|
|
|
|
|
my @keep; |
170
|
|
|
|
|
|
|
my %headers = $self->header_props; |
171
|
|
|
|
|
|
|
my $cookies = $headers{'-cookie'} || []; |
172
|
|
|
|
|
|
|
$cookies = [$cookies] unless ref $cookies eq 'ARRAY'; |
173
|
|
|
|
|
|
|
foreach my $cookie (@$cookies) { |
174
|
|
|
|
|
|
|
if ( ref($cookie) ne 'CGI::Cookie' || $cookie->name ne CGI::Session->name ) { |
175
|
|
|
|
|
|
|
# keep this cookie |
176
|
|
|
|
|
|
|
push @keep, $cookie; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
push @keep, $newcookie; |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# We have to set the cookies this way, because CGI::Application has |
182
|
|
|
|
|
|
|
# an annoying interface to the headers (why can't we have |
183
|
|
|
|
|
|
|
# 'header_set as well as header_add?). The first call replaces all |
184
|
|
|
|
|
|
|
# cookie headers with the one new cookie header, and the next call |
185
|
|
|
|
|
|
|
# adds in the rest of the cookies if there are any. |
186
|
|
|
|
|
|
|
$self->header_add( -cookie => shift @keep ); |
187
|
|
|
|
|
|
|
$self->header_add( -cookie => \@keep ) if @keep; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
} |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
1; |
193
|
|
|
|
|
|
|
__END__ |