net/http: use sync.Pool

Update #4720

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/44080043
diff --git a/src/pkg/net/http/header.go b/src/pkg/net/http/header.go
index ca1ae07..de62bef 100644
--- a/src/pkg/net/http/header.go
+++ b/src/pkg/net/http/header.go
@@ -9,6 +9,7 @@
 	"net/textproto"
 	"sort"
 	"strings"
+	"sync"
 	"time"
 )
 
@@ -114,18 +115,15 @@
 func (s *headerSorter) Swap(i, j int)      { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
 func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
 
-// TODO: convert this to a sync.Cache (issue 4720)
-var headerSorterCache = make(chan *headerSorter, 8)
+var headerSorterPool = sync.Pool{
+	New: func() interface{} { return new(headerSorter) },
+}
 
 // sortedKeyValues returns h's keys sorted in the returned kvs
 // slice. The headerSorter used to sort is also returned, for possible
 // return to headerSorterCache.
 func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
-	select {
-	case hs = <-headerSorterCache:
-	default:
-		hs = new(headerSorter)
-	}
+	hs = headerSorterPool.Get().(*headerSorter)
 	if cap(hs.kvs) < len(h) {
 		hs.kvs = make([]keyValues, 0, len(h))
 	}
@@ -159,10 +157,7 @@
 			}
 		}
 	}
-	select {
-	case headerSorterCache <- sorter:
-	default:
-	}
+	headerSorterPool.Put(sorter)
 	return nil
 }
 
diff --git a/src/pkg/net/http/request.go b/src/pkg/net/http/request.go
index 57b5d09..7702d32 100644
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -20,6 +20,7 @@
 	"net/url"
 	"strconv"
 	"strings"
+	"sync"
 )
 
 const (
@@ -494,25 +495,20 @@
 	return line[:s1], line[s1+1 : s2], line[s2+1:], true
 }
 
-// TODO(bradfitz): use a sync.Cache when available
-var textprotoReaderCache = make(chan *textproto.Reader, 4)
+var textprotoReaderPool sync.Pool
 
 func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
-	select {
-	case r := <-textprotoReaderCache:
-		r.R = br
-		return r
-	default:
-		return textproto.NewReader(br)
+	if v := textprotoReaderPool.Get(); v != nil {
+		tr := v.(*textproto.Reader)
+		tr.R = br
+		return tr
 	}
+	return textproto.NewReader(br)
 }
 
 func putTextprotoReader(r *textproto.Reader) {
 	r.R = nil
-	select {
-	case textprotoReaderCache <- r:
-	default:
-	}
+	textprotoReaderPool.Put(r)
 }
 
 // ReadRequest reads and parses a request from b.
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index 0e46863..3b80d45 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -435,56 +435,52 @@
 	return c, nil
 }
 
-// TODO: use a sync.Cache instead
 var (
-	bufioReaderCache   = make(chan *bufio.Reader, 4)
-	bufioWriterCache2k = make(chan *bufio.Writer, 4)
-	bufioWriterCache4k = make(chan *bufio.Writer, 4)
+	bufioReaderPool   sync.Pool
+	bufioWriter2kPool sync.Pool
+	bufioWriter4kPool sync.Pool
 )
 
-func bufioWriterCache(size int) chan *bufio.Writer {
+func bufioWriterPool(size int) *sync.Pool {
 	switch size {
 	case 2 << 10:
-		return bufioWriterCache2k
+		return &bufioWriter2kPool
 	case 4 << 10:
-		return bufioWriterCache4k
+		return &bufioWriter4kPool
 	}
 	return nil
 }
 
 func newBufioReader(r io.Reader) *bufio.Reader {
-	select {
-	case p := <-bufioReaderCache:
-		p.Reset(r)
-		return p
-	default:
-		return bufio.NewReader(r)
+	if v := bufioReaderPool.Get(); v != nil {
+		br := v.(*bufio.Reader)
+		br.Reset(r)
+		return br
 	}
+	return bufio.NewReader(r)
 }
 
 func putBufioReader(br *bufio.Reader) {
 	br.Reset(nil)
-	select {
-	case bufioReaderCache <- br:
-	default:
-	}
+	bufioReaderPool.Put(br)
 }
 
 func newBufioWriterSize(w io.Writer, size int) *bufio.Writer {
-	select {
-	case p := <-bufioWriterCache(size):
-		p.Reset(w)
-		return p
-	default:
-		return bufio.NewWriterSize(w, size)
+	pool := bufioWriterPool(size)
+	if pool != nil {
+		if v := pool.Get(); v != nil {
+			bw := v.(*bufio.Writer)
+			bw.Reset(w)
+			return bw
+		}
 	}
+	return bufio.NewWriterSize(w, size)
 }
 
 func putBufioWriter(bw *bufio.Writer) {
 	bw.Reset(nil)
-	select {
-	case bufioWriterCache(bw.Available()) <- bw:
-	default:
+	if pool := bufioWriterPool(bw.Available()); pool != nil {
+		pool.Put(bw)
 	}
 }