AxKit2
view release on metacpan or search on metacpan
lib/AxKit2/HTTPHeaders.pm view on Meta::CPAN
$new->{origcase} = { %{$self->{origcase}} };
$new->{hdorder} = [ @{$self->{hdorder}} ];
return $new;
}
=head2 C<< $obj->set_version( VER ) >>
Set the HTTP version using the C<N.N> format.
=cut
sub set_version {
my AxKit2::HTTPHeaders $self = shift;
my $ver = shift;
die "Bogus version" unless $ver =~ /^(\d+)\.(\d+)$/;
my ($ver_ma, $ver_mi) = ($1, $2);
# check for req, as the other can be res or httpres
if ($self->{type} eq 'req') {
$self->{requestLine} = "$self->{method} $self->{uri} HTTP/$ver";
} else {
$self->{responseLine} = "HTTP/$ver $self->{code} " . $self->_codetext;
}
$self->{ver} = "$ver_ma.$ver_mi";
$self->{vernum} = $ver_ma*1000 + $ver_mi;
return $self;
}
=head2 C<< $obj->content_length >>
Using all available information, attempt to determine the content length of
the message body being sent to us.
=cut
sub content_length {
my AxKit2::HTTPHeaders $self = shift;
# shortcuts depending on our method/code, depending on what we are
if ($self->{type} eq 'req') {
# no content length for head requests
return 0 if $self->{method} eq 'HEAD';
} elsif ($self->{type} eq 'res' || $self->{type} eq 'httpres') {
# no content length in any of these
if ($self->{code} == 304 || $self->{code} == 204 ||
($self->{code} >= 100 && $self->{code} <= 199)) {
return 0;
}
}
# the normal case for a GET/POST, etc. real data coming back
# also, an OPTIONS requests generally has a defined but 0 content-length
if (defined(my $clen = $self->header("Content-Length"))) {
return $clen;
}
# if we get here, nothing matched, so we don't definitively know what the
# content length is. this is usually an error, but we try to work around it.
return undef;
}
=head2 C<< $obj->req_keep_alive( RESPONSE_HEADERS ) >>
Given C<$obj> is the request headers, answers the question: "should a response
to this person specify keep-alive, given the request and the given response?"
This is used in proxy mode to determine based on the client's request and the
backend's response whether or not the response from the proxy (us) should do
keep-alive.
For normal responses (should a response be kept alive) see C<res_keep_alive>.
=cut
sub req_keep_alive {
my AxKit2::HTTPHeaders $self = $_[0];
my AxKit2::HTTPHeaders $res = $_[1] or Carp::confess("ASSERT: No response headers given");
# get the connection header now (saves warnings later)
my $conn = lc ($self->header('Connection') || '');
# check the client
if ($self->version_number < 1001) {
# they must specify a keep-alive header
return 0 unless $conn =~ /\bkeep-alive\b/i;
}
# so it must be 1.1 which means keep-alive is on, unless they say not to
return 0 if $conn =~ /\bclose\b/i;
# if we get here, the user wants keep-alive and seems to support it,
# so we make sure that the response is in a form that we can understand
# well enough to do keep-alive. FIXME: support chunked encoding in the
# future, which means this check changes.
return 1 if defined $res->header('Content-length') ||
$res->response_code == 304 || # not modified
$res->response_code == 204 || # no content
$self->request_method eq 'HEAD';
# fail-safe, no keep-alive
return 0;
}
=head2 C<< $obj->res_keep_alive_options >>
Determine if an options response from a backend looks like it can do keep-alive.
=cut
sub res_keep_alive_options {
my AxKit2::HTTPHeaders $self = $_[0];
return $self->res_keep_alive(undef, 1);
}
=head2 C<< $obj->res_keep_alive( REQUEST_HEADERS ) >>
Given C<$obj> is the response headers, answers the question: "is the backend
expected to stay open?" this is a combination of the request we sent to it and
the response they sent...
You don't normally need to call this - it is automatically performed by the
backend.
=cut
sub res_keep_alive {
my AxKit2::HTTPHeaders $self = $_[0];
my AxKit2::HTTPHeaders $req = $_[1];
my $is_options = $_[2];
Carp::confess("ASSERT: No request headers given") unless $req || $is_options;
# get the connection header now (saves warnings later)
my $conn = lc ($self->header('Connection') || '');
# if they said Connection: close, it's always not keep-alive
return 0 if $conn =~ /\bclose\b/i;
# handle the http 1.0/0.9 case which requires keep-alive specified
if ($self->version_number < 1001) {
# must specify keep-alive, and must have a content length OR
# the request must be a head request
return 1 if
$conn =~ /\bkeep-alive\b/i &&
($is_options ||
defined $self->header('Content-length') ||
$req->request_method eq 'HEAD' ||
$self->response_code == 304 || # not modified
$self->response_code == 204
); # no content
return 0;
}
# HTTP/1.1 case. defaults to keep-alive, per spec, unless
# asked for otherwise (checked above)
# FIXME: make sure we handle a HTTP/1.1 response from backend
# with connection: close, no content-length, going to a
# HTTP/1.1 persistent client. we'll have to add chunk markers.
# (not here, obviously)
return 1;
}
=head2 C<< $obj->range( SIZE ) >>
Given a size, returns C<STATUS, RANGE_START, RANGE_END>.
Status will be one of:
=over 4
=item * 200 - Invalid or non-existant range header. Serve normally.
=item * 206 - Parsable range is good. Serve partial content.
=item * 416 - Range is unsatisfiable.
=back
=cut
sub range {
my AxKit2::HTTPHeaders $self = $_[0];
my $size = $_[1];
my $not_satisfiable;
my $range = $self->header("Range");
return 200 unless
$range &&
defined $size &&
$range =~ /^bytes=(\d*)-(\d*)$/;
my ($range_start, $range_end) = ($1, $2);
undef $range_start if $range_start eq '';
undef $range_end if $range_end eq '';
return 200 unless defined($range_start) or defined($range_end);
if (defined($range_start) and defined($range_end) and $range_start > $range_end) {
return 416;
} elsif (not defined($range_start) and defined($range_end) and $range_end == 0) {
return 416;
} elsif (defined($range_start) and $size <= $range_start) {
return 416;
}
$range_start = 0 unless defined($range_start);
$range_end = $size - 1 unless defined($range_end) and $range_end < $size;
return (206, $range_start, $range_end);
}
1;
( run in 0.541 second using v1.01-cache-2.11-cpan-df04353d9ac )