Re: H2 vs responses which should not carry any payload

Hi Mark,

On Sat, Oct 24, 2020 at 01:07:19PM +1100, Mark Nottingham wrote:
> My .02 -
> 
> 204/304/1xx and head responses are defined by HTTP's core semantics to not have a body. 
> 
> HTTP/1 enforced those in the framing mechanism (if you didn't, you lost framing reliability and Bad Things happened).
> 
> HTTP/2 doesn't explicitly enforce them, which means that we're now in similar territory to "Can GET have a request body?" ... and we've all seen how much angst that causes.
> 
> Whether or not you should strip them, generate an error, or just pass them
> through depends on what you're doing. In general, HTTP wants implementations
> that don't have to "know" the whole protocol, to allow extensions to be
> deployed successfully, and to allow simpler implementations to succeed. So
> while HTTP/1 requires that implementations understand these situations to
> maintain framing, I think it's reasonable to not have that requirement (and
> we don't) in HTTP/2, because framing doesn't depend upon it.
> 
> That doesn't mean that putting a response body on a 304 or HEAD response is
> interoperable or a good thing to do; it just means that you're not obligated
> to refuse that message -- and we should be super crisp in http-core about
> what this means.

That's exactly the difficulty. We know that responses to HEAD containing
body were quite frequent due to error pages. Typically a hard-coded 403
or 500 returned directly based on the URI or due to a server malfunction
would not even check the method. But I think that it's getting tricky for
intermediaries, as they want to have the smallest possible impact on the
existing infrastructure, thus if possible not add errors on top of existing
errors. Also they have a greater responsibility here, for example when
translating H1 requests to H2: if an H2 response contains a body where
it's not supposed to, it must in no way be serialized to H1. So this is
what makes me think that the "cleanup" if any should be enforced at the
semantic layer, and that the messaging layers should only produce errors
if the unexpected situation would break the protocol.

In haproxy's case, this would mean always passing headers of 204/304/HEAD
responses to a client, and silently dropping any body for H2 or breaking
the server-side connection for H1 if a body appears there.

For H2 remains the case of trailers. My view on this (possibly skewed by
H1) is that trailers extend the body and must not be delivered when no
body is expected. In H1 there's no doubt about it since it was explicitly
stated that bodyless responses end after the "first empty line" and
"regardless of headers" which means that T-E is ignored and that there's
no way to append trailers. But in H2 they can be used to trivially deliver
an operational status and I can understand how some implementations would
prefer to always send their status in a trailer rather than in a header.
This could result in HEAD/204/304 to contain trailers. And I'm even
wondering if gRPC doesn't do that with their "grpc-status" trailer.
Thus I suspect that for now we'll stick to strict semantics by trimming
any received body but possibly appending trailers for H2. We may revisit
this later if that causes trouble :-/

Thanks!
Willy

Received on Saturday, 24 October 2020 06:16:41 UTC