http2: don't flush a stream's write queue in sc.resetStream
resetStream(st) queues a RST_STREAM frame and then calls closeStream(st). Unfortunately, closeStream(st) flushes any writes pending on st, which can drop the RST_STREAM that was just queued. (If we are lucky, the RST_STREAM will fit in the send buffer and won't be dropped, however, if we are unlucky the RST_STREAM will be dropped.) I fixed this bug by removing closeStream(st) from resetStream. Instead, closeStream happens after the RST_STREAM frame is written. This is a more direct implementation of the diagram in RFC 7540 Section 5.1, which says that a stream does not transition to "closed" until after the RST_STREAM has been sent. A side-effect is that the stream may stay open for longer than it did previously (since it won't close until *after* the RST_STREAM frame is actually written). Situations like the following are a problem: - Client sends a DATA frame that exceeds its flow-control window - Server returns streamError(ErrCodeFlowControl) from processData - RST_STREAM is queued behind other frames - Server process the request body and releases flow-control - Client sends another DATA frame, this one fits in the flow-control window. Server should NOT process this frame. To avoid the above problem, we set a bool st.resetQueued=true when RST_STREAM is queued, then ignore all future incoming HEADERS and DATA frames on that stream. I also removed st.sentReset and st.gotReset, which were used to ignore frames after RST_STREAM is sent. Now we just check if the stream is closed. Fixes golang/go#18111 Change-Id: Ieb7c848989431add5b7d95f40d6d91db7edc4980 Reviewed-on: https://go-review.googlesource.com/34238Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Showing
Please
register
or
sign in
to comment