Skip to content

Commit 702349b

Browse files
committed
http2/h2c: handle errors when reading HTTP/1 request body
When processing an HTTP/1 Upgrade: h2c request, detect errors reading the request body and fail the request rather than passing off the partially-read request to the HTTP/2 server. Correctly handles the case where a MaxBytesHandler has limited the size of the initial HTTP/1 request body. Fixes golang/go#56352 Change-Id: I08d60953cea26961cffbab3094cc1b44236f4e37 Reviewed-on: https://go-review.googlesource.com/c/net/+/447396 Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: John Howard <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Run-TryBot: Damien Neil <[email protected]>
1 parent 7a67682 commit 702349b

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

http2/h2c/h2c.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
109109
if http2VerboseLogs {
110110
log.Printf("h2c: error h2c upgrade: %v", err)
111111
}
112+
w.WriteHeader(http.StatusInternalServerError)
112113
return
113114
}
114115
defer conn.Close()
@@ -167,7 +168,10 @@ func h2cUpgrade(w http.ResponseWriter, r *http.Request) (_ net.Conn, settings []
167168
return nil, nil, errors.New("h2c: connection does not support Hijack")
168169
}
169170

170-
body, _ := io.ReadAll(r.Body)
171+
body, err := io.ReadAll(r.Body)
172+
if err != nil {
173+
return nil, nil, err
174+
}
171175
r.Body = io.NopCloser(bytes.NewBuffer(body))
172176

173177
conn, rw, err := hijacker.Hijack()

http2/h2c/h2c_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"context"
99
"crypto/tls"
1010
"fmt"
11+
"io"
1112
"io/ioutil"
1213
"log"
1314
"net"
@@ -134,3 +135,38 @@ func TestPropagation(t *testing.T) {
134135
t.Fatal("expected server err, got nil")
135136
}
136137
}
138+
139+
func TestMaxBytesHandler(t *testing.T) {
140+
const bodyLimit = 10
141+
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
142+
t.Errorf("got request, expected to be blocked by body limit")
143+
})
144+
145+
h2s := &http2.Server{}
146+
h1s := httptest.NewUnstartedServer(http.MaxBytesHandler(NewHandler(handler, h2s), bodyLimit))
147+
h1s.Start()
148+
defer h1s.Close()
149+
150+
// Wrap the body in a struct{io.Reader} to prevent it being rewound and resent.
151+
body := "0123456789abcdef"
152+
req, err := http.NewRequest("POST", h1s.URL, struct{ io.Reader }{strings.NewReader(body)})
153+
if err != nil {
154+
t.Fatal(err)
155+
}
156+
req.Header.Set("Http2-Settings", "")
157+
req.Header.Set("Upgrade", "h2c")
158+
req.Header.Set("Connection", "Upgrade, HTTP2-Settings")
159+
160+
resp, err := h1s.Client().Do(req)
161+
if err != nil {
162+
t.Fatal(err)
163+
}
164+
defer resp.Body.Close()
165+
_, err = ioutil.ReadAll(resp.Body)
166+
if err != nil {
167+
t.Fatal(err)
168+
}
169+
if got, want := resp.StatusCode, http.StatusInternalServerError; got != want {
170+
t.Errorf("resp.StatusCode = %v, want %v", got, want)
171+
}
172+
}

0 commit comments

Comments
 (0)