diff --git a/bin/tests/system/statschannel/clean.sh b/bin/tests/system/statschannel/clean.sh index 03cb1bb87d..09218d5b5b 100644 --- a/bin/tests/system/statschannel/clean.sh +++ b/bin/tests/system/statschannel/clean.sh @@ -29,3 +29,4 @@ rm -f xml.*stats json.*stats rm -f zones zones.out.* zones.json.* zones.xml.* zones.expect.* rm -rf ./__pycache__ rm -f nc.out* +rm -f send.in* send.out* diff --git a/bin/tests/system/statschannel/send64k.pl b/bin/tests/system/statschannel/send64k.pl new file mode 100644 index 0000000000..b382dd59da --- /dev/null +++ b/bin/tests/system/statschannel/send64k.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl +# +# Copyright (C) Internet Systems Consortium, Inc. ("ISC") +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, you can obtain one at https://mozilla.org/MPL/2.0/. +# +# See the COPYRIGHT file distributed with this work for additional +# information regarding copyright ownership. + +# +# Send a file to a given address and port using TCP. Used for +# configuring the test server in ans.pl. +# + +use IO::File; +use IO::Socket; + +@ARGV == 2 or die "usage: send.pl host port\n"; + +my $host = shift @ARGV; +my $port = shift @ARGV; + +my $sock = IO::Socket::INET->new(PeerAddr => $host, PeerPort => $port, + Proto => "tcp",) or die "$!"; +#send the file +while ($n = read(STDIN, $buf, 64000)) { + $sock->syswrite($buf, $n); +} + +#get the response with with a 15 second timeout +my $rin; +my $rout; +my $n; +do { + $rin = ''; + vec($rin, fileno($sock), 1) = 1; + $n = select($rout = $rin, undef, undef, 15); + $n = $sock->sysread($buf, 64000) if ($n > 0); + print STDOUT $buf if ($n > 0); +} while ($n > 0); + +$sock->close; diff --git a/bin/tests/system/statschannel/tests.sh b/bin/tests/system/statschannel/tests.sh index ce145b7c3e..2ce484b5db 100644 --- a/bin/tests/system/statschannel/tests.sh +++ b/bin/tests/system/statschannel/tests.sh @@ -395,5 +395,32 @@ else echo_i "skipping test as nc not found" fi +echo_i "Check HTTP/1.1 pipelined with truncated stream ($n)" +ret=0 +i=0 +# build input stream. +cp /dev/null send.in$n +while test $i -lt 500 +do +cat >> send.in$n << EOF +GET /xml/v3/status HTTP/1.1 +Host: 10.53.0.3 + +EOF +i=$((i+1)) +done + +# send the requests then wait for named to close the socket. +time1=$($PERL -e 'print time(), "\n";') +${PERL} send64k.pl 10.53.0.3 ${EXTRAPORT1} < send.in$n > send.out$n +time2=$($PERL -e 'print time(), "\n";') +test $((time2 - time1)) -lt 5 || ret=1 +# we expect 91 of the 500 requests to be processed. +lines=$(grep "^HTTP/1.1" send.out$n | wc -l) +test $lines = 91 || ret=1 +if [ $ret != 0 ]; then echo_i "failed"; fi +status=`expr $status + $ret` +n=`expr $n + 1` + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c index 0787da8c18..1d79668b91 100644 --- a/lib/isc/httpd.c +++ b/lib/isc/httpd.c @@ -89,6 +89,7 @@ struct isc_httpd { uint32_t recvlen; /*%< length recv'd */ uint32_t consume; /*%< length of last command */ char *headers; /*%< set in process_request() */ + bool truncated; method_t method; char *url; char *querystring; @@ -398,17 +399,25 @@ process_request(isc_httpd_t *httpd, isc_region_t *region, size_t *buflen) { size_t limit = sizeof(httpd->recvbuf) - httpd->recvlen - 1; size_t len = region->length; int delim; + bool truncated = false; if (len > limit) { len = limit; + truncated = true; } if (len > 0U) { + if (httpd->truncated) { + return (ISC_R_NOSPACE); + } memmove(httpd->recvbuf + httpd->recvlen, region->base, len); httpd->recvlen += len; httpd->recvbuf[httpd->recvlen] = 0; isc_region_consume(region, len); } + if (truncated) { + httpd->truncated = true; + } httpd->headers = NULL; *buflen = httpd->recvlen; @@ -422,7 +431,8 @@ process_request(isc_httpd_t *httpd, isc_region_t *region, size_t *buflen) { s = strstr(httpd->recvbuf, "\n\n"); delim = 1; if (s == NULL) { - return (ISC_R_NOTFOUND); + return (httpd->truncated ? ISC_R_NOSPACE + : ISC_R_NOTFOUND); } httpd->consume = s + 2 - httpd->recvbuf; } else { @@ -609,6 +619,7 @@ httpd_reset(void *arg) { httpd->recvbuf[0] = 0; httpd->recvlen = 0; httpd->consume = 0; + httpd->truncated = false; httpd->headers = NULL; httpd->method = METHOD_UNKNOWN; httpd->url = NULL; @@ -1174,7 +1185,7 @@ httpd_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) { */ isc_nmhandle_attach(handle, &httpd->readhandle); httpd_request(handle, ISC_R_SUCCESS, NULL, httpd->mgr); - } else { + } else if (!httpd->truncated) { isc_nm_resumeread(handle); } } diff --git a/util/copyrights b/util/copyrights index ede8082947..36a154d760 100644 --- a/util/copyrights +++ b/util/copyrights @@ -765,6 +765,7 @@ ./bin/tests/system/statschannel/helper.py PYTHON 2020,2021 ./bin/tests/system/statschannel/mem-xml.pl PERL 2017,2018,2019,2020,2021 ./bin/tests/system/statschannel/ns2/sign.sh SH 2019,2020,2021 +./bin/tests/system/statschannel/send64k.pl PERL 2021 ./bin/tests/system/statschannel/server-json.pl PERL 2015,2016,2017,2018,2019,2020,2021 ./bin/tests/system/statschannel/server-xml.pl PERL 2015,2016,2017,2018,2019,2020,2021 ./bin/tests/system/statschannel/setup.sh SH 2018,2019,2020,2021