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

Trailing Headers #1149

Closed
tomchristie opened this issue Aug 8, 2020 · 11 comments
Closed

Trailing Headers #1149

tomchristie opened this issue Aug 8, 2020 · 11 comments
Labels
enhancement New feature or request
Milestone

Comments

@tomchristie
Copy link
Member

One HTTP/1.1 feature that we don't currently support is trailing headers.

Hardly a high priority since it's seems so rarely used, but it might be worth our while someday.
It'd be interesting to hear from folks who do have use-cases here.

One option at the Transport API layer might be to update the AsyncByteStream/SyncByteStream APIs in order to handle this, without affecting the majority of code that doesn't expect or care about trailing headers, for example...

def get_trailing_headers() -> List[Tuple[byte, byte]]:
    # This method depends on the state of `__iter__`/`__aiter__`.
    # Once the byte stream has been fully consumed, any trailing headers may be accessed via this method.
    return []

At the httpx level we could expose this information by mutating the response.headers once the stream has been iterated over.

@tomchristie tomchristie added the enhancement New feature or request label Aug 8, 2020
@tomchristie tomchristie added this to the someday milestone Aug 8, 2020
@florimondmanca
Copy link
Member

Interesting related docs on MDN: Trailer Header.

Example they provide:

Chunked transfer encoding using a trailing header

In this example, the Expires header is used at the end of the chunked message and serves as a trailing header.

HTTP/1.1 200 OK 
Content-Type: text/plain 
Transfer-Encoding: chunked
Trailer: Expires

7\r\n 
Mozilla\r\n 
9\r\n 
Developer\r\n 
7\r\n 
Network\r\n 
0\r\n 
Expires: Wed, 21 Oct 2015 07:28:00 GMT\r\n
\r\n

@tomchristie
Copy link
Member Author

Be interested to know if there's any good examples of trailing headers actually being used in the wild.

The low-level part of this would prob be a trailing headers extension that can be provided to the Transport API, eg...

def trailing_headers(headers):
    # Callback that is invoked when response trailing headers are included.
    ...


transport.handle_request(
    method=b"GET",
    url=(b"https", b"www.example.com", None, b"/"),
    headers=[(b"Host", b"www.example.com")],
    stream=httpx.ByteStream(b""),
    extensions={"trailing_headers": trailing_headers}
)

We could then integrate this into httpx without requiring any extra API, by supplying that callback, with an implementation that mutates the response headers.

Anyways, I think this is probably all rather unnecessary unless there's clear a good driving use-case that some users are bumping up against, but leaving this all here for possible future reference.

@tomchristie
Copy link
Member Author

Ya know what? No. Just no.
I've never seen this used in the wild, or seen client support for it. It's a great thing that we've got a decent API around httpcore that'd allow us to add this as a documented extension at some point if we really needed too, but let's have that driven by user requirements. Entirely possible we'll just never ever see this realistically come up as something worth supporting.

@tmc
Copy link

tmc commented Sep 27, 2022

I'd like for this to be reconsidered as the folks behind https://connect.build/ are interested in supporting python clients but this would require trailing header support.

@tomchristie
Copy link
Member Author

I'd like for this to be reconsidered

Okay, we could possibly?...

as the folks behind https://connect.build/ are interested in supporting python clients but this would require trailing header support.

Could you provide some more context?
What are you looking for that the official grpcio client doesn't provide?

@akshayjshah
Copy link

akshayjshah commented Sep 28, 2022

Hi! I'm from @bufbuild and work on the Connect family of RPC libraries. Trailer support would indeed be valuable to us. Really appreciate you even engaging in discussion on this 😻 I'm happy to provide some context, both specific to RPC and generally.

What are you looking for that the official grpcio client doesn't provide?

grpcio does many things well, but it makes some tradeoffs that aren't always great for Python developers. If we end up building it, I'd like a future Connect library in Python to:

  • Be ASGI-compatible, so servers integrate easily with other web frameworks.
  • Be small, on par with a REST framework. Even if you don't count the large C++ core, grpcio is nearly 50k lines of Python. That's a lot to absorb and debug for a relatively simple protocol!
  • Be async by default.
  • Support the gRPC-Web protocol natively, rather than relying on Envoy to translate. This makes using grpc-web (or connect-web) in React/Angular/Vue/etc. apps much nicer.
  • Support Connect's own RPC protocol, which is friendlier to cURL and browsers.

In general, it'd be nice to have a gRPC-compatible package that's built as a thin layer around best-in-class Python HTTP packages - it lets Python developers leverage everything they already know. grpcio instead replaces the HTTP layer completely.

More generally, trailers are sometimes useful to avoid buffering lots of data. Outside of gRPC's reliance on them, the most common use I've seen is checksumming data - it's nice to send the checksum as a trailer, rather than buffering and sending it as a header.

@tomchristie tomchristie reopened this Sep 29, 2022
@tomchristie
Copy link
Member Author

Okay, so I'm up for putting time into this.

I'm particularly interested in being able to support gRPC. Even though that's a niche use-case for our audience as a whole, it's also a great example of pushing hard against the lower-level bits of API, and ensuring that httpx is suitable for being used in something-else-over-HTTP protocols.

@tomchristie
Copy link
Member Author

tomchristie commented Sep 29, 2022

Does anyone have any examples of public URLs that return trailing headers?

I can also hack something, but it'd be nice if there's an easy place to point at from demonstration purposes.

@tomchristie
Copy link
Member Author

First pass onto this. ☝️

@SamStephens
Copy link

@tomchristie what happened to this? It looks like encode/httpcore#582 was closed without being merged.

Anyhow, I have a real world use case for sending Trailing Headers, as AWS use them for errors in streaming responses from Lambda: https://docs.aws.amazon.com/lambda/latest/dg/runtimes-custom.html#runtimes-custom-response-streaming

@tomchristie
Copy link
Member Author

Looks like it was closed off as low priority.
You could take a second pass at it based on that PR, if it's valuable to you.

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants