Skip to content

Commit

Permalink
Add cache of common HTTP headers mapped between lower and canonical c…
Browse files Browse the repository at this point in the history
…ase.

For garbage reduction.
  • Loading branch information
bradfitz committed Nov 15, 2014
1 parent 9e0eccc commit 6520e26
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 11 deletions.
80 changes: 80 additions & 0 deletions headermap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
// Licensed under the same terms as Go itself:
// https://code.google.com/p/go/source/browse/LICENSE

package http2

import (
"net/http"
"strings"
)

var (
commonLowerHeader = map[string]string{} // Go-Canonical-Case -> lower-case
commonCanonHeader = map[string]string{} // lower-case -> Go-Canonical-Case
)

func init() {
for _, v := range []string{
"accept",
"accept-charset",
"accept-encoding",
"accept-language",
"accept-ranges",
"age",
"access-control-allow-origin",
"allow",
"authorization",
"cache-control",
"content-disposition",
"content-encoding",
"content-language",
"content-length",
"content-location",
"content-range",
"content-type",
"cookie",
"date",
"etag",
"expect",
"expires",
"from",
"host",
"if-match",
"if-modified-since",
"if-none-match",
"if-unmodified-since",
"last-modified",
"link",
"location",
"max-forwards",
"proxy-authenticate",
"proxy-authorization",
"range",
"referer",
"refresh",
"retry-after",
"server",
"set-cookie",
"strict-transport-security",
"transfer-encoding",
"user-agent",
"vary",
"via",
"www-authenticate",
} {
chk := http.CanonicalHeaderKey(v)
commonLowerHeader[chk] = v
commonCanonHeader[v] = chk
}
}

func lowerHeader(v string) string {
if s, ok := commonLowerHeader[v]; ok {
return s
}
return strings.ToLower(v)
}
26 changes: 15 additions & 11 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) {
handler: h,
framer: NewFramer(c, c), // TODO: write to a (custom?) buffered writer that can alternate when it's in buffered mode.
streams: make(map[uint32]*stream),
canonHeader: make(map[string]string),
readFrameCh: make(chan frameAndProcessed),
readFrameErrCh: make(chan error, 1), // must be buffered for 1
wantWriteFrameCh: make(chan frameWriteMsg, 8),
Expand Down Expand Up @@ -258,12 +257,19 @@ func (sc *serverConn) onNewHeaderField(f hpack.HeaderField) {

func (sc *serverConn) canonicalHeader(v string) string {
sc.serveG.check()
// TODO: use a sync.Pool instead of putting the cache on *serverConn?
cv, ok := sc.canonHeader[v]
if !ok {
cv = http.CanonicalHeaderKey(v)
sc.canonHeader[v] = cv
cv, ok := commonCanonHeader[v]
if ok {
return cv
}
cv, ok = sc.canonHeader[v]
if ok {
return cv
}
if sc.canonHeader == nil {
sc.canonHeader = make(map[string]string)
}
cv = http.CanonicalHeaderKey(v)
sc.canonHeader[v] = cv
return cv
}

Expand Down Expand Up @@ -845,15 +851,13 @@ func (sc *serverConn) writeHeadersFrame(v interface{}) error {
sc.headerWriteBuf.Reset()
sc.hpackEncoder.WriteField(hpack.HeaderField{Name: ":status", Value: httpCodeString(req.httpResCode)})
for k, vv := range req.h {
k = lowerHeader(k)
for _, v := range vv {
// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
if k == "Transfer-Encoding" && v != "trailers" {
if k == "transfer-encoding" && v != "trailers" {
continue
}
// TODO: for gargage, cache lowercase copies of headers at
// least for common ones and/or popular recent ones for
// this serverConn. LRU?
sc.hpackEncoder.WriteField(hpack.HeaderField{Name: strings.ToLower(k), Value: v})
sc.hpackEncoder.WriteField(hpack.HeaderField{Name: k, Value: v})
}
}
if req.contentType != "" {
Expand Down

0 comments on commit 6520e26

Please sign in to comment.