Filename | /usr/share/perl5/HTTP/Response.pm |
Statements | Executed 10 statements in 1.83ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 20µs | 25µs | BEGIN@7 | HTTP::Response::
1 | 1 | 1 | 6µs | 6µs | BEGIN@8 | HTTP::Response::
0 | 0 | 0 | 0s | 0s | as_string | HTTP::Response::
0 | 0 | 0 | 0s | 0s | base | HTTP::Response::
0 | 0 | 0 | 0s | 0s | clone | HTTP::Response::
0 | 0 | 0 | 0s | 0s | code | HTTP::Response::
0 | 0 | 0 | 0s | 0s | current_age | HTTP::Response::
0 | 0 | 0 | 0s | 0s | dump | HTTP::Response::
0 | 0 | 0 | 0s | 0s | error_as_HTML | HTTP::Response::
0 | 0 | 0 | 0s | 0s | filename | HTTP::Response::
0 | 0 | 0 | 0s | 0s | fresh_until | HTTP::Response::
0 | 0 | 0 | 0s | 0s | freshness_lifetime | HTTP::Response::
0 | 0 | 0 | 0s | 0s | is_error | HTTP::Response::
0 | 0 | 0 | 0s | 0s | is_fresh | HTTP::Response::
0 | 0 | 0 | 0s | 0s | is_info | HTTP::Response::
0 | 0 | 0 | 0s | 0s | is_redirect | HTTP::Response::
0 | 0 | 0 | 0s | 0s | is_success | HTTP::Response::
0 | 0 | 0 | 0s | 0s | message | HTTP::Response::
0 | 0 | 0 | 0s | 0s | new | HTTP::Response::
0 | 0 | 0 | 0s | 0s | parse | HTTP::Response::
0 | 0 | 0 | 0s | 0s | previous | HTTP::Response::
0 | 0 | 0 | 0s | 0s | redirects | HTTP::Response::
0 | 0 | 0 | 0s | 0s | request | HTTP::Response::
0 | 0 | 0 | 0s | 0s | status_line | HTTP::Response::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package HTTP::Response; | ||||
2 | |||||
3 | 1 | 2µs | require HTTP::Message; | ||
4 | 1 | 12µs | @ISA = qw(HTTP::Message); | ||
5 | 1 | 800ns | $VERSION = "5.836"; | ||
6 | |||||
7 | 3 | 30µs | 2 | 30µs | # spent 25µs (20+5) within HTTP::Response::BEGIN@7 which was called:
# once (20µs+5µs) by LWP::UserAgent::BEGIN@11 at line 7 # spent 25µs making 1 call to HTTP::Response::BEGIN@7
# spent 5µs making 1 call to strict::import |
8 | 3 | 1.78ms | 1 | 6µs | # spent 6µs within HTTP::Response::BEGIN@8 which was called:
# once (6µs+0s) by LWP::UserAgent::BEGIN@11 at line 8 # spent 6µs making 1 call to HTTP::Response::BEGIN@8 |
9 | |||||
- - | |||||
12 | sub new | ||||
13 | { | ||||
14 | my($class, $rc, $msg, $header, $content) = @_; | ||||
15 | my $self = $class->SUPER::new($header, $content); | ||||
16 | $self->code($rc); | ||||
17 | $self->message($msg); | ||||
18 | $self; | ||||
19 | } | ||||
20 | |||||
21 | |||||
22 | sub parse | ||||
23 | { | ||||
24 | my($class, $str) = @_; | ||||
25 | my $status_line; | ||||
26 | if ($str =~ s/^(.*)\n//) { | ||||
27 | $status_line = $1; | ||||
28 | } | ||||
29 | else { | ||||
30 | $status_line = $str; | ||||
31 | $str = ""; | ||||
32 | } | ||||
33 | |||||
34 | my $self = $class->SUPER::parse($str); | ||||
35 | my($protocol, $code, $message); | ||||
36 | if ($status_line =~ /^\d{3} /) { | ||||
37 | # Looks like a response created by HTTP::Response->new | ||||
38 | ($code, $message) = split(' ', $status_line, 2); | ||||
39 | } else { | ||||
40 | ($protocol, $code, $message) = split(' ', $status_line, 3); | ||||
41 | } | ||||
42 | $self->protocol($protocol) if $protocol; | ||||
43 | $self->code($code) if defined($code); | ||||
44 | $self->message($message) if defined($message); | ||||
45 | $self; | ||||
46 | } | ||||
47 | |||||
48 | |||||
49 | sub clone | ||||
50 | { | ||||
51 | my $self = shift; | ||||
52 | my $clone = bless $self->SUPER::clone, ref($self); | ||||
53 | $clone->code($self->code); | ||||
54 | $clone->message($self->message); | ||||
55 | $clone->request($self->request->clone) if $self->request; | ||||
56 | # we don't clone previous | ||||
57 | $clone; | ||||
58 | } | ||||
59 | |||||
60 | |||||
61 | sub code { shift->_elem('_rc', @_); } | ||||
62 | sub message { shift->_elem('_msg', @_); } | ||||
63 | sub previous { shift->_elem('_previous',@_); } | ||||
64 | sub request { shift->_elem('_request', @_); } | ||||
65 | |||||
66 | |||||
67 | sub status_line | ||||
68 | { | ||||
69 | my $self = shift; | ||||
70 | my $code = $self->{'_rc'} || "000"; | ||||
71 | my $mess = $self->{'_msg'} || HTTP::Status::status_message($code) || "Unknown code"; | ||||
72 | return "$code $mess"; | ||||
73 | } | ||||
74 | |||||
75 | |||||
76 | sub base | ||||
77 | { | ||||
78 | my $self = shift; | ||||
79 | my $base = ( | ||||
80 | $self->header('Content-Base'), # used to be HTTP/1.1 | ||||
81 | $self->header('Content-Location'), # HTTP/1.1 | ||||
82 | $self->header('Base'), # HTTP/1.0 | ||||
83 | )[0]; | ||||
84 | if ($base && $base =~ /^$URI::scheme_re:/o) { | ||||
85 | # already absolute | ||||
86 | return $HTTP::URI_CLASS->new($base); | ||||
87 | } | ||||
88 | |||||
89 | my $req = $self->request; | ||||
90 | if ($req) { | ||||
91 | # if $base is undef here, the return value is effectively | ||||
92 | # just a copy of $self->request->uri. | ||||
93 | return $HTTP::URI_CLASS->new_abs($base, $req->uri); | ||||
94 | } | ||||
95 | |||||
96 | # can't find an absolute base | ||||
97 | return undef; | ||||
98 | } | ||||
99 | |||||
100 | |||||
101 | sub redirects { | ||||
102 | my $self = shift; | ||||
103 | my @r; | ||||
104 | my $r = $self; | ||||
105 | while (my $p = $r->previous) { | ||||
106 | push(@r, $p); | ||||
107 | $r = $p; | ||||
108 | } | ||||
109 | return @r unless wantarray; | ||||
110 | return reverse @r; | ||||
111 | } | ||||
112 | |||||
113 | |||||
114 | sub filename | ||||
115 | { | ||||
116 | my $self = shift; | ||||
117 | my $file; | ||||
118 | |||||
119 | my $cd = $self->header('Content-Disposition'); | ||||
120 | if ($cd) { | ||||
121 | require HTTP::Headers::Util; | ||||
122 | if (my @cd = HTTP::Headers::Util::split_header_words($cd)) { | ||||
123 | my ($disposition, undef, %cd_param) = @{$cd[-1]}; | ||||
124 | $file = $cd_param{filename}; | ||||
125 | |||||
126 | # RFC 2047 encoded? | ||||
127 | if ($file && $file =~ /^=\?(.+?)\?(.+?)\?(.+)\?=$/) { | ||||
128 | my $charset = $1; | ||||
129 | my $encoding = uc($2); | ||||
130 | my $encfile = $3; | ||||
131 | |||||
132 | if ($encoding eq 'Q' || $encoding eq 'B') { | ||||
133 | local($SIG{__DIE__}); | ||||
134 | eval { | ||||
135 | if ($encoding eq 'Q') { | ||||
136 | $encfile =~ s/_/ /g; | ||||
137 | require MIME::QuotedPrint; | ||||
138 | $encfile = MIME::QuotedPrint::decode($encfile); | ||||
139 | } | ||||
140 | else { # $encoding eq 'B' | ||||
141 | require MIME::Base64; | ||||
142 | $encfile = MIME::Base64::decode($encfile); | ||||
143 | } | ||||
144 | |||||
145 | require Encode; | ||||
146 | require encoding; | ||||
147 | # This is ugly use of non-public API, but is there | ||||
148 | # a better way to accomplish what we want (locally | ||||
149 | # as-is usable filename string)? | ||||
150 | my $locale_charset = encoding::_get_locale_encoding(); | ||||
151 | Encode::from_to($encfile, $charset, $locale_charset); | ||||
152 | }; | ||||
153 | |||||
154 | $file = $encfile unless $@; | ||||
155 | } | ||||
156 | } | ||||
157 | } | ||||
158 | } | ||||
159 | |||||
160 | unless (defined($file) && length($file)) { | ||||
161 | my $uri; | ||||
162 | if (my $cl = $self->header('Content-Location')) { | ||||
163 | $uri = URI->new($cl); | ||||
164 | } | ||||
165 | elsif (my $request = $self->request) { | ||||
166 | $uri = $request->uri; | ||||
167 | } | ||||
168 | |||||
169 | if ($uri) { | ||||
170 | $file = ($uri->path_segments)[-1]; | ||||
171 | } | ||||
172 | } | ||||
173 | |||||
174 | if ($file) { | ||||
175 | $file =~ s,.*[\\/],,; # basename | ||||
176 | } | ||||
177 | |||||
178 | if ($file && !length($file)) { | ||||
179 | $file = undef; | ||||
180 | } | ||||
181 | |||||
182 | $file; | ||||
183 | } | ||||
184 | |||||
185 | |||||
186 | sub as_string | ||||
187 | { | ||||
188 | require HTTP::Status; | ||||
189 | my $self = shift; | ||||
190 | my($eol) = @_; | ||||
191 | $eol = "\n" unless defined $eol; | ||||
192 | |||||
193 | my $status_line = $self->status_line; | ||||
194 | my $proto = $self->protocol; | ||||
195 | $status_line = "$proto $status_line" if $proto; | ||||
196 | |||||
197 | return join($eol, $status_line, $self->SUPER::as_string(@_)); | ||||
198 | } | ||||
199 | |||||
200 | |||||
201 | sub dump | ||||
202 | { | ||||
203 | my $self = shift; | ||||
204 | |||||
205 | my $status_line = $self->status_line; | ||||
206 | my $proto = $self->protocol; | ||||
207 | $status_line = "$proto $status_line" if $proto; | ||||
208 | |||||
209 | return $self->SUPER::dump( | ||||
210 | preheader => $status_line, | ||||
211 | @_, | ||||
212 | ); | ||||
213 | } | ||||
214 | |||||
215 | |||||
216 | sub is_info { HTTP::Status::is_info (shift->{'_rc'}); } | ||||
217 | sub is_success { HTTP::Status::is_success (shift->{'_rc'}); } | ||||
218 | sub is_redirect { HTTP::Status::is_redirect (shift->{'_rc'}); } | ||||
219 | sub is_error { HTTP::Status::is_error (shift->{'_rc'}); } | ||||
220 | |||||
221 | |||||
222 | sub error_as_HTML | ||||
223 | { | ||||
224 | require HTML::Entities; | ||||
225 | my $self = shift; | ||||
226 | my $title = 'An Error Occurred'; | ||||
227 | my $body = HTML::Entities::encode($self->status_line); | ||||
228 | return <<EOM; | ||||
229 | <html> | ||||
230 | <head><title>$title</title></head> | ||||
231 | <body> | ||||
232 | <h1>$title</h1> | ||||
233 | <p>$body</p> | ||||
234 | </body> | ||||
235 | </html> | ||||
236 | EOM | ||||
237 | } | ||||
238 | |||||
239 | |||||
240 | sub current_age | ||||
241 | { | ||||
242 | my $self = shift; | ||||
243 | my $time = shift; | ||||
244 | |||||
245 | # Implementation of RFC 2616 section 13.2.3 | ||||
246 | # (age calculations) | ||||
247 | my $response_time = $self->client_date; | ||||
248 | my $date = $self->date; | ||||
249 | |||||
250 | my $age = 0; | ||||
251 | if ($response_time && $date) { | ||||
252 | $age = $response_time - $date; # apparent_age | ||||
253 | $age = 0 if $age < 0; | ||||
254 | } | ||||
255 | |||||
256 | my $age_v = $self->header('Age'); | ||||
257 | if ($age_v && $age_v > $age) { | ||||
258 | $age = $age_v; # corrected_received_age | ||||
259 | } | ||||
260 | |||||
261 | if ($response_time) { | ||||
262 | my $request = $self->request; | ||||
263 | if ($request) { | ||||
264 | my $request_time = $request->date; | ||||
265 | if ($request_time && $request_time < $response_time) { | ||||
266 | # Add response_delay to age to get 'corrected_initial_age' | ||||
267 | $age += $response_time - $request_time; | ||||
268 | } | ||||
269 | } | ||||
270 | $age += ($time || time) - $response_time; | ||||
271 | } | ||||
272 | return $age; | ||||
273 | } | ||||
274 | |||||
275 | |||||
276 | sub freshness_lifetime | ||||
277 | { | ||||
278 | my($self, %opt) = @_; | ||||
279 | |||||
280 | # First look for the Cache-Control: max-age=n header | ||||
281 | for my $cc ($self->header('Cache-Control')) { | ||||
282 | for my $cc_dir (split(/\s*,\s*/, $cc)) { | ||||
283 | return $1 if $cc_dir =~ /^max-age\s*=\s*(\d+)/i; | ||||
284 | } | ||||
285 | } | ||||
286 | |||||
287 | # Next possibility is to look at the "Expires" header | ||||
288 | my $date = $self->date || $self->client_date || $opt{time} || time; | ||||
289 | if (my $expires = $self->expires) { | ||||
290 | return $expires - $date; | ||||
291 | } | ||||
292 | |||||
293 | # Must apply heuristic expiration | ||||
294 | return undef if exists $opt{heuristic_expiry} && !$opt{heuristic_expiry}; | ||||
295 | |||||
296 | # Default heuristic expiration parameters | ||||
297 | $opt{h_min} ||= 60; | ||||
298 | $opt{h_max} ||= 24 * 3600; | ||||
299 | $opt{h_lastmod_fraction} ||= 0.10; # 10% since last-mod suggested by RFC2616 | ||||
300 | $opt{h_default} ||= 3600; | ||||
301 | |||||
302 | # Should give a warning if more than 24 hours according to | ||||
303 | # RFC 2616 section 13.2.4. Here we just make this the default | ||||
304 | # maximum value. | ||||
305 | |||||
306 | if (my $last_modified = $self->last_modified) { | ||||
307 | my $h_exp = ($date - $last_modified) * $opt{h_lastmod_fraction}; | ||||
308 | return $opt{h_min} if $h_exp < $opt{h_min}; | ||||
309 | return $opt{h_max} if $h_exp > $opt{h_max}; | ||||
310 | return $h_exp; | ||||
311 | } | ||||
312 | |||||
313 | # default when all else fails | ||||
314 | return $opt{h_min} if $opt{h_min} > $opt{h_default}; | ||||
315 | return $opt{h_default}; | ||||
316 | } | ||||
317 | |||||
318 | |||||
319 | sub is_fresh | ||||
320 | { | ||||
321 | my($self, %opt) = @_; | ||||
322 | $opt{time} ||= time; | ||||
323 | my $f = $self->freshness_lifetime(%opt); | ||||
324 | return undef unless defined($f); | ||||
325 | return $f > $self->current_age($opt{time}); | ||||
326 | } | ||||
327 | |||||
328 | |||||
329 | sub fresh_until | ||||
330 | { | ||||
331 | my($self, %opt) = @_; | ||||
332 | $opt{time} ||= time; | ||||
333 | my $f = $self->freshness_lifetime(%opt); | ||||
334 | return undef unless defined($f); | ||||
335 | return $f - $self->current_age($opt{time}) + $opt{time}; | ||||
336 | } | ||||
337 | |||||
338 | 1 | 6µs | 1; | ||
339 | |||||
340 | |||||
341 | __END__ |