diff --git a/test/functional/interface_http.py b/test/functional/interface_http.py index dbdceb52d15..5566b08881b 100755 --- a/test/functional/interface_http.py +++ b/test/functional/interface_http.py @@ -105,5 +105,55 @@ class HTTPBasicsTest (BitcoinTestFramework): assert_equal(out1.status, http.client.BAD_REQUEST) + self.log.info("Check pipelining") + # Requests are responded to in order they were received + # See https://www.rfc-editor.org/rfc/rfc7230#section-6.3.2 + tip_height = self.nodes[2].getblockcount() + + req = "POST / HTTP/1.1\r\n" + req += f'Authorization: Basic {str_to_b64str(authpair)}\r\n' + + # First request will take a long time to process + body1 = f'{{"method": "waitforblockheight", "params": [{tip_height + 1}]}}' + req1 = req + req1 += f'Content-Length: {len(body1)}\r\n\r\n' + req1 += body1 + + # Second request will process very fast + body2 = '{"method": "getblockcount"}' + req2 = req + req2 += f'Content-Length: {len(body2)}\r\n\r\n' + req2 += body2 + + # 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.settimeout(1) + # Send two requests in a row. The first will block the second indefinitely + sock.sendall(req1.encode("utf-8")) + sock.sendall(req2.encode("utf-8")) + try: + # The server should not respond to the fast, second request + # until the (very) slow first request has been handled: + res = sock.recv(1024) + assert not res + except TimeoutError: + pass + + # Use a separate http connection to generate a block + self.generate(self.nodes[2], 1, sync_fun=self.no_op) + + # Wait for two responses to be received + res = b"" + while res.count(b"result") != 2: + res += sock.recv(1024) + + # waitforblockheight was responded to first, and then getblockcount + # which includes the block added after the request was made + chunks = res.split(b'"result":') + assert chunks[1].startswith(b'{"hash":') + assert chunks[2].startswith(bytes(f'{tip_height + 1}', 'utf8')) + if __name__ == '__main__': HTTPBasicsTest(__file__).main()