From: Brad Fitzpatrick Date: Mon, 20 May 2013 14:23:59 +0000 (-0700) Subject: net/http: simplify transfer body; reduces allocations too X-Git-Tag: go1.2rc2~1469 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=27f7427995782bf60195ca65fd9b44aa34913b75;p=gostls13.git net/http: simplify transfer body; reduces allocations too benchmark old ns/op new ns/op delta BenchmarkServerFakeConnNoKeepAlive 14431 14247 -1.28% BenchmarkServerFakeConnWithKeepAlive 11618 11357 -2.25% BenchmarkServerFakeConnWithKeepAliveLite 6735 6427 -4.57% BenchmarkServerHandlerTypeLen 8842 8740 -1.15% BenchmarkServerHandlerNoLen 8001 7828 -2.16% BenchmarkServerHandlerNoType 8270 8227 -0.52% BenchmarkServerHandlerNoHeader 6148 5920 -3.71% benchmark old allocs new allocs delta BenchmarkServerFakeConnNoKeepAlive 30 29 -3.33% BenchmarkServerFakeConnWithKeepAlive 25 24 -4.00% BenchmarkServerFakeConnWithKeepAliveLite 10 9 -10.00% BenchmarkServerHandlerTypeLen 18 17 -5.56% BenchmarkServerHandlerNoLen 15 14 -6.67% BenchmarkServerHandlerNoType 16 15 -6.25% BenchmarkServerHandlerNoHeader 10 9 -10.00% benchmark old bytes new bytes delta BenchmarkServerFakeConnNoKeepAlive 2557 2492 -2.54% BenchmarkServerFakeConnWithKeepAlive 2260 2194 -2.92% BenchmarkServerFakeConnWithKeepAliveLite 1092 1026 -6.04% BenchmarkServerHandlerTypeLen 1941 1875 -3.40% BenchmarkServerHandlerNoLen 1898 1832 -3.48% BenchmarkServerHandlerNoType 1906 1840 -3.46% BenchmarkServerHandlerNoHeader 1092 1026 -6.04% Update #5195 R=golang-dev, daniel.morsing CC=golang-dev https://golang.org/cl/9492044 --- diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go index fe35562447..698d3f9d46 100644 --- a/src/pkg/net/http/server.go +++ b/src/pkg/net/http/server.go @@ -1814,7 +1814,15 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) { } // eofReader is a non-nil io.ReadCloser that always returns EOF. -var eofReader = ioutil.NopCloser(strings.NewReader("")) +// It embeds a *strings.Reader so it still has a WriteTo method +// and io.Copy won't need a buffer. +var eofReader = &struct { + *strings.Reader + io.Closer +}{ + strings.NewReader(""), + ioutil.NopCloser(nil), +} // initNPNRequest is an HTTP handler that initializes certain // uninitialized fields in its *Request. Such partially-initialized diff --git a/src/pkg/net/http/transfer.go b/src/pkg/net/http/transfer.go index 53569bcc2f..b97f7160f4 100644 --- a/src/pkg/net/http/transfer.go +++ b/src/pkg/net/http/transfer.go @@ -328,12 +328,12 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { switch { case chunked(t.TransferEncoding): if noBodyExpected(t.RequestMethod) { - t.Body = &body{Reader: eofReader, closing: t.Close} + t.Body = eofReader } else { t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close} } case realLength == 0: - t.Body = &body{Reader: eofReader, closing: t.Close} + t.Body = eofReader case realLength > 0: t.Body = &body{Reader: io.LimitReader(r, realLength), closing: t.Close} default: @@ -343,7 +343,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { t.Body = &body{Reader: r, closing: t.Close} } else { // Persistent connection (i.e. HTTP/1.1) - t.Body = &body{Reader: eofReader, closing: t.Close} + t.Body = eofReader } } @@ -518,8 +518,6 @@ type body struct { r *bufio.Reader // underlying wire-format reader for the trailer closing bool // is the connection to be closed after reading body? closed bool - - res *response // response writer for server requests, else nil } // ErrBodyReadAfterClose is returned when reading a Request or Response @@ -618,14 +616,6 @@ func (b *body) Close() error { case b.hdr == nil && b.closing: // no trailer and closing the connection next. // no point in reading to EOF. - case b.res != nil && b.res.requestBodyLimitHit: - // In a server request, don't continue reading from the client - // if we've already hit the maximum body size set by the - // handler. If this is set, that also means the TCP connection - // is about to be closed, so getting to the next HTTP request - // in the stream is not necessary. - case b.Reader == eofReader: - // Nothing to read. No need to io.Copy from it. default: // Fully consume the body, which will also lead to us reading // the trailer headers after the body, if present.