Filename | /usr/share/perl5/HTTP/Headers.pm |
Statements | Executed 164 statements in 2.17ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 12µs | 26µs | BEGIN@3 | HTTP::Headers::
1 | 1 | 1 | 9µs | 50µs | BEGIN@6 | HTTP::Headers::
1 | 1 | 1 | 4µs | 4µs | BEGIN@4 | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | __ANON__[:293] | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | __ANON__[:295] | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | _basic_auth | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | _date_header | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | _header | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | _process_newline | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | _sorted_field_names | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | as_string | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | authorization | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | authorization_basic | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | clear | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | client_date | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_encoding | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_is_html | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_is_text | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_is_xhtml | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_is_xml | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_language | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_length | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_type | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | content_type_charset | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | date | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | expires | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | from | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | header | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | header_field_names | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | if_modified_since | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | if_unmodified_since | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | init_header | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | last_modified | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | new | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | proxy_authenticate | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | proxy_authorization | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | proxy_authorization_basic | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | push_header | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | referer | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | remove_content_headers | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | remove_header | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | scan | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | server | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | title | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | user_agent | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | warning | HTTP::Headers::
0 | 0 | 0 | 0s | 0s | www_authenticate | HTTP::Headers::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package HTTP::Headers; | ||||
2 | |||||
3 | 2 | 24µs | 2 | 40µs | # spent 26µs (12+14) within HTTP::Headers::BEGIN@3 which was called:
# once (12µs+14µs) by LWP::UserAgent::BEGIN@10 at line 3 # spent 26µs making 1 call to HTTP::Headers::BEGIN@3
# spent 14µs making 1 call to strict::import |
4 | 2 | 23µs | 1 | 4µs | # spent 4µs within HTTP::Headers::BEGIN@4 which was called:
# once (4µs+0s) by LWP::UserAgent::BEGIN@10 at line 4 # spent 4µs making 1 call to HTTP::Headers::BEGIN@4 |
5 | |||||
6 | 2 | 2.04ms | 2 | 90µs | # spent 50µs (9+40) within HTTP::Headers::BEGIN@6 which was called:
# once (9µs+40µs) by LWP::UserAgent::BEGIN@10 at line 6 # spent 50µs making 1 call to HTTP::Headers::BEGIN@6
# spent 40µs making 1 call to vars::import |
7 | 1 | 400ns | $VERSION = "6.05"; | ||
8 | |||||
9 | # The $TRANSLATE_UNDERSCORE variable controls whether '_' can be used | ||||
10 | # as a replacement for '-' in header field names. | ||||
11 | 1 | 400ns | $TRANSLATE_UNDERSCORE = 1 unless defined $TRANSLATE_UNDERSCORE; | ||
12 | |||||
13 | # "Good Practice" order of HTTP message headers: | ||||
14 | # - General-Headers | ||||
15 | # - Request-Headers | ||||
16 | # - Response-Headers | ||||
17 | # - Entity-Headers | ||||
18 | |||||
19 | 1 | 1µs | my @general_headers = qw( | ||
20 | Cache-Control Connection Date Pragma Trailer Transfer-Encoding Upgrade | ||||
21 | Via Warning | ||||
22 | ); | ||||
23 | |||||
24 | 1 | 2µs | my @request_headers = qw( | ||
25 | Accept Accept-Charset Accept-Encoding Accept-Language | ||||
26 | Authorization Expect From Host | ||||
27 | If-Match If-Modified-Since If-None-Match If-Range If-Unmodified-Since | ||||
28 | Max-Forwards Proxy-Authorization Range Referer TE User-Agent | ||||
29 | ); | ||||
30 | |||||
31 | 1 | 600ns | my @response_headers = qw( | ||
32 | Accept-Ranges Age ETag Location Proxy-Authenticate Retry-After Server | ||||
33 | Vary WWW-Authenticate | ||||
34 | ); | ||||
35 | |||||
36 | 1 | 700ns | my @entity_headers = qw( | ||
37 | Allow Content-Encoding Content-Language Content-Length Content-Location | ||||
38 | Content-MD5 Content-Range Content-Type Expires Last-Modified | ||||
39 | ); | ||||
40 | |||||
41 | 1 | 11µs | my %entity_header = map { lc($_) => 1 } @entity_headers; | ||
42 | |||||
43 | 1 | 2µs | my @header_order = ( | ||
44 | @general_headers, | ||||
45 | @request_headers, | ||||
46 | @response_headers, | ||||
47 | @entity_headers, | ||||
48 | ); | ||||
49 | |||||
50 | # Make alternative representations of @header_order. This is used | ||||
51 | # for sorting and case matching. | ||||
52 | 1 | 0s | my %header_order; | ||
53 | my %standard_case; | ||||
54 | |||||
55 | { | ||||
56 | 2 | 600ns | my $i = 0; | ||
57 | 1 | 600ns | for (@header_order) { | ||
58 | 47 | 7µs | my $lc = lc $_; | ||
59 | 47 | 21µs | $header_order{$lc} = ++$i; | ||
60 | 47 | 19µs | $standard_case{$lc} = $_; | ||
61 | } | ||||
62 | } | ||||
63 | |||||
- - | |||||
66 | sub new | ||||
67 | { | ||||
68 | my($class) = shift; | ||||
69 | my $self = bless {}, $class; | ||||
70 | $self->header(@_) if @_; # set up initial headers | ||||
71 | $self; | ||||
72 | } | ||||
73 | |||||
74 | |||||
75 | sub header | ||||
76 | { | ||||
77 | my $self = shift; | ||||
78 | Carp::croak('Usage: $h->header($field, ...)') unless @_; | ||||
79 | my(@old); | ||||
80 | my %seen; | ||||
81 | while (@_) { | ||||
82 | my $field = shift; | ||||
83 | my $op = @_ ? ($seen{lc($field)}++ ? 'PUSH' : 'SET') : 'GET'; | ||||
84 | @old = $self->_header($field, shift, $op); | ||||
85 | } | ||||
86 | return @old if wantarray; | ||||
87 | return $old[0] if @old <= 1; | ||||
88 | join(", ", @old); | ||||
89 | } | ||||
90 | |||||
91 | sub clear | ||||
92 | { | ||||
93 | my $self = shift; | ||||
94 | %$self = (); | ||||
95 | } | ||||
96 | |||||
97 | |||||
98 | sub push_header | ||||
99 | { | ||||
100 | my $self = shift; | ||||
101 | return $self->_header(@_, 'PUSH_H') if @_ == 2; | ||||
102 | while (@_) { | ||||
103 | $self->_header(splice(@_, 0, 2), 'PUSH_H'); | ||||
104 | } | ||||
105 | } | ||||
106 | |||||
107 | |||||
108 | sub init_header | ||||
109 | { | ||||
110 | Carp::croak('Usage: $h->init_header($field, $val)') if @_ != 3; | ||||
111 | shift->_header(@_, 'INIT'); | ||||
112 | } | ||||
113 | |||||
114 | |||||
115 | sub remove_header | ||||
116 | { | ||||
117 | my($self, @fields) = @_; | ||||
118 | my $field; | ||||
119 | my @values; | ||||
120 | foreach $field (@fields) { | ||||
121 | $field =~ tr/_/-/ if $field !~ /^:/ && $TRANSLATE_UNDERSCORE; | ||||
122 | my $v = delete $self->{lc $field}; | ||||
123 | push(@values, ref($v) eq 'ARRAY' ? @$v : $v) if defined $v; | ||||
124 | } | ||||
125 | return @values; | ||||
126 | } | ||||
127 | |||||
128 | sub remove_content_headers | ||||
129 | { | ||||
130 | my $self = shift; | ||||
131 | unless (defined(wantarray)) { | ||||
132 | # fast branch that does not create return object | ||||
133 | delete @$self{grep $entity_header{$_} || /^content-/, keys %$self}; | ||||
134 | return; | ||||
135 | } | ||||
136 | |||||
137 | my $c = ref($self)->new; | ||||
138 | for my $f (grep $entity_header{$_} || /^content-/, keys %$self) { | ||||
139 | $c->{$f} = delete $self->{$f}; | ||||
140 | } | ||||
141 | if (exists $self->{'::std_case'}) { | ||||
142 | $c->{'::std_case'} = $self->{'::std_case'}; | ||||
143 | } | ||||
144 | $c; | ||||
145 | } | ||||
146 | |||||
147 | |||||
148 | sub _header | ||||
149 | { | ||||
150 | my($self, $field, $val, $op) = @_; | ||||
151 | |||||
152 | Carp::croak("Illegal field name '$field'") | ||||
153 | if rindex($field, ':') > 1 || !length($field); | ||||
154 | |||||
155 | unless ($field =~ /^:/) { | ||||
156 | $field =~ tr/_/-/ if $TRANSLATE_UNDERSCORE; | ||||
157 | my $old = $field; | ||||
158 | $field = lc $field; | ||||
159 | unless($standard_case{$field} || $self->{'::std_case'}{$field}) { | ||||
160 | # generate a %std_case entry for this field | ||||
161 | $old =~ s/\b(\w)/\u$1/g; | ||||
162 | $self->{'::std_case'}{$field} = $old; | ||||
163 | } | ||||
164 | } | ||||
165 | |||||
166 | $op ||= defined($val) ? 'SET' : 'GET'; | ||||
167 | if ($op eq 'PUSH_H') { | ||||
168 | # Like PUSH but where we don't care about the return value | ||||
169 | if (exists $self->{$field}) { | ||||
170 | my $h = $self->{$field}; | ||||
171 | if (ref($h) eq 'ARRAY') { | ||||
172 | push(@$h, ref($val) eq "ARRAY" ? @$val : $val); | ||||
173 | } | ||||
174 | else { | ||||
175 | $self->{$field} = [$h, ref($val) eq "ARRAY" ? @$val : $val] | ||||
176 | } | ||||
177 | return; | ||||
178 | } | ||||
179 | $self->{$field} = $val; | ||||
180 | return; | ||||
181 | } | ||||
182 | |||||
183 | my $h = $self->{$field}; | ||||
184 | my @old = ref($h) eq 'ARRAY' ? @$h : (defined($h) ? ($h) : ()); | ||||
185 | |||||
186 | unless ($op eq 'GET' || ($op eq 'INIT' && @old)) { | ||||
187 | if (defined($val)) { | ||||
188 | my @new = ($op eq 'PUSH') ? @old : (); | ||||
189 | if (ref($val) ne 'ARRAY') { | ||||
190 | push(@new, $val); | ||||
191 | } | ||||
192 | else { | ||||
193 | push(@new, @$val); | ||||
194 | } | ||||
195 | $self->{$field} = @new > 1 ? \@new : $new[0]; | ||||
196 | } | ||||
197 | elsif ($op ne 'PUSH') { | ||||
198 | delete $self->{$field}; | ||||
199 | } | ||||
200 | } | ||||
201 | @old; | ||||
202 | } | ||||
203 | |||||
204 | |||||
205 | sub _sorted_field_names | ||||
206 | { | ||||
207 | my $self = shift; | ||||
208 | return [ sort { | ||||
209 | ($header_order{$a} || 999) <=> ($header_order{$b} || 999) || | ||||
210 | $a cmp $b | ||||
211 | } grep !/^::/, keys %$self ]; | ||||
212 | } | ||||
213 | |||||
214 | |||||
215 | sub header_field_names { | ||||
216 | my $self = shift; | ||||
217 | return map $standard_case{$_} || $self->{'::std_case'}{$_} || $_, @{ $self->_sorted_field_names }, | ||||
218 | if wantarray; | ||||
219 | return grep !/^::/, keys %$self; | ||||
220 | } | ||||
221 | |||||
222 | |||||
223 | sub scan | ||||
224 | { | ||||
225 | my($self, $sub) = @_; | ||||
226 | my $key; | ||||
227 | for $key (@{ $self->_sorted_field_names }) { | ||||
228 | my $vals = $self->{$key}; | ||||
229 | if (ref($vals) eq 'ARRAY') { | ||||
230 | my $val; | ||||
231 | for $val (@$vals) { | ||||
232 | $sub->($standard_case{$key} || $self->{'::std_case'}{$key} || $key, $val); | ||||
233 | } | ||||
234 | } | ||||
235 | else { | ||||
236 | $sub->($standard_case{$key} || $self->{'::std_case'}{$key} || $key, $vals); | ||||
237 | } | ||||
238 | } | ||||
239 | } | ||||
240 | |||||
241 | |||||
242 | sub as_string | ||||
243 | { | ||||
244 | my($self, $endl) = @_; | ||||
245 | $endl = "\n" unless defined $endl; | ||||
246 | |||||
247 | my @result = (); | ||||
248 | for my $key (@{ $self->_sorted_field_names }) { | ||||
249 | next if index($key, '_') == 0; | ||||
250 | my $vals = $self->{$key}; | ||||
251 | if ( ref($vals) eq 'ARRAY' ) { | ||||
252 | for my $val (@$vals) { | ||||
253 | my $field = $standard_case{$key} || $self->{'::std_case'}{$key} || $key; | ||||
254 | $field =~ s/^://; | ||||
255 | if ( index($val, "\n") >= 0 ) { | ||||
256 | $val = _process_newline($val, $endl); | ||||
257 | } | ||||
258 | push @result, $field . ': ' . $val; | ||||
259 | } | ||||
260 | } | ||||
261 | else { | ||||
262 | my $field = $standard_case{$key} || $self->{'::std_case'}{$key} || $key; | ||||
263 | $field =~ s/^://; | ||||
264 | if ( index($vals, "\n") >= 0 ) { | ||||
265 | $vals = _process_newline($vals, $endl); | ||||
266 | } | ||||
267 | push @result, $field . ': ' . $vals; | ||||
268 | } | ||||
269 | } | ||||
270 | |||||
271 | join($endl, @result, ''); | ||||
272 | } | ||||
273 | |||||
274 | sub _process_newline { | ||||
275 | local $_ = shift; | ||||
276 | my $endl = shift; | ||||
277 | # must handle header values with embedded newlines with care | ||||
278 | s/\s+$//; # trailing newlines and space must go | ||||
279 | s/\n(\x0d?\n)+/\n/g; # no empty lines | ||||
280 | s/\n([^\040\t])/\n $1/g; # initial space for continuation | ||||
281 | s/\n/$endl/g; # substitute with requested line ending | ||||
282 | $_; | ||||
283 | } | ||||
284 | |||||
- - | |||||
287 | 3 | 3µs | if (eval { require Storable; 1 }) { | ||
288 | *clone = \&Storable::dclone; | ||||
289 | } else { | ||||
290 | *clone = sub { | ||||
291 | my $self = shift; | ||||
292 | my $clone = HTTP::Headers->new; | ||||
293 | $self->scan(sub { $clone->push_header(@_);} ); | ||||
294 | $clone; | ||||
295 | }; | ||||
296 | } | ||||
297 | |||||
298 | |||||
299 | sub _date_header | ||||
300 | { | ||||
301 | require HTTP::Date; | ||||
302 | my($self, $header, $time) = @_; | ||||
303 | my($old) = $self->_header($header); | ||||
304 | if (defined $time) { | ||||
305 | $self->_header($header, HTTP::Date::time2str($time)); | ||||
306 | } | ||||
307 | $old =~ s/;.*// if defined($old); | ||||
308 | HTTP::Date::str2time($old); | ||||
309 | } | ||||
310 | |||||
311 | |||||
312 | sub date { shift->_date_header('Date', @_); } | ||||
313 | sub expires { shift->_date_header('Expires', @_); } | ||||
314 | sub if_modified_since { shift->_date_header('If-Modified-Since', @_); } | ||||
315 | sub if_unmodified_since { shift->_date_header('If-Unmodified-Since', @_); } | ||||
316 | sub last_modified { shift->_date_header('Last-Modified', @_); } | ||||
317 | |||||
318 | # This is used as a private LWP extension. The Client-Date header is | ||||
319 | # added as a timestamp to a response when it has been received. | ||||
320 | sub client_date { shift->_date_header('Client-Date', @_); } | ||||
321 | |||||
322 | # The retry_after field is dual format (can also be a expressed as | ||||
323 | # number of seconds from now), so we don't provide an easy way to | ||||
324 | # access it until we have know how both these interfaces can be | ||||
325 | # addressed. One possibility is to return a negative value for | ||||
326 | # relative seconds and a positive value for epoch based time values. | ||||
327 | #sub retry_after { shift->_date_header('Retry-After', @_); } | ||||
328 | |||||
329 | sub content_type { | ||||
330 | my $self = shift; | ||||
331 | my $ct = $self->{'content-type'}; | ||||
332 | $self->{'content-type'} = shift if @_; | ||||
333 | $ct = $ct->[0] if ref($ct) eq 'ARRAY'; | ||||
334 | return '' unless defined($ct) && length($ct); | ||||
335 | my @ct = split(/;\s*/, $ct, 2); | ||||
336 | for ($ct[0]) { | ||||
337 | s/\s+//g; | ||||
338 | $_ = lc($_); | ||||
339 | } | ||||
340 | wantarray ? @ct : $ct[0]; | ||||
341 | } | ||||
342 | |||||
343 | sub content_type_charset { | ||||
344 | my $self = shift; | ||||
345 | require HTTP::Headers::Util; | ||||
346 | my $h = $self->{'content-type'}; | ||||
347 | $h = $h->[0] if ref($h); | ||||
348 | $h = "" unless defined $h; | ||||
349 | my @v = HTTP::Headers::Util::split_header_words($h); | ||||
350 | if (@v) { | ||||
351 | my($ct, undef, %ct_param) = @{$v[0]}; | ||||
352 | my $charset = $ct_param{charset}; | ||||
353 | if ($ct) { | ||||
354 | $ct = lc($ct); | ||||
355 | $ct =~ s/\s+//; | ||||
356 | } | ||||
357 | if ($charset) { | ||||
358 | $charset = uc($charset); | ||||
359 | $charset =~ s/^\s+//; $charset =~ s/\s+\z//; | ||||
360 | undef($charset) if $charset eq ""; | ||||
361 | } | ||||
362 | return $ct, $charset if wantarray; | ||||
363 | return $charset; | ||||
364 | } | ||||
365 | return undef, undef if wantarray; | ||||
366 | return undef; | ||||
367 | } | ||||
368 | |||||
369 | sub content_is_text { | ||||
370 | my $self = shift; | ||||
371 | return $self->content_type =~ m,^text/,; | ||||
372 | } | ||||
373 | |||||
374 | sub content_is_html { | ||||
375 | my $self = shift; | ||||
376 | return $self->content_type eq 'text/html' || $self->content_is_xhtml; | ||||
377 | } | ||||
378 | |||||
379 | sub content_is_xhtml { | ||||
380 | my $ct = shift->content_type; | ||||
381 | return $ct eq "application/xhtml+xml" || | ||||
382 | $ct eq "application/vnd.wap.xhtml+xml"; | ||||
383 | } | ||||
384 | |||||
385 | sub content_is_xml { | ||||
386 | my $ct = shift->content_type; | ||||
387 | return 1 if $ct eq "text/xml"; | ||||
388 | return 1 if $ct eq "application/xml"; | ||||
389 | return 1 if $ct =~ /\+xml$/; | ||||
390 | return 0; | ||||
391 | } | ||||
392 | |||||
393 | sub referer { | ||||
394 | my $self = shift; | ||||
395 | if (@_ && $_[0] =~ /#/) { | ||||
396 | # Strip fragment per RFC 2616, section 14.36. | ||||
397 | my $uri = shift; | ||||
398 | if (ref($uri)) { | ||||
399 | $uri = $uri->clone; | ||||
400 | $uri->fragment(undef); | ||||
401 | } | ||||
402 | else { | ||||
403 | $uri =~ s/\#.*//; | ||||
404 | } | ||||
405 | unshift @_, $uri; | ||||
406 | } | ||||
407 | ($self->_header('Referer', @_))[0]; | ||||
408 | } | ||||
409 | 1 | 400ns | *referrer = \&referer; # on tchrist's request | ||
410 | |||||
411 | sub title { (shift->_header('Title', @_))[0] } | ||||
412 | sub content_encoding { (shift->_header('Content-Encoding', @_))[0] } | ||||
413 | sub content_language { (shift->_header('Content-Language', @_))[0] } | ||||
414 | sub content_length { (shift->_header('Content-Length', @_))[0] } | ||||
415 | |||||
416 | sub user_agent { (shift->_header('User-Agent', @_))[0] } | ||||
417 | sub server { (shift->_header('Server', @_))[0] } | ||||
418 | |||||
419 | sub from { (shift->_header('From', @_))[0] } | ||||
420 | sub warning { (shift->_header('Warning', @_))[0] } | ||||
421 | |||||
422 | sub www_authenticate { (shift->_header('WWW-Authenticate', @_))[0] } | ||||
423 | sub authorization { (shift->_header('Authorization', @_))[0] } | ||||
424 | |||||
425 | sub proxy_authenticate { (shift->_header('Proxy-Authenticate', @_))[0] } | ||||
426 | sub proxy_authorization { (shift->_header('Proxy-Authorization', @_))[0] } | ||||
427 | |||||
428 | sub authorization_basic { shift->_basic_auth("Authorization", @_) } | ||||
429 | sub proxy_authorization_basic { shift->_basic_auth("Proxy-Authorization", @_) } | ||||
430 | |||||
431 | sub _basic_auth { | ||||
432 | require MIME::Base64; | ||||
433 | my($self, $h, $user, $passwd) = @_; | ||||
434 | my($old) = $self->_header($h); | ||||
435 | if (defined $user) { | ||||
436 | Carp::croak("Basic authorization user name can't contain ':'") | ||||
437 | if $user =~ /:/; | ||||
438 | $passwd = '' unless defined $passwd; | ||||
439 | $self->_header($h => 'Basic ' . | ||||
440 | MIME::Base64::encode("$user:$passwd", '')); | ||||
441 | } | ||||
442 | if (defined $old && $old =~ s/^\s*Basic\s+//) { | ||||
443 | my $val = MIME::Base64::decode($old); | ||||
444 | return $val unless wantarray; | ||||
445 | return split(/:/, $val, 2); | ||||
446 | } | ||||
447 | return; | ||||
448 | } | ||||
449 | |||||
450 | |||||
451 | 1 | 12µs | 1; | ||
452 | |||||
453 | __END__ |