File Coverage

blib/lib/Plack/App/CGIBin/Streaming.pm
Criterion Covered Total %
statement 80 84 95.2
branch 3 8 37.5
condition 5 9 55.5
subroutine 19 19 100.0
pod 2 5 40.0
total 109 125 87.2


line stmt bran cond sub pod time code
1             package Plack::App::CGIBin::Streaming;
2              
3 15     15   2004249 use 5.014;
  15         57  
  15         561  
4 15     15   81 use strict;
  15         27  
  15         504  
5 15     15   72 use warnings;
  15         45  
  15         1032  
6             our $VERSION = '0.04';
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 15     15   840 local $SIG{CHLD}=$SIG{CHLD};
19             }
20              
21 15     15   828 use parent qw/Plack::App::File/;
  15         27  
  15         78  
22 15     15   1205985 use CGI;
  15         244806  
  15         120  
23 15     15   14184 use CGI::Compile;
  15         338526  
  15         639  
24 15     15   126 use File::Spec;
  15         27  
  15         294  
25 15     15   10263 use Plack::App::CGIBin::Streaming::Request;
  15         42  
  15         414  
26 15     15   8808 use Plack::App::CGIBin::Streaming::IO;
  15         9108  
  15         2553  
27              
28 15         4164 use Plack::Util::Accessor qw/request_class
29             request_params
30 15     15   606 preload/;
  15         30  
31              
32 1     1 0 18 sub allow_path_info { 1 }
33              
34             sub prepare_app {
35 15     15 1 827 my $self=shift;
36              
37             # warn "\n\nprepare_app [@{$self->preload}]\n\n";
38              
39 15         192 $self->SUPER::prepare_app;
40 15 50       296666 return unless $self->preload;
41              
42 1         54 for my $pattern (@{$self->preload}) {
  1         13  
43 1 0       9 my $pat=($pattern=~m!^/!
44             ? $pattern
45             : $self->root.'/'.$pattern);
46             # warn " pat=$pat\n";
47 0         0 for my $fn (glob $pat) {
48             # warn "preloading $fn\n";
49 0         0 $self->{_compiled}->{$fn} = do {
50 0         0 local $0 = $fn; # keep FindBin happy
51              
52 0         0 $self->mkapp(CGI::Compile->compile($fn));
53             };
54             }
55             }
56             }
57              
58             our $R;
59 7     8 1 5747 sub request { return $R }
60              
61             sub mkapp {
62 4     4 0 23304 my ($self, $sub) = @_;
63              
64             return sub {
65 11     12   28 my $env = shift;
66             return sub {
67 12         338 my $responder = shift;
68              
69 17         74 local $env->{SCRIPT_NAME} = $env->{'plack.file.SCRIPT_NAME'};
70 17         120 local $env->{PATH_INFO} = $env->{'plack.file.PATH_INFO'};
71              
72 17         853 my @env_keys = grep !/^(?:plack|psgi.*)\./, keys %$env;
73 17         69 local @ENV{@env_keys} = @{$env}{@env_keys};
  17         649  
74              
75 17         291 select STDOUT;
76 17         65 $|=0;
77 17     10   880 binmode STDOUT, 'via(Plack::App::CGIBin::Streaming::IO)';
  5         104  
  5         74  
  10         247  
78              
79 17   50     161 my $class = ($self->request_class //
80             'Plack::App::CGIBin::Streaming::Request');
81 17   50     329 local $R = $class->new
82             (
83             env => $env,
84             responder => $responder,
85 17         1613 @{$self->request_params//[]},
86             );
87              
88 17         90 local *STDIN = $env->{'psgi.input'};
89 17         581 binmode STDIN, 'via(Plack::App::CGIBin::Streaming::IO)';
90              
91             # CGI::Compile localizes $0 and %SIG and calls
92             # CGI::initialize_globals.
93 17         65 my $err = eval {
94 17         175 local ($/, $\) = ($/, $\);
95 17   50     195 $sub->() // '';
96             };
97 17         6998 my $exc = $@;
98 17         120 $R->suppress_flush=1; # turn off normal flush behavior
99             {
100 15     15   9675 no warnings 'uninitialized';
  15         27  
  15         3834  
  17         55  
101 17         3239 binmode STDOUT;
102 17         85 binmode STDIN;
103             }
104 17         75 $R->finalize;
105 17 50       517 unless (defined $err) { # $sub died
106 6         25 warn "$env->{REQUEST_URI}: $exc";
107             }
108 12         4766 };
109 4         211 };
110             }
111              
112             sub serve_path {
113 17     17 0 1598671 my($self, $env, $file) = @_;
114              
115 17 50       434 die "need a server that supports streaming" unless $env->{'psgi.streaming'};
116              
117 11   66     607 my $app = $self->{_compiled}->{$file} ||= do {
118 10         95213 local $0 = $file; # keep FindBin happy
119              
120 10         437 $self->mkapp(CGI::Compile->compile($file));
121             };
122              
123 17         110 $app->($env);
124             }
125              
126             1;
127              
128             __END__