line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Test::Override::UserAgent; |
2
|
|
|
|
|
|
|
|
3
|
18
|
|
|
18
|
|
1530990
|
use 5.008001; |
|
18
|
|
|
|
|
79
|
|
|
18
|
|
|
|
|
785
|
|
4
|
18
|
|
|
18
|
|
115
|
use strict; |
|
18
|
|
|
|
|
41
|
|
|
18
|
|
|
|
|
666
|
|
5
|
18
|
|
|
18
|
|
148
|
use warnings 'all'; |
|
18
|
|
|
|
|
44
|
|
|
18
|
|
|
|
|
1505
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
########################################################################### |
8
|
|
|
|
|
|
|
# METADATA |
9
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:DOUGDUDE'; |
10
|
|
|
|
|
|
|
our $VERSION = '0.004001'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
########################################################################### |
13
|
|
|
|
|
|
|
# MODULE IMPORTS |
14
|
18
|
|
|
18
|
|
107
|
use Carp qw(croak); |
|
18
|
|
|
|
|
63
|
|
|
18
|
|
|
|
|
1352
|
|
15
|
18
|
|
|
18
|
|
19567
|
use Clone; |
|
18
|
|
|
|
|
60928
|
|
|
18
|
|
|
|
|
1067
|
|
16
|
18
|
|
|
18
|
|
16130
|
use HTTP::Config 5.815; |
|
18
|
|
|
|
|
72784
|
|
|
18
|
|
|
|
|
544
|
|
17
|
18
|
|
|
18
|
|
3349
|
use HTTP::Date (); |
|
18
|
|
|
|
|
14408
|
|
|
18
|
|
|
|
|
386
|
|
18
|
18
|
|
|
18
|
|
2309
|
use HTTP::Headers; |
|
18
|
|
|
|
|
19043
|
|
|
18
|
|
|
|
|
534
|
|
19
|
18
|
|
|
18
|
|
1958
|
use HTTP::Response; |
|
18
|
|
|
|
|
695529
|
|
|
18
|
|
|
|
|
634
|
|
20
|
18
|
|
|
18
|
|
297
|
use HTTP::Status 5.817 (); |
|
18
|
|
|
|
|
565
|
|
|
18
|
|
|
|
|
378
|
|
21
|
18
|
|
|
18
|
|
18021
|
use LWP::UserAgent; # Not actually required here, but want it to be loaded |
|
18
|
|
|
|
|
75573
|
|
|
18
|
|
|
|
|
512
|
|
22
|
18
|
|
|
18
|
|
141
|
use Scalar::Util; |
|
18
|
|
|
|
|
34
|
|
|
18
|
|
|
|
|
1408
|
|
23
|
18
|
|
|
18
|
|
17825
|
use Sub::Install 0.90; |
|
18
|
|
|
|
|
33051
|
|
|
18
|
|
|
|
|
132
|
|
24
|
18
|
|
|
18
|
|
13763
|
use Test::Override::UserAgent::Scope; |
|
18
|
|
|
|
|
68
|
|
|
18
|
|
|
|
|
709
|
|
25
|
18
|
|
|
18
|
|
201
|
use Try::Tiny; |
|
18
|
|
|
|
|
35
|
|
|
18
|
|
|
|
|
1232
|
|
26
|
18
|
|
|
18
|
|
110
|
use URI; |
|
18
|
|
|
|
|
37
|
|
|
18
|
|
|
|
|
694
|
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
########################################################################### |
29
|
|
|
|
|
|
|
# ALL IMPORTS BEFORE THIS WILL BE ERASED |
30
|
18
|
|
|
18
|
|
110
|
use namespace::clean 0.04 -except => [qw(meta)]; |
|
18
|
|
|
|
|
330
|
|
|
18
|
|
|
|
|
156
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
########################################################################### |
33
|
|
|
|
|
|
|
# METHODS |
34
|
|
|
|
|
|
|
sub allow_live_requests { |
35
|
26
|
|
|
26
|
1
|
6481
|
my ($self, $new_value) = @_; |
36
|
|
|
|
|
|
|
|
37
|
26
|
100
|
|
|
|
103
|
if (defined $new_value) { |
38
|
|
|
|
|
|
|
# Set the new value |
39
|
6
|
|
|
|
|
16
|
$self->{allow_live_requests} = $new_value; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
|
42
|
26
|
|
|
|
|
128
|
return $self->{allow_live_requests}; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
sub handle_request { |
45
|
60
|
|
|
60
|
1
|
11299
|
my ($self, $request, %args) = @_; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
# Lookup the handler for the request |
48
|
60
|
|
|
|
|
234
|
my $handler = $self->_get_handler_for($request); |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
# Hold the response |
51
|
60
|
|
|
|
|
119
|
my $response; |
52
|
|
|
|
|
|
|
|
53
|
60
|
100
|
|
|
|
233
|
if (defined $handler) { |
54
|
|
|
|
|
|
|
# Get the response |
55
|
44
|
|
|
|
|
197
|
$response = _convert_psgi_response($handler->($request)); |
56
|
|
|
|
|
|
|
|
57
|
44
|
100
|
|
|
|
262
|
if (!defined $response->request) { |
58
|
|
|
|
|
|
|
# Set the request that made this response |
59
|
43
|
|
|
|
|
667
|
$response->request($request); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
60
|
100
|
100
|
|
|
846
|
if (!defined $response && exists $args{live_request_handler}) { |
64
|
|
|
|
|
|
|
# There was no handler/response and a live requestor was provided |
65
|
15
|
100
|
|
|
|
139
|
if ($self->allow_live_requests) { |
66
|
|
|
|
|
|
|
# Make the live request |
67
|
2
|
|
|
|
|
10
|
$response = $args{live_request_handler}->($request); |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
else { |
70
|
|
|
|
|
|
|
# Make an internal response for not successful since no |
71
|
|
|
|
|
|
|
# live requests are allowed. |
72
|
13
|
|
|
|
|
143
|
$response = _new_internal_response( |
73
|
|
|
|
|
|
|
HTTP::Status::HTTP_NOT_FOUND, |
74
|
|
|
|
|
|
|
'Not Found (No Live Requests)', |
75
|
|
|
|
|
|
|
); |
76
|
|
|
|
|
|
|
} |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
60
|
|
|
|
|
267
|
return $response; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
sub install_in_scope { |
82
|
2
|
|
|
2
|
1
|
5731
|
my ($self) = @_; |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# Return the scope variable |
85
|
2
|
|
|
|
|
33
|
return Test::Override::UserAgent::Scope->new( |
86
|
|
|
|
|
|
|
override => $self, |
87
|
|
|
|
|
|
|
); |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
sub install_in_user_agent { |
90
|
15
|
|
|
15
|
1
|
70419
|
my ($self, $user_agent, %args) = @_; |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Get the clone argument |
93
|
15
|
100
|
|
|
|
79
|
my $clone = exists $args{clone} ? $args{clone} : 0; |
94
|
|
|
|
|
|
|
|
95
|
15
|
100
|
|
|
|
78
|
if ($clone) { |
96
|
|
|
|
|
|
|
# Make a clone of the user agent |
97
|
1
|
|
|
|
|
7
|
$user_agent = $user_agent->clone; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
# Add as a handler in the user agent |
101
|
|
|
|
|
|
|
$user_agent->add_handler( |
102
|
|
|
|
|
|
|
request_send => sub { |
103
|
|
|
|
|
|
|
# Get the response |
104
|
|
|
|
|
|
|
my $response = $self->handle_request( |
105
|
|
|
|
|
|
|
shift, |
106
|
1
|
|
|
|
|
3
|
live_request_handler => sub { return; }, |
107
|
51
|
|
|
51
|
|
2704834
|
); |
108
|
|
|
|
|
|
|
|
109
|
51
|
|
|
|
|
251
|
return $response; |
110
|
|
|
|
|
|
|
}, |
111
|
15
|
|
|
|
|
500
|
owner => Scalar::Util::refaddr($self), |
112
|
|
|
|
|
|
|
); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Return the user agent |
115
|
15
|
|
|
|
|
830
|
return $user_agent; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
sub override_request { |
118
|
45
|
|
|
45
|
1
|
3867
|
my ($self, @args) = @_; |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
# Get the handler from the end |
121
|
45
|
|
|
|
|
78
|
my $handler = pop @args; |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Convert the arguments into a hash |
124
|
45
|
|
|
|
|
141
|
my %args = @args; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Register the handler |
127
|
45
|
|
|
|
|
166
|
$self->_register_handler($handler, %args); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# Enable chaining |
130
|
45
|
|
|
|
|
187
|
return $self; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
sub uninstall_from_user_agent { |
133
|
2
|
|
|
2
|
1
|
54200
|
my ($self, $user_agent) = @_; |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Remove our handlers from the user agent |
136
|
2
|
|
|
|
|
27
|
$user_agent->remove_handler( |
137
|
|
|
|
|
|
|
'request_send', |
138
|
|
|
|
|
|
|
owner => Scalar::Util::refaddr($self), |
139
|
|
|
|
|
|
|
); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# Return the user agent for some reason |
142
|
2
|
|
|
|
|
430
|
return $user_agent; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
########################################################################### |
146
|
|
|
|
|
|
|
# STATIC METHODS |
147
|
|
|
|
|
|
|
sub import { |
148
|
19
|
|
|
19
|
|
1620
|
my ($class, %args) = @_; |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# What this module is being used for |
151
|
19
|
|
100
|
|
|
133
|
my $use_for = $args{for} || 'testing'; |
152
|
|
|
|
|
|
|
|
153
|
19
|
100
|
|
|
|
83
|
if ($use_for eq 'configuration') { |
154
|
|
|
|
|
|
|
# Get the calling package |
155
|
4
|
|
|
|
|
12
|
my $caller = caller; |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# Create a new configuration object that will be wrapped in |
158
|
|
|
|
|
|
|
# closures. |
159
|
4
|
|
|
|
|
36
|
my $conf = $class->new; |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Create a defaults hash for colsures |
162
|
4
|
|
|
|
|
9
|
my $defaults = {}; |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
# Install override_request |
165
|
|
|
|
|
|
|
Sub::Install::install_sub({ |
166
|
12
|
|
|
12
|
|
62
|
code => sub { return $conf->override_request(%{$defaults}, @_); }, |
|
12
|
|
|
|
|
41
|
|
167
|
4
|
|
|
|
|
40
|
into => $caller, |
168
|
|
|
|
|
|
|
as => 'override_request', |
169
|
|
|
|
|
|
|
}); |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# Install override_for |
172
|
|
|
|
|
|
|
Sub::Install::install_sub({ |
173
|
|
|
|
|
|
|
code => sub { |
174
|
3
|
|
|
3
|
|
19
|
my $block = pop; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
# Rember the current defaults |
177
|
3
|
|
|
|
|
5
|
my $previous_defaults = $defaults; |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# Set the new defaults as an extension of the current |
180
|
3
|
|
|
|
|
4
|
$defaults = {%{Clone::clone($defaults)}, @_}; |
|
3
|
|
|
|
|
35
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# Run the block with the defaults in effect |
183
|
3
|
|
|
|
|
11
|
$block->(); |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# Restore the defaults |
186
|
3
|
|
|
|
|
8
|
$defaults = $previous_defaults; |
187
|
|
|
|
|
|
|
}, |
188
|
4
|
|
|
|
|
305
|
into => $caller, |
189
|
|
|
|
|
|
|
as => 'override_for', |
190
|
|
|
|
|
|
|
}); |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# Install allow_live |
193
|
|
|
|
|
|
|
Sub::Install::install_sub({ |
194
|
|
|
|
|
|
|
code => sub { |
195
|
4
|
|
|
4
|
|
17
|
my $allow = shift; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# Set the allow live requests (no arguments defaults to 1) |
198
|
4
|
100
|
|
|
|
21
|
$conf->allow_live_requests(defined $allow ? $allow : 1); |
199
|
|
|
|
|
|
|
}, |
200
|
4
|
|
|
|
|
208
|
into => $caller, |
201
|
|
|
|
|
|
|
as => 'allow_live', |
202
|
|
|
|
|
|
|
}); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
# Install custom configuration which retuns the config object |
205
|
|
|
|
|
|
|
Sub::Install::install_sub({ |
206
|
5
|
|
|
5
|
|
2361
|
code => sub { return $conf; }, |
207
|
4
|
|
|
|
|
218
|
into => $caller, |
208
|
|
|
|
|
|
|
as => 'configuration', |
209
|
|
|
|
|
|
|
}); |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
19
|
|
|
|
|
35073
|
return; |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
########################################################################### |
216
|
|
|
|
|
|
|
# CONSTRUCTOR |
217
|
|
|
|
|
|
|
sub new { |
218
|
20
|
|
|
20
|
1
|
1844
|
my ($class, @args) = @_; |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# Get the arguments as a plain hash |
221
|
20
|
100
|
|
|
|
126
|
my %args = @args == 1 ? %{shift @args} |
|
1
|
|
|
|
|
4
|
|
222
|
|
|
|
|
|
|
: @args |
223
|
|
|
|
|
|
|
; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# Create a hash with configuration information |
226
|
20
|
|
|
|
|
274
|
my %data = ( |
227
|
|
|
|
|
|
|
# Attributes |
228
|
|
|
|
|
|
|
allow_live_requests => 0, |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Private attributes |
231
|
|
|
|
|
|
|
_lookup_table => HTTP::Config->new, |
232
|
|
|
|
|
|
|
_protocol_classes => {}, |
233
|
|
|
|
|
|
|
); |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# Set attributes |
236
|
20
|
|
|
|
|
311
|
foreach my $arg (grep { m{\A [^_]}msx } keys %data) { |
|
60
|
|
|
|
|
255
|
|
237
|
20
|
100
|
|
|
|
189
|
if (exists $args{$arg}) { |
238
|
2
|
|
|
|
|
7
|
$data{$arg} = $args{$arg}; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
# Bless the hash to this class |
243
|
20
|
|
|
|
|
88
|
my $self = bless \%data, $class; |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
# Set our unique name |
246
|
20
|
|
|
|
|
253
|
$self->{_uniq_name} = $class . '::Number' . Scalar::Util::refaddr($self); |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
# Return our blessed configuration |
249
|
20
|
|
|
|
|
148
|
return $self; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
########################################################################### |
253
|
|
|
|
|
|
|
# PRIVATE METHODS |
254
|
|
|
|
|
|
|
sub _get_handler_for { |
255
|
60
|
|
|
60
|
|
150
|
my ($self, $request) = @_; |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
# Get the handler |
258
|
60
|
|
|
|
|
354
|
my @handlers = $self->{_lookup_table}->matching_items($request); |
259
|
|
|
|
|
|
|
|
260
|
60
|
|
|
|
|
19475
|
return $handlers[0]; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
sub _register_handler { |
263
|
45
|
|
|
45
|
|
122
|
my ($self, $handler, %args) = @_; |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
# Add m_ to the beginning of the arguments |
266
|
45
|
|
|
|
|
122
|
for my $key (keys %args) { |
267
|
|
|
|
|
|
|
# Specially handle "url" key as HTTP::Config does not |
268
|
76
|
100
|
100
|
|
|
781
|
if ($key eq 'url' || $key eq 'uri') { |
|
|
50
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# Get the URI from the arguments |
270
|
3
|
|
|
|
|
21
|
my $uri = URI->new(delete $args{$key}); |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# Set a match against it's canonical value |
273
|
3
|
|
|
|
|
12184
|
$args{m_uri__canonical} = $uri->canonical; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
elsif (q{m_} ne substr $key, 0, 2) { |
276
|
|
|
|
|
|
|
# Add m_ |
277
|
73
|
|
|
|
|
351
|
$args{"m_$key"} = delete $args{$key}; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# Set the handler |
282
|
45
|
|
|
|
|
1094
|
$self->{_lookup_table}->add_item($handler, %args); |
283
|
|
|
|
|
|
|
|
284
|
45
|
|
|
|
|
645
|
return; |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
########################################################################### |
288
|
|
|
|
|
|
|
# PRIVATE FUNCTIONS |
289
|
|
|
|
|
|
|
sub _convert_psgi_response { |
290
|
44
|
|
|
44
|
|
528
|
my ($response) = @_; |
291
|
|
|
|
|
|
|
|
292
|
44
|
100
|
|
|
|
255
|
if (!defined Scalar::Util::blessed($response)) { |
293
|
|
|
|
|
|
|
# Get the type of the response |
294
|
43
|
|
|
|
|
178
|
my $response_type = Scalar::Util::reftype($response); |
295
|
|
|
|
|
|
|
|
296
|
43
|
100
|
100
|
|
|
409
|
if (defined $response_type && $response_type eq 'ARRAY') { |
297
|
|
|
|
|
|
|
# This is a PSGI-formatted response |
298
|
|
|
|
|
|
|
try { |
299
|
|
|
|
|
|
|
# Validate the response |
300
|
41
|
|
|
41
|
|
1732
|
_validate_psgi_response($response); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Unwrap the PSGI response |
303
|
32
|
|
|
|
|
49
|
my ($status_code, $headers, $body) = @{$response}; |
|
32
|
|
|
|
|
81
|
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
# Change the headers to a header object |
306
|
32
|
|
|
|
|
61
|
$headers = HTTP::Headers->new(@{$headers}); |
|
32
|
|
|
|
|
225
|
|
307
|
|
|
|
|
|
|
|
308
|
32
|
100
|
|
|
|
2873
|
if (ref $body ne 'ARRAY') { |
309
|
|
|
|
|
|
|
# The body is a filehandle |
310
|
1
|
|
|
|
|
2
|
my $fh = $body; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
# Change the body to an array reference |
313
|
1
|
|
|
|
|
4
|
$body = []; |
314
|
|
|
|
|
|
|
|
315
|
1
|
|
|
|
|
8
|
while (defined(my $line = $fh->getline)) { |
316
|
|
|
|
|
|
|
# Push the line into the body |
317
|
2
|
|
|
|
|
52
|
push @{$body}, $line; |
|
2
|
|
|
|
|
10
|
|
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# Close the file |
321
|
1
|
|
|
|
|
14
|
$fh->close; |
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# Create the response object |
325
|
32
|
|
|
|
|
257
|
$response = HTTP::Response->new( |
326
|
32
|
|
|
|
|
91
|
$status_code, undef, $headers, join q{}, @{$body}); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
catch { |
329
|
|
|
|
|
|
|
# Invalid PSGI response |
330
|
9
|
|
|
9
|
|
587
|
my $error = "$_"; # stringify error |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
# Remove line information from croak |
333
|
9
|
|
|
|
|
59
|
$error =~ s{\s at \s .+ \z}{}msx; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# Set the response |
336
|
9
|
|
|
|
|
32
|
$response = _new_internal_response( |
337
|
|
|
|
|
|
|
HTTP::Status::HTTP_EXPECTATION_FAILED, |
338
|
|
|
|
|
|
|
$error, |
339
|
|
|
|
|
|
|
); |
340
|
41
|
|
|
|
|
531
|
}; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
else { |
343
|
|
|
|
|
|
|
# Bad return value from handler |
344
|
2
|
|
|
|
|
12
|
$response = _new_internal_response( |
345
|
|
|
|
|
|
|
HTTP::Status::HTTP_EXPECTATION_FAILED, |
346
|
|
|
|
|
|
|
'Override handler returned invalid value: ' . $response |
347
|
|
|
|
|
|
|
); |
348
|
|
|
|
|
|
|
} |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
44
|
|
|
|
|
6986
|
return $response; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
sub _is_invalid_psgi_header_key { |
354
|
59
|
|
|
59
|
|
94
|
my ($key) = @_; |
355
|
|
|
|
|
|
|
|
356
|
59
|
|
100
|
|
|
890
|
return $key =~ m{(?:\A status \z | [:\n] | [_-] \z)}imsx |
357
|
|
|
|
|
|
|
|| $key !~ m{\A [a-z] [a-z0-9_-]* \z}imsx; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
sub _is_invalid_psgi_header_value { |
360
|
59
|
|
|
59
|
|
106
|
my ($value) = @_; |
361
|
|
|
|
|
|
|
|
362
|
59
|
|
100
|
|
|
3223
|
return ref $value ne q{} || $value =~ m{[\x00-\x19\x21-\x25]}imsx; |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
sub _new_internal_response { |
365
|
24
|
|
|
24
|
|
54
|
my ($code, $message) = @_; |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
# Make a new response |
368
|
24
|
|
|
|
|
212
|
my $response = HTTP::Response->new($code, $message); |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# Set some headers for client information |
371
|
24
|
|
|
|
|
1326
|
$response->header( |
372
|
|
|
|
|
|
|
'Client-Date' => HTTP::Date::time2str(time), |
373
|
|
|
|
|
|
|
'Client-Response-Source' => __PACKAGE__, |
374
|
|
|
|
|
|
|
'Client-Warning' => 'Internal response', |
375
|
|
|
|
|
|
|
'Content-Type' => 'text/plain', |
376
|
|
|
|
|
|
|
); |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# Set the content as the status_line |
379
|
24
|
|
|
|
|
5130
|
$response->content("$code $message"); |
380
|
|
|
|
|
|
|
|
381
|
24
|
|
|
|
|
587
|
return $response; |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
sub _validate_psgi_response { |
384
|
41
|
|
|
41
|
|
87
|
my ($psgi) = @_; |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# Unwrap the response |
387
|
41
|
|
|
|
|
78
|
my ($code, $headers, $body) = @{$psgi}; |
|
41
|
|
|
|
|
103
|
|
388
|
|
|
|
|
|
|
|
389
|
41
|
100
|
|
|
|
261
|
if ($code !~ m{\A [1-9] \d{2,} \z}msx) { |
390
|
1
|
|
|
|
|
193
|
croak 'PSGI HTTP status code MUST be 100 or greater'; |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
|
393
|
40
|
100
|
|
|
|
164
|
if (ref $headers ne 'ARRAY') { |
394
|
1
|
|
|
|
|
167
|
croak 'PSGI headers MUST be an array reference'; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
39
|
100
|
|
|
|
83
|
if (@{$headers} % 2 != 0) { |
|
39
|
|
|
|
|
180
|
|
398
|
1
|
|
|
|
|
162
|
croak 'PSGI headers MUST have even number of elements'; |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
# Headers copied |
402
|
38
|
|
|
|
|
75
|
my @headers = @{$headers}; |
|
38
|
|
|
|
|
118
|
|
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# Hold invalid stuff |
405
|
38
|
|
|
|
|
702
|
my (@invalid_header_keys, @invalid_header_values, |
406
|
|
|
|
|
|
|
$has_content_type, $has_content_length); |
407
|
|
|
|
|
|
|
|
408
|
38
|
|
|
|
|
195
|
while (my ($key, $value) = splice @headers, 0, 2) { |
409
|
59
|
100
|
|
|
|
179
|
if (_is_invalid_psgi_header_key($key)) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
410
|
|
|
|
|
|
|
# Remember the invalid key |
411
|
3
|
|
|
|
|
8
|
push @invalid_header_keys, $key; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
elsif (lc $key eq 'content-type') { |
414
|
|
|
|
|
|
|
# The response has a defined content type |
415
|
32
|
|
|
|
|
68
|
$has_content_type = 1; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
elsif (lc $key eq 'content-length') { |
418
|
|
|
|
|
|
|
# The response has a defined content length |
419
|
2
|
|
|
|
|
4
|
$has_content_length = 1; |
420
|
|
|
|
|
|
|
} |
421
|
|
|
|
|
|
|
|
422
|
59
|
100
|
|
|
|
227
|
if (_is_invalid_psgi_header_value($value)) { |
423
|
|
|
|
|
|
|
# Remember the key of the invalid value |
424
|
2
|
|
|
|
|
10
|
push @invalid_header_values, $key; |
425
|
|
|
|
|
|
|
} |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
38
|
100
|
|
|
|
198
|
if (@invalid_header_keys) { |
429
|
1
|
|
|
|
|
174
|
croak 'PSGI headers have invalid key(s): ', |
430
|
|
|
|
|
|
|
join q{, }, sort @invalid_header_keys; |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
|
433
|
37
|
100
|
|
|
|
188
|
if (@invalid_header_values) { |
434
|
1
|
|
|
|
|
164
|
croak 'PSGI headers have invalid value(s): ', |
435
|
|
|
|
|
|
|
join q{, }, sort @invalid_header_values; |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
36
|
100
|
66
|
|
|
171
|
if (!$has_content_type && $code !~ m{\A 1 | [23]04}msx) { |
439
|
3
|
|
|
|
|
513
|
croak 'There MUST be a Content-Type for code other than 1xx, 204, and 304'; |
440
|
|
|
|
|
|
|
} |
441
|
|
|
|
|
|
|
|
442
|
33
|
100
|
100
|
|
|
171
|
if ($has_content_length && $code =~ m{\A 1 | [23]04}msx) { |
443
|
1
|
|
|
|
|
163
|
croak 'There MUST NOT be a Content-Length for 1xx, 204, and 304'; |
444
|
|
|
|
|
|
|
} |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
# Return true for successful check |
447
|
32
|
|
|
|
|
96
|
return 1; |
448
|
|
|
|
|
|
|
} |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
1; |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
__END__ |