Plack
view release on metacpan or search on metacpan
lib/HTTP/Message/PSGI.pm view on Meta::CPAN
our @EXPORT = qw( req_to_psgi res_from_psgi );
use Carp ();
use HTTP::Status qw(status_message);
use URI::Escape ();
use Plack::Util;
use Scalar::Util ();
my $TRUE = (1 == 1);
my $FALSE = !$TRUE;
sub req_to_psgi {
my $req = shift;
unless (Scalar::Util::blessed($req) && $req->isa('HTTP::Request')) {
Carp::croak("Request is not HTTP::Request: $req");
}
# from HTTP::Request::AsCGI
my $host = $req->header('Host');
my $uri = $req->uri->clone;
$uri->scheme('http') unless $uri->scheme;
$uri->host('localhost') unless $uri->host;
$uri->port(80) unless $uri->port;
$uri->host_port($host) unless !$host || ( $host eq $uri->host_port );
my $input;
my $content = $req->content;
if (ref $content eq 'CODE') {
if (defined $req->content_length) {
$input = HTTP::Message::PSGI::ChunkedInput->new($content);
} else {
$req->header("Transfer-Encoding" => "chunked");
$input = HTTP::Message::PSGI::ChunkedInput->new($content, 1);
}
} else {
open $input, "<", \$content;
$req->content_length(length $content)
unless defined $req->content_length;
}
my $env = {
PATH_INFO => URI::Escape::uri_unescape($uri->path || '/'),
QUERY_STRING => $uri->query || '',
SCRIPT_NAME => '',
SERVER_NAME => $uri->host,
SERVER_PORT => $uri->port,
SERVER_PROTOCOL => $req->protocol || 'HTTP/1.1',
REMOTE_ADDR => '127.0.0.1',
REMOTE_HOST => 'localhost',
REMOTE_PORT => int( rand(64000) + 1000 ), # not in RFC 3875
REQUEST_URI => $uri->path_query || '/', # not in RFC 3875
REQUEST_METHOD => $req->method,
'psgi.version' => [ 1, 1 ],
'psgi.url_scheme' => $uri->scheme eq 'https' ? 'https' : 'http',
'psgi.input' => $input,
'psgi.errors' => *STDERR,
'psgi.multithread' => $FALSE,
'psgi.multiprocess' => $FALSE,
'psgi.run_once' => $TRUE,
'psgi.streaming' => $TRUE,
'psgi.nonblocking' => $FALSE,
@_,
};
for my $field ( $req->headers->header_field_names ) {
my $key = uc("HTTP_$field");
$key =~ tr/-/_/;
$key =~ s/^HTTP_// if $field =~ /^Content-(Length|Type)$/;
unless ( exists $env->{$key} ) {
$env->{$key} = $req->headers->header($field);
}
}
if ($env->{SCRIPT_NAME}) {
$env->{PATH_INFO} =~ s/^\Q$env->{SCRIPT_NAME}\E/\//;
$env->{PATH_INFO} =~ s/^\/+/\//;
}
if (!defined($env->{HTTP_HOST}) && $req->uri->can('host')) {
$env->{HTTP_HOST} = $req->uri->host;
$env->{HTTP_HOST} .= ':' . $req->uri->port
if $req->uri->port ne $req->uri->default_port;
}
return $env;
}
sub res_from_psgi {
my ($psgi_res) = @_;
require HTTP::Response;
my $res;
if (ref $psgi_res eq 'ARRAY') {
_res_from_psgi($psgi_res, \$res);
} elsif (ref $psgi_res eq 'CODE') {
$psgi_res->(sub {
_res_from_psgi($_[0], \$res);
});
} else {
Carp::croak("Bad response: ", defined $psgi_res ? $psgi_res : 'undef');
}
return $res;
}
sub _res_from_psgi {
my ($status, $headers, $body) = @{+shift};
my $res_ref = shift;
my $convert_resp = sub {
my $res = HTTP::Response->new($status);
$res->message(status_message($status));
$res->headers->header(@$headers) if @$headers;
if (ref $body eq 'ARRAY') {
$res->content(join '', grep defined, @$body);
} else {
local $/ = \4096;
( run in 1.645 second using v1.01-cache-2.11-cpan-d7f47b0818f )