WsgiToAsgi: Set `wsgi.input_terminated`
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.