]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Handle truncating the request stream in isc_httpd
authorMark Andrews <marka@isc.org>
Thu, 4 Nov 2021 03:36:33 +0000 (14:36 +1100)
committerEvan Hunt <each@isc.org>
Fri, 5 Nov 2021 00:06:36 +0000 (17:06 -0700)
If we have had to truncate the request stream, don't resume
reading from it.

bin/tests/system/statschannel/clean.sh
bin/tests/system/statschannel/send64k.pl [new file with mode: 0644]
bin/tests/system/statschannel/tests.sh
lib/isc/httpd.c
util/copyrights

index 03cb1bb87d1f0594c6aa345ade3a51dace04a92e..09218d5b5bb657abb40e20219a6b6faf60281513 100644 (file)
@@ -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 (file)
index 0000000..b382dd5
--- /dev/null
@@ -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;
index ce145b7c3e72e42dcf74d5c32abc3733bf189abd..2ce484b5db740a85290fa09dbce3127365b83d92 100644 (file)
@@ -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
index 0787da8c1852dc806a6e7eff7a129e74c79f3538..1d79668b91816c91b81e2ad782c499fe0cc5dc7b 100644 (file)
@@ -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);
        }
 }
index ede808294726e59739441207e114c43767ca4d1c..36a154d7601cce9d1b31de802ef718ad55571498 100644 (file)
 ./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