File Coverage

blib/lib/Plack/Handler/CLI.pm
Criterion Covered Total %
statement 68 77 88.3
branch 20 28 71.4
condition 5 5 100.0
subroutine 11 12 91.6
pod 1 1 100.0
total 105 123 85.3


line stmt bran cond sub pod time code
1             package Plack::Handler::CLI;
2 3     3   461626 use 5.008_001;
  3         11  
  3         130  
3 3     3   2781 use Mouse;
  3         153480  
  3         20  
4              
5             our $VERSION = '0.05';
6              
7 3     3   3963 use IO::Handle (); # autoflush
  3         40710  
  3         91  
8 3     3   2202 use Plack::Util ();
  3         29095  
  3         67  
9 3     3   4502 use URI ();
  3         16364  
  3         102  
10              
11             use constant {
12 3         483 _RES_STATUS => 0,
13             _RES_HEADERS => 1,
14             _RES_BODY => 2,
15 3     3   26 };
  3         7  
16              
17             BEGIN {
18 3 50   3   6 if(eval { require URI::Escape::XS }) {
  3         10384  
19 3         37906 *_uri_escape = \&URI::Escape::XS::encodeURIComponent;
20             }
21             else {
22 0         0 require URI::Escape;
23 0         0 *_uri_escape = \&URI::Escape::uri_escape_utf8;
24             }
25             }
26              
27             my $CRLF = "\015\012";
28              
29             has need_headers => (
30             is => 'ro',
31             isa => 'Bool',
32             default => 1,
33             );
34              
35             has stdin => (
36             is => 'ro',
37             isa => 'FileHandle',
38             default => sub { \*STDIN },
39             );
40              
41             has stdout => (
42             is => 'ro',
43             isa => 'FileHandle',
44             default => sub { \*STDOUT },
45             );
46              
47             has stderr => (
48             is => 'ro',
49             isa => 'FileHandle',
50             default => sub { \*STDERR },
51             );
52              
53             sub run {
54 43     43 1 5223 my($self, $app, $argv_ref) = @_;
55              
56 43         79 my @argv;
57 43 100       141 if($argv_ref) {
58 6         11 @argv = @{$argv_ref};
  6         17  
59             }
60             else {
61             # skip after *.psgi
62 37         112 @argv = @ARGV;
63 37 50       190 if(grep { /\.psgi \z/xms } @argv) {
  0         0  
64 0         0 while(@argv) {
65 0         0 my $a = shift @argv;
66 0 0       0 last if $a =~ /\.psgi \z/xms;
67             }
68             }
69             }
70              
71 43         121 my @params;
72 43         168 while(defined(my $s = shift @argv)) {
73 8 100       36 if($s =~ s/\A -- //xms) {
74 4         17 my($name, $value) = split /=/, $s, 2;
75 4 100       14 if(not defined $value) {
76 3 50       11 $value = @argv
77             ? shift(@argv)
78             : Plack::Util::TRUE;
79             }
80 4         18 push @params, $name, $value;
81             }
82             else {
83 4         12 unshift @argv, $s; # push back
84 4         8 last;
85             }
86             }
87              
88 43         273 my $uri = URI->new();
89 43 100 100     10863 if ( @argv && $argv[0] =~ m{\Ahttp} ) {
90 3         13 $uri = URI->new(shift @argv);
91             }
92              
93 43 100       362 $uri->scheme('http') if not $uri->scheme;
94 43 100       8335 $uri->host('localhost') if not $uri->host;
95 43         3461 $uri->path_segments($uri->path_segments, @argv);
96 43         1664 $uri->query_form($uri->query_form, @params);
97              
98 43   100     2247 my %env = (
99             # HTTP
100             HTTP_USER_AGENT => sprintf('%s/%s', ref($self), $self->VERSION),
101              
102             HTTP_COOKIE => '', # TODO?
103             HTTP_HOST => $uri->host,
104              
105             # Client
106             REQUEST_METHOD => 'GET',
107             REQUEST_URI => $uri,
108             QUERY_STRING => $uri->query,
109             PATH_INFO => $uri->path || '/',
110             SCRIPT_NAME => '',
111             REMOTE_ADDR => '0.0.0.0',
112             REMOTE_USER => $ENV{USER},
113              
114             # Server
115             SERVER_PROTOCOL => 'HTTP/1.0',
116             SERVER_PORT => 0,
117             SERVER_NAME => 'localhost',
118             SERVER_SOFTWARE => ref($self),
119              
120             # PSGI
121             'psgi.version' => [1,1],
122             'psgi.url_scheme' => $uri->scheme,
123             'psgi.input' => $self->stdin,
124             'psgi.errors' => $self->stderr,
125             'psgi.multithread' => Plack::Util::FALSE,
126             'psgi.multiprocess' => Plack::Util::TRUE,
127             'psgi.run_once' => Plack::Util::TRUE,
128             'psgi.streaming' => Plack::Util::FALSE,
129             'psgi.nonblocking' => Plack::Util::FALSE,
130              
131             %ENV, # override
132             );
133 43 100       5497 $env{SCRIPT_NAME} = '' if $env{SCRIPT_NAME} eq '/';
134              
135 43         253 my $res = Plack::Util::run_app($app, \%env);
136              
137 43 50       15959 if (ref $res eq 'ARRAY') {
    0          
138 43         392 $self->_handle_response($res);
139             }
140             elsif (ref $res eq 'CODE') {
141             $res->(sub {
142 0     0   0 $self->_handle_response($_[0]);
143 0         0 });
144             }
145             else {
146 0         0 die "Bad response $res";
147             }
148             }
149              
150             sub _handle_response {
151 43     43   93 my ($self, $res) = @_;
152              
153 43         220 my $stdout = $self->stdout;
154              
155 43         308 $stdout->autoflush(1);
156              
157 43 100       2409 if($self->need_headers) {
158 40         149 my $hdrs = "Status: $res->[_RES_STATUS]" . $CRLF;
159              
160 40         129 $hdrs .= "Server: " . ref($self) . $CRLF;
161              
162 40         117 my $headers = $res->[_RES_HEADERS];
163 40         215 while (my ($k, $v) = splice @$headers, 0, 2) {
164 52         256 $hdrs .= "$k: $v" . $CRLF;
165             }
166 40         76 $hdrs .= $CRLF;
167              
168 40         2175 print $stdout $hdrs;
169             }
170              
171 43         229 my $body = $res->[_RES_BODY];
172 43     44   272 my $cb = sub { print $stdout @_ };
  44         2631  
173 43         204 Plack::Util::foreach($body, $cb);
174 43         5270 return;
175             }
176              
177 3     3   41 no Mouse;
  3         8  
  3         32  
178             __PACKAGE__->meta->make_immutable();
179             __END__