| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package HTTP::Message::PSGI; |
|
2
|
70
|
|
|
70
|
|
600269
|
use strict; |
|
|
70
|
|
|
|
|
331
|
|
|
|
70
|
|
|
|
|
2258
|
|
|
3
|
70
|
|
|
70
|
|
526
|
use warnings; |
|
|
70
|
|
|
|
|
154
|
|
|
|
70
|
|
|
|
|
2117
|
|
|
4
|
70
|
|
|
70
|
|
3777
|
use parent qw(Exporter); |
|
|
70
|
|
|
|
|
2304
|
|
|
|
70
|
|
|
|
|
446
|
|
|
5
|
|
|
|
|
|
|
our @EXPORT = qw( req_to_psgi res_from_psgi ); |
|
6
|
|
|
|
|
|
|
|
|
7
|
70
|
|
|
70
|
|
5375
|
use Carp (); |
|
|
70
|
|
|
|
|
200
|
|
|
|
70
|
|
|
|
|
1684
|
|
|
8
|
70
|
|
|
70
|
|
5264
|
use HTTP::Status qw(status_message); |
|
|
70
|
|
|
|
|
50075
|
|
|
|
70
|
|
|
|
|
10046
|
|
|
9
|
70
|
|
|
70
|
|
4103
|
use URI::Escape (); |
|
|
70
|
|
|
|
|
10776
|
|
|
|
70
|
|
|
|
|
1760
|
|
|
10
|
70
|
|
|
70
|
|
10589
|
use Plack::Util; |
|
|
70
|
|
|
|
|
205
|
|
|
|
70
|
|
|
|
|
2237
|
|
|
11
|
70
|
|
|
70
|
|
32187
|
use Try::Tiny; |
|
|
70
|
|
|
|
|
123594
|
|
|
|
70
|
|
|
|
|
97433
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my $TRUE = (1 == 1); |
|
14
|
|
|
|
|
|
|
my $FALSE = !$TRUE; |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub req_to_psgi { |
|
17
|
346
|
|
|
346
|
1
|
73566
|
my $req = shift; |
|
18
|
|
|
|
|
|
|
|
|
19
|
346
|
50
|
|
346
|
|
1975
|
unless (try { $req->isa('HTTP::Request') }) { |
|
|
346
|
|
|
|
|
10796
|
|
|
20
|
0
|
|
|
|
|
0
|
Carp::croak("Request is not HTTP::Request: $req"); |
|
21
|
|
|
|
|
|
|
} |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# from HTTP::Request::AsCGI |
|
24
|
346
|
|
|
|
|
5708
|
my $host = $req->header('Host'); |
|
25
|
346
|
|
|
|
|
19335
|
my $uri = $req->uri->clone; |
|
26
|
346
|
100
|
|
|
|
5780
|
$uri->scheme('http') unless $uri->scheme; |
|
27
|
346
|
100
|
|
|
|
10928
|
$uri->host('localhost') unless $uri->host; |
|
28
|
346
|
50
|
|
|
|
10929
|
$uri->port(80) unless $uri->port; |
|
29
|
346
|
100
|
66
|
|
|
8894
|
$uri->host_port($host) unless !$host || ( $host eq $uri->host_port ); |
|
30
|
|
|
|
|
|
|
|
|
31
|
346
|
|
|
|
|
912
|
my $input; |
|
32
|
346
|
|
|
|
|
1155
|
my $content = $req->content; |
|
33
|
346
|
50
|
|
|
|
4550
|
if (ref $content eq 'CODE') { |
|
34
|
0
|
0
|
|
|
|
0
|
if (defined $req->content_length) { |
|
35
|
0
|
|
|
|
|
0
|
$input = HTTP::Message::PSGI::ChunkedInput->new($content); |
|
36
|
|
|
|
|
|
|
} else { |
|
37
|
0
|
|
|
|
|
0
|
$req->header("Transfer-Encoding" => "chunked"); |
|
38
|
0
|
|
|
|
|
0
|
$input = HTTP::Message::PSGI::ChunkedInput->new($content, 1); |
|
39
|
|
|
|
|
|
|
} |
|
40
|
|
|
|
|
|
|
} else { |
|
41
|
66
|
|
|
66
|
|
470
|
open $input, "<", \$content; |
|
|
66
|
|
|
|
|
145
|
|
|
|
66
|
|
|
|
|
564
|
|
|
|
346
|
|
|
|
|
5393
|
|
|
42
|
346
|
100
|
|
|
|
56305
|
$req->content_length(length $content) |
|
43
|
|
|
|
|
|
|
unless defined $req->content_length; |
|
44
|
|
|
|
|
|
|
} |
|
45
|
|
|
|
|
|
|
|
|
46
|
346
|
50
|
100
|
|
|
26558
|
my $env = { |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
47
|
|
|
|
|
|
|
PATH_INFO => URI::Escape::uri_unescape($uri->path || '/'), |
|
48
|
|
|
|
|
|
|
QUERY_STRING => $uri->query || '', |
|
49
|
|
|
|
|
|
|
SCRIPT_NAME => '', |
|
50
|
|
|
|
|
|
|
SERVER_NAME => $uri->host, |
|
51
|
|
|
|
|
|
|
SERVER_PORT => $uri->port, |
|
52
|
|
|
|
|
|
|
SERVER_PROTOCOL => $req->protocol || 'HTTP/1.1', |
|
53
|
|
|
|
|
|
|
REMOTE_ADDR => '127.0.0.1', |
|
54
|
|
|
|
|
|
|
REMOTE_HOST => 'localhost', |
|
55
|
|
|
|
|
|
|
REMOTE_PORT => int( rand(64000) + 1000 ), # not in RFC 3875 |
|
56
|
|
|
|
|
|
|
REQUEST_URI => $uri->path_query || '/', # not in RFC 3875 |
|
57
|
|
|
|
|
|
|
REQUEST_METHOD => $req->method, |
|
58
|
|
|
|
|
|
|
'psgi.version' => [ 1, 1 ], |
|
59
|
|
|
|
|
|
|
'psgi.url_scheme' => $uri->scheme eq 'https' ? 'https' : 'http', |
|
60
|
|
|
|
|
|
|
'psgi.input' => $input, |
|
61
|
|
|
|
|
|
|
'psgi.errors' => *STDERR, |
|
62
|
|
|
|
|
|
|
'psgi.multithread' => $FALSE, |
|
63
|
|
|
|
|
|
|
'psgi.multiprocess' => $FALSE, |
|
64
|
|
|
|
|
|
|
'psgi.run_once' => $TRUE, |
|
65
|
|
|
|
|
|
|
'psgi.streaming' => $TRUE, |
|
66
|
|
|
|
|
|
|
'psgi.nonblocking' => $FALSE, |
|
67
|
|
|
|
|
|
|
@_, |
|
68
|
|
|
|
|
|
|
}; |
|
69
|
|
|
|
|
|
|
|
|
70
|
346
|
|
|
|
|
52563
|
for my $field ( $req->headers->header_field_names ) { |
|
71
|
394
|
|
|
|
|
10498
|
my $key = uc("HTTP_$field"); |
|
72
|
394
|
|
|
|
|
769
|
$key =~ tr/-/_/; |
|
73
|
394
|
100
|
|
|
|
2502
|
$key =~ s/^HTTP_// if $field =~ /^Content-(Length|Type)$/; |
|
74
|
|
|
|
|
|
|
|
|
75
|
394
|
50
|
|
|
|
1329
|
unless ( exists $env->{$key} ) { |
|
76
|
394
|
|
|
|
|
990
|
$env->{$key} = $req->headers->header($field); |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
} |
|
79
|
|
|
|
|
|
|
|
|
80
|
346
|
50
|
|
|
|
14378
|
if ($env->{SCRIPT_NAME}) { |
|
81
|
0
|
|
|
|
|
0
|
$env->{PATH_INFO} =~ s/^\Q$env->{SCRIPT_NAME}\E/\//; |
|
82
|
0
|
|
|
|
|
0
|
$env->{PATH_INFO} =~ s/^\/+/\//; |
|
83
|
|
|
|
|
|
|
} |
|
84
|
|
|
|
|
|
|
|
|
85
|
346
|
100
|
100
|
|
|
1548
|
if (!defined($env->{HTTP_HOST}) && $req->uri->can('host')) { |
|
86
|
336
|
|
|
|
|
3952
|
$env->{HTTP_HOST} = $req->uri->host; |
|
87
|
336
|
100
|
|
|
|
11216
|
$env->{HTTP_HOST} .= ':' . $req->uri->port |
|
88
|
|
|
|
|
|
|
if $req->uri->port ne $req->uri->default_port; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
|
|
|
|
|
|
|
|
91
|
346
|
|
|
|
|
13164
|
return $env; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub res_from_psgi { |
|
95
|
328
|
|
|
328
|
1
|
675
|
my ($psgi_res) = @_; |
|
96
|
|
|
|
|
|
|
|
|
97
|
328
|
|
|
|
|
1818
|
require HTTP::Response; |
|
98
|
|
|
|
|
|
|
|
|
99
|
328
|
|
|
|
|
548
|
my $res; |
|
100
|
328
|
100
|
|
|
|
960
|
if (ref $psgi_res eq 'ARRAY') { |
|
|
|
100
|
|
|
|
|
|
|
101
|
291
|
|
|
|
|
809
|
_res_from_psgi($psgi_res, \$res); |
|
102
|
|
|
|
|
|
|
} elsif (ref $psgi_res eq 'CODE') { |
|
103
|
|
|
|
|
|
|
$psgi_res->(sub { |
|
104
|
33
|
|
|
33
|
|
135
|
_res_from_psgi($_[0], \$res); |
|
105
|
35
|
|
|
|
|
197
|
}); |
|
106
|
|
|
|
|
|
|
} else { |
|
107
|
2
|
100
|
|
|
|
350
|
Carp::croak("Bad response: ", defined $psgi_res ? $psgi_res : 'undef'); |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
|
|
110
|
324
|
|
|
|
|
2067
|
return $res; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub _res_from_psgi { |
|
114
|
324
|
|
|
324
|
|
491
|
my ($status, $headers, $body) = @{+shift}; |
|
|
324
|
|
|
|
|
950
|
|
|
115
|
324
|
|
|
|
|
547
|
my $res_ref = shift; |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
my $convert_resp = sub { |
|
118
|
324
|
|
|
324
|
|
1285
|
my $res = HTTP::Response->new($status); |
|
119
|
324
|
|
|
|
|
16038
|
$res->message(status_message($status)); |
|
120
|
324
|
100
|
|
|
|
4737
|
$res->headers->header(@$headers) if @$headers; |
|
121
|
|
|
|
|
|
|
|
|
122
|
324
|
100
|
|
|
|
22142
|
if (ref $body eq 'ARRAY') { |
|
123
|
293
|
|
|
|
|
2037
|
$res->content(join '', grep defined, @$body); |
|
124
|
|
|
|
|
|
|
} else { |
|
125
|
31
|
|
|
|
|
210
|
local $/ = \4096; |
|
126
|
31
|
|
|
|
|
60
|
my $content = ''; |
|
127
|
31
|
|
|
|
|
683
|
while (defined(my $buf = $body->getline)) { |
|
128
|
93
|
|
|
|
|
4968
|
$content .= $buf; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
31
|
|
|
|
|
696
|
$body->close; |
|
131
|
31
|
|
|
|
|
3179
|
$res->content($content); |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
324
|
|
|
|
|
7102
|
${ $res_ref } = $res; |
|
|
324
|
|
|
|
|
613
|
|
|
135
|
|
|
|
|
|
|
|
|
136
|
324
|
|
|
|
|
2390
|
return; |
|
137
|
324
|
|
|
|
|
1708
|
}; |
|
138
|
|
|
|
|
|
|
|
|
139
|
324
|
100
|
|
|
|
880
|
if (!defined $body) { |
|
140
|
15
|
|
|
|
|
29
|
$body = []; |
|
141
|
|
|
|
|
|
|
my $o = Plack::Util::inline_object |
|
142
|
21
|
|
|
21
|
|
74
|
write => sub { push @$body, @_ }, |
|
143
|
15
|
|
|
|
|
95
|
close => $convert_resp; |
|
144
|
|
|
|
|
|
|
|
|
145
|
15
|
|
|
|
|
63
|
return $o; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
309
|
|
|
|
|
664
|
$convert_resp->(); |
|
149
|
|
|
|
|
|
|
} |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub HTTP::Request::to_psgi { |
|
152
|
290
|
|
|
290
|
0
|
22179
|
req_to_psgi(@_); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub HTTP::Response::from_psgi { |
|
156
|
291
|
|
|
291
|
0
|
3128
|
my $class = shift; |
|
157
|
291
|
|
|
|
|
804
|
res_from_psgi(@_); |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
package |
|
161
|
|
|
|
|
|
|
HTTP::Message::PSGI::ChunkedInput; |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub new { |
|
164
|
0
|
|
|
0
|
|
|
my($class, $content, $chunked) = @_; |
|
165
|
|
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
my $content_cb; |
|
167
|
0
|
0
|
|
|
|
|
if ($chunked) { |
|
168
|
0
|
|
|
|
|
|
my $done; |
|
169
|
|
|
|
|
|
|
$content_cb = sub { |
|
170
|
0
|
|
|
0
|
|
|
my $chunk = $content->(); |
|
171
|
0
|
0
|
|
|
|
|
return if $done; |
|
172
|
0
|
0
|
|
|
|
|
unless (defined $chunk) { |
|
173
|
0
|
|
|
|
|
|
$done = 1; |
|
174
|
0
|
|
|
|
|
|
return "0\015\012\015\012"; |
|
175
|
|
|
|
|
|
|
} |
|
176
|
0
|
0
|
|
|
|
|
return '' unless length $chunk; |
|
177
|
0
|
|
|
|
|
|
return sprintf('%x', length $chunk) . "\015\012$chunk\015\012"; |
|
178
|
0
|
|
|
|
|
|
}; |
|
179
|
|
|
|
|
|
|
} else { |
|
180
|
0
|
|
|
|
|
|
$content_cb = $content; |
|
181
|
|
|
|
|
|
|
} |
|
182
|
|
|
|
|
|
|
|
|
183
|
0
|
|
|
|
|
|
bless { content => $content_cb }, $class; |
|
184
|
|
|
|
|
|
|
} |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub read { |
|
187
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
188
|
|
|
|
|
|
|
|
|
189
|
0
|
|
|
|
|
|
my $chunk = $self->{content}->(); |
|
190
|
0
|
0
|
|
|
|
|
return 0 unless defined $chunk; |
|
191
|
|
|
|
|
|
|
|
|
192
|
0
|
|
|
|
|
|
$_[0] = ''; |
|
193
|
0
|
|
0
|
|
|
|
substr($_[0], $_[2] || 0, length $chunk) = $chunk; |
|
194
|
|
|
|
|
|
|
|
|
195
|
0
|
|
|
|
|
|
return length $chunk; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
0
|
|
|
sub close { } |
|
199
|
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
package HTTP::Message::PSGI; |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
1; |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
__END__ |