Skip to content

Commit

Permalink
factor out scheme handling into separate backends
Browse files Browse the repository at this point in the history
docs still need updating
  • Loading branch information
doy committed Jan 7, 2011
1 parent 6cf2b2c commit 459dd00
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 62 deletions.
1 change: 1 addition & 0 deletions dist.ini
Expand Up @@ -7,6 +7,7 @@ copyright_holder = Jesse Luehrs
dist = Plack-Client

[Prereqs]
Class::Load = 0
HTTP::Request = 0
Plack = 0.9910
Plack::App::Proxy = 0
Expand Down
115 changes: 60 additions & 55 deletions lib/Plack/Client.pm
Expand Up @@ -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);

Expand Down Expand Up @@ -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<apps> 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
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
}
Expand All @@ -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) = @_;
Expand Down
28 changes: 28 additions & 0 deletions 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;
41 changes: 41 additions & 0 deletions 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;
5 changes: 1 addition & 4 deletions t/01-basic.t
Expand Up @@ -35,11 +35,8 @@ test_tcp_plackup(
]
},
};
my $client = Plack::Client->new(apps => $apps);
my $client = Plack::Client->new('psgi-local' => {apps => $apps});
isa_ok($client, 'Plack::Client');
is($client->apps, $apps, "got apps back");
is($client->app_for('foo'), $apps->{foo}, "got the right app");
is($client->app_for('bar'), undef, "didn't get nonexistent app");

{
my $res = $client->get('psgi-local://foo/');
Expand Down
5 changes: 4 additions & 1 deletion t/02-inputs.t
Expand Up @@ -48,7 +48,10 @@ test_tcp_plackup(
};
my $base_uri = 'psgi-local://foo';

test_responses($base_uri, Plack::Client->new(apps => $apps));
test_responses(
$base_uri,
Plack::Client->new('psgi-local' => {apps => $apps})
);
}

sub test_responses {
Expand Down
5 changes: 4 additions & 1 deletion t/03-delayed-response.t
Expand Up @@ -51,7 +51,10 @@ test_tcp_plackup(
};
my $base_uri = 'psgi-local://foo';

test_responses($base_uri, Plack::Client->new(apps => $apps));
test_responses(
$base_uri,
Plack::Client->new('psgi-local' => {apps => $apps})
);
}

sub test_responses {
Expand Down
5 changes: 4 additions & 1 deletion t/04-streaming.t
Expand Up @@ -52,7 +52,10 @@ test_tcp_plackup(
};
my $base_uri = 'psgi-local://foo';

test_responses($base_uri, Plack::Client->new(apps => $apps));
test_responses(
$base_uri,
Plack::Client->new('psgi-local' => {apps => $apps})
);
}

sub test_responses {
Expand Down

0 comments on commit 459dd00

Please sign in to comment.