Skip to content

Trailing Headers #1149

Closed
Closed

Description

@lovelydinosaur

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.

Activity

  1. added this to the someday milestone on Aug 8, 2020
  2. florimondmanca commented on Aug 9, 2020

    @florimondmanca
    Contributor

    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
  3. lovelydinosaur commented on May 6, 2021

    @lovelydinosaur
    MemberAuthor

    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.

  4. lovelydinosaur commented on Jan 22, 2022

    @lovelydinosaur
    MemberAuthor

    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.

  5. tmc commented on Sep 27, 2022

    @tmc

    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.

  6. lovelydinosaur commented on Sep 28, 2022

    @lovelydinosaur
    MemberAuthor

    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?

  7. akshayjshah commented on Sep 28, 2022

    @akshayjshah

    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.

  8. lovelydinosaur commented on Sep 29, 2022

    @lovelydinosaur
    MemberAuthor

    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.

  9. lovelydinosaur commented on Sep 29, 2022

    @lovelydinosaur
    MemberAuthor

    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.

  10. lovelydinosaur commented on Sep 29, 2022

    @lovelydinosaur
    MemberAuthor

    First pass onto this. ☝️

  11. SamStephens commented on Jun 10, 2024

    @SamStephens

    @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

  12. lovelydinosaur commented on Jun 11, 2024

    @lovelydinosaur
    MemberAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions