Skip to content

gthread worker will block #3301

Open
@oallenj

Description

@oallenj

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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions