]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Handle HTTP/1.1 pipelined requests
authorMark Andrews <marka@isc.org>
Tue, 26 Oct 2021 04:28:36 +0000 (15:28 +1100)
committerEvan Hunt <each@isc.org>
Fri, 5 Nov 2021 00:05:29 +0000 (17:05 -0700)
Check to see whether there are outstanding requests in the
httpd receive buffer after sending the response, and if so,
process them.

Test that pipelined requests are handled by sending multiple
minimal HTTP/1.1 using netcat (nc) and checking that we get
back the same number of responses.

bin/tests/system/conf.sh.in
bin/tests/system/statistics/tests.sh
bin/tests/system/statschannel/clean.sh
bin/tests/system/statschannel/tests.sh
configure.ac
lib/isc/httpd.c

index 06aaad39c25fedf3014fbe6a7499c8348471692c..ff6c6e4b6779952e8b0587c30404073c44784cc0 100644 (file)
@@ -112,6 +112,9 @@ SHELL=@SHELL@
 # CURL will be empty if no program was found by configure
 CURL=@CURL@
 
+# NC will be empty if no program was found by configure
+NC=@NC@
+
 # XMLLINT will be empty if no program was found by configure
 XMLLINT=@XMLLINT@
 
index 4cb8008180649f3c7276d85c9a722b80382663e3..7e0190c60444298d0b82f06c5cd613a8541c421e 100644 (file)
@@ -175,8 +175,12 @@ echo_i "checking bind9.xsl vs xml ($n)"
 if $FEATURETEST --have-libxml2 && [ -x "${CURL}" ] && [ -x "${XSLTPROC}" ]  ; then
     $DIGCMD +notcp +recurse @10.53.0.3 soa . > dig.out.test$n.1 2>&1
     $DIGCMD +notcp +recurse @10.53.0.3 soa example > dig.out.test$n.2 2>&1
-    ${CURL} http://10.53.0.3:${EXTRAPORT1}/xml/v3 > curl.out.${n}.xml 2>/dev/null || ret=1
-    ${CURL} http://10.53.0.3:${EXTRAPORT1}/bind9.xsl > curl.out.${n}.xsl 2>/dev/null || ret=1
+    # check multiple requests over the same socket
+    time1=$($PERL -e 'print time(), "\n";')
+    ${CURL} --http1.1 -o curl.out.${n}.xml http://10.53.0.3:${EXTRAPORT1}/xml/v3 \
+           -o curl.out.${n}.xsl http://10.53.0.3:${EXTRAPORT1}/bind9.xsl 2>/dev/null || ret=1
+    time2=$($PERL -e 'print time(), "\n";')
+    test $((time2 - time1)) -lt 5 || ret=1
     ${DIFF} ${TOP_SRCDIR}/bin/named/bind9.xsl curl.out.${n}.xsl || ret=1
     ${XSLTPROC} curl.out.${n}.xsl - < curl.out.${n}.xml > xsltproc.out.${n} 2>/dev/null || ret=1
     cp curl.out.${n}.xml stats.xml.out || ret=1
index 2e13b1a9a5a0b557320c1d58a31288e8cfd8ab88..03cb1bb87d1f0594c6aa345ade3a51dace04a92e 100644 (file)
@@ -28,3 +28,4 @@ rm -f xml.*mem json.*mem
 rm -f xml.*stats json.*stats
 rm -f zones zones.out.* zones.json.* zones.xml.* zones.expect.*
 rm -rf ./__pycache__
+rm -f nc.out*
index bbbc8a0c97aa5055de68d139c1dfd27f875bf6f6..ce145b7c3e72e42dcf74d5c32abc3733bf189abd 100644 (file)
@@ -374,5 +374,26 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
 status=`expr $status + $ret`
 n=`expr $n + 1`
 
+if [ -x "${NC}" ] ; then
+    echo_i "Check HTTP/1.1 pipelined requests are handled ($n)"
+    ret=0
+    ${NC} 10.53.0.3 ${EXTRAPORT1} << EOF > nc.out$n || ret=1
+GET /xml/v3/status HTTP/1.1
+Host: 10.53.0.3:${EXTRAPORT1}
+
+GET /xml/v3/status HTTP/1.1
+Host: 10.53.0.3:${EXTRAPORT1}
+Connection: close
+
+EOF
+    lines=$(grep "^HTTP/1.1" nc.out$n | wc -l)
+    test $lines = 2 || ret=1
+    if [ $ret != 0 ]; then echo_i "failed"; fi
+    status=`expr $status + $ret`
+    n=`expr $n + 1`
+else
+    echo_i "skipping test as nc not found"
+fi
+
 echo_i "exit status: $status"
 [ $status -eq 0 ] || exit 1
index fa1dbae1628572275e7b72d804de75ec760c1640..17ca8eb60c70f6d839d3f2b0360b3bec12a4b993 100644 (file)
@@ -1256,6 +1256,13 @@ AC_CONFIG_FILES([doc/doxygen/doxygen-input-filter],
 AC_PATH_PROG(CURL, curl, curl)
 AC_SUBST(CURL)
 
+#
+# Look for nc
+#
+
+AC_PATH_PROGS(NC, nc, nc)
+AC_SUBST(NC)
+
 #
 # IDN support using libidn2
 #
index 9596b8e0af64ce049d824ec7f568a77706f90c2f..0787da8c1852dc806a6e7eff7a129e74c79f3538 100644 (file)
@@ -403,11 +403,14 @@ process_request(isc_httpd_t *httpd, isc_region_t *region, size_t *buflen) {
                len = limit;
        }
 
-       memmove(httpd->recvbuf + httpd->recvlen, region->base, len);
-       httpd->recvlen += len;
-       httpd->recvbuf[httpd->recvlen] = 0;
-       *buflen = httpd->recvlen;
+       if (len > 0U) {
+               memmove(httpd->recvbuf + httpd->recvlen, region->base, len);
+               httpd->recvlen += len;
+               httpd->recvbuf[httpd->recvlen] = 0;
+               isc_region_consume(region, len);
+       }
        httpd->headers = NULL;
+       *buflen = httpd->recvlen;
 
        /*
         * If we don't find a blank line in our buffer, return that we need
@@ -858,10 +861,22 @@ httpd_request(isc_nmhandle_t *handle, isc_result_t eresult,
                goto cleanup_readhandle;
        }
 
-       result = process_request(httpd, region, &buflen);
+       result = process_request(
+               httpd, region == NULL ? &(isc_region_t){ NULL, 0 } : region,
+               &buflen);
        if (result == ISC_R_NOTFOUND) {
                if (buflen < HTTP_RECVLEN - 1) {
-                       /* don't unref, keep reading */
+                       if (region != NULL) {
+                               /* don't unref, keep reading */
+                               return;
+                       }
+                       /*
+                        * We have been called from httpd_senddone
+                        * and we need to resume reading.  Detach
+                        * readhandle before resuming.
+                        */
+                       isc_nmhandle_detach(&httpd->readhandle);
+                       isc_nm_resumeread(handle);
                        return;
                }
                goto cleanup_readhandle;
@@ -950,6 +965,7 @@ httpd_request(isc_nmhandle_t *handle, isc_result_t eresult,
         * the response headers and store the result in httpd->sendbuffer.
         */
        isc_buffer_dup(mgr->mctx, &httpd->sendbuffer, &httpd->headerbuffer);
+       isc_buffer_clear(&httpd->headerbuffer);
        isc_buffer_setautorealloc(httpd->sendbuffer, true);
        databuffer = (is_compressed ? &httpd->compbuffer : &httpd->bodybuffer);
        isc_buffer_usedregion(databuffer, &r);
@@ -965,6 +981,7 @@ httpd_request(isc_nmhandle_t *handle, isc_result_t eresult,
                }
                httpd->recvlen -= httpd->consume;
                httpd->consume = 0;
+               httpd->recvbuf[httpd->recvlen] = 0;
        }
 
        /*
@@ -1150,7 +1167,16 @@ httpd_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
        }
 
        httpd->state = RECV;
-       isc_nm_resumeread(handle);
+       if (httpd->recvlen != 0) {
+               /*
+                * Outstanding requests still exist, start processing
+                * them.
+                */
+               isc_nmhandle_attach(handle, &httpd->readhandle);
+               httpd_request(handle, ISC_R_SUCCESS, NULL, httpd->mgr);
+       } else {
+               isc_nm_resumeread(handle);
+       }
 }
 
 isc_result_t