Commit b1050542 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: don't panic after request if Handler sets Request.Body to nil

The Server's server goroutine was panicing (but recovering) when
cleaning up after handling a request. It was pretty harmless (it just
closed that one connection and didn't kill the whole process) but it
was distracting.

Updates #13135

Change-Id: I2a0ce9e8b52c8d364e3f4ce245e05c6f8d62df14
Reviewed-on: https://go-review.googlesource.com/16572
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarAndrew Gerrand <adg@golang.org>
parent 9179c9cb
...@@ -3381,6 +3381,31 @@ func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) { ...@@ -3381,6 +3381,31 @@ func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) {
} }
} }
func TestHandlerSetsBodyNil(t *testing.T) {
defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
r.Body = nil
fmt.Fprintf(w, "%v", r.RemoteAddr)
}))
defer ts.Close()
get := func() string {
res, err := Get(ts.URL)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
slurp, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
return string(slurp)
}
a, b := get(), get()
if a != b {
t.Errorf("Failed to reuse connections between requests: %v vs %v", a, b)
}
}
func BenchmarkClientServer(b *testing.B) { func BenchmarkClientServer(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
b.StopTimer() b.StopTimer()
......
...@@ -317,8 +317,9 @@ func (cw *chunkWriter) close() { ...@@ -317,8 +317,9 @@ func (cw *chunkWriter) close() {
type response struct { type response struct {
conn *conn conn *conn
req *Request // request for this response req *Request // request for this response
wroteHeader bool // reply header has been (logically) written reqBody io.ReadCloser
wroteContinue bool // 100 Continue response was written wroteHeader bool // reply header has been (logically) written
wroteContinue bool // 100 Continue response was written
w *bufio.Writer // buffers output in chunks to chunkWriter w *bufio.Writer // buffers output in chunks to chunkWriter
cw chunkWriter cw chunkWriter
...@@ -658,6 +659,7 @@ func (c *conn) readRequest() (w *response, err error) { ...@@ -658,6 +659,7 @@ func (c *conn) readRequest() (w *response, err error) {
w = &response{ w = &response{
conn: c, conn: c,
req: req, req: req,
reqBody: req.Body,
handlerHeader: make(Header), handlerHeader: make(Header),
contentLength: -1, contentLength: -1,
} }
...@@ -1167,7 +1169,7 @@ func (w *response) finishRequest() { ...@@ -1167,7 +1169,7 @@ func (w *response) finishRequest() {
// Close the body (regardless of w.closeAfterReply) so we can // Close the body (regardless of w.closeAfterReply) so we can
// re-use its bufio.Reader later safely. // re-use its bufio.Reader later safely.
w.req.Body.Close() w.reqBody.Close()
if w.req.MultipartForm != nil { if w.req.MultipartForm != nil {
w.req.MultipartForm.RemoveAll() w.req.MultipartForm.RemoveAll()
......
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