diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py index dbdceb52d15..324a0883516 100755 --- a/test/functional/interface_http.py +++ b/test/functional/interface_http.py @@ -8,6 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal, str_to_b64str import http.client +import time import urllib.parse class HTTPBasicsTest (BitcoinTestFramework): @@ -104,6 +105,52 @@ class HTTPBasicsTest (BitcoinTestFramework): out1 = conn.getresponse() assert_equal(out1.status, http.client.BAD_REQUEST) + self.log.info("Check -rpcservertimeout") + self.restart_node(2, extra_args=["-rpcservertimeout=1"]) + # This is the amount of time the server will wait for a client to + # send a complete request. Test it by sending an incomplete but + # so-far otherwise well-formed HTTP request, and never finishing it. + + # Copied from http_incomplete_test_() in regress_http.c in libevent. + # A complete request would have an additional "\r\n" at the end. + http_request = "GET /test1 HTTP/1.1\r\nHost: somehost\r\n" + + # Get the underlying socket from HTTP connection so we can send something unusual + conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port) + conn.connect() + sock = conn.sock + sock.sendall(http_request.encode("utf-8")) + # Wait for response, but expect a timeout disconnection after 1 second + start = time.time() + res = sock.recv(1024) + stop = time.time() + assert res == b"" + assert stop - start >= 1 + # definitely closed + try: + conn.request('GET', '/') + conn.getresponse() + except ConnectionResetError: + pass + + # Sanity check + http_request = "GET /test2 HTTP/1.1\r\nHost: somehost\r\n\r\n" + conn = http.client.HTTPConnection(urlNode2.hostname, urlNode2.port) + conn.connect() + sock = conn.sock + sock.sendall(http_request.encode("utf-8")) + res = sock.recv(1024) + assert res.startswith(b"HTTP/1.1 404 Not Found") + # still open + conn.request('GET', '/') + conn.getresponse() + + # Because we have set -rpcservertimeout so low, the persistent connection + # created by AuthServiceProxy for this node when the test framework + # started has likely closed. Force the test framework to use a fresh + # new connection for the next RPC otherwise the cleanup process + # calling `stop` will raise a connection error. + self.nodes[2]._set_conn() if __name__ == '__main__': HTTPBasicsTest(__file__).main()