From 642b11b4f8d5edacd55e6b10e0b287047acc1ae1 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Thu, 6 Jan 2011 14:38:24 -0600 Subject: major refactoring, things are a lot cleaner now --- lib/Plack/Client.pm | 150 +++++++++++++++++++++++++++++++++++----------------- t/02-inputs.t | 28 +++++----- 2 files changed, 117 insertions(+), 61 deletions(-) diff --git a/lib/Plack/Client.pm b/lib/Plack/Client.pm index 5a2abb4..80824d8 100644 --- a/lib/Plack/Client.pm +++ b/lib/Plack/Client.pm @@ -7,7 +7,7 @@ use HTTP::Request; use Plack::App::Proxy; use Plack::Middleware::ContentLength; use Plack::Response; -use Scalar::Util qw(blessed); +use Scalar::Util qw(blessed reftype); sub new { my $class = shift; @@ -30,37 +30,9 @@ sub app_for { sub request { my $self = shift; - my $req = blessed($_[0]) && ($_[0]->isa('HTTP::Request') - || $_[0]->isa('Plack::Request')) - ? $_[0] - : ref($_[0]) eq 'HASH' - ? Plack::Request->new(@_) - : HTTP::Request->new(@_); - - # both Plack::Request and HTTP::Request have a ->uri method - my $scheme = $req->uri->scheme; - my $app; - if ($scheme eq 'psgi-local') { - if ($req->isa('Plack::Request')) { - $req->env->{REQUEST_URI} = '/' unless length $req->request_uri; - } - else { - $req->uri->path('/') unless length $req->uri->path; - } - my $app_name = $req->uri->authority; - $app_name =~ s/:.*//; - $app = $self->app_for($app_name); - $app = Plack::Middleware::ContentLength->wrap($app); - } - elsif ($scheme eq 'http' || $scheme eq 'https') { - my $uri = $req->uri->clone; - $uri->path('/'); - $app = Plack::App::Proxy->new(remote => $uri->as_string)->to_app; - } - die 'XXX' unless $app; + my ($app, $env) = $self->_parse_request_args(@_); - my $env = $self->_req_to_env($req); my $psgi_res = $self->_resolve_response($app->($env)); # is there a better place to do this? Plack::App::Proxy already takes care # of this (since it's making a real http request) @@ -70,41 +42,121 @@ sub request { return Plack::Response->new(@$psgi_res); } -sub _req_to_env { +sub _parse_request_args { my $self = shift; - my ($req) = @_; - my $env; - if ($req->isa('HTTP::Request')) { - my $scheme = $req->uri->scheme; - # hack around with this - psgi requires a host and port to exist, and - # for the scheme to be either http or https - if ($scheme eq 'psgi-local') { - $req->uri->scheme('http'); - $req->uri->host('Plack::Client'); - $req->uri->port(-1); + if (blessed($_[0])) { + if ($_[0]->isa('HTTP::Request')) { + return $self->_request_from_http_request(@_); } - elsif ($scheme eq 'psgi-local-ssl') { - $req->uri->scheme('https'); - $req->uri->host('Plack::Client'); - $req->uri->port(-1); + elsif ($_[0]->isa('Plack::Request')) { + return $self->_request_from_plack_request(@_); } - elsif ($scheme ne 'http' && $scheme ne 'https') { + else { die 'XXX'; } - - $env = $req->to_psgi; + } + elsif ((reftype($_[0]) || '') eq 'HASH') { + return $self->_request_from_env(@_); } else { - $env = $req->env; + return $self->_request_from_http_request_args(@_); } +} + +sub _request_from_http_request { + my $self = shift; + my ($http_request) = @_; + my $env = $self->_http_request_to_env($http_request); + return $self->_request_from_env($env); +} + +sub _request_from_plack_request { + my $self = shift; + my ($req) = @_; + + return ($self->_app_from_req($req), $req->env); +} + +sub _request_from_env { + my $self = shift; + return $self->_request_from_plack_request(Plack::Request->new(@_)); +} + +sub _request_from_http_request_args { + my $self = shift; + return $self->_request_from_http_request(HTTP::Request->new(@_)); +} + +sub _http_request_to_env { + my $self = shift; + my ($req) = @_; + + my $scheme = $req->uri->scheme; + my $app_name; + # hack around with this - psgi requires a host and port to exist, and + # for the scheme to be either http or https + if ($scheme eq 'psgi-local') { + $app_name = $req->uri->authority; + $req->uri->scheme('http'); + $req->uri->host('Plack::Client'); + $req->uri->port(-1); + } + elsif ($scheme eq 'psgi-local-ssl') { + $app_name = $req->uri->authority; + $req->uri->scheme('https'); + $req->uri->host('Plack::Client'); + $req->uri->port(-1); + } + elsif ($scheme ne 'http' && $scheme ne 'https') { + die 'XXX'; + } + + # work around http::message::psgi bug - see github issue 163 for plack + if (!$req->uri->path) { + $req->uri->path('/'); + } + + my $env = $req->to_psgi; # work around http::message::psgi bug - see github issue 150 for plack $env->{CONTENT_LENGTH} ||= length($req->content); + $env->{'plack.client.url_scheme'} = $scheme; + $env->{'plack.client.app_name'} = $app_name + if defined $app_name; + return $env; } +sub _app_from_req { + my $self = shift; + my ($req) = @_; + + my $uri = $req->uri; + my $scheme = $req->env->{'plack.client.url_scheme'} || $uri->scheme; + my $app_name = $req->env->{'plack.client.app_name'}; + + my $app; + if ($scheme eq 'psgi-local') { + if (!defined $app_name) { + $app_name = $uri->authority; + $app_name =~ s/(.*):.*/$1/; # in case a port was added at some point + } + $app = $self->app_for($app_name); + $app = Plack::Middleware::ContentLength->wrap($app); + } + elsif ($scheme eq 'http' || $scheme eq 'https') { + my $uri = $uri->clone; + $uri->path('/'); + $app = Plack::App::Proxy->new(remote => $uri->as_string)->to_app; + } + + die 'XXX' unless $app; + + return $app; +} + sub _resolve_response { my $self = shift; my ($psgi_res) = @_; diff --git a/t/02-inputs.t b/t/02-inputs.t index 4b27630..faa5e5a 100644 --- a/t/02-inputs.t +++ b/t/02-inputs.t @@ -125,18 +125,22 @@ sub test_responses { "GET\n/\n\n" ); - my $uri = URI->new($base_uri); - $uri->scheme('http') - if $base_uri =~ /psgi-local/; - my $env = HTTP::Request->new(GET => $uri)->to_psgi; - $env->{'psgi.url_scheme'} = 'psgi-local' - if $base_uri =~ /psgi-local/; - response_is( - $client->request($env), - 200, - ['Content-Type' => 'text/plain', 'Content-Length' => '7'], - "GET\n/\n\n" - ); + { + my $base = URI->new($base_uri); + my $uri = $base->clone; + $uri->scheme('http'); + $uri->path('/') unless $uri->path; + my $env = HTTP::Request->new(GET => $uri)->to_psgi; + $env->{'plack.client.url_scheme'} = $base->scheme; + $env->{'plack.client.app_name'} = $base->authority + if $base->scheme eq 'psgi-local'; + response_is( + $client->request($env), + 200, + ['Content-Type' => 'text/plain', 'Content-Length' => '7'], + "GET\n/\n\n" + ); + } } done_testing; -- cgit v1.2.3