Re: Can servers generate responses to malformed requests in h2?

2023年9月24日(日) 16:23 Martin Thomson <mt@lowentropy.net>:

> (The below is forwarded with permission.)
>
> The question below about error handling in HTTP/2 came up and I think that
> there is an opportunity to document things a little better.  The question
> is whether a server can send a response instead of treating something as a
> stream error.
>
> There are two paragraphs in Section 8.1.1 that are relevant to this
> discussion.  I'll quote them in their entirety, because the context is
> important.
>
> > Intermediaries that process HTTP requests or responses (i.e., any
> intermediary not acting as a tunnel) MUST NOT forward a malformed request
> or response. Malformed requests or responses that are detected MUST be
> treated as a stream error (Section 5.4.2) of type PROTOCOL_ERROR.
> >
> > For malformed requests, a server MAY send an HTTP response prior to
> closing or resetting the stream. Clients MUST NOT accept a malformed
> response.
>
> There are four statements here:
>
> 1. If you are an intermediary, you are responsible for ensuring that
> messages are well formed.  If you forward stuff without checking, that's
> your fault. (Not relevant to this question.)
>
> 2. If you detect an error in a stream, you have to generate an error for
> that stream.
>
> 3. A server MAY send an HTTP response before closing or resetting.  (This
> is the hard one and something that we might have messed up.)
>
> 4. A malformed response is not a response. (Not relevant to this question.)
>
> Now, take the described scenario.  A server receives a malformed request.
> Does it follow (2) and generate a stream (or connection) error or can it
> just follow (3) and send an ordinary response?  The two clauses seem to be
> in tension.
>
> If you assume that (2) applies only to intermediaries, by virtue of it
> being attached to a paragraph about intermediaries, then that strengthens
> the argument for a 4xx response being allowed.
>
> Or, you might say that the specific conditions of (3) override previous
> requirements and give general license to a server to generate responses if
> a stream error is detected.
>
> Either of those interpretations would seem to allow that.  The problem
> with that interpretation is that it doesn't fit our general philosophy in
> developing HTTP/2, which was to ensure that bad behaviour results in
> immediate feedback.  That way, bugs are driven out of the system more
> rapidly.  By that reasoning, a connection error is even better than a
> stream error.  A 4xx response in this case still provides some feedback,
> but the feedback is at a different layer of the stack, so it might less
> effective.
>
> My understanding is that (2) is not intermediary-specific.  Also, (3) is
> less about giving permission, but is instead an attempt to acknowledge the
> possibility that a server might generate a complete response before
> processing an entire request stream.  That is, by the time the server
> detects the error, it's too late to send the error message (though it
> probably could generate a connection error...).  Let's say that the stream
> is properly formed up to a point that a server can parse out a URL, so it
> might know that it needs to generate a 404; or maybe the method might be
> unsupported on any resource on that server, resulting in a 405; or the
> server is overloaded and sends a 503 without processing any data from the
> stream; etc...  In this interpretation, the MAY is a way of saying X MAY do
> A or B and so Y MUST accept A or B.
>
> Either way, this is a little clumsy.  A rearrangement of this text might
> make this position clearer:
>
> > Intermediaries that process HTTP requests or responses (i.e., any
> intermediary not acting as a tunnel) MUST NOT forward a malformed request
> or response.
> >
> > Malformed requests or responses that are detected MUST be treated as a
> stream error (Section 5.4.2) of type PROTOCOL_ERROR. Clients MUST NOT
> accept a malformed response. A malformed request might not be detected
> before a server sends an HTTP response. A server that has generated a
> response can ignore a malformed request, but MAY generate a connection
> error.
>
> Ultimately, I think that Glenn's literal interpretation of the text is a
> defensible one, but it would be better if that interpretation were not
> possible.
>

Just FWIW, h2o intentionally returns a 400 error rather than an H2-level
error when it detects a malformed response in the following two forms: when
an invalid header name is found, or when an invalid header value is found
(e.g., whitespaces surrounding the value).

There are two reasons for using an HTTP error rather than a stream error.

First is that it's carries more information. RST_STREAM only carries an
error code, it does not provide enough information for the peer to
understand why the request was rejected.

Second is that the behavior becomes more consistent across HTTP versions.
In HTTP/1, the only way is to send a 400 error. By doing the same in H2 and
H3, we provide consistency.

I think these benefits have already been pointed out by others, but
hopefully this email act as another data point.


>
> Cheers,
> Martin
>
> ----- Original message -----
> From: Matthew Davidson <matthew@modulolotus.net>
> To: mt@lowentropy.net, cbenfield@apple.com
> Subject: Can you clear up a question we have on RFC 9113 stream error
> requirements?
> Date: Friday, September 22, 2023 04:03
>
> Hi, I'm Matthew Davidson, the maintainer of the Aleph web server. First,
> thank you for all the work you've put into the HTTP specs over the years.
>
> Over in an issue for h2spec (
> https://github.com/summerwind/h2spec/issues/120), we're trying to
> determine what's required/expected/optional from a server in regards to a
> stream error.
>
> The issue creator, Glenn, thinks a normal HTTP response is sufficient, and
> that no RST_STREAM, GOAWAY, or connection close is required, while I think
> an HTTP response is insufficient.
>
> I see a lot of language in the RFC that expects a server to respond to a
> stream error with RST_STREAM (or GOAWAY), but our disagreement hinges on
> one sentence in §8.1.1:
>
> "Malformed requests or responses that are detected MUST be treated as a
> stream error (Section 5.4.2) of type PROTOCOL_ERROR."
>
> Glenn thinks this sentence applies only to intermediaries; I think it
> applies in general. Can you clarify?
>
> Thanks again for all your work,
> Matthew
>
>

-- 
Kazuho Oku

Received on Thursday, 5 October 2023 08:00:43 UTC