spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.77k stars 38.16k forks source link

Support HTTP trailer fields #33640

Open bclozel opened 1 month ago

bclozel commented 1 month ago

The HTTP protocol supports, in some situation, the addition of "trailer fields" after the entity body. They're often used for supplying information about message integrity, metrics, or post-processing information. While this information could be in theory sent with regular HTTP headers, it is sometimes needed to send/receive the entity body first. For example, buffering the entire body for calculating message integrity would require too much memory, or we need to write the body first before sending out telemetry.

This issue is about supporting HTTP trailer fields in Spring Framework, meaning considering those in:

We'll treat this as an umbrella issue for the points listed above.

There are several key aspects that we should pay attention to while designing the API and implementing support.

Constraints

A trailer section is only possible when supported by the version of HTTP in use and enabled by an explicit framing mechanism. For example, the chunked transfer coding in HTTP/1.1 allows a trailer section to be sent after the content

This means that setting a "Content-Length" response header is incompatible with trailer fields.

Also, the client should send a TE: trailers HTTP request header if it is willing to accept trailers in the respnose. The server must set the "Trailer" header with the list of trailer fields to be sent.

Unlike HTTP headers, request/response trailers are only available at a certain point in the exchange lifecyle. The API must reflect this asynchronous nature to ensure that trailers are read/written at the right time.

We should consider how we can make this as easy and transparent as possible for developers.

Server: Servlet API support

See [the request API for getting trailer fields](https://jakarta.ee/specifications/servlet/6.1/apidocs/jakarta.servlet/jakarta/servlet/http/httpservletrequest#getTrailerFields()) and the response API for supplying them.

Server: Reactive support

Reactor Netty, Jetty and Undertow seem to support trailer fields on their native APIs.

HTTP clients

Library support is still spotty, we cannot expose this feature on our HTTP clients at this time.

bclozel commented 1 day ago

After some initial prototyping, I came to the following conclusion. The main use case for trailer fields seems to be about integrity checks, for example calculating a hash of the HTTP message body, chunk by chunk, without buffering the entire content in memory.

Libraries at the HTTP level (Reactor, or the Servlet API) already provide some support there. Implementing this integrity check requires quite a few manual steps at a low level.

The goal here would be to provide first a higher level integration in HttpInputMessage/HttpOutputMessage/ReactiveHttpInputMessage/ReactiveHttpOutputMessage, providing a way to "listen" for HTTP body chunks and then retrieve the trailer fields when the body has been fully read. On the server side, we would need to expose this in both our annotation and functional programming models; the main issue is that there are many ways to read/write the HTTP message body, and one can only get trailers once the body has been fully read. This makes the API more complicated and developers need to be aware of those lifecycle issues.

Because the HTTP client coverage is not good enough now, this also means that the *InputMessage/*OutputMessage would need to throw "unsupported operation" exceptions for the client implementations.

I'm moving this issue to the General Backlog for now, waiting for 1) better support in client libraries and 2) stronger demand and clearer use cases. It could be that trailers will be mostly used by browsers and CDNs, so not really popular in the server application world.