File Coverage

blib/lib/Plack/App/CGIBin/Streaming/Request.pm
Criterion Covered Total %
statement 112 117 95.7
branch 25 28 89.2
condition 1 3 33.3
subroutine 23 27 85.1
pod 5 6 83.3
total 166 181 91.7


line stmt bran cond sub pod time code
1             package Plack::App::CGIBin::Streaming::Request;
2              
3 36     36   957 use 5.014;
  36         126  
  36         1269  
4 36     36   204 use strict;
  36         666  
  36         1176  
5 36     36   186 use warnings;
  36         69  
  36         1143  
6 36     36   174 no warnings 'uninitialized';
  36         78  
  36         1095  
7 36     36   189 use Carp;
  36         57  
  36         2832  
8              
9             my %trace=
10             (
11             # new=>sub {warn "NEW: @_"},
12             # header=>sub {warn "HEADER: @_"},
13             # flush=>sub {warn "FLUSH: @_"},
14             # status_out=>sub {warn "STATUS OUT: @_"},
15             # content=>sub {warn "CONTENT: @_"},
16             # finalize_start=>sub {warn "FINALIZE START: @_"},
17             # finalize_end=>sub {warn "FINALIZE END: @_"},
18             );
19 36     36   186 use constant TRACE=>0; do {
  36         84  
  36         2376  
20 36     36   180 no warnings 'void';
  36         63  
  36         5631  
21             sub {
22             my $what=shift;
23             local $SIG{__WARN__};
24             $trace{$what} and $trace{$what}->(@_);
25             };
26             };
27              
28             our @attr;
29              
30             our $DEFAULT_CONTENT_TYPE='text/plain';
31             our $DEFAULT_MAX_BUFFER=8000;
32              
33             BEGIN {
34 36     36   237 @attr=(qw/env responder writer _buffer _buflen _headers max_buffer
35             content_type filter_before filter_after on_status_output
36             parse_headers _header_buffer status notes on_flush on_finalize
37             suppress_flush binmode_ok/);
38 36         96 for (@attr) {
39 684         987 my $attr=$_;
40 36     36   186 no strict 'refs';
  36         57  
  36         3084  
41 684         48279 *{__PACKAGE__.'::'.$attr}=sub : lvalue {
42 83944     83944   90864 my $I=$_[0];
43 83944 100       149511 $I->{$attr}=$_[1] if @_>1;
44 83944         194498 $I->{$attr};
45 684         1953 };
46             }
47             }
48              
49             sub new {
50 33     33 0 1102 my $class=shift;
51 33   33     315 $class=ref($class) || $class;
52             my $self=bless {
53             content_type=>$DEFAULT_CONTENT_TYPE,
54             max_buffer=>$DEFAULT_MAX_BUFFER,
55 83447     83447   92199 filter_before=>sub{},
56 83455     83455   198776 filter_after=>sub{},
57 29     29   46 on_status_output=>sub{},
58 993     993   1209 on_flush=>sub{},
59 25     25   45 on_finalize=>sub{},
60 33         1706 notes=>+{},
61             _headers=>[],
62             _buffer=>[],
63             _buflen=>0,
64             status=>200,
65             }, $class;
66              
67 33         188 for( my $i=0; $i<@_; $i+=2 ) {
68 145         421 my $method=$_[$i];
69 145         714 $self->$method($_[$i+1]);
70             }
71              
72 33         57 if (TRACE) {
73             (ref(TRACE) eq 'CODE'
74             ? TRACE->(new=>$self)
75             : warn "NEW $self");
76             }
77              
78 33         227 return $self;
79             }
80              
81             sub print_header {
82 70     70 1 223 my $self = shift;
83              
84 70 50       372 croak "KEY => VALUE pairs expected" if @_%2;
85 70 50       282 croak "It's too late to set a HTTP header" if $self->{writer};
86              
87 70         259 if (TRACE) {
88             (ref(TRACE)
89             ? TRACE->(header=>$self, @_)
90             : warn "print_header $self: @_");
91             }
92              
93 70         98 push @{$self->{_headers}}, @_;
  70         500  
94             }
95              
96             sub print_content {
97 83489     83489 1 99396 my $self = shift;
98              
99 83489 100       162923 if ($self->{parse_headers}) {
100 24         331 $self->{_header_buffer}.=join('', @_);
101 24         396 while( $self->{_header_buffer}=~s/\A(\S+)[ \t]*:[ \t]*(.+?)\r?\n// ) {
102 52         190 my ($hdr, $val)=($1, $2);
103 52 100       383 if ($hdr=~/\Astatus\z/i) {
    100          
104 20         406 $self->{status}=$val;
105             } elsif ($hdr=~/\Acontent-type\z/i) {
106 24         148 $self->{content_type}=$val;
107             } else {
108 8         32 $self->print_header($hdr, $val);
109             }
110             }
111 24 50       350 if ($self->{_header_buffer}=~s/\A\r?\n//) {
112 24         62 delete $self->{parse_headers}; # done
113 24 100       179 $self->print_content(delete $self->{_header_buffer})
114             if length $self->{_header_buffer};
115             }
116 24         90 return;
117             }
118              
119 83465         146481 my @data=@_;
120 83465         153340 $self->{filter_before}->($self, \@data);
121              
122 83465         97839 my $len = 0;
123 83465         195825 $len += length $_ for @data;
124              
125 83465         88624 if (TRACE) {
126             (ref(TRACE)
127             ? TRACE->(content=>$self, @data)
128             : warn "print_content $self: $len bytes");
129             }
130              
131 83465         89282 push @{$self->{_buffer}}, @data;
  83465         145441  
132 83465         109486 $len += $self->{_buflen};
133 83465         104101 $self->{_buflen}=$len;
134              
135 83465 100       158420 if ($len > $self->{max_buffer}) {
136 996         1934 local $self->{suppress_flush};
137 996         2037 $self->flush;
138             }
139              
140 83465         149386 $self->filter_after->($self, \@data);
141             }
142              
143             sub _status_out {
144 33     33   749 my $self = shift;
145 33         156 my $is_done = shift;
146              
147 33         191 if (TRACE) {
148             (ref(TRACE)
149             ? TRACE->(status_out=>$self, $is_done)
150             : warn "status_out $self: $self->{status}");
151             }
152              
153 33         148 $self->print_header('Content-Type', $self->{content_type});
154 33 100       177 $self->print_header('Content-Length', $self->{_buflen})
155             if $is_done;
156 33         100 $self->on_status_output->($self);
157              
158 33 100       305 $self->{writer}=$self->{responder}->([$self->{status},
159             $self->{_headers},
160             $is_done ? $self->{_buffer}: ()]);
161             }
162              
163             sub status_written {
164 7     7 1 89 my $self = shift;
165 7         31 return !!$self->{writer};
166             }
167              
168             sub flush {
169 1010     1010 1 1419 my $self = shift;
170 1010 100       1009 return 0 unless @{$self->{_buffer}};
  1010         2646  
171              
172 1008         1094 if (TRACE) {
173             (ref(TRACE)
174             ? TRACE->(flush=>$self)
175             : warn "flush $self");
176             }
177              
178 1008 100       2678 $self->_status_out unless $self->{writer};
179              
180 1008         12839 $self->{writer}->write(join '', @{$self->{_buffer}});
  1008         16147  
181 1008         227731 @{$self->{_buffer}}=();
  1008         9041  
182 1008         2060 $self->{_buflen}=0;
183              
184 1008         2200 $self->{on_flush}->($self);
185              
186 1008         2294 return 0;
187             }
188              
189             sub finalize {
190 33     33 1 88 my $self = shift;
191              
192 33         51 if (TRACE) {
193             (ref(TRACE)
194             ? TRACE->(finalize_start=>$self)
195             : warn "finalize start $self");
196             }
197              
198 33         135 $self->{on_finalize}->($self);
199 33 100       162 if ($self->{writer}) {
200 12         31 $self->{writer}->write(join '', @{$self->{_buffer}});
  12         121  
201 12         941 $self->{writer}->close;
202             } else {
203 21         97 $self->_status_out(1);
204             }
205              
206 33         93865 if (TRACE) {
207             (ref(TRACE)
208             ? TRACE->(finalize_end=>$self)
209             : warn "finalize end $self");
210             }
211              
212 33         946 %$self=();
213 33         452 bless $self, 'Plack::App::CGIBin::Streaming::Request::Demolished';
214             }
215              
216             package # prevent CPAN indexing
217             Plack::App::CGIBin::Streaming::Request::Demolished;
218 36     36   234 use strict;
  36         72  
  36         4524  
219              
220             sub AUTOLOAD {
221 0     0     our $AUTOLOAD;
222 0           die "Calling $AUTOLOAD on a demolished request.";
223             }
224              
225 0     0     sub flush {}
226 0     0     sub finalize {}
227 0     0     sub DESTROY {}
228              
229             1;
230              
231             __END__