File Coverage

blib/lib/Plack/App/CGIBin/Streaming.pm
Criterion Covered Total %
statement 88 88 100.0
branch 9 12 75.0
condition 6 9 66.6
subroutine 19 19 100.0
pod 2 5 40.0
total 124 133 93.2


line stmt bran cond sub pod time code
1             package Plack::App::CGIBin::Streaming;
2              
3 36     36   2154195 use 5.014;
  36         126  
  36         1431  
4 36     36   177 use strict;
  36         120  
  36         1089  
5 36     36   177 use warnings;
  36         69  
  36         2325  
6             our $VERSION = '0.06';
7              
8             BEGIN {
9             # this works around a bug in perl
10              
11             # In Perl (at least up to 5.18.0) the first assignment to $SIG{CHLD}
12             # or $SIG{CLD} determines which name is later passed to the signal handler
13             # on systems like Linux that support both names.
14             # This hack tries to be the first such assignment in the perl program
15             # and thus pin down that name.
16             # Net::Server based servers like starman rely on "CHLD" to be passed to
17             # the signal handler.
18 36     36   2028 local $SIG{CHLD}=$SIG{CHLD};
19             }
20              
21 36     36   180 use parent qw/Plack::App::File/;
  36         66  
  36         171  
22 36     36   1128312 use CGI;
  36         591435  
  36         285  
23 36     36   36111 use CGI::Compile;
  36         781230  
  36         1287  
24 36     36   351 use File::Spec;
  36         75  
  36         708  
25 36     36   28728 use Plack::App::CGIBin::Streaming::Request;
  36         102  
  36         1041  
26 36     36   22827 use Plack::App::CGIBin::Streaming::IO;
  36         102  
  36         1341  
27              
28 36         513 use Plack::Util::Accessor qw/request_class
29             request_params
30 36     36   219 preload/;
  36         75  
31              
32 1     1 0 17 sub allow_path_info { 1 }
33              
34             sub prepare_app {
35 36     36 1 2154 my $self=shift;
36              
37             # warn "\n\nprepare_app [@{$self->preload}]\n\n";
38              
39 36         429 $self->SUPER::prepare_app;
40 36 100       316628 return unless $self->preload;
41              
42 4         328 for my $pattern (@{$self->preload}) {
  4         19  
43 7 50       71 my $pat=($pattern=~m!^/!
44             ? $pattern
45             : $self->root.'/'.$pattern);
46             # warn " pat=$pat\n";
47 6         768 for my $fn (glob $pat) {
48             # warn "preloading $fn\n";
49 9         15 $self->{_compiled}->{$fn} = do {
50 9         129 local $0 = $fn; # keep FindBin happy
51              
52 9         72 $self->mkapp(CGI::Compile->compile($fn));
53             };
54             }
55             }
56             }
57              
58             our $R;
59 13     14 1 7814 sub request { return $R }
60              
61             sub mkapp {
62 20     20 0 86569 my ($self, $sub) = @_;
63              
64             return sub {
65 27     28   77 my $env = shift;
66             return sub {
67 28         491 my $responder = shift;
68              
69 33         145 local $env->{SCRIPT_NAME} = $env->{'plack.file.SCRIPT_NAME'};
70 33         191 local $env->{PATH_INFO} = $env->{'plack.file.PATH_INFO'};
71              
72 33         1622 my @env_keys = grep !/^(?:plack|psgi.*)\./, keys %$env;
73 33         130 local @ENV{@env_keys} = @{$env}{@env_keys};
  33         2054  
74              
75 33         568 select STDOUT;
76 33         147 $|=0;
77 33     17   2355 binmode STDOUT, 'via(Plack::App::CGIBin::Streaming::IO)';
  12         272  
  12         100  
  17         600  
78              
79 33   50     249 my $class = ($self->request_class //
80             'Plack::App::CGIBin::Streaming::Request');
81 33   100     378 local $R = $class->new
82             (
83             env => $env,
84             responder => $responder,
85 33         2131 @{$self->request_params//[]},
86             );
87              
88 33         179 local *STDIN = $env->{'psgi.input'};
89 33         722 binmode STDIN, 'via(Plack::App::CGIBin::Streaming::IO)';
90              
91             # CGI::Compile localizes $0 and %SIG and calls
92             # CGI::initialize_globals.
93 33         120 my $err = eval {
94 33         493 local ($/, $\) = ($/, $\);
95 33   50     272 $sub->() // '';
96             };
97 33         19402 my $exc = $@;
98 33         285 $R->suppress_flush=1; # turn off normal flush behavior
99 33         168 $R->binmode_ok=1; # allow binmode to remove the layer
100             {
101 36     36   17928 no warnings 'uninitialized';
  36         66  
  36         9918  
  33         3356  
102 33         207 binmode STDOUT;
103 33         138 binmode STDIN;
104             }
105 33 100       191 unless (defined $err) {
106 7 50       48 warn "$env->{REQUEST_URI}: It's too late to set a HTTP status"
107             if $R->status_written;
108 7         28 $R->status(500);
109             }
110 33         232 $R->finalize;
111 27 100       1165 unless (defined $err) { # $sub died
112 1         145 warn "$env->{REQUEST_URI}: $exc";
113             }
114 28         4782 };
115 20         1064 };
116             }
117              
118             sub serve_path {
119 33     33 0 4831187 my($self, $env, $file) = @_;
120              
121 33 50       1032 die "need a server that supports streaming" unless $env->{'psgi.streaming'};
122              
123 27   66     1293 my $app = $self->{_compiled}->{$file} ||= do {
124 17         60446 local $0 = $file; # keep FindBin happy
125              
126 17         783 $self->mkapp(CGI::Compile->compile($file));
127             };
128              
129 33         262 $app->($env);
130             }
131              
132             1;
133              
134             __END__