-
Notifications
You must be signed in to change notification settings - Fork 216
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
Add HTTP Trailers extension #339
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@synodriver According to what we talked, is this what you think it should be written?
(Because I've been cc'ed) Does it matter if we've seen enough of a genuine use case or not? I'm aware that HTTP trailing headers exist in the spec, but I've never encountered their usage in my career. So I'd be a bit wary of introducing that complexity into the spec, and the expectation that can then introduce onto other projects to include that complexity in their implementations. I'd probably put an "HTTP trailing headers" extension into the "technology for the sake of technology", unless there was a clearer indication that it's solving someone's actual use-case. Perhaps that'd involve something like a "here's a functional gRPC implementation that we can show works if we have this extension and doesn't work without it" (?) But, also shrug. 🤷♂️ "Sensible pushback" or "Mildly grumpy old geezer"? You decide. 😇 |
I did the uvicorn PR and didnt realize this would be controversial. I have an actual need for this and some use cases are laid out in that PR. But in short, It is useful when streaming a response in a couple cases. You may encounter an error that you want the client to know about, As you have already responded 200 and sent headers, how else could you get this information to them? You may also be streaming a large file that you want to compute the hash of as it stream through the sever and send that hash at the end. |
Copying some comments from my separate PR above. I wanted to open this to add options to the discussion. I did the uvicorn implementation. My original POC did not account for chunked trailers but this would be easy to add with a more_trailers property similar to the more_body property. Though this could be an issue in h11 as mentioned above
The original purpose of the new Personally I like the more_body being set to false when the body is done and trailers being sent after. It makes more sense to me, but at the end of the day if any trailers get added I will be happy. |
I think I slightly prefer the design proposed in #341 - it's more explicit, and doesn't rely on parsing the content of headers sent back. Is there any strong reason not to go with that design? (I would want to add the extension signifier over there too, rather than just have it appear in the spec and force a new version) |
So, by slightly prefer you mean the I'm fine with this. The client will still should to send what trailing headers are those, but it's not mandatory. Is the |
Yes, to be specific:
|
Is there a scenario on which we have this sequence:
Without the |
I used the name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'm OK with it being called headers
in the trailer response - that is, after all, what they are, rather than trailing body.
@@ -99,6 +100,7 @@ class HTTPResponseStartEvent(TypedDict): | |||
type: Literal["http.response.start"] | |||
status: int | |||
headers: Iterable[Tuple[bytes, bytes]] | |||
trailers: bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypedDict is total
by default, so this would require trailers
to always be present which it won't be (as we're doing this as a non-major change by making it optional). We need to switch this so that trailers
is optional, which may need to be done with two inheriting types due to TypedDict not having fine-grained options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
more_body
is bool
on HTTPResponseBodyEvent
. What's the difference between those?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to switch this so that
trailers
is optional, which may need to be done with two inheriting types due to TypedDict not having fine-grained options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What both are suggesting was already discussed when the asgiref.typing
module was implemented. See #221 (comment).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was, but that was "types for the first time" whereas this is modifying existing types - if we land this change, anything that currently (correctly) typechecks as a response no longer will, and that seems bad.
The suggestion in that thread of Unioning two other dict types together would also work, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was, but that was "types for the first time"
What's the difference? asgiref
is versioned... 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we land this change, anything that currently (correctly) typechecks as a response no longer will, and that seems bad.
Not sure if it's important, but... uvicorn
is the only ASGI server implementation that uses asgiref.typing
... 🤷♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I think this is good enough to go. I'll leave a bit more time for any further objections and then we'll merge it.
Thanks everybody for the comments! 🙏 |
`asgiref==3.6.0` introduced a new required `trailers` key to the `asgiref.types.HTTPResponseStartEvent` type. As the django/asgiref#339 code review pointed out, this is a breaking change for type checking, but it was added in a minor release, and not mentioned in the changelog. django/asgiref#339 django/asgiref#362
Currently, there are two implementations of HTTP Trailer:
What this PR proposes doesn't match any of those two implementations. I've tried to simplify a bit...
The uvicorn one introduces a new key on the
http.response.start
calledtrailers
, to show the intention from the application to the server that trailing headers will be sent. I think this is not needed. The server can understand the intention if the headerTrailer:
is provided on theheaders
from thehttp.response.start
.The nonecorn uses a different name for the extension, but it was the first one implemented. I just thought the name
http.response.trailers
was a bit better, but happy to change if wanted. cc @synodriverI understood less about the nonecorn implementation in comparison to the one from uvicorn, so I may be missing something here that I couldn't grasp from there. So I'd like your opinion here @synodriver. 🙏The
nonecorn
implementation makes the ASGI framework in charge of sending theTrailer:
header, and it sets themore_body
field toTrue
on the lasthttp.response.body
message, and then it's able to use trailing headers message (calledhttp.trailingheaders.send
there) as last message, and then close the transport after it.cc @simonw @abersheeran @pgjones @synodriver @sam-kleiner @tomchristie
References used to write this: