from threading import Thread, Event from http.client import HTTPConnection from http.client import OK import errno from platform import platform from socket import socket from time import sleep def main(): print("Platform:", platform()) with socket() as server_socket: server_socket.bind(("localhost", 0)) server_socket.listen(1) allow_close = Event() close_done = Event() args = (server_socket, allow_close, close_done) thread = Thread(target=run_server, args=args) thread.start() address = server_socket.getsockname() allow_close.set() demo_request("short-request", address, "GET", "/", close_done=close_done) demo_request("2mb-request", address, "POST", "/", body=bytes(int(2e6)), close_done=close_done) allow_close.clear() demo_request("close-while-sending", address, "POST", "/", headers={"Content-Length": "10"}, body=close_in_body(allow_close, close_done)) thread.join() def close_in_body(allow_close, close_done): # HTTPConnection has already sent header data sleep(0.1) # Attempt to allow data to be buffered at TCP level allow_close.set() close_done.wait() yield b"123456789\n" def demo_request(desc, address, *pos, close_done=None, **kw): client = HTTPConnection(*address) try: client.request("GET", "/" + desc) response = client.getresponse() assert response.status == OK assert response.read() == b"" sleep(0.3) # Emulate period in which server might drop connection if close_done: close_done.wait() try: stage = "request()" client.request(*pos, **kw) stage = "getresponse()" response = client.getresponse() except Exception as exception: code = "" if isinstance(exception, EnvironmentError): code = "; errno=" + errno.errorcode[exception.errno] msg = "{}: {} raised {!r}{}" print(msg.format(desc, stage, exception, code)) else: msg = "{}: Got response: {} {}" print(msg.format(desc, response.status, response.reason)) response.read() finally: client.close() def run_server(server, allow_close, close_done): for _ in range(3): [client, _] = server.accept() close_done.clear() with client, client.makefile("rb") as reader: assert reader.readline().startswith(b"GET ") while reader.readline().rstrip(b"\r\n"): pass client.sendall( b"HTTP/1.1 200 OK\r\n" b"Content-Length: 0\r\n" b"\r\n" ) sleep(0.1) # Emulate server timing out the connection allow_close.wait() close_done.set() if __name__ == "__main__": main()