Description
The gthread worker will block and try to read a request that wasn't sent on the wire in a specific scenario:
- A POST request is sent with a total size (request header and body) greater than 8192 bytes.
- The application does not read the request body
- The connection is kept alive
The worker will then be blocked on that connection until it is closed, and is not able to accept any requests.
Reproduction:
Create myapp.py:
def app(environ, start_response):
data = b"Hello, World!\n"
start_response("200 OK", [
("Content-Type", "text/plain"),
("Content-Length", str(len(data)))
])
return iter([data])
Run with gunicorn myapp:app --keep-alive 120 --worker-class gthread
Then create another Python file to open a connection and make a POST request httppost.py
import sys, socket
host, port, numbytes = sys.argv[1], int(sys.argv[2]), int(sys.argv[3])
with socket.create_connection((host, port)) as sock:
req = b"POST /test HTTP/1.1\r\nHost: " + host.encode("ascii") + b"\r\nContent-Length: " + bytes(str(numbytes), "ascii") + b"\r\n\r\n" + (b"f" * numbytes)
sock.sendall(req)
while True:
data = sock.recv(1024)
print(data)
Execute with python3 httppost.py 127.0.0.1 8000 9000
Then try to make another request on a different connection such as with curl "http://127.0.0.1:8000/test"
and notice that you do not get a response. Ctrl+C the httppost.py program and the curl will complete as expected.
If you run httppost.py with a shorter request body, such as python3 httppost.py 127.0.0.1 8000 100
, then this issue doesn't happen.