diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in index 06aaad39c2..ff6c6e4b67 100644 --- a/bin/tests/system/conf.sh.in +++ b/bin/tests/system/conf.sh.in @@ -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@ diff --git a/bin/tests/system/statistics/tests.sh b/bin/tests/system/statistics/tests.sh index 4cb8008180..7e0190c604 100644 --- a/bin/tests/system/statistics/tests.sh +++ b/bin/tests/system/statistics/tests.sh @@ -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 diff --git a/bin/tests/system/statschannel/clean.sh b/bin/tests/system/statschannel/clean.sh index 2e13b1a9a5..03cb1bb87d 100644 --- a/bin/tests/system/statschannel/clean.sh +++ b/bin/tests/system/statschannel/clean.sh @@ -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* diff --git a/bin/tests/system/statschannel/tests.sh b/bin/tests/system/statschannel/tests.sh index bbbc8a0c97..ce145b7c3e 100644 --- a/bin/tests/system/statschannel/tests.sh +++ b/bin/tests/system/statschannel/tests.sh @@ -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 diff --git a/configure.ac b/configure.ac index fa1dbae162..17ca8eb60c 100644 --- a/configure.ac +++ b/configure.ac @@ -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 # diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c index 9596b8e0af..0787da8c18 100644 --- a/lib/isc/httpd.c +++ b/lib/isc/httpd.c @@ -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