Opened 4 years ago

Closed 4 years ago

#32586 closed Bug (invalid)

ASGI responses from Django do not provide lowercased HTTP headers as required by the spec

Reported by: Myers Carpenter Owned by: nobody
Component: HTTP handling Version: 3.1
Severity: Normal Keywords:
Cc: Andrew Godwin, Carlton Gibson Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Every time HTTP headers are talked about in the ASGI spec it always says: "Header names must be lowercased."

They never explain why they should be in lowercase, which maybe is a bug in the spec, but it turns out http headers are to be treated case insensitively https://stackoverflow.com/questions/5258977/are-http-headers-case-sensitive

Using Django 3.1.7 and uvicorn and adding a ASGI middleware like this:

class SpamMiddleware:
    def __init__(self, app):
        self.app = app

    async def __call__(self, scope, receive, send):
        print(f"start {scope!r}")
        async def send_wrapper(message):
            print(f"send {message!r}")
            return await send(message)
        async def receive_wrapper():
            message = await receive()
            print(f"receive {message!r}")
            return message

        return await self.app(scope, receive_wrapper, send_wrapper)

you can see that django does not follow the spec:

send {'type': 'http.response.start', 'status': 200, 'headers': [(b'Content-Type', b'application/javascript; charset="utf-8"'), (b'X-Frame-Options', b'DENY'), (b'Vary', b'Cookie'), (b'Content-Length', b'189761')]}

A possible fix (and I would be happy to make a PR) is to add a call to .lower() on the header name on https://github.com/django/django/blob/76c0b32f826469320c59709d31e2f2126dd7c505/django/core/handlers/asgi.py#L227

The upside, beyond being spec compliant, would be that middleware that need to filter/modify headers wouldn't need to apply .lower() themselves.

This all came up because I'm attempting to add the zerocopysend extension to uvicorn and middleware to translate the X-Sendfile header from django-sendfile2 to using zerocopysend.

Change History (4)

comment:1 by Mariusz Felisiak, 4 years ago

Cc: Andrew Godwin Carlton Gibson added

This is explained in the comment. Andrew, what do you think?

comment:2 by Andrew Godwin, 4 years ago

Unsurprisingly, I agree with the way Django currently implements it, since I wrote it - the ASGI spec is in the wrong here, and I'll fix that separately.

comment:3 by Andrew Godwin, 4 years ago

The ASGI spec has been updated to reflect the actual situation here: https://github.com/django/asgiref/commit/c1d3d97d212c6e6ba1c29905f38fa611c7269779

comment:4 by Mariusz Felisiak, 4 years ago

Resolution: invalid
Status: newclosed

Thanks Andrew.

Note: See TracTickets for help on using tickets.
Back to Top