-
Notifications
You must be signed in to change notification settings - Fork 213
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
Header name lowercase requirement is excessive #246
Comments
We don't actually REQUIRE lowercase, it's just a nice convention to have. Some rare clients do, actually, care about case, so carve out a best-effort channel for that.
Probably a good direction, yup. It's possible there's some places we need to be careful with here. Eg from a cursory look, there might be some bits of Starlette that would have minor breakages if an ASGI server implementation switched to not lowercasing the incoming headers. Eg... https://github.com/encode/starlette/blob/master/starlette/datastructures.py#L28 # Determine the hostname to use when reconstructing the URL from the ASGI scope.
host_header = None
for key, value in scope["headers"]:
if key == b"host":
host_header = value.decode("latin-1")
break Not really a big deal to review and fix up that project, but there might be other bits of the ecosystem that'd need some review. The other thing is I don't think I quite understand the wording in "Header names should be lowercased, but it is not required; servers should preserve header case on a best-effort basis.". It's not clear to me if it's advising lowercasing or advising not lowercasing? Is the difference in wording intended to mean that servers SHOULD lowercase incoming request headers, but SHOULD preserve case on outgoing response headers? Perhaps something like "Header names may optionally be lowercase, but this is not required" is more clear. Not sure. |
Yes, this is not for incoming request headers, but for outgoing request headers. I agree that all incoming ones should be lowercased; it's the response headers that it seems we occasionally need to keep case sensitivity. How about this wording instead:
|
➕ this seems quite reasonable. I have to assume that there are no clients that break with non-lowercase headers (i.e. they only accept lowercase headers and so they were okay so far because the ASGI server lowercases them) so that if an ASGI server updated itself to preserve case it might break their system? |
I've a request not to lowercase the incoming headers for a use case whereby Hypercorn is used as a proxy and the casing is sensitive downstream. Not lower-casing, does however cause some bugs e.g. pgjones/hypercorn#77. I'm not sure what the least unpleasant solution is. |
I think an asgi middleware could do that. The middleware can be configured whether to lowercase the incoming header or not. |
There's also a point where we can't accommodate literally every single HTTP feature - ASGI has always been about handling 98% of cases, not 100%. I might argue that proxying stuff to specialist servers is a case where it's reasonable to ask someone to write a bit more HTTP handling code than merely running a web app. |
From my current understanding, if neither WSGI nor ASGI is capable of preserving header casing, it effectively makes any compliant python web server unusable as application-layer proxy for any backend that expects headers to arrive as they were sent by the client. I wouldn't consider an L7 proxy to be in the 2% bucket of use-cases, but I suppose that's debatable. More generally, I would be interested in understanding the argument to force lower-casing of incoming request headers in the first place. Are there any benefits for server-side implementations that are so fundamental that it warrants a MUST in the spec? |
At the time the spec was designed, we did an extensive review of a lot of different backends, applications and servers in the Python ecosystem and beyond, and header case being important almost never came up. Combine that with the fact that ASGI (like WSGI) is meant to be an application abstraction, it made sense to remove one potential point of confusion away from frameworks having to implement it and just making it part of the spec - which was especially important given we wanted to make middleware more powerful and easier to write, and having a simpler spec helps there tremendously. My view is that writing a perfect L7 proxy that has to back a header-case-sensitive server is pretty far on the long tail of use cases, especially as there are several other HTTP features that ASGI deliberately does not implement as it's designed to be an application web abstraction, not a perfect HTTP connection layer. We can move from "must" to "best effort" as I suggested further upthread, but in my experience, if you want to write an L7 proxy, you're probably going to need to go low-level at some point. |
It was pointed out in https://code.djangoproject.com/ticket/32586 that the initial ASGI requirement that header names in responses MUST be lowercased - inherited from ASGI 1, I believe - doesn't actually match the Django codebase, and upon inspection, this is because, unfortunately, a very small number of HTTP clients are case-sensitive to headers like
Content-Type
.I believe the appropriate action is to relax the MUST requirement, and say that servers can/should try to preserve case when passed to them, but nothing requires it; this saves us from entirely flipping the expectation here. Thoughts?
The text was updated successfully, but these errors were encountered: