Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WsgiToAsgi: Set wsgi.input_terminated #286

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mhils
Copy link

@mhils mhils commented Aug 2, 2021

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 (mitmproxy/mitmproxy#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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant