Skip to content

Commit

Permalink
http2: reject incoming HEADERS in Server on half-closed streams
Browse files Browse the repository at this point in the history
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 <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Brad Fitzpatrick <[email protected]>
  • Loading branch information
fraenkel authored and bradfitz committed Jul 10, 2018
1 parent 6a8eb5e commit 292b43b
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
7 changes: 7 additions & 0 deletions http2/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,13 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
// 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)
}

Expand Down
48 changes: 48 additions & 0 deletions http2/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3841,3 +3841,51 @@ func TestServerHandlerConnectionClose(t *testing.T) {
}
})
}

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)
}

0 comments on commit 292b43b

Please sign in to comment.