FU: Some FastCGI fixes; FU::Util: utf8_decode & URI escaping
This commit is contained in:
parent
d9fba4e8d8
commit
90cfd66069
6 changed files with 146 additions and 33 deletions
39
FU.pm
39
FU.pm
|
|
@ -163,13 +163,6 @@ sub _monitor {
|
|||
}
|
||||
|
||||
|
||||
sub _decode_utf8 {
|
||||
return if !defined $_[0];
|
||||
fu->error(400, 'Invalid UTF-8 in request') if !utf8::decode($_[0]);
|
||||
# Disallow any control codes, except for x09 (tab), x0a (newline) and x0d (carriage return)
|
||||
fu->error(400, 'Invalid control character in request') if $_[0] =~ /[\x00-\x08\x0b\x0c\x0e-\x1f]/;
|
||||
}
|
||||
|
||||
our $hdrname_re = qr/[!#\$\%&'\*\+-\.^_`\|~0-9a-zA-Z]{1,127}/;
|
||||
our $method_re = qr/(?:GET|POST|DELETE|OPTIONS|PUT|PATCH|QUERY)/;
|
||||
|
||||
|
|
@ -181,8 +174,7 @@ sub _read_req_http($sock, $req) {
|
|||
fu->error(400, 'Client disconnect before request was read') if !defined $line;
|
||||
fu->error(400, 'Invalid request') if $line !~ /^($method_re)\s+(\S+)\s+HTTP\/1\.[01]\r\n$/;
|
||||
$req->{method} = $1;
|
||||
($req->{path}, $req->{qs}) = split /\?/, $2 =~ s{^https?://[^/]+/}{/}r, 2;
|
||||
$req->{path} =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
|
||||
$req->{path} = $2 =~ s{^https?://[^/]+/}{/}r;
|
||||
|
||||
while (1) {
|
||||
# Turns out header line folding has been officially deprecated, so I'm
|
||||
|
|
@ -225,7 +217,7 @@ sub _read_req($c) {
|
|||
: $r == -2 ? "I/O error while reading from FastCGI socket\n"
|
||||
: $r == -3 ? "FastCGI protocol error\n"
|
||||
: $r == -4 ? "Too long FastCGI parameter\n"
|
||||
: $r == -5 ? "Too long request body\n" : undef;
|
||||
: $r == -5 ? "Too long request body\n" : undef if $r != -7;
|
||||
delete $c->{fcgi_obj};
|
||||
fu->error(-1);
|
||||
}
|
||||
|
|
@ -236,7 +228,12 @@ sub _read_req($c) {
|
|||
|
||||
# The HTTP reader above and the FastCGI XS reader operate on bytes.
|
||||
# Decode these into Unicode strings and check for special characters.
|
||||
_decode_utf8 $_ for ($REQ->{path}, $REQ->{qs}, values $REQ->{hdr}->%*);
|
||||
eval { FU::Util::utf8_decode($_); 1} || fu->err(400, $@)
|
||||
for ($REQ->{path}, $REQ->{qs}, values $REQ->{hdr}->%*);
|
||||
|
||||
($REQ->{path}, my $qs) = split /\?/, $REQ->{path}//'', 2;
|
||||
$REQ->{qs} //= $qs;
|
||||
$REQ->{path} = FU::Util::uri_unescape($REQ->{path});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -418,7 +415,7 @@ sub _spawn {
|
|||
|
||||
if (!keys %c) {
|
||||
%c = (
|
||||
http => $ENV{FU_HTTP} // '127.0.0.1:3000',
|
||||
http => $ENV{FU_HTTP},
|
||||
fcgi => $ENV{FU_FCGI},
|
||||
proc => $ENV{FU_PROC} // 1,
|
||||
monitor => $ENV{FU_MONITOR} // 0,
|
||||
|
|
@ -447,8 +444,17 @@ sub _spawn {
|
|||
my $need_supervisor = !$c{supervisor_sock} && !$c{client_sock} && ($c{proc} > 1 || $c{monitor} || $c{max_reqs});
|
||||
return if !@_ && !$need_supervisor;
|
||||
|
||||
if (!$c{http} && !$c{fcgi} && !$c{listen_sock}) {
|
||||
# When spawned under FastCGI, stdin is our listen socket
|
||||
local $_ = getpeername \*STDIN;
|
||||
if ($!{ENOTCONN}) {
|
||||
$c{listen_sock} = IO::Socket->new_from_fd(0, 'r');
|
||||
$c{listen_proto} = 'fcgi';
|
||||
}
|
||||
};
|
||||
$c{http} //= '127.0.0.1:3000';
|
||||
|
||||
if (!$c{listen_sock}) {
|
||||
# TODO: check if stdin is a fastcgi sock
|
||||
$c{listen_proto} //= $c{fcgi} ? 'fcgi' : 'http';
|
||||
my $addr = $c{$c{listen_proto}};
|
||||
$c{listen_sock} = IO::Socket->new(
|
||||
|
|
@ -520,6 +526,7 @@ sub method { $FU::REQ->{method} }
|
|||
sub header($, $h) { $FU::REQ->{hdr}{ lc $h } }
|
||||
sub headers { $FU::REQ->{hdr} }
|
||||
sub ip { $FU::REQ->{ip} }
|
||||
sub query { $FU::REQ->{qs} } # TODO: parse & validate
|
||||
|
||||
|
||||
|
||||
|
|
@ -773,7 +780,7 @@ this option is set, it takes precedence over the HTTP option.
|
|||
Nginx and Apache will, in their default configuration, use a separate
|
||||
connection per request. If you have a more esoteric setup, you should probably
|
||||
be aware of the following: this implementation does not support multiplexing or
|
||||
pipelining. It does support keepalive, but this come with a few caveats:
|
||||
pipelining. It does support keepalive, but this comes with a few caveats:
|
||||
|
||||
=over
|
||||
|
||||
|
|
@ -786,7 +793,7 @@ I<after> each request rather than before, so clients may get a response from
|
|||
stale code.
|
||||
|
||||
=item * When worker processes shut down, either through C<--max-reqs> or in
|
||||
response to a signal, there is the possibility that an incoming request on an
|
||||
response to a signal, there is a possibility that an incoming request on an
|
||||
existing connection gets interrupted.
|
||||
|
||||
=back
|
||||
|
|
@ -822,6 +829,8 @@ Set the initial value for C<FU::debug>.
|
|||
|
||||
=item LISTEN_FD=num
|
||||
|
||||
=item LISTEN_PROTO=http/fcgi
|
||||
|
||||
Listen for incoming connections on the given file descriptor instead of
|
||||
creating a new listen socket. This is mainly useful if you are using an
|
||||
external process manager.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue