/usr/local/CPAN/HTTP-Engine/HTTP/Engine/ResponseFinalizer.pm


package HTTP::Engine::ResponseFinalizer;
use strict;
use warnings;
use Scalar::Util        ();
use Carp                ();
use CGI::Simple::Cookie;

sub finalize {
    my ($class, $req, $res, $interface) = @_;
    Carp::confess 'argument missing: $res' unless $res;

    # protocol
    $res->protocol( $req->protocol ) unless $res->protocol;

    # Content-Length
    if ($res->body) {
        # get the length from a filehandle
        if (
            ref($res->body) eq 'GLOB' ||
            ( Scalar::Util::blessed($res->body) && ($res->body->can('getline') || $res->body->can('read')) )
        ) {
            my $st_size = 7; # see perldoc -f stat
            my $size = eval { (stat($res->body))[$st_size] };
            if (defined $size) {
                $res->content_length($size);
            } elsif (!$interface->can_has_streaming) { # can_has_streaming for PSGI streaming response
                die "Serving filehandle without a content-length($@)";
            }
        } else {
            use bytes;
            $res->content_length(bytes::length($res->body));
        }
    } else {
        $res->content_length(0);
    }

    # Errors
    if ($res->status =~ /^(1\d\d|[23]04)$/) {
        $res->headers->remove_header("Content-Length");
        $res->body('');
    }

    $res->content_type('text/html') unless $res->content_type;
    $res->header(Status => $res->status);

    $class->_finalize_cookies($res);

    # HTTP/1.1's default Connection: close
    if ($res->protocol && $res->protocol =~ m!1\.1! && !!!$res->header('Connection')) {
        $res->header( Connection => 'close' );
    }

    $res->body('') if ((defined $req->method) and ($req->method eq 'HEAD'));
}

sub _finalize_cookies  {
    my ($class, $res) = @_;

    my $cookies = $res->cookies;
    my @keys = keys %$cookies;
    if (@keys) {
        for my $name (@keys) {
            my $val = $cookies->{$name};
            my $cookie = (
                Scalar::Util::blessed($val)
                ? $val
                : CGI::Simple::Cookie->new(
                    -name    => $name,
                    -value   => $val->{value},
                    -expires => $val->{expires},
                    -domain  => $val->{domain},
                    -path    => $val->{path},
                    -secure  => ($val->{secure} || 0)
                )
            );

            $res->headers->push_header('Set-Cookie' => $cookie->as_string);
        }
    }
}

1;