kazu-yamamoto / http2

HTTP/2.0 library including HPACK
BSD 3-Clause "New" or "Revised" License
84 stars 22 forks source link

Drop frames after reset #106

Closed edsko closed 8 months ago

edsko commented 8 months ago

I don't have a small reproducer for this, but I'm seeing that when I'm sending an ill-formed gRPC request to one of Google's servers (specifically, when I use a GET request instead of a POST request), I'm getting a response back from the server that looks something like this:

HyperText Transfer Protocol 2
    Stream: HEADERS, Stream ID: 1, Length 91, 200 OK
        (..)
        Header: :status: 200 OK
        Header: content-type: application/grpc
        Header: grpc-status: 2
        Header: grpc-message: Bad method header
HyperText Transfer Protocol 2
    Stream: RST_STREAM, Stream ID: 1, Length 4
        Length: 4
        Type: RST_STREAM (3)
        Flags: 0x00
        0... .... .... .... .... .... .... .... = Reserved: 0x0
        .000 0000 0000 0000 0000 0000 0000 0001 = Stream Identifier: 1
        Error: NO_ERROR (0)

and this then repeats a few times (within a single packet). I don't know why this repeats, but both the Google Python implementation and the the C++ implementation do this. When this happens, http2 (the lib) throws an undefined exception after it receives another HTTP2 messages on that now-reset stream. This commit changes this to simply drop such messages instead.

The spec (https://datatracker.ietf.org/doc/html/rfc7540#section-6.4) is strangely silent on this topic: it says that when you receive a RST_STREAM, you MUST NOT send any messages on that stream anymore, and when you send a RST_STREAM, you MUST be prepared to receive frames that your counterpart might have sent before it received the RST_STREAM. However, it is silent on whether or not it's legal to send further frames after sending a RST_STREAM, which is what we are observing here.

kazu-yamamoto commented 8 months ago

Rebased, merged and released. Thanks!