File Coverage

blib/lib/Net/Async/FastCGI/Request.pm
Criterion Covered Total %
statement 236 240 98.3
branch 61 80 76.2
condition 18 25 72.0
subroutine 59 59 100.0
pod 23 28 82.1
total 397 432 91.9


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2005-2024 -- leonerd@leonerd.org.uk
5              
6             package Net::Async::FastCGI::Request 0.26;
7              
8 18     18   264 use v5.14;
  18         76  
9 18     18   166 use warnings;
  18         67  
  18         1183  
10              
11 18     18   113 use Carp;
  18         41  
  18         1644  
12              
13 18     18   136 use Net::FastCGI::Constant qw( :type :flag :protocol_status );
  18         41  
  18         3647  
14 18         1165 use Net::FastCGI::Protocol qw(
15             parse_params
16             build_end_request_body
17 18     18   122 );
  18         30  
18              
19             # The largest amount of data we can fit in a FastCGI record - MUST NOT
20             # be greater than 2^16-1
21 18     18   103 use constant MAXRECORDDATA => 65535;
  18         33  
  18         1517  
22              
23 18     18   108 use Encode qw( find_encoding );
  18         73  
  18         1061  
24 18     18   98 use POSIX qw( EAGAIN );
  18         46  
  18         188  
25              
26             my $CRLF = "\x0d\x0a";
27              
28             =head1 NAME
29              
30             C - a single active FastCGI request
31              
32             =head1 SYNOPSIS
33              
34             use Net::Async::FastCGI;
35             use IO::Async::Loop;
36              
37             my $fcgi = Net::Async::FastCGI->new(
38             on_request => sub {
39             my ( $fcgi, $req ) = @_;
40              
41             my $path = $req->param( "PATH_INFO" );
42             $req->print_stdout( "Status: 200 OK\r\n" .
43             "Content-type: text/plain\r\n" .
44             "\r\n" .
45             "You requested $path" );
46             $req->finish();
47             }
48             );
49              
50             my $loop = IO::Async::Loop->new();
51              
52             $loop->add( $fcgi );
53              
54             $loop->run;
55              
56             =head1 DESCRIPTION
57              
58             Instances of this object class represent individual requests received from the
59             webserver that are currently in-progress, and have not yet been completed.
60             When given to the controlling program, each request will already have its
61             parameters (and, on servers without stdin streaming enabled, its STDIN data).
62             The program can then write response data to the STDOUT stream, messages to the
63             STDERR stream, and eventually finish it.
64              
65             This module would not be used directly by a program using
66             C, but rather, objects in this class are passed into the
67             C event of the containing C object.
68              
69             =cut
70              
71             sub new
72             {
73 24     24 0 72 my $class = shift;
74 24         218 my %args = @_;
75              
76 24         77 my $rec = $args{rec};
77              
78             my $self = bless {
79             conn => $args{conn},
80             fcgi => $args{fcgi},
81              
82             reqid => $rec->{reqid},
83             keepconn => $rec->{flags} & FCGI_KEEP_CONN,
84              
85             stdin => "",
86             stdindone => 0,
87             stream_stdin => $args{stream_stdin},
88              
89 24         362 params => {},
90             paramsdone => 0,
91              
92             stdout => "",
93             stderr => "",
94              
95             used_stderr => 0,
96             }, $class;
97              
98 24         189 $self->set_encoding( $args{fcgi}->_default_encoding );
99              
100 24         105 return $self;
101             }
102              
103             sub write_record
104             {
105 66     66 0 330 my $self = shift;
106 66         371 my ( $rec ) = @_;
107              
108 66 50       182 return if $self->is_aborted;
109              
110 66         158 my $content = $rec->{content};
111 66         166 my $contentlen = length( $content );
112 66 50       175 if( $contentlen > MAXRECORDDATA ) {
113 0         0 warn __PACKAGE__."->write_record() called with content longer than ".MAXRECORDDATA." bytes - truncating";
114 0         0 $content = substr( $content, 0, MAXRECORDDATA );
115             }
116              
117 66 50       229 $rec->{reqid} = $self->{reqid} unless defined $rec->{reqid};
118              
119 66         118 my $conn = $self->{conn};
120              
121 66         375 $conn->write_record( $rec, $content );
122              
123             }
124              
125             sub incomingrecord
126             {
127 73     73 0 138 my $self = shift;
128 73         175 my ( $rec ) = @_;
129              
130 73         166 my $type = $rec->{type};
131              
132 73 100       305 if( $type == FCGI_PARAMS ) {
    50          
133 41         166 $self->incomingrecord_params( $rec );
134             }
135             elsif( $type == FCGI_STDIN ) {
136 32         131 $self->incomingrecord_stdin( $rec );
137             }
138             else {
139 0         0 warn "$self just received unknown record type";
140             }
141             }
142              
143             sub _ready_check
144             {
145 52     52   89 my $self = shift;
146              
147 52 100 100     487 if( $self->{paramsdone} and ( $self->{stdindone} || $self->{stream_stdin} ) ) {
      66        
148 24         155 $self->{fcgi}->_request_ready( $self );
149             }
150             }
151              
152             sub incomingrecord_params
153             {
154 41     41 0 76 my $self = shift;
155 41         84 my ( $rec ) = @_;
156              
157 41         105 my $content = $rec->{content};
158 41         99 my $len = $rec->{len};
159              
160 41 100       128 if( $len ) {
161 18     18   11253 no warnings 'uninitialized';
  18         47  
  18         50541  
162 17         76 $self->{paramscontent} .= $content;
163 17         68 return;
164             }
165             else {
166 24         139 $self->{params} = parse_params( delete $self->{paramscontent} );
167 24         1868 $self->{paramsdone} = 1;
168             }
169              
170 24         161 $self->_ready_check;
171             }
172              
173             sub incomingrecord_stdin
174             {
175 32     32 0 158 my $self = shift;
176 32         146 my ( $rec ) = @_;
177              
178 32         166 my $content = $rec->{content};
179 32         105 my $len = $rec->{len};
180              
181 32 100       88 if( $len ) {
182 10         37 $self->{stdin} .= $content;
183             }
184             else {
185 22         52 $self->{stdindone} = 1;
186             }
187              
188 32 100       96 if( $self->{stream_stdin} ) {
189 4         8 $self->_flush_stdin;
190             }
191             else {
192 28         95 $self->_ready_check;
193             }
194             }
195              
196             sub _start
197             {
198 24     24   45 my $self = shift;
199 24         87 $self->{started} = 1;
200              
201 24 100 100     209 $self->_flush_stdin if $self->{stream_stdin} and length $self->{stdin};
202             }
203              
204             sub _flush_stdin
205             {
206 5     5   7 my $self = shift;
207              
208 5         7 my $on_stdin = $self->{on_stdin_read};
209 5 100       11 if( !$on_stdin ) {
210 1 50       5 warn "NaFastCGI::Request incoming STDIN data with on on_stdin_read\n" if $self->{started};
211 1         4 return;
212             }
213              
214             {
215 4         4 my $ret = $self->$on_stdin( \$self->{stdin}, $self->{stdindone} );
  13         35  
216 13 100 100     112 redo if $ret and length $self->{stdin};
217             }
218             }
219              
220             =head1 METHODS
221              
222             =cut
223              
224             =head2 params
225              
226             $hashref = $req->params;
227              
228             This method returns a reference to a hash containing a copy of the request
229             parameters that had been sent by the webserver as part of the request.
230              
231             =cut
232              
233             sub params
234             {
235 18     18 1 1178 my $self = shift;
236              
237 18         50 my %p = %{$self->{params}};
  18         190  
238              
239 18         185 return \%p;
240             }
241              
242             =head2 param
243              
244             $p = $req->param( $key );
245              
246             This method returns the value of a single request parameter, or C if no
247             such key exists.
248              
249             =cut
250              
251             sub param
252             {
253 20     20 1 90 my $self = shift;
254 20         59 my ( $key ) = @_;
255              
256 20         234 return $self->{params}{$key};
257             }
258              
259             =head2 method
260              
261             $method = $req->method;
262              
263             Returns the value of the C parameter, or C if there is no
264             value set for it.
265              
266             =cut
267              
268             sub method
269             {
270 2     2 1 5 my $self = shift;
271 2   50     8 return $self->param( "REQUEST_METHOD" ) || "GET";
272             }
273              
274             =head2 script_name
275              
276             $script_name = $req->script_name;
277              
278             Returns the value of the C parameter.
279              
280             =cut
281              
282             sub script_name
283             {
284 3     3 1 8 my $self = shift;
285 3         10 return $self->param( "SCRIPT_NAME" );
286             }
287              
288             =head2 path_info
289              
290             $path_info = $req->path_info;
291              
292             Returns the value of the C parameter.
293              
294             =cut
295              
296             sub path_info
297             {
298 3     3 1 9 my $self = shift;
299 3         8 return $self->param( "PATH_INFO" );
300             }
301              
302             =head2 path
303              
304             $path = $req->path;
305              
306             Returns the full request path by reconstructing it from C and
307             C.
308              
309             =cut
310              
311             sub path
312             {
313 2     2 1 5 my $self = shift;
314              
315 2   33     9 my $path = join "", grep defined && length,
316             $self->script_name,
317             $self->path_info;
318 2 50       11 $path = "/" if !length $path;
319              
320 2         11 return $path;
321             }
322              
323             =head2 query_string
324              
325             $query_string = $req->query_string;
326              
327             Returns the value of the C parameter.
328              
329             =cut
330              
331             sub query_string
332             {
333 2     2 1 5 my $self = shift;
334 2   100     8 return $self->param( "QUERY_STRING" ) || "";
335             }
336              
337             =head2 protocol
338              
339             $protocol = $req->protocol;
340              
341             Returns the value of the C parameter.
342              
343             =cut
344              
345             sub protocol
346             {
347 2     2 1 6 my $self = shift;
348 2         8 return $self->param( "SERVER_PROTOCOL" );
349             }
350              
351             =head2 set_encoding
352              
353             $req->set_encoding( $encoding );
354              
355             Sets the character encoding used by the request's STDIN, STDOUT and STDERR
356             streams. This method may be called at any time to change the encoding in
357             effect, which will be used the next time C, C,
358             C or C are called. This encoding will remain in
359             effect until changed again. The encoding of a new request is determined by the
360             C parameter of the containing C object.
361             If the value C is passed, the encoding will be removed, and the above
362             methods will work directly on bytes instead of encoded strings.
363              
364             =cut
365              
366             sub set_encoding
367             {
368 25     25 1 1882 my $self = shift;
369 25         78 my ( $encoding ) = @_;
370              
371 25 50       95 if( defined $encoding ) {
372 25         156 my $codec = find_encoding( $encoding );
373 25 50       1416 defined $codec or croak "Unrecognised encoding '$encoding'";
374 25         158 $self->{codec} = $codec;
375             }
376             else {
377 0         0 undef $self->{codec};
378             }
379             }
380              
381             =head2 read_stdin_line
382              
383             $line = $req->read_stdin_line;
384              
385             This method works similarly to the C<< >> operator. If at least one
386             line of data is available then it is returned, including the linefeed, and
387             removed from the buffer. If not, then any remaining partial line is returned
388             and removed from the buffer. If no data is available any more, then C
389             is returned instead.
390              
391             =cut
392              
393             sub read_stdin_line
394             {
395 13     13 1 1579 my $self = shift;
396 13 50       58 croak "Cannot call ->read_stdin_line on streaming-stdin requests" if $self->{stream_stdin};
397              
398 13         36 my $codec = $self->{codec};
399              
400 13 100       101 if( $self->{stdin} =~ s/^(.*[\r\n])// ) {
    100          
401 4 50       45 return $codec ? $codec->decode( $1 ) : $1;
402             }
403             elsif( $self->{stdin} =~ s/^(.+)// ) {
404 1 50       17 return $codec ? $codec->decode( $1 ) : $1;
405             }
406             else {
407 8         44 return undef;
408             }
409             }
410              
411             =head2 read_stdin
412              
413             $data = $req->read_stdin( $size );
414              
415             This method works similarly to the C function. It returns the
416             next block of up to $size bytes from the STDIN buffer. If no data is available
417             any more, then C is returned instead. If $size is not defined, then it
418             will return all the available data.
419              
420             =cut
421              
422             sub read_stdin
423             {
424 8     8 1 1041 my $self = shift;
425 8 50       45 croak "Cannot call ->read_stdin on streaming-stdin requests" if $self->{stream_stdin};
426 8         15 my ( $size ) = @_;
427              
428 8 100       29 return undef unless length $self->{stdin};
429              
430 6 100       13 $size = length $self->{stdin} unless defined $size;
431              
432 6         99 my $codec = $self->{codec};
433              
434             # If $size is too big, substr() will cope
435 6         37 my $bytes = substr( $self->{stdin}, 0, $size, "" );
436 6 50       61 return $codec ? $codec->decode( $bytes ) : $bytes;
437             }
438              
439             =head2 set_on_stdin_read
440              
441             $req->set_on_stdin_read( $on_stdin_read );
442              
443             $again = $on_stdin_read->( $req, $buffref, $eof );
444              
445             I
446              
447             Only valid on requests on servers with stdin streaming enabled.
448              
449             This method should be called as part of the C event on the server,
450             to set the callback function to invoke when new data is provided to the stdin
451             stream for this request.
452              
453             The callback function is invoked in a similar style to the C event
454             handler of an L. It is passed the request itself, along
455             with a SCALAR reference to the buffer containing the stdin data, and a boolean
456             indicating if the end of stdin data has been reached.
457              
458             It should inspect this buffer and remove some prefix of it that it wishes to
459             consume. Any remaining content will be present on the next call. If it returns
460             a true value, the callback will be invoked again immediately, to consume more
461             data. This continues until there is no more data left, or it returns false.
462              
463             =cut
464              
465             sub set_on_stdin_read
466             {
467 3     3 1 107 my $self = shift;
468 3 50       11 croak "Cannot call ->set_on_stdin_read except on streaming-stdin requests" unless $self->{stream_stdin};
469 3         11 ( $self->{on_stdin_read} ) = @_;
470             }
471              
472             sub _print_stream
473             {
474 23     23   49 my $self = shift;
475 23         84 my ( $data, $stream ) = @_;
476              
477 23         91 while( length $data ) {
478             # Send chunks of up to MAXRECORDDATA bytes at once
479 23         86 my $chunk = substr( $data, 0, MAXRECORDDATA, "" );
480 23         141 $self->write_record( { type => $stream, content => $chunk } );
481             }
482             }
483              
484             sub _flush_streams
485             {
486 36     36   91 my $self = shift;
487              
488 36 100       205 if( length $self->{stdout} ) {
    100          
489 20         95 $self->_print_stream( $self->{stdout}, FCGI_STDOUT );
490 20         3478 $self->{stdout} = "";
491             }
492             elsif( my $cb = $self->{stdout_cb} ) {
493 4         11 $cb->();
494             }
495              
496 36 100       521 if( length $self->{stderr} ) {
497 3         15 $self->_print_stream( $self->{stderr}, FCGI_STDERR );
498 3         553 $self->{stderr} = "";
499             }
500             }
501              
502             sub _needs_flush
503             {
504 16     16   31 my $self = shift;
505 16         96 return defined $self->{stdout_cb};
506             }
507              
508             =head2 print_stdout
509              
510             $req->print_stdout( $data );
511              
512             This method appends the given data to the STDOUT stream of the FastCGI
513             request, sending it to the webserver to be sent to the client.
514              
515             =cut
516              
517             sub print_stdout
518             {
519 41     41 1 2100 my $self = shift;
520 41         91 my ( $data ) = @_;
521              
522 41         95 my $codec = $self->{codec};
523              
524 41 50       336 $self->{stdout} .= $codec ? $codec->encode( $data ) : $data;
525              
526 41         191 $self->{conn}->_req_needs_flush( $self );
527             }
528              
529             =head2 print_stderr
530              
531             $req->print_stderr( $data );
532              
533             This method appends the given data to the STDERR stream of the FastCGI
534             request, sending it to the webserver.
535              
536             =cut
537              
538             sub print_stderr
539             {
540 3     3 1 7 my $self = shift;
541 3         10 my ( $data ) = @_;
542              
543 3         10 my $codec = $self->{codec};
544              
545 3         7 $self->{used_stderr} = 1;
546 3 50       32 $self->{stderr} .= $codec ? $codec->encode( $data ) : $data;
547              
548 3         1536 $self->{conn}->_req_needs_flush( $self );
549             }
550              
551             =head2 stream_stdout_then_finish
552              
553             $req->stream_stdout_then_finish( $readfn, $exitcode );
554              
555             This method installs a callback for streaming data to the STDOUT stream.
556             Whenever the output stream is otherwise-idle, the function will be called to
557             generate some more data to output. When this function returns C it
558             indicates the end of the stream, and the request will be finished with the
559             given exit code.
560              
561             If this method is used, then care should be taken to ensure that the number of
562             bytes written to the server matches the number that was claimed in the
563             C, if such was provided. This logic should be performed by the
564             containing application; C will not track it.
565              
566             =cut
567              
568             sub stream_stdout_then_finish
569             {
570 2     2 1 4 my $self = shift;
571 2         7 my ( $readfn, $exitcode ) = @_;
572              
573             $self->{stdout_cb} = sub {
574 4     4   15 my $data = $readfn->();
575              
576 4 100       32 if( defined $data ) {
577 2         9 $self->print_stdout( $data );
578             }
579             else {
580 2         8 delete $self->{stdout_cb};
581 2         12 $self->finish( $exitcode );
582             }
583 2         15 };
584              
585 2         15 $self->{conn}->_req_needs_flush( $self );
586             }
587              
588             =head2 stdin
589              
590             $stdin = $req->stdin;
591              
592             Returns an IO handle representing the request's STDIN buffer. This may be read
593             from using the C or C functions or the C<< <$stdin> >>
594             operator.
595              
596             Note that this will be a tied IO handle, it will not be useable directly as an
597             OS-level filehandle.
598              
599             =cut
600              
601             sub stdin
602             {
603 7     7 1 120 my $self = shift;
604              
605             return Net::Async::FastCGI::Request::TiedHandle->new(
606             READ => sub {
607 3     3   16 $_[1] = $self->read_stdin( $_[2] );
608 3 100       35 return defined $_[1] ? length $_[1] : 0;
609             },
610             READLINE => sub {
611 1     1   3 return $self->read_stdin_line;
612             },
613 7         100 );
614             }
615              
616             =head2 stdout
617              
618             =head2 stderr
619              
620             $stdout = $req->stdout;
621              
622             $stderr = $req->stderr;
623              
624             Returns an IO handle representing the request's STDOUT or STDERR streams
625             respectively. These may written to using C, C, C, etc..
626              
627             Note that these will be tied IO handles, they will not be useable directly as
628             an OS-level filehandle.
629              
630             =cut
631              
632             sub _stdouterr
633             {
634 8     8   16 my $self = shift;
635 8         21 my ( $method ) = @_;
636              
637             return Net::Async::FastCGI::Request::TiedHandle->new(
638 3     3   15 WRITE => sub { $self->$method( $_[1] ) },
639 8         74 );
640             }
641              
642             sub stdout
643             {
644 1     1 1 4 return shift->_stdouterr( "print_stdout" );
645             }
646              
647             sub stderr
648             {
649 7     7 1 2981 return shift->_stdouterr( "print_stderr" );
650             }
651              
652             =head2 finish
653              
654             $req->finish( $exitcode );
655              
656             When the request has been dealt with, this method should be called to indicate
657             to the webserver that it is finished. After calling this method, no more data
658             may be appended to the STDOUT stream. At some point after calling this method,
659             the request object will be removed from the containing C
660             object, once all the buffered outbound data has been sent.
661              
662             If present, C<$exitcode> should indicate the numeric status code to send to
663             the webserver. If absent, a value of C<0> is presumed.
664              
665             =cut
666              
667             sub finish
668             {
669 21     21 1 2447 my $self = shift;
670 21         59 my ( $exitcode ) = @_;
671              
672 21 100       113 return if $self->is_aborted;
673              
674 20         109 $self->_flush_streams;
675              
676             # Signal the end of STDOUT
677 20         135 $self->write_record( { type => FCGI_STDOUT, content => "" } );
678              
679             # Signal the end of STDERR if we used it
680 20 100       4587 $self->write_record( { type => FCGI_STDERR, content => "" } ) if $self->{used_stderr};
681              
682 20   100     586 $self->write_record( { type => FCGI_END_REQUEST,
683             content => build_end_request_body( $exitcode || 0, FCGI_REQUEST_COMPLETE )
684             } );
685              
686 20         3684 my $conn = $self->{conn};
687              
688 20 100       86 if( $self->{keepconn} ) {
689 12         63 $conn->_removereq( $self->{reqid} );
690             }
691             else {
692 8         98 $conn->close;
693             }
694             }
695              
696             =head2 stdout_with_close
697              
698             $stdout = $req->stdout_with_close;
699              
700             Similar to the C method, except that when the C method is
701             called on the returned filehandle, the request will be finished by calling
702             C.
703              
704             =cut
705              
706             sub stdout_with_close
707             {
708 1     1 1 2 my $self = shift;
709              
710             return Net::Async::FastCGI::Request::TiedHandle->new(
711 2     2   11 WRITE => sub { $self->print_stdout( $_[1] ) },
712 1     1   64 CLOSE => sub { $self->finish( 0 ) },
713 1         7 );
714             }
715              
716             sub _abort
717             {
718 9     9   17 my $self = shift;
719 9         27 $self->{aborted} = 1;
720              
721 9         20 my $conn = $self->{conn};
722 9         55 $conn->_removereq( $self->{reqid} );
723              
724 9         40 delete $self->{stdout_cb};
725             }
726              
727             =head2 is_aborted
728              
729             $req->is_aborted;
730              
731             Returns true if the webserver has already closed the control connection. No
732             further work on this request is necessary, as it will be discarded.
733              
734             It is not required to call this method; if the request is aborted then any
735             output will be discarded. It may however be useful to call just before
736             expensive operations, in case effort can be avoided if it would otherwise be
737             wasted.
738              
739             =cut
740              
741             sub is_aborted
742             {
743 90     90 1 697 my $self = shift;
744 90         349 return $self->{aborted};
745             }
746              
747             =head1 HTTP::Request/Response Interface
748              
749             The following pair of methods form an interface that allows the request to be
750             used as a source of L objects, responding to them by sending
751             L objects. This may be useful to fit it in to existing code
752             that already uses these.
753              
754             =cut
755              
756             =head2 as_http_request
757              
758             $http_req = $req->as_http_request;
759              
760             Returns a new C object that gives a reasonable approximation to
761             the request. Because the webserver has translated the original HTTP request
762             into FastCGI parameters, this may not be a perfect recreation of the request
763             as received by the webserver.
764              
765             =cut
766              
767             sub as_http_request
768             {
769 1     1 1 125 my $self = shift;
770              
771 1         722 require HTTP::Request;
772              
773 1         24348 my $params = $self->params;
774              
775             my $authority =
776             ( $params->{HTTP_HOST} || $params->{SERVER_NAME} || "" ) . ":" .
777 1   0     10 ( $params->{SERVER_PORT} || "80" );
      50        
778              
779 1         5 my $path = $self->path;
780 1         5 my $query_string = $self->query_string;
781              
782 1 50       5 $path .= "?$query_string" if length $query_string;
783              
784 1         7 my $uri = URI->new( "http://$authority$path" )->canonical;
785              
786 1         10557 my @headers;
787              
788             # Content-Type and Content-Length come specially
789             push @headers, "Content-Type" => $params->{CONTENT_TYPE}
790 1 50       10 if exists $params->{CONTENT_TYPE};
791              
792             push @headers, "Content-Length" => $params->{CONTENT_LENGTH}
793 1 50       24 if exists $params->{CONTENT_LENGTH};
794              
795             # Pull all the HTTP_FOO parameters as headers. These will be in all-caps
796             # and use _ for word separators, but HTTP::Headers can cope
797 1         7 foreach ( keys %$params ) {
798 11 100       24 m/^HTTP_(.*)$/ and push @headers, $1 => $params->{$_};
799             }
800              
801 1         3 my $content = $self->{stdin};
802              
803 1         5 my $req = HTTP::Request->new( $self->method, $uri, \@headers, $content );
804              
805 1         181 $req->protocol( $self->protocol );
806              
807 1         24 return $req;
808             }
809              
810             =head2 send_http_response
811              
812             $req->send_http_response( $resp );
813              
814             Sends the given C object as the response to this request. The
815             status, headers and content are all written out to the request's STDOUT stream
816             and then the request is finished with 0 as the exit code.
817              
818             =cut
819              
820             sub send_http_response
821             {
822 1     1 1 15451 my $self = shift;
823 1         4 my ( $resp ) = @_;
824              
825             # (Fast)CGI suggests this is the way to report the status
826 1         6 $resp->header( Status => $resp->code );
827              
828 1         107 my $topline = $resp->protocol . " " . $resp->status_line;
829              
830 1         43 $self->print_stdout( $topline . $CRLF );
831 1         314 $self->print_stdout( $resp->headers_as_string( $CRLF ) );
832              
833 1         5 $self->print_stdout( $CRLF );
834              
835 1         3 $self->print_stdout( $resp->content );
836 1         5 $self->finish( 0 );
837             }
838              
839             package # hide from CPAN
840             Net::Async::FastCGI::Request::TiedHandle;
841 18     18   186 use base qw( Tie::Handle );
  18         52  
  18         10683  
842              
843 18     18   38887 use Symbol qw( gensym );
  18         44  
  18         4360  
844              
845             sub new
846             {
847 16     16   30 my $class = shift;
848              
849 16         50 my $handle = gensym;
850 16         471 tie *$handle, $class, @_;
851              
852 16         99 return $handle;
853             }
854              
855             sub TIEHANDLE
856             {
857 16     16   33 my $class = shift;
858 16         81 return bless { @_ }, $class;
859             }
860              
861 1     1   550 sub CLOSE { shift->{CLOSE}->( @_ ) }
862 3     3   594 sub READ { shift->{READ}->( @_ ) }
863 1     1   5774 sub READLINE { shift->{READLINE}->( @_ ) }
864 5     5   40611 sub WRITE { shift->{WRITE}->( @_ ) }
865              
866             =head1 EXAMPLES
867              
868             =head2 Streaming A File
869              
870             To serve contents of files on disk, it may be more efficient to use
871             C:
872              
873             use Net::Async::FastCGI;
874             use IO::Async::Loop;
875              
876             my $fcgi = Net::Async::FastCGI->new(
877             on_request => sub {
878             my ( $fcgi, $req ) = @_;
879              
880             open( my $file, "<", "/path/to/file" );
881             $req->print_stdout( "Status: 200 OK\r\n" .
882             "Content-type: application/octet-stream\r\n" .
883             "\r\n" );
884              
885             $req->stream_stdout_then_finish(
886             sub { read( $file, my $buffer, 8192 ) or return undef; return $buffer },
887             0
888             );
889             }
890              
891             my $loop = IO::Async::Loop->new();
892              
893             $loop->add( $fcgi );
894              
895             $loop->run;
896              
897             It may be more efficient again to instead use the C feature of
898             certain webservers, which allows the webserver itself to serve the file
899             efficiently. See your webserver's documentation for more detail.
900              
901             =head1 AUTHOR
902              
903             Paul Evans
904              
905             =cut
906              
907             0x55AA;