| 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 | HTTP::Headers::BEGIN@3 |
| 1 | 1 | 1 | 9µs | 50µs | HTTP::Headers::BEGIN@6 |
| 1 | 1 | 1 | 4µs | 4µs | HTTP::Headers::BEGIN@4 |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::__ANON__[:293] |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::__ANON__[:295] |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::_basic_auth |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::_date_header |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::_header |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::_process_newline |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::_sorted_field_names |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::as_string |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::authorization |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::authorization_basic |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::clear |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::client_date |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_encoding |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_is_html |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_is_text |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_is_xhtml |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_is_xml |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_language |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_length |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_type |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::content_type_charset |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::date |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::expires |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::from |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::header |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::header_field_names |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::if_modified_since |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::if_unmodified_since |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::init_header |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::last_modified |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::new |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::proxy_authenticate |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::proxy_authorization |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::proxy_authorization_basic |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::push_header |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::referer |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::remove_content_headers |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::remove_header |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::scan |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::server |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::title |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::user_agent |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::warning |
| 0 | 0 | 0 | 0s | 0s | HTTP::Headers::www_authenticate |
| 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__ |