asgiref icon indicating copy to clipboard operation
asgiref copied to clipboard

WsgiToAsgi: Set `wsgi.input_terminated`

Open mhils opened this issue 4 years ago • 0 comments

Hi folks! We very happily use asgiref in @mitmproxy since the last release, thank you very much for your work here. 😃🍰

Following a bug report where a user's Flask app (wrapped with asgiref) did not see request bodies (https://github.com/mitmproxy/mitmproxy/issues/4717), I discovered that Flask expects a content-length header to be set, as it doesn't trust wsgi.input to have read-until-EOF semantics. This then fails for chunked request bodies and no body is read at all.

To demonstrate this, here's a self-contained example with asgiref+Flask:

import asyncio

import asgiref.wsgi
from flask import Flask, request

app = Flask(__name__)

@app.route('/', methods=['GET', 'POST'])
def hello_world():
    return f"{request.data=}"

asgi_app = asgiref.wsgi.WsgiToAsgi(app)

if __name__ == "__main__":
    scope = {
        "type": "http",
        "asgi": {
            "version": "3.0",
            "spec_version": "2.1",
        },
        "http_version": "1.1",
        "method": "POST",
        "scheme": "http",
        "path": "/",
        "raw_path": b"/",
        "query_string": b"",
        "headers": [[b"transfer-encoding", b"chunked"]],
    }

    async def receive():
        return {
            "type": "http.request",
            "body": b"Hello world",
        }

    async def send(data):
        print(f"send {data=}")
        
    asyncio.run(asgi_app(scope, receive, send))

Output:

send data={'type': 'http.response.start', 'status': 200, 'headers': [(b'content-type', b'text/html; charset=utf-8'), (b'content-length', b'16')]}
send data={'type': 'http.response.body', 'body': b"request.data=b''", 'more_body': True}
send data={'type': 'http.response.body'}

Observe in the second line that there's no request data. The fix here seems to be to signal to WSGI apps that read-until-EOF semantics actually do exist by setting wsgi.input_terminated (proposed in https://gist.github.com/mitsuhiko/5721547). This PR simply does that and adds a test for it.

mhils avatar Aug 02 '21 14:08 mhils