From 459dd0062bfc3ff82ee10a01e7dbb34ae003ce21 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Fri, 7 Jan 2011 16:43:29 -0600 Subject: factor out scheme handling into separate backends docs still need updating --- lib/Plack/Client.pm | 115 +++++++++++++++++---------------- lib/Plack/Client/Backend/http.pm | 28 ++++++++ lib/Plack/Client/Backend/psgi_local.pm | 41 ++++++++++++ 3 files changed, 129 insertions(+), 55 deletions(-) create mode 100644 lib/Plack/Client/Backend/http.pm create mode 100644 lib/Plack/Client/Backend/psgi_local.pm (limited to 'lib') diff --git a/lib/Plack/Client.pm b/lib/Plack/Client.pm index 588ef69..d05293b 100644 --- a/lib/Plack/Client.pm +++ b/lib/Plack/Client.pm @@ -3,10 +3,10 @@ use strict; use warnings; # ABSTRACT: abstract interface to remote web servers and local PSGI apps +use Class::Load; use HTTP::Message::PSGI; use HTTP::Request; -use Plack::App::Proxy; -use Plack::Middleware::ContentLength; +use Plack::Request; use Plack::Response; use Scalar::Util qw(blessed reftype); @@ -76,39 +76,44 @@ sub new { my $class = shift; my %params = @_; - die 'apps must be a hashref' - if exists($params{apps}) && ref($params{apps}) ne 'HASH'; - bless { - apps => $params{apps}, - proxy => Plack::App::Proxy->new->to_app, + backend => {}, + backend_args => \%params, }, $class; } -=method apps - - my $apps = $client->apps; - -Returns the C hashref that was passed to the constructor. +=method backend =cut -sub apps { shift->{apps} } -sub _proxy { shift->{proxy} } +sub backend { + my $self = shift; + my ($scheme) = @_; + $scheme = $self->_normalize_scheme($scheme); + return $self->{backend}->{$scheme}; +} -=method app_for +sub _set_backend { + my $self = shift; + my ($scheme, $backend) = @_; + $scheme = $self->_normalize_scheme($scheme); + $self->{backend}->{$scheme} = $backend; +} - my $app = $client->app_for('foo'); +sub _normalize_scheme { + my $self = shift; -Returns the app corresponding to the given app name (or undef, if no such app -exists). + my $scheme = blessed($_[0]) ? $_[0]->scheme : $_[0]; + $scheme =~ s/-ssl$//; + $scheme = 'http' if $scheme eq 'https'; -=cut + return $scheme; +} -sub app_for { +sub _backend_args { my $self = shift; - my ($for) = @_; - return $self->apps->{$for}; + my ($scheme) = @_; + return %{ $self->{backend_args}->{$scheme} || {} }; } =method request @@ -196,25 +201,21 @@ sub _http_request_to_env { my $self = shift; my ($req) = @_; - my $scheme = $req->uri->scheme; - my $app_name; + my $scheme = $req->uri->scheme; + my $authority = $req->uri->authority; + # 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'); + if ($scheme ne 'http' && $scheme ne 'https') { + if ($scheme =~ /-ssl$/) { + $req->uri->scheme('https'); + } + else { + $req->uri->scheme('http'); + } $req->uri->host('Plack::Client'); $req->uri->port(-1); } - elsif ($scheme ne 'http' && $scheme ne 'https') { - die 'Invalid URL scheme ' . $scheme; - } # work around http::message::psgi bug - see github issue 163 for plack if (!$req->uri->path) { @@ -227,8 +228,8 @@ sub _http_request_to_env { $env->{CONTENT_LENGTH} ||= length($req->content); $env->{'plack.client.url_scheme'} = $scheme; - $env->{'plack.client.app_name'} = $app_name - if defined $app_name; + $env->{'plack.client.authority'} = $authority + if defined $authority; return $env; } @@ -239,30 +240,34 @@ sub _app_from_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); - die "Unknown app: $app_name" unless $app; - $app = Plack::Middleware::ContentLength->wrap($app); - } - elsif ($scheme eq 'http' || $scheme eq 'https') { - my $uri = $uri->clone; - $uri->path('/'); - $req->env->{'plack.proxy.remote'} = $uri->as_string; - $app = $self->_proxy; - } + my $backend = $self->_scheme_to_backend($scheme); + my $app = $backend->app_from_req($req); die "Couldn't find app" unless $app; return $app; } +sub _scheme_to_backend { + my $self = shift; + my ($scheme) = @_; + + $scheme = $self->_normalize_scheme($scheme); + + my $backend = $self->backend($scheme); + return $backend if $backend; + + (my $scheme_class = $scheme) =~ s/-/_/; + $scheme_class = "Plack::Client::Backend::$scheme_class"; + Class::Load::load_class($scheme_class); + + $backend = $scheme_class->new($self->_backend_args($scheme)); + $self->_set_backend($scheme, $backend); + + return $self->backend($scheme); +} + sub _resolve_response { my $self = shift; my ($psgi_res) = @_; diff --git a/lib/Plack/Client/Backend/http.pm b/lib/Plack/Client/Backend/http.pm new file mode 100644 index 0000000..9982cd1 --- /dev/null +++ b/lib/Plack/Client/Backend/http.pm @@ -0,0 +1,28 @@ +package Plack::Client::Backend::http; +use strict; +use warnings; + +use Plack::App::Proxy; + +sub new { + my $class = shift; + my %params = @_; + + bless { + proxy => Plack::App::Proxy->new->to_app, + }, $class; +} + +sub proxy { shift->{proxy} } + +sub app_from_req { + my $self = shift; + my ($req) = @_; + + my $uri = $req->uri->clone; + $uri->path('/'); + $req->env->{'plack.proxy.remote'} = $uri->as_string; + return $self->proxy; +} + +1; diff --git a/lib/Plack/Client/Backend/psgi_local.pm b/lib/Plack/Client/Backend/psgi_local.pm new file mode 100644 index 0000000..212479e --- /dev/null +++ b/lib/Plack/Client/Backend/psgi_local.pm @@ -0,0 +1,41 @@ +package Plack::Client::Backend::psgi_local; +use strict; +use warnings; + +use Plack::Middleware::ContentLength; + +sub new { + my $class = shift; + my %params = @_; + + die 'apps must be a hashref' + if exists($params{apps}) && ref($params{apps}) ne 'HASH'; + + bless { + apps => $params{apps}, + }, $class; +} + +sub apps { shift->{apps} } + +sub app_for { + my $self = shift; + my ($for) = @_; + return $self->apps->{$for}; +} + +sub app_from_req { + my $self = shift; + my ($req) = @_; + + my $app_name = $req->env->{'plack.client.authority'}; + if (!defined $app_name) { + $app_name = $req->uri->authority; + $app_name =~ s/(.*):.*/$1/; # in case a port was added at some point + } + my $app = $self->app_for($app_name); + die "Unknown app: $app_name" unless $app; + return Plack::Middleware::ContentLength->wrap($app); +} + +1; -- cgit v1.2.3-54-g00ecf