Commit 41c5c5cb authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

http2: make Server return conn protocol errors on bad idle stream frames

Per RFC 7540, section 5.1 discussing the "idle" state: "Receiving any
frame other than HEADERS or PRIORITY on a stream in this state MUST be
treated as a connection error (Section 5.4.1) of type PROTOCOL_ERROR."x

Updates golang/go#16046

Change-Id: Ie0696059e76a092e483aea5ee017d9729339d309
Reviewed-on: https://go-review.googlesource.com/31736
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 40a0a189
......@@ -1122,7 +1122,14 @@ func (sc *serverConn) processWindowUpdate(f *WindowUpdateFrame) error {
sc.serveG.check()
switch {
case f.StreamID != 0: // stream-level flow control
st := sc.streams[f.StreamID]
state, st := sc.state(f.StreamID)
if state == stateIdle {
// Section 5.1: "Receiving any frame other than HEADERS
// or PRIORITY on a stream in this state MUST be
// treated as a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR."
return ConnectionError(ErrCodeProtocol)
}
if st == nil {
// "WINDOW_UPDATE can be sent by a peer that has sent a
// frame bearing the END_STREAM flag. This means that a
......@@ -1274,8 +1281,15 @@ func (sc *serverConn) processData(f *DataFrame) error {
// or "half closed (local)" state, the recipient MUST respond
// with a stream error (Section 5.4.2) of type STREAM_CLOSED."
id := f.Header().StreamID
st, ok := sc.streams[id]
if !ok || st.state != stateOpen || st.gotTrailerHeader {
state, st := sc.state(id)
if id == 0 || state == stateIdle {
// Section 5.1: "Receiving any frame other than HEADERS
// or PRIORITY on a stream in this state MUST be
// treated as a connection error (Section 5.4.1) of
// type PROTOCOL_ERROR."
return ConnectionError(ErrCodeProtocol)
}
if st == nil || state != stateOpen || st.gotTrailerHeader {
// This includes sending a RST_STREAM if the stream is
// in stateHalfClosedLocal (which currently means that
// the http.Handler returned, so it's done reading &
......
......@@ -937,7 +937,7 @@ func TestServer_Request_Reject_Pseudo_Unknown(t *testing.T) {
func testRejectRequest(t *testing.T, send func(*serverTester)) {
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
t.Fatal("server request made it to handler; should've been rejected")
t.Error("server request made it to handler; should've been rejected")
})
defer st.Close()
......@@ -946,6 +946,39 @@ func testRejectRequest(t *testing.T, send func(*serverTester)) {
st.wantRSTStream(1, ErrCodeProtocol)
}
func testRejectRequestWithProtocolError(t *testing.T, send func(*serverTester)) {
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
t.Error("server request made it to handler; should've been rejected")
}, optQuiet)
defer st.Close()
st.greet()
send(st)
gf := st.wantGoAway()
if gf.ErrCode != ErrCodeProtocol {
t.Errorf("err code = %v; want %v", gf.ErrCode, ErrCodeProtocol)
}
}
// Section 5.1, on idle connections: "Receiving any frame other than
// HEADERS or PRIORITY on a stream in this state MUST be treated as a
// connection error (Section 5.4.1) of type PROTOCOL_ERROR."
func TestRejectFrameOnIdle_WindowUpdate(t *testing.T) {
testRejectRequestWithProtocolError(t, func(st *serverTester) {
st.fr.WriteWindowUpdate(123, 456)
})
}
func TestRejectFrameOnIdle_Data(t *testing.T) {
testRejectRequestWithProtocolError(t, func(st *serverTester) {
st.fr.WriteData(123, true, nil)
})
}
func TestRejectFrameOnIdle_RSTStream(t *testing.T) {
testRejectRequestWithProtocolError(t, func(st *serverTester) {
st.fr.WriteRSTStream(123, ErrCodeCancel)
})
}
func TestServer_Request_Connect(t *testing.T) {
testServerRequest(t, func(st *serverTester) {
st.writeHeaders(HeadersFrameParam{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment