aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJed Denlea <jed@fastly.com>2015-08-03 18:00:44 -0700
committerRuss Cox <rsc@golang.org>2015-08-05 19:30:24 +0000
commit26049f6f9171d1190f3bbe05ec304845cfe6399f (patch)
tree53007dee2c3a1ed34d25e2a6f3c9bc2370741355
parentf51b7fbdc402716c282a2767ecc9a22e7d977316 (diff)
downloadgo-26049f6f9171d1190f3bbe05ec304845cfe6399f.tar.gz
go-26049f6f9171d1190f3bbe05ec304845cfe6399f.zip
net/http: close server conn after broken trailers
Prior to this change, broken trailers would be handled by body.Read, and an error would be returned to its caller (likely a Handler), but that error would go completely unnoticed by the rest of the server flow allowing a broken connection to be reused. This is a possible request smuggling vector. Fixes #12027. Change-Id: I077eb0b8dff35c5d5534ee5f6386127c9954bd58 Reviewed-on: https://go-review.googlesource.com/13148 Reviewed-by: Russ Cox <rsc@golang.org>
-rw-r--r--src/net/http/serve_test.go34
-rw-r--r--src/net/http/transfer.go6
2 files changed, 40 insertions, 0 deletions
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 7e49981071..d51417eb4a 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -1373,6 +1373,40 @@ func TestRequestBodyReadErrorClosesConnection(t *testing.T) {
}
}
+func TestInvalidTrailerClosesConnection(t *testing.T) {
+ defer afterTest(t)
+ for _, handler := range testHandlerBodyConsumers {
+ conn := new(testConn)
+ conn.readBuf.WriteString("POST /public HTTP/1.1\r\n" +
+ "Host: test\r\n" +
+ "Trailer: hack\r\n" +
+ "Transfer-Encoding: chunked\r\n" +
+ "\r\n" +
+ "3\r\n" +
+ "hax\r\n" +
+ "0\r\n" +
+ "I'm not a valid trailer\r\n" +
+ "GET /secret HTTP/1.1\r\n" +
+ "Host: test\r\n" +
+ "\r\n")
+
+ conn.closec = make(chan bool, 1)
+ ln := &oneConnListener{conn}
+ var numReqs int
+ go Serve(ln, HandlerFunc(func(_ ResponseWriter, req *Request) {
+ numReqs++
+ if strings.Contains(req.URL.Path, "secret") {
+ t.Errorf("Handler %s, Request for /secret encountered, should not have happened.", handler.name)
+ }
+ handler.f(req.Body)
+ }))
+ <-conn.closec
+ if numReqs != 1 {
+ t.Errorf("Handler %s: got %d reqs; want 1", handler.name, numReqs)
+ }
+ }
+}
+
// slowTestConn is a net.Conn that provides a means to simulate parts of a
// request being received piecemeal. Deadlines can be set and enforced in both
// Read and Write.
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index c128a1d3cd..a8736b28e1 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -637,6 +637,12 @@ func (b *body) readLocked(p []byte) (n int, err error) {
if b.hdr != nil {
if e := b.readTrailer(); e != nil {
err = e
+ // Something went wrong in the trailer, we must not allow any
+ // further reads of any kind to succeed from body, nor any
+ // subsequent requests on the server connection. See
+ // golang.org/issue/12027
+ b.sawEOF = false
+ b.closed = true
}
b.hdr = nil
} else {