Skip to content

Commit bf014ff

Browse files
committed
http2: send undeclared trailers when body is not written
Fix a bug wherein undeclared trailers (set with the "Trailer:" prefix) were not sent when the response body is neither written nor flushed. We were testing responseWriterState.hasTrailers before promoting undeclared trailers into rws.trailers, resulting in the response headers being sent with an END_STREAM flag. Promote undeclared headers earlier so that we leave the stream open for them to be sent. For golang/go#54723 Change-Id: Ic036925f4a7ec775282b6e474aa72249d6418b23 Reviewed-on: https://go-review.googlesource.com/c/net/+/426874 TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Damien Neil <dneil@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
1 parent 4a395b0 commit bf014ff

File tree

2 files changed

+28
-4
lines changed

2 files changed

+28
-4
lines changed

‎http2/server.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2500,6 +2500,10 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
25002500
rws.writeHeader(200)
25012501
}
25022502

2503+
if rws.handlerDone {
2504+
rws.promoteUndeclaredTrailers()
2505+
}
2506+
25032507
isHeadResp := rws.req.Method == "HEAD"
25042508
if !rws.sentHeader {
25052509
rws.sentHeader = true
@@ -2571,10 +2575,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
25712575
return 0, nil
25722576
}
25732577

2574-
if rws.handlerDone {
2575-
rws.promoteUndeclaredTrailers()
2576-
}
2577-
25782578
// only send trailers if they have actually been defined by the
25792579
// server handler.
25802580
hasNonemptyTrailers := rws.hasNonemptyTrailers()

‎http2/server_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3055,6 +3055,30 @@ func testServerWritesTrailers(t *testing.T, withFlush bool) {
30553055
})
30563056
}
30573057

3058+
func TestServerWritesUndeclaredTrailers(t *testing.T) {
3059+
const trailer = "Trailer-Header"
3060+
const value = "hi1"
3061+
st := newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
3062+
w.Header().Set(http.TrailerPrefix+trailer, value)
3063+
}, optOnlyServer)
3064+
defer st.Close()
3065+
3066+
tr := &Transport{TLSClientConfig: tlsConfigInsecure}
3067+
defer tr.CloseIdleConnections()
3068+
3069+
cl := &http.Client{Transport: tr}
3070+
resp, err := cl.Get(st.ts.URL)
3071+
if err != nil {
3072+
t.Fatal(err)
3073+
}
3074+
io.Copy(io.Discard, resp.Body)
3075+
resp.Body.Close()
3076+
3077+
if got, want := resp.Trailer.Get(trailer), value; got != want {
3078+
t.Errorf("trailer %v = %q, want %q", trailer, got, want)
3079+
}
3080+
}
3081+
30583082
// validate transmitted header field names & values
30593083
// golang.org/issue/14048
30603084
func TestServerDoesntWriteInvalidHeaders(t *testing.T) {

0 commit comments

Comments
 (0)