File Coverage

blib/lib/Plack/Util/Load.pm
Criterion Covered Total %
statement 56 83 67.4
branch 21 38 55.2
condition 4 9 44.4
subroutine 12 14 85.7
pod 0 3 0.0
total 93 147 63.2


line stmt bran cond sub pod time code
1             package Plack::Util::Load;
2 1     1   16902 use strict;
  1         1  
  1         28  
3 1     1   3 use warnings;
  1         1  
  1         34  
4              
5             our $VERSION = '0.1';
6              
7 1     1   3 use parent 'Exporter';
  1         5  
  1         3  
8             our @EXPORT = qw(load_app);
9              
10 1     1   577 use Plack::Util;
  1         9144  
  1         28  
11 1     1   487 use Plack::Request;
  1         232844  
  1         31  
12 1     1   569 use Plack::Response;
  1         1937  
  1         30  
13 1     1   11478 use HTTP::Tiny;
  1         39650  
  1         42  
14 1     1   8 use URI;
  1         1  
  1         15  
15              
16 1     1   4 use Carp;
  1         1  
  1         307  
17             our @CARP_NOT = ('Plack::Util');
18              
19             our $VERBOSE = 0;
20              
21             sub load_app {
22 12     12 0 29823 my ($app, %options) = @_;
23              
24 12 50       36 if ( !defined $options{verbose} ) {
25 12         54 $options{verbose} = $VERBOSE;
26             }
27              
28 12 100 100     63 if ( ref $app ) {
    100          
29 2 50       6 if (ref $app eq 'CODE') {
    100          
30 0         0 return $app;
31 2         19 } elsif ( eval { $app->can('to_app') } ) {
32 1         4 return $app->to_app;
33             } else {
34 1         99 croak "failed to load app from object or reference " . ref $app;
35             }
36             } elsif ( !defined $app or $app eq '' ) {
37 3         5 $app = 'app.psgi';
38             }
39              
40 10 50 33     180 if ( $app =~ /^:?(\d+)$/ and $1 > 0 ) {
    50          
    50          
    100          
    100          
41 0         0 return load_url("http://localhost:$1/", %options);
42             } elsif ( $app eq 'localhost' ) {
43 0         0 return load_url("http://localhost/", %options);
44             } elsif ( $app =~ /^https?:\/\// ) {
45 0         0 return load_url($app, %options);
46             } elsif ( -f $app ) {
47 2         10 return Plack::Util::load_psgi($app);
48             } elsif ( $app =~ /^[a-zA-Z0-9\_\:]+$/ ) {
49 5         19 return load_package($app, %options);
50             }
51              
52 3         352 croak "failed to load app $app";
53             }
54              
55             sub load_package {
56 5     5 0 12 my ($module, %options) = @_;
57              
58             # check defined module
59 1     1   5 no strict 'refs';
  1         1  
  1         527  
60 5 100       6 if ( %{ $module.'::' } ) {
  5         31  
61 2         4 my $app = eval { $module->new->to_app };
  2         8  
62 2 100       35 if ( ref $app ) {
63 1 50       4 print "# load_app defined package $module\n" if $options{verbose};
64 1         5 return $app;
65             }
66 1         140 croak "failed to load app $module from package";
67             }
68              
69              
70             # load and instanciate new module
71 3         14 Plack::Util::load_class( $module );
72 2         11294 my $app = $module->new->to_app;
73 2 50       45 print "# load_app new package $module\n" if $options{verbose};
74              
75 2         14 return $app;
76             }
77              
78             sub load_url {
79 0 0   0 0   my ($url, %options) = @_ % 2 ? @_ : (undef, @_);
80              
81 0           $url = URI->new($url);
82 0           my ($scheme, $host, $port) = ($url->scheme, $url->host, $url->port);
83            
84 0           my $verbose = $options{verbose};
85              
86             return sub {
87 0     0     my $req = Plack::Request->new($_[0]);
88 0           my @headers;
89 0           $req->headers->scan(sub { push @headers, @_ });
  0            
90 0           my $options = { headers => {} };
91 0 0         $options->{headers} = Hash::MultiValue->new(@headers)->mixed if @headers;
92 0           delete $options->{headers}->{Host}; # not allowed by HTTP::Tiny
93 0 0         $options->{content} = $req->content if length($req->content);
94 0           my $uri = $req->uri;
95 0           $uri->scheme($scheme);
96 0           $uri->host($host);
97 0           $uri->port($port);
98              
99 0 0         if ($verbose) {
100 0           printf "# %s %s\n", $req->method, $uri;
101             }
102              
103 0           my $res = HTTP::Tiny->new->request( $req->method, $uri, $options );
104              
105 0 0 0       if ($res->{status} == 599 and $verbose) {
106 0           print STDERR "# ".$res->{content};
107             }
108              
109 0           return Plack::Response->new( $res->{status}, $res->{headers}, $res->{content} )->finalize;
110 0           };
111             }
112              
113             1;
114             __END__