File Coverage

blib/lib/Plack/App/CGIBin/Streaming.pm
Criterion Covered Total %
statement 84 85 98.8
branch 5 8 62.5
condition 6 9 66.6
subroutine 19 19 100.0
pod 2 5 40.0
total 116 126 92.0


line stmt bran cond sub pod time code
1             package Plack::App::CGIBin::Streaming;
2              
3 22     22   1375309 use 5.014;
  22         128  
  22         946  
4 22     22   128 use strict;
  22         39  
  22         795  
5 22     22   107 use warnings;
  22         44  
  22         1415  
6             our $VERSION = '0.05';
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 22     22   1214 local $SIG{CHLD}=$SIG{CHLD};
19             }
20              
21 22     22   137 use parent qw/Plack::App::File/;
  22         34  
  22         117  
22 22     22   673355 use CGI;
  22         343208  
  22         175  
23 22     22   22345 use CGI::Compile;
  22         584762  
  22         809  
24 22     22   212 use File::Spec;
  22         37  
  22         426  
25 22     22   17981 use Plack::App::CGIBin::Streaming::Request;
  22         56  
  22         727  
26 22     22   12919 use Plack::App::CGIBin::Streaming::IO;
  22         48  
  22         722  
27              
28 22         264 use Plack::Util::Accessor qw/request_class
29             request_params
30 22     22   154 preload/;
  22         41  
31              
32 2     2 0 291403 sub allow_path_info { 1 }
33              
34             sub prepare_app {
35 21     21 1 1319 my $self=shift;
36              
37             # warn "\n\nprepare_app [@{$self->preload}]\n\n";
38              
39 21         230 $self->SUPER::prepare_app;
40 21 100       181 return unless $self->preload;
41              
42 3         333 for my $pattern (@{$self->preload}) {
  3         15  
43 6 50       75 my $pat=($pattern=~m!^/!
44             ? $pattern
45             : $self->root.'/'.$pattern);
46             # warn " pat=$pat\n";
47 6         972 for my $fn (glob $pat) {
48             # warn "preloading $fn\n";
49 9         21 $self->{_compiled}->{$fn} = do {
50 9         159 local $0 = $fn; # keep FindBin happy
51              
52 9         87 $self->mkapp(CGI::Compile->compile($fn));
53             };
54             }
55             }
56             }
57              
58             our $R;
59 8     8 1 9809 sub request { return $R }
60              
61             sub mkapp {
62 16     16 0 52123 my ($self, $sub) = @_;
63              
64             return sub {
65 22     22   92 my $env = shift;
66             return sub {
67 22         642 my $responder = shift;
68              
69 22         108 local $env->{SCRIPT_NAME} = $env->{'plack.file.SCRIPT_NAME'};
70 22         93 local $env->{PATH_INFO} = $env->{'plack.file.PATH_INFO'};
71              
72 22         1368 my @env_keys = grep !/^(?:plack|psgi.*)\./, keys %$env;
73 22         101 local @ENV{@env_keys} = @{$env}{@env_keys};
  22         1181  
74              
75 22         130 select STDOUT;
76 22         90 $|=0;
77 7     7   226 binmode STDOUT, 'via(Plack::App::CGIBin::Streaming::IO)';
  8         80  
  8         336  
  22         1185  
78              
79 22   50     274 my $class = ($self->request_class //
80             'Plack::App::CGIBin::Streaming::Request');
81 22   100     129 local $R = $class->new
82             (
83             env => $env,
84             responder => $responder,
85 22         1287 @{$self->request_params//[]},
86             );
87              
88 22         126 local *STDIN = $env->{'psgi.input'};
89 22         761 binmode STDIN, 'via(Plack::App::CGIBin::Streaming::IO)';
90              
91             # CGI::Compile localizes $0 and %SIG and calls
92             # CGI::initialize_globals.
93 22         63 my $err = eval {
94 22         259 local ($/, $\) = ($/, $\);
95 22   50     132 $sub->() // '';
96             };
97 22         16191 my $exc = $@;
98 22         132 $R->suppress_flush=1; # turn off normal flush behavior
99 22         99 $R->binmode_ok=1; # allow binmode to remove the layer
100             {
101 22     22   11050 no warnings 'uninitialized';
  22         46  
  22         5335  
  22         45  
102 22         155 binmode STDOUT;
103 22         116 binmode STDIN;
104             }
105 22         143 $R->finalize;
106 22 50       1195 unless (defined $err) { # $sub died
107 0         0 warn "$env->{REQUEST_URI}: $exc";
108             }
109 22         340 };
110 16         440 };
111             }
112              
113             sub serve_path {
114 22     22 0 3165694 my($self, $env, $file) = @_;
115              
116 22 50       346 die "need a server that supports streaming" unless $env->{'psgi.streaming'};
117              
118 22   66     823 my $app = $self->{_compiled}->{$file} ||= do {
119 7         601 local $0 = $file; # keep FindBin happy
120              
121 7         477 $self->mkapp(CGI::Compile->compile($file));
122             };
123              
124 22         178 $app->($env);
125             }
126              
127             1;
128              
129             __END__