| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Kelp::Request; |
|
2
|
|
|
|
|
|
|
|
|
3
|
21
|
|
|
21
|
|
707
|
use Kelp::Base 'Plack::Request'; |
|
|
21
|
|
|
|
|
63
|
|
|
|
21
|
|
|
|
|
205
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
21
|
|
|
21
|
|
2091
|
use Encode; |
|
|
21
|
|
|
|
|
104
|
|
|
|
21
|
|
|
|
|
1728
|
|
|
6
|
21
|
|
|
21
|
|
142
|
use Carp; |
|
|
21
|
|
|
|
|
91
|
|
|
|
21
|
|
|
|
|
1163
|
|
|
7
|
21
|
|
|
21
|
|
138
|
use Try::Tiny; |
|
|
21
|
|
|
|
|
44
|
|
|
|
21
|
|
|
|
|
19109
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
attr -app => sub { croak "app is required" }; |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# The stash is used to pass values from one route to another |
|
12
|
|
|
|
|
|
|
attr stash => sub { {} }; |
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# The named hash contains the values of the named placeholders |
|
15
|
|
|
|
|
|
|
attr named => sub { {} }; |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# The name of the matched route for this request |
|
18
|
|
|
|
|
|
|
attr route_name => sub { undef }; |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# If you're running the web app as a proxy, use Plack::Middleware::ReverseProxy |
|
21
|
1
|
|
|
1
|
1
|
4
|
sub address { $_[0]->env->{REMOTE_ADDR} } |
|
22
|
0
|
|
|
0
|
1
|
0
|
sub remote_host { $_[0]->env->{REMOTE_HOST} } |
|
23
|
0
|
|
|
0
|
1
|
0
|
sub user { $_[0]->env->{REMOTE_USER} } |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub new { |
|
26
|
202
|
|
|
202
|
1
|
744
|
my ( $class, %args ) = @_; |
|
27
|
202
|
|
|
|
|
958
|
my $self = $class->SUPER::new( delete $args{env} ); |
|
28
|
202
|
|
|
|
|
2403
|
$self->{$_} = $args{$_} for keys %args; |
|
29
|
202
|
|
|
|
|
911
|
return $self; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub is_ajax { |
|
33
|
1
|
|
|
1
|
1
|
3
|
my $self = shift; |
|
34
|
1
|
50
|
|
|
|
8
|
return unless my $with = $self->headers->header('X-Requested-With'); |
|
35
|
1
|
|
|
|
|
247
|
return $with =~ /XMLHttpRequest/i; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub is_json { |
|
39
|
76
|
|
|
76
|
1
|
122
|
my $self = shift; |
|
40
|
76
|
100
|
|
|
|
235
|
return unless $self->content_type; |
|
41
|
43
|
|
|
|
|
331
|
return lc($self->content_type) =~ qr[^application/json]i; |
|
42
|
|
|
|
|
|
|
} |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub param { |
|
46
|
72
|
|
|
72
|
1
|
134
|
my $self = shift; |
|
47
|
72
|
|
100
|
|
|
176
|
my $safe_param = $self->app->config('safe_param') // 0; |
|
48
|
72
|
|
|
|
|
157
|
my $warn_message = |
|
49
|
|
|
|
|
|
|
'Using "param" with argument in list context is deprecated ' . |
|
50
|
|
|
|
|
|
|
'in Kelp version 1.04. See documentation of for details' |
|
51
|
|
|
|
|
|
|
; |
|
52
|
|
|
|
|
|
|
|
|
53
|
72
|
100
|
66
|
|
|
161
|
if ( $self->is_json && $self->app->can('json') ) { |
|
54
|
|
|
|
|
|
|
my $hash = try { |
|
55
|
21
|
|
|
21
|
|
846
|
$self->app->json->decode( $self->content ); |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
catch { |
|
58
|
1
|
|
|
1
|
|
253
|
{}; |
|
59
|
21
|
|
|
|
|
133
|
}; |
|
60
|
21
|
100
|
|
|
|
5070
|
$hash = { ref($hash), $hash } unless ref($hash) eq 'HASH'; |
|
61
|
|
|
|
|
|
|
|
|
62
|
21
|
100
|
|
|
|
122
|
return $hash->{ $_[0] } if @_; |
|
63
|
7
|
100
|
|
|
|
36
|
return $hash if !wantarray; |
|
64
|
4
|
|
|
|
|
34
|
return keys %$hash; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# unsafe method - Plack::Request::param |
|
68
|
51
|
100
|
100
|
|
|
681
|
if (@_ && wantarray && !$safe_param) { |
|
|
|
|
100
|
|
|
|
|
|
69
|
14
|
|
|
|
|
2543
|
carp $warn_message; |
|
70
|
14
|
|
|
|
|
473
|
return $self->SUPER::param(@_); |
|
71
|
|
|
|
|
|
|
} |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# safe method without calling PLack::Request::param |
|
74
|
37
|
100
|
|
|
|
147
|
return $self->parameters->get($_[0]) if @_; |
|
75
|
9
|
|
|
|
|
15
|
return keys %{ $self->parameters }; |
|
|
9
|
|
|
|
|
32
|
|
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub cgi_param { |
|
79
|
0
|
|
|
0
|
1
|
0
|
shift->SUPER::param(@_); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub session { |
|
83
|
10
|
|
|
10
|
1
|
28
|
my $self = shift; |
|
84
|
10
|
|
50
|
|
|
28
|
my $session = $self->env->{'psgix.session'} |
|
85
|
|
|
|
|
|
|
// die "No Session middleware wrapped"; |
|
86
|
|
|
|
|
|
|
|
|
87
|
10
|
100
|
|
|
|
56
|
return $session if !@_; |
|
88
|
|
|
|
|
|
|
|
|
89
|
8
|
100
|
|
|
|
18
|
if ( @_ == 1 ) { |
|
90
|
5
|
|
|
|
|
7
|
my $value = shift; |
|
91
|
5
|
100
|
|
|
|
26
|
return $session->{$value} unless ref $value; |
|
92
|
1
|
|
|
|
|
3
|
return $self->env->{'psgix.session'} = $value; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
|
|
95
|
3
|
|
|
|
|
9
|
my %hash = @_; |
|
96
|
3
|
|
|
|
|
12
|
$session->{$_} = $hash{$_} for keys %hash; |
|
97
|
3
|
|
|
|
|
14
|
return $session; |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1; |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
__END__ |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=pod |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head1 NAME |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
Kelp::Request - Request class for a Kelp application |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
my $request = Kelp::Request( app => $app, env => $env ); |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
This module provides a convenience layer on top of L<Plack::Request>. It extends |
|
117
|
|
|
|
|
|
|
it to add several convenience methods. |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head2 app |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
A reference to the Kelp application. |
|
124
|
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
=head2 stash |
|
126
|
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
Returns a hashref, which represents the stash of the current the request |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
An all use, utility hash to use to pass information between routes. The stash |
|
130
|
|
|
|
|
|
|
is a concept originally conceived by the developers of L<Catalyst>. It's a hash |
|
131
|
|
|
|
|
|
|
that you can use to pass data from one route to another. |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# put value into stash |
|
134
|
|
|
|
|
|
|
$self->req->stash->{username} = app->authenticate(); |
|
135
|
|
|
|
|
|
|
# more convenient way |
|
136
|
|
|
|
|
|
|
$self->stash->{username} = app->authenticate(); |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# get value from stash |
|
139
|
|
|
|
|
|
|
return "Hello " . $self->req->stash->{username}; |
|
140
|
|
|
|
|
|
|
# more convenient way |
|
141
|
|
|
|
|
|
|
return "Hello " . $self->stash('username'); |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head2 named |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
This hash is initialized with the named placeholders of the path that the |
|
146
|
|
|
|
|
|
|
current route is processing. |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
=head2 route_name |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
Contains a string name of the route matched for this request. Contains route pattern |
|
151
|
|
|
|
|
|
|
if the route was not named. |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=head2 param |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
I<B<Change of behavior> in version 1.04, see below for details> |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Returns the HTTP parameters of the request. This method delegates all the work |
|
158
|
|
|
|
|
|
|
to L<Plack::Request/param>, except when the content type of the request is |
|
159
|
|
|
|
|
|
|
C<application/json> and a JSON module is loaded. In that case, it will decode |
|
160
|
|
|
|
|
|
|
the JSON body and return as follows: |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=over |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=item |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
If no arguments are passed, then it will return the names of the HTTP parameters |
|
167
|
|
|
|
|
|
|
when called in array contest, and a reference to the entire JSON hash when |
|
168
|
|
|
|
|
|
|
called in scalar context. |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# JSON body = { bar => 1, foo => 2 } |
|
171
|
|
|
|
|
|
|
my @names = $self->param; # @names = ('bar', 'foo') |
|
172
|
|
|
|
|
|
|
my $json = $self->param; # $json = { bar => 1, foo => 2 } |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=item |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
If a single argument is passed, then the corresponding value in the JSON |
|
178
|
|
|
|
|
|
|
document is returned. |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
my $bar = $self->param('bar'); # $bar = 1 |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=item |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
If the root contents of the JSON document is not an C<HASH> (after decoding), then it will be wrapped into a hash with its reftype as a key, for example: |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
{ ARRAY => [...] } # when JSON contains an array as root element |
|
187
|
|
|
|
|
|
|
{ '' => [...] } # when JSON contains something that's not a reference |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
my $array = $kelp->param('ARRAY'); |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=back |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
Since version I<1.04>, a new application configuration field C<safe_param> is |
|
194
|
|
|
|
|
|
|
introduced that B<changes the behavior> of this method: |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
=over |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=item |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
Without C<safe_param>, method will produce a warning if used in list context |
|
201
|
|
|
|
|
|
|
while passing the first argument, but will continue to work the same. This is |
|
202
|
|
|
|
|
|
|
done to combat a very nasty and easy to make bug: |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
$kelp->some_function( |
|
205
|
|
|
|
|
|
|
param1 => $value, |
|
206
|
|
|
|
|
|
|
param2 => $kelp->param('key'), # BUG, list context |
|
207
|
|
|
|
|
|
|
); |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Since HTTP requests can accept multiple values for the same key, someone could |
|
210
|
|
|
|
|
|
|
inject additional parameters to the function with the simple query, due to |
|
211
|
|
|
|
|
|
|
array flattening: |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
?key=something&key=additional_hash_key&key=additional_hash_value |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=item |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
With C<safe_param>, a call to C<param> with an argument (a key to fetch from |
|
218
|
|
|
|
|
|
|
the parameters) will no longer return a list but always a scalar value |
|
219
|
|
|
|
|
|
|
regardless of context, even if there are more than one entries of that name |
|
220
|
|
|
|
|
|
|
(will then return the last one). This makes usages like the one above perfectly |
|
221
|
|
|
|
|
|
|
safe. |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
my @array = $kelp->param('name'); # changed, will never return more than one scalar |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Since this method has so many ways to use it, you're still B<encouraged> to use |
|
228
|
|
|
|
|
|
|
other, more specific methods from L<Plack::Request>. |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=back |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
You are B<strongly advised> to introduce C<safe_param> into your configuration as |
|
233
|
|
|
|
|
|
|
quickly as possible. Currently, a value of C<0> is the default, meaning that |
|
234
|
|
|
|
|
|
|
param will work the same as it did, but produce warnings. In no less than half |
|
235
|
|
|
|
|
|
|
a year from version 1.04 the old behavior of C<param> will be removed |
|
236
|
|
|
|
|
|
|
altogether, and C<safe_param> configuration will no longer cause any change in |
|
237
|
|
|
|
|
|
|
behavior, allowing for its safe removal. Use L</cgi_param> if you'd like to |
|
238
|
|
|
|
|
|
|
retain the old behavior regardless of security risks. |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=head2 cgi_param |
|
241
|
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
Calls C<param> in L<Plack::Request>, which is CGI.pm compatible. It is B<not |
|
243
|
|
|
|
|
|
|
recommended> to use this method, unless for some reason you have to maintain |
|
244
|
|
|
|
|
|
|
CGI.pm compatibility. Misusing this method can lead to bugs and security |
|
245
|
|
|
|
|
|
|
vulnerabilities. |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
=head2 address, remote_host, user |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
These are shortcuts to the REMOTE_ADDR, REMOTE_HOST and REMOTE_USER environment |
|
250
|
|
|
|
|
|
|
variables. |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
if ( $self->req->address eq '127.0.0.1' ) { |
|
253
|
|
|
|
|
|
|
... |
|
254
|
|
|
|
|
|
|
} |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
Note: See L<Kelp::Cookbook/Deploying> for configuration required for these |
|
257
|
|
|
|
|
|
|
fields when using a proxy. |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=head2 session |
|
260
|
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
Returns the Plack session hash or dies if no C<Session> middleware was included. |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub get_session_value { |
|
264
|
|
|
|
|
|
|
my $self = shift; |
|
265
|
|
|
|
|
|
|
$self->session->{user} = 45; |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
If called with a single argument, returns that value from the session hash: |
|
269
|
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub set_session_value { |
|
271
|
|
|
|
|
|
|
my $self = shift; |
|
272
|
|
|
|
|
|
|
my $user = $self->req->session('user'); |
|
273
|
|
|
|
|
|
|
# Same as $self->req->session->{'user'}; |
|
274
|
|
|
|
|
|
|
} |
|
275
|
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
Set values in the session using key-value pairs: |
|
277
|
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
sub set_session_hash { |
|
279
|
|
|
|
|
|
|
my $self = shift; |
|
280
|
|
|
|
|
|
|
$self->req->session( |
|
281
|
|
|
|
|
|
|
name => 'Jill Andrews', |
|
282
|
|
|
|
|
|
|
age => 24, |
|
283
|
|
|
|
|
|
|
email => 'jill@perlkelp.com' |
|
284
|
|
|
|
|
|
|
); |
|
285
|
|
|
|
|
|
|
} |
|
286
|
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Set values using a Hashref: |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub set_session_hashref { |
|
290
|
|
|
|
|
|
|
my $self = shift; |
|
291
|
|
|
|
|
|
|
$self->req->session( { bar => 'foo' } ); |
|
292
|
|
|
|
|
|
|
} |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
Clear the session: |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
sub clear_session { |
|
297
|
|
|
|
|
|
|
my $self = shift; |
|
298
|
|
|
|
|
|
|
$self->req->session( {} ); |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head3 Common tasks with sessions |
|
302
|
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=over |
|
304
|
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=item Initialize file sessions |
|
306
|
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
In your config file: |
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
middleware => ['Session'], |
|
310
|
|
|
|
|
|
|
middleware_init => { |
|
311
|
|
|
|
|
|
|
Session => { |
|
312
|
|
|
|
|
|
|
store => 'File' |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=item Delete session value |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
delete $self->req->session->{'useless'}; |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=item Remove all session values |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
$self->req->session( {} ); |
|
323
|
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=back |
|
325
|
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=head2 is_ajax |
|
327
|
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
Returns true if the request was called with C<XMLHttpRequest>. |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=head2 is_json |
|
331
|
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
Returns true if the request's content type was C<application/json>. |
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
=cut |
|
335
|
|
|
|
|
|
|
|