3 # CGI::FCGI -- Alternative Pure Perl CGI::Fast and FCGI implementation
4 # Copyright (C) 2015,2016,2017,2020 Kyle J. McKay.
7 # Licensed under the same license as Perl OR GNU GPL v2 or later
8 # There is NO WARRANTY, to the extent permitted by law.
9 # See license below starting with '=head1 LICENSE'
11 # See documentation below starting with '=head1'
13 # MUST be used BEFORE CGI::Fast and FCGI.
15 $CGI::FCGI
::VERSION
= '1.0';
32 my $name = $subtoname->(__PACKAGE__
);
33 $INC{$name} = __FILE__
if !$INC{$name};
34 foreach my $pkg (qw(CGI::Fast FCGI)) {
35 my $pkgn = $subtoname->($pkg);
36 croak
"Must `use ".__PACKAGE__
.";` ".
38 if $INC{$pkgn} && $INC{$pkgn} ne $INC{$name};
39 $INC{$pkgn} = $INC{$name};
47 FCGI_MAX_CONNS
=> 1, # Maximum concurrent connections
48 FCGI_MAX_REQS
=> 1, # Max concurrent requests on a connection
49 FCGI_MPXS_CONNS
=> 0, # No multiplexing capabilities here
54 3 => "FILTER", # Not currently supported
59 open my $fh, '+<&0' or return 0;
60 return 0 unless getsockname $fh;
61 defined(my $st = getsockopt($fh, SOL_SOCKET
, SO_TYPE
)) or return 0;
62 $st = unpack("i", $st);
63 defined($st) && $st == SOCK_STREAM
or return 0;
64 return 0 if getpeername $fh;
65 return $!{ENOTCONN
} ?
1 : 0;
69 # Make sure state's not saved
82 return unless !$is_inited;
86 croak
'STDIN_FILENO (0) is not an accept socket' unless IsFCGI
;
88 open ASOCK
, '<&=0' or croak
'STDIN_FILENO (0) is not valid';
89 $fcgi{'asock'} = *ASOCK
;
95 return unless defined $data;
97 my $len = length $data;
99 my $cnt = syswrite $fh, $data, $len, $offset;
100 next if !defined($cnt) && $!{EINTR
};
101 croak
"syswrite failed: $!" unless defined $cnt;
102 croak
"syswrite of $len wrote 0" unless $cnt;
112 return undef unless defined $cnt && $cnt >= 0;
115 while ($len < $cnt) {
116 my $r = sysread $fh, $data, $cnt - $len, $len;
117 next if !defined($r) && $!{EINTR
};
118 croak
"sysread failed: $!" unless defined $r;
119 return '' if $eofok && !$r && !$len; # EOF at beginning okay
120 croak
"sysread of @{[$cnt - $len]} read 0" unless $r;
129 return undef unless defined $cnt && $cnt >= 0;
131 while ($len < $cnt) {
133 my $r = sysread $fh, $data, 32768;
134 next if !defined($r) && $!{EINTR
};
135 croak
"sysread failed: $!" unless defined $r;
136 croak
"sysread of 32768 read 0" unless $r;
144 my $offset = shift || 0;
145 my $discardvalue = shift || 0;
146 my $len = length($data);
147 croak
"_read_one_var invalid input" unless $offset >= 0 && $offset + 3 <= $len;
149 my $nlen = unpack('C', substr($data, $ptr++, 1));
151 croak
"_read_one_var invalid input" unless $ptr + 5 <= $len;
152 my @bytes = unpack('CCC', substr($data, $ptr, 3));
154 $nlen = (($nlen & 0x7f) << 24) | ($bytes[0] << 16) |
155 ($bytes[1] << 8) | $bytes[2];
157 my $vlen = unpack('C', substr($data, $ptr++, 1));
159 croak
"_read_one_var invalid input" unless $ptr + 4 <= $len;
160 my @bytes = unpack('CCC', substr($data, $ptr, 3));
162 $vlen = (($vlen & 0x7f) << 24) | ($bytes[0] << 16) |
163 ($bytes[1] << 8) | $bytes[2];
165 croak
"FCGI out of bounds var name/value length" if $ptr + $nlen + $vlen > $len;
167 _read_discard
($fcgi{'csock'}, $nlen + $vlen);
168 return ("_ZERO_LENGTH_VAR_NAME", "", $ptr - $offset + $nlen + $vlen);
171 _read_discard
($fcgi{'csock'}, $nlen + $vlen);
172 return ("_TOO_LONG_VAR_NAME", "", $ptr - $offset + $nlen + $vlen);
175 _read_discard
($fcgi{'csock'}, $nlen + $vlen);
176 return ("_TOO_LONG_VAR_VAL", "", $ptr - $offset + $nlen + $vlen);
178 return (substr($data, $ptr, $nlen),
179 ($discardvalue ?
undef : substr($data, $ptr+$nlen, $vlen)),
180 $ptr - $offset + $nlen + $vlen);
185 return pack('C', ($l & 0x7f)) if $l < 128;
193 return pack('CCCC', $b3, $b2, $b1, $b0);
196 sub _encode_one_var
{
198 return _encode_length
(length($n)).
199 _encode_length
(length($v)).
205 my $rem = $len & 0x7;
206 return '' unless $rem;
207 return pack('C', 0) x
(8 - $rem);
216 return unless ($type == 6 || $type == 7) && length($data) || $force;
217 my $padding = _get_padding
(length($data));
218 _write_all
($fh, pack('CCnnCC', 1, $type, $rid, length($data), length($padding), 0).$data.$padding);
221 sub _write_end_stream
{
225 return _write_stream
($fh, $type, $rid, '', 1);
228 sub _write_end_request
{
231 my $pstat = shift || 0;
232 my $astat = shift || 0;
233 _write_all
($fh, pack('CCnnCCNCCCC',
234 1, 3, $rid, 8, 0, 0, $astat, $pstat, 0, 0, 0));
237 sub _handle_unknown_packet
{
238 my ($fh, $rid, $clen, $plen) = @_;
239 croak
"FCGI invalid unkown packet content length $clen (must be >= 1)"
241 my $t = _read_all
($fh, 1);
242 _read_discard
($fh, $clen + $plen - 1);
243 _write_all
($fh, pack('CCnnCCCCCCCCCC',
244 1, 11, $rid, 8, 0, 0, unpack('C', $t), 0, 0, 0, 0, 0, 0, 0));
247 sub _handle_get_params
{
248 my ($fh, $rid, $clen, $plen) = @_;
249 my $varnames = _read_all
($fh, $clen);
250 _read_discard
($fh, $plen);
253 my $len = length($varnames);
254 while ($offset < $len) {
255 my ($n, undef, $b) = _read_one_var
($varnames, $offset, 1);
261 map({exists($PARAMS{$_}) ? _encode_one_var
($_, $PARAMS{$_}) : ()} @v))
263 _write_stream
($fh, 10, $rid, $vars, 1);
266 # Can only return types 1, 2, 4, 5, or 8
267 # And for types 1 and 2 the packet is fully read along with its padding
272 my ($type, $rid, $clen, $plen);
274 my $request = _read_all
($fh, 8, $eofok);
275 return undef if !defined($request) && $eofok;
277 ($vers, $type, $rid, $clen, $plen) = unpack('CCnnC', $request);
278 croak
"FCGI bad packet header version $vers (should be 1)"
280 croak
"FCGI invalid packet type $type (should be 1..11)"
281 unless $type >= 1 && $type <= 11;
282 croak
"FCGI unexpected packet type $type (should be 1, 2, 4, 5, 8, 9 or 11)"
283 if $type == 3 || $type == 6 || $type == 7 || $type == 10;
284 _handle_get_params
($fh, $rid, $clen, $plen), redo if $type == 9;
285 _handle_unknown_packet
($fh, $rid, $clen, $plen), redo if $type == 11;
286 croak
"FCGI invalid BEGIN content length $clen (should be 8)"
287 if $type == 1 && $clen != 8;
288 croak
"FCGI invalid ABORT content length $clen (should be 0)"
289 if $type == 2 && $clen != 0;
290 croak
"FCGI invalid requestId == 0 for BEGIN/ABORT/PARAMS/STDIN/DATA"
291 if ($type <= 2 || $type == 4 || $type == 5 || $type == 8) && !$rid;
295 my $begin = _read_all
($fh, $clen);
296 _read_discard
($fh, $plen);
297 ($role, $flags) = unpack('nC', $begin);
300 _read_discard
($fh, $plen);
302 return ($type, $rid, $clen, $plen, $role, $flags);
306 return unless $active{'active'};
307 my $pstat = shift || 0;
308 my $astat = shift || 0;
309 my $done = shift || 0;
310 _write_end_stream
($fcgi{'csock'}, 6, $active{'active'}) if $done;
311 _write_end_request
($fcgi{'csock'}, $active{'active'}, $pstat, $astat);
312 *STDIN
= $active{'STDIN'};
313 *STDOUT
= $active{'STDOUT'};
314 *STDERR
= $active{'STDERR'};
315 %ENV = %{$active{'ENV'}};
317 unless ($active{'keep'}) {
318 close($fcgi{'csock'});
319 undef $fcgi{'csock'};
326 _init
unless $is_inited;
327 _close_active
(0, 0, 1) if $active{'active'};
330 while (!$active{'active'}) {
331 while (!$fcgi{'csock'}) {
333 unless (accept(CSOCK
, $fcgi{'asock'})) {
334 next if $!{EINTR
} || $!{ECONNABORTED
};
335 croak
"accept failed: $!";
337 $fcgi{'csock'} = *CSOCK
;
339 my ($type, $rid, $clen, $plen, $role, $flags) = _read_packet
($fcgi{'csock'}, 1);
341 close($fcgi{'csock'});
342 undef $fcgi{'csock'};
345 _read_discard
($fcgi{'csock'}, $clen+$plen), redo if $type == 5 || $type == 8;
346 croak
"FCGI unexpected packet type $type (expecting 1 -- BEGIN)"
348 if ($role != 1 && $role != 2) {
349 _write_end_request
($fcgi{'csock'}, $rid, 3);
350 unless($flags & 0x01) {
351 close($fcgi{'csock'});
352 undef $fcgi{'csock'};
356 $active{'active'} = $rid;
357 $active{'role'} = $role;
358 $active{'keep'} = 1 if $flags & 0x01;
359 $active{'STDIN'} = *STDIN
;
360 $active{'STDOUT'} = *STDOUT
;
361 $active{'STDERR'} = *STDERR
;
363 $active{'ENV'} = \
%saveenv;
368 my ($type, $rid, $clen, $plen) = _read_packet
($fcgi{'csock'});
370 _write_end_request
($fcgi{'sock'}, $rid, 1)
371 unless $rid == $active{'active'};
374 redo unless $rid == $active{'active'};
379 croak
"FCGI unexpected packet type $type (expecting 4 -- PARAMS)"
382 my $vars = _read_all
($fcgi{'csock'}, $clen);
383 _read_discard
($plen);
385 my $len = length($vars);
386 while ($offset < $len) {
387 my ($n, $v, $b) = _read_one_var
($vars, $offset);
393 _read_discard
($plen);
395 $vars{'FCGI_ROLE'} = $ROLES{$active{'role'}}; # We must add this
397 # Tie the streams, set %ENV and off we go!
399 tie
*TI
, 'CGI::FCGI::IStream' or croak
"CGI::FCGI::IStream tie STDIN failed";
401 tie
*TO
, 'CGI::FCGI::OStream', 6 or croak
"CGI::FCGI::IStream tie STDOUT failed";
403 tie
*TE
, 'CGI::FCGI::OStream', 7 or croak
"CGI::FCGI::IStream tie STDERR failed";
408 $ENV{$n} = $v while ($n,$v) = each %vars;
412 my $min = shift || 1;
413 return '' unless $active{'active'};
415 while (!$active{'eof'} && $min > 0) {
416 my ($type, $rid, $clen, $plen) = _read_packet
($fcgi{'csock'});
418 _write_end_request
($fcgi{'sock'}, $rid, 1)
419 unless $rid == $active{'active'};
422 redo unless $rid == $active{'active'};
427 croak
"FCGI unexpected packet type $type (expecting 5 -- STDIN)"
429 my $input = _read_all
($fcgi{'csock'}, $clen);
430 _read_discard
($fcgi{'sock'}, $plen);
431 $min -= length($input);
432 $active{'eof'} = 1 unless length($input);
441 return unless $active{'active'};
442 _write_stream
($fcgi{'csock'}, $type, $active{'active'}, $data)
443 if defined($data) && length($data);
448 my ($class, $package) = @_;
449 $package or $package = __PACKAGE__
;
450 my $try = ref $class || $class || $package;
451 UNIVERSAL
::isa
($try, $package)
452 or croak
"Cannot call ${package}::new with a class ($try)".
453 " that does not inherit from $package";
458 my $class = _get_new_class
(shift);
460 CGI
->_reset_globals();
461 $class->_setup_symbols(@CGI::SAVED_SYMBOLS
) if @CGI::SAVED_SYMBOLS
;
463 my $self = $CGI::Q
= $class->SUPER::new
(@_);
464 $self->{'.fcgi_generation'} = $generation if $self;
470 $self->SUPER::DESTROY
if $self->can('SUPER::DESTROY');
471 _close_active
(0, 0, 1)
472 if $active{'active'} && $self->{'.fcgi_generation'} == $generation;
475 sub CGI
::FCGI
::Raw
::new
{
476 my $class = _get_new_class
(shift, 'CGI::FCGI::Raw');
480 $self->{'.fcgi_generation'} = $generation if $self;
484 sub CGI
::FCGI
::Raw
::DESTROY
{
486 _close_active
(0, 0, 1)
487 if $active{'active'} && $self->{'.fcgi_generation'} == $generation;
490 sub CGI
::FCGI
::Raw
::ResetCGI
{
492 CGI
->_reset_globals();
493 CGI
->_setup_symbols(@CGI::SAVED_SYMBOLS
) if @CGI::SAVED_SYMBOLS
;
497 package CGI
::FCGI
::IStream
;
504 $self->{'buffer'} = '';
505 return bless $self, $class;
519 if (!$self->{'eof'}) {
520 my $more = CGI
::FCGI
::_read_more
($min);
521 $self->{'eof'} = 1 if !length($more);
522 $self->{'buffer'} .= $more;
529 if !$self->{'eof'} && !length($self->{'buffer'});
530 return $self->{'eof'} ?
1 : 0;
536 if !$self->{'eof'} && !length($self->{'buffer'});
537 return undef unless length($self->{'buffer'});
538 my $c = substr($self->{'buffer'}, 0, 1);
539 substr($self->{'buffer'}, 0, 1) = '';
544 my ($self, undef, $length, $offset) = @_;
546 $offset = 0 unless defined($offset);
547 $$bufref = '' unless defined($$bufref);
548 croak
"CGI::FCGI::IStream::READ invalid length $length"
550 $offset += length($$bufref) if $offset < 0;
551 croak
"CGI::FCGI::IStream::READ invalid read offset"
552 if $offset > length($$bufref);
553 $self->_read_more(length($self->{'buffer'} - $length))
554 if length($self->{'buffer'}) < $length;
555 $length = length($self->{'buffer'}) if $length > length($self->{'buffer'});
556 substr($$bufref, $offset) = substr($self->{'buffer'}, 0, $length);
557 substr($self->{'buffer'}, 0, $length) = '';
563 if (ref($/) eq 'SCALAR') {
564 $self->_read_more(${$/} - length($self->{'buffer'}))
565 if !$self->{'eof'} && length($self->{'buffer'}) < ${$/};
566 my $ans = substr($self->{'buffer'}, 0, ${$/});
567 substr($self->{'buffer'}, 0, ${$/}) = '';
569 } elsif (defined($/)) {
572 my $d = $/ eq '' ? "\n\n" : $/;
573 while (($pos = index($self->{'buffer'}, $d, $offset)) < 0 && !$self->{'eof'}) {
574 $offset += length($self->{'buffer'}) - (length($d) - 1);
582 if !$self->{'eeof'} && length($self->{'buffer'}) <= $pos;
584 if substr($self->{'buffer'}, $pos, 1) eq "\n";
586 my $ans = substr($self->{'buffer'}, 0, $cpos);
587 substr($self->{'buffer'}, 0, $pos) = '';
591 $self->_read_more(32768) while !$self->{'eof'};
593 return undef unless length($self->{'buffer'});
594 my $ans = $self->{'buffer'};
595 $self->{'buffer'} = '';
604 push(@a, $l) while defined($l = $self->_read_line);
607 return $self->_read_line;
618 package CGI
::FCGI
::OStream
;
626 $self->{'type'} = $type;
627 return bless $self, $class;
651 my $template = shift;
652 return $self->PRINT(sprintf $template, @_);
655 sub PRINT
{goto &FCGI
::Stream
::PRINT
}
657 sub FCGI
::Stream
::PRINT
{
659 CGI
::FCGI
::_write_more
($self->{'type'}, join('', @_));
665 my ($scalar, $length, $offset) = @_;
666 $scalar = '' if !defined($scalar);
667 $length = length($scalar) if !defined($length);
668 croak
"CGI::FCGI::OStream::WRITE invalid length $length"
670 $offset = 0 if !defined($offset);
671 $offset += length($scalar) if $offset < 0;
672 croak
"CGI::FCGI::OStream::WRITE invalid write offset"
673 if $offset < 0 || $offset > $length;
674 my $max = length($scalar) - $offset;
675 $length = $max if $length > $max;
676 $self->PRINT(substr($scalar, $offset, $length));
684 sub new
{croak
'FCGI->new is not permitted when `use CGI::FCGI;` is in effect'}
688 our @ISA = ('CGI::FCGI');
690 sub new
{goto &CGI
::FCGI
::new
}
696 CGI::FCGI - Alternative CGI::Fast and FCGI Interface
701 use CGI qw/ :standard /;
705 if (CGI::FCGI::IsFCGI) {
710 while (my $q = $CGI->new) {
712 last unless --$maxrequests;
718 # Perform standard CGI processing for one request
725 CGI::FCGI is intended as a bare bones Pure Perl replacement for
726 both CGI::Fast and FCGI. It's lightweight and supports the most
727 common use case of wanting to support FastCGI but missing one
728 or both of the CGI::Fast and FCGI modules.
730 It only supports 'RESPONDER' and 'AUTHORIZER' roles (the
731 'RESPONDER' role corresponding to standard CGI applications) and it
732 only handles one request at a time on one socket at a time. For
733 compatibility with FCGI.pm, the FCGI_ROLE environment variable is always
734 set to either "RESPONDER" or "AUTHORIZER".
736 Nevertheless, this is quite sufficient to reap a huge performance
737 gain as Perl need not be restarted once for every CGI request.
739 Note that just like FCGI, input/output is always byte oriented so
740 the caller is responsible for decoding/encoding as needed. To
741 facilitate compatibility with the standard FCGI, the tied output
742 streams call a FCGI::Stream::PRINT function which contains the
743 actual PRINT implementation and may be head-patched in exactly
744 the same manner as the standard FCGI::Stream::PRINT implemention
745 to provide UTF-8 encoding on output.
747 Other than CGI::Fast::new and FCGI::Stream::PRINT, B<none> of the
748 other standard CGI::Fast or FCGI functions are provided!
750 Remember, if using CGI::FCGI::Raw to allow custom handling of any
751 'POST' data, the data B<MUST> be read from <STDIN> and B<NOT>
752 the <ARGV> file handle which is also known as <>.
758 =item CGI::FCGI::IsFCGI
760 Returns true if STDIN_FILENO appears to be a FastCGI socket.
762 As there's not a direct equivalent in CGI::Fast or FCGI, don't
763 call this if code is to be interchangeable between CGI::FCGI and
768 Returns a new CGI instance for the next request. Returns undef
769 if the listen socket has been closed. All arguments are passed
774 Convenient alias for CGI::FCGI::new, all arguments are passed
777 =item CGI::FCGI::Raw::new
779 Returns a new instance for the next request that is B<NOT> a CGI instance.
780 This is similar to FCGI::Request()->Accept() but can be used in a loop just the
781 same way CGI::FCGI::new (or the equivalent CGI::Fast::new) can. While the
782 returned instance is alive, STDIN, STDOUT, STDERR and %ENV are directed to the
783 request being serviced (in just the same way as for CGI::FCGI::new), but
784 B<none> of the CGI processing happens (e.g. slurping up 'POST' data, parsing
785 QUERY_STRING, etc.) as the instance is B<NOT> a CGI instance and for the same
786 reason B<NONE> of the standard CGI methods are available on the instance.
787 No arguments are passed up to CGI since the new instance is B<NOT> a CGI.
788 Returns undef if the listen socket has been closed. However, it is possible
789 to explicitly create a new CGI instance (CGI->new) after calling this function
790 provided the CGI global state has first been reset to its normal "empty" state.
791 See the CGI::FCGI::Raw::ResetCGI function for help with this.
793 =item CGI::FCGI::Raw::ResetCGI
795 Resets the global CGI state so that a call to CGI->new will create a new
796 CGI instance from the current environment in %ENV without being influenced by a
797 previously handled request.
799 Do B<NOT> call this unless the "Raw" interface is being used! The regular
800 interface (CGI::FCGI::new or CGI::Fast::new) takes care of this automatically.
802 When using the "Raw" interface (i.e. CGI::FCGI::Raw::new) B<AND> then calling
803 CGI->new directly, this function should be called B<AFTER> CGI::FCGI::Raw::new
804 but B<BEFORE> CGI->new to make sure that CGI->new doesn't return an instance
805 with leftover configuration and/or data from a previously handled request.
807 =item FCGI::Stream::PRINT
809 All stream output passes through this function which may be head-patched
810 to perform custom processing such as UTF-8 encoding. This is the same
811 name used by the standard FCGI module for compatibility.
817 Although the implementation is Pure Perl, it I<does> make heavy use of
818 the socket functions so may not function properly on platforms where the
819 socket functions are not available or only partially supported.
821 This module must be use'd B<before> CGI::Fast and FCGI otherwise it
822 will die with a fatal error.
824 While a request is active, STDIN, STDOUT, STDERR and %ENV are temporarily
825 altered and there's no option to do otherwise.
827 When a new request is started, the current values of the STDIN, STDOUT,
828 STDERR, %ENV and $/ variables are preserved before tying STDIN, STDOUT,
829 STDERR and adding received variables to %ENV.
831 When the request ends (i.e. it's DESTROY'd) those variables are restored
832 to the values they had just prior to the start of the request therefore
833 changes to any of those variables during the processing of a request are,
834 deliberately, nonpersistent.
838 CGI::FCGI Copyright (C) 2015,2016,2017,2020 Kyle J. McKay. All rights reserved.
840 This library is free software; you can redistribute it and/or modify
841 it under the same terms as Perl itself or under the terms of the
842 GNU General Public License version 2 (or, at your option, any later
845 This program is distributed in the hope that it will be useful,
846 but WITHOUT ANY WARRANTY; without even the implied warranty of
847 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
849 Address feedback to mackyle <at> gmail.com.