http2: reject incoming HEADERS in Server on half-closed streams
Headers received on a half closed remote stream must respond with a
stream error of type STREAM_CLOSED.
Updates golang/go#25023
Change-Id: Ia369b24318aec6df769ecf0911d5152459bb25b2
Reviewed-on: https://go-review.googlesource.com/111677
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/http2/server.go b/http2/server.go
index 7938991..e111019 100644
--- a/http2/server.go
+++ b/http2/server.go
@@ -1721,6 +1721,13 @@
// processing this frame.
return nil
}
+ // RFC 7540, sec 5.1: If an endpoint receives additional frames, other than
+ // WINDOW_UPDATE, PRIORITY, or RST_STREAM, for a stream that is in
+ // this state, it MUST respond with a stream error (Section 5.4.2) of
+ // type STREAM_CLOSED.
+ if st.state == stateHalfClosedRemote {
+ return streamError(id, ErrCodeStreamClosed)
+ }
return st.processTrailerHeaders(f)
}
diff --git a/http2/server_test.go b/http2/server_test.go
index 9c3e549..1573889 100644
--- a/http2/server_test.go
+++ b/http2/server_test.go
@@ -3841,3 +3841,51 @@
}
})
}
+
+func TestServer_Headers_HalfCloseRemote(t *testing.T) {
+ var st *serverTester
+ inHandler := make(chan bool)
+ writeHeaders := make(chan bool)
+ leaveHandler := make(chan bool)
+ st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
+ inHandler <- true
+ if st.stream(1) == nil {
+ t.Errorf("nil stream 1 in handler")
+ }
+ if got, want := st.streamState(1), stateOpen; got != want {
+ t.Errorf("in handler, state is %v; want %v", got, want)
+ }
+ if n, err := r.Body.Read(make([]byte, 1)); n != 0 || err != io.EOF {
+ t.Errorf("body read = %d, %v; want 0, EOF", n, err)
+ }
+ if got, want := st.streamState(1), stateHalfClosedRemote; got != want {
+ t.Errorf("in handler, state is %v; want %v", got, want)
+ }
+ writeHeaders <- true
+
+ <-leaveHandler
+ })
+ st.greet()
+
+ st.writeHeaders(HeadersFrameParam{
+ StreamID: 1,
+ BlockFragment: st.encodeHeader(),
+ EndStream: false, // keep it open
+ EndHeaders: true,
+ })
+ <-inHandler
+ st.writeData(1, true, nil)
+
+ <-writeHeaders
+
+ st.writeHeaders(HeadersFrameParam{
+ StreamID: 1,
+ BlockFragment: st.encodeHeader(),
+ EndStream: false, // keep it open
+ EndHeaders: true,
+ })
+
+ defer close(leaveHandler)
+
+ st.wantRSTStream(1, ErrCodeStreamClosed)
+}