my $self = shift;
return sort {
($header_order{$a} || 999) <=> ($header_order{$b} || 999) ||
$a cmp $b
} keys %$self
}
sub header_field_names {
my $self = shift;
return map $standard_case{$_} || $_, $self->_sorted_field_names
if wantarray;
return keys %$self;
}
sub scan
{
my($self, $sub) = @_;
my $key;
foreach $key ($self->_sorted_field_names) {
next if $key =~ /^_/;
my $vals = $self->{$key};
if (ref($vals) eq 'ARRAY') {
my $val;
for $val (@$vals) {
&$sub($standard_case{$key} || $key, $val);
}
}
else {
&$sub($standard_case{$key} || $key, $vals);
}
}
}
sub as_string
{
my($self, $endl) = @_;
$endl = "\n" unless defined $endl;
my @result = ();
$self->scan(sub {
my($field, $val) = @_;
$field =~ s/^://;
if ($val =~ /\n/) {
# must handle header values with embedded newlines with care
$val =~ s/\s+$//; # trailing newlines and space must go
$val =~ s/\n\n+/\n/g; # no empty lines
$val =~ s/\n([^\040\t])/\n $1/g; # intial space for continuation
$val =~ s/\n/$endl/g; # substitute with requested line ending
}
push(@result, "$field: $val");
});
join($endl, @result, '');
}
if (eval { require Storable; 1 }) {
*clone = \&Storable::dclone;
} else {
*clone = sub {
my $self = shift;
my $clone = new HTTP::Headers;
$self->scan(sub { $clone->push_header(@_);} );
$clone;
};
}
sub _date_header
{
require HTTP::Date;
my($self, $header, $time) = @_;
my($old) = $self->_header($header);
if (defined $time) {
$self->_header($header, HTTP::Date::time2str($time));
}
$old =~ s/;.*// if defined($old);
HTTP::Date::str2time($old);
}
sub date { shift->_date_header('Date', @_); }
sub expires { shift->_date_header('Expires', @_); }
sub if_modified_since { shift->_date_header('If-Modified-Since', @_); }
sub if_unmodified_since { shift->_date_header('If-Unmodified-Since', @_); }
sub last_modified { shift->_date_header('Last-Modified', @_); }
# This is used as a private LWP extension. The Client-Date header is
# added as a timestamp to a response when it has been received.
sub client_date { shift->_date_header('Client-Date', @_); }
# The retry_after field is dual format (can also be a expressed as
# number of seconds from now), so we don't provide an easy way to
# access it until we have know how both these interfaces can be
# addressed. One possibility is to return a negative value for
# relative seconds and a positive value for epoch based time values.
#sub retry_after { shift->_date_header('Retry-After', @_); }
=3= |