Commit 0a798aaf authored by Matthew Holt's avatar Matthew Holt

mitm, templates, context: Pool buffers to reduce allocations

Also disable some tests on context.Hostname because they're not portable
parent f8614b87
......@@ -11,6 +11,7 @@ import (
"net/url"
"path"
"strings"
"sync"
"text/template"
"time"
......@@ -256,9 +257,6 @@ func (c Context) Markdown(filename string) (string, error) {
return string(markdown), nil
}
// TemplateFuncs contains user defined functions
var TemplateFuncs = template.FuncMap{}
// ContextInclude opens filename using fs and executes a template with the context ctx.
// This does the same thing that Context.Include() does, but with the ability to provide
// your own context so that the included files can have access to additional fields your
......@@ -281,8 +279,10 @@ func ContextInclude(filename string, ctx interface{}, fs http.FileSystem) (strin
return "", err
}
var buf bytes.Buffer
err = tpl.Execute(&buf, ctx)
buf := includeBufs.Get().(*bytes.Buffer)
buf.Reset()
defer includeBufs.Put(buf)
err = tpl.Execute(buf, ctx)
if err != nil {
return "", err
}
......@@ -409,3 +409,14 @@ func (c Context) RandomString(minLen, maxLen int) string {
return string(result)
}
// buffer pool for .Include context actions
var includeBufs = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
// TemplateFuncs contains user-defined functions
// for execution in templates.
var TemplateFuncs = template.FuncMap{}
......@@ -251,14 +251,16 @@ func TestHostname(t *testing.T) {
inputRemoteAddr string
expectedHostname string
}{
// TODO(mholt): Fix these tests, they're not portable. i.e. my resolver
// returns "fwdr-8.fwdr-8.fwdr-8.fwdr-8." instead of these google ones.
// Test 0 - ipv4 with port
{"8.8.8.8:1111", "google-public-dns-a.google.com."},
// Test 1 - ipv4 without port
{"8.8.8.8", "google-public-dns-a.google.com."},
// Test 2 - ipv6 with port
{"[2001:4860:4860::8888]:11", "google-public-dns-a.google.com."},
// Test 3 - ipv6 without port and brackets
{"2001:4860:4860::8888", "google-public-dns-a.google.com."},
// {"8.8.8.8:1111", "google-public-dns-a.google.com."},
// // Test 1 - ipv4 without port
// {"8.8.8.8", "google-public-dns-a.google.com."},
// // Test 2 - ipv6 with port
// {"[2001:4860:4860::8888]:11", "google-public-dns-a.google.com."},
// // Test 3 - ipv6 without port and brackets
// {"2001:4860:4860::8888", "google-public-dns-a.google.com."},
// Test 4 - no hostname available
{"1.1.1.1", "1.1.1.1"},
}
......
......@@ -133,7 +133,7 @@ func (c *clientHelloConn) Read(b []byte) (n int, err error) {
if err != nil {
return
}
c.buf = nil // buffer no longer needed
bufpool.Put(c.buf) // buffer no longer needed
// parse the ClientHello and store it in the map
rawParsed := parseRawClientHello(hello)
......@@ -285,7 +285,9 @@ func (l *tlsHelloListener) Accept() (net.Conn, error) {
if err != nil {
return nil, err
}
helloConn := &clientHelloConn{Conn: conn, listener: l, buf: new(bytes.Buffer)}
buf := bufpool.Get().(*bytes.Buffer)
buf.Reset()
helloConn := &clientHelloConn{Conn: conn, listener: l, buf: buf}
return tls.Server(helloConn, l.config), nil
}
......@@ -570,6 +572,13 @@ func hasGreaseCiphers(cipherSuites []uint16) bool {
return false
}
// pool buffers so we can reuse allocations over time
var bufpool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
var greaseCiphers = map[uint16]struct{}{
0x0A0A: {},
0x1A1A: {},
......
package templates
import (
"bytes"
"net/http"
"sync"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
......@@ -27,6 +29,11 @@ func setup(c *caddy.Controller) error {
Rules: rules,
Root: cfg.Root,
FileSys: http.Dir(cfg.Root),
BufPool: &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
},
}
cfg.AddMiddleware(func(next httpserver.Handler) httpserver.Handler {
......
......@@ -9,6 +9,7 @@ import (
"os"
"path"
"path/filepath"
"sync"
"text/template"
"github.com/mholt/caddy/caddyhttp/httpserver"
......@@ -60,8 +61,10 @@ func (t Templates) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
}
// Execute it
var buf bytes.Buffer
err = tpl.Execute(&buf, ctx)
buf := t.BufPool.Get().(*bytes.Buffer)
buf.Reset()
defer t.BufPool.Put(buf)
err = tpl.Execute(buf, ctx)
if err != nil {
return http.StatusInternalServerError, err
}
......@@ -97,6 +100,7 @@ type Templates struct {
Rules []Rule
Root string
FileSys http.FileSystem
BufPool *sync.Pool // docs: "A Pool must not be copied after first use."
}
// Rule represents a template rule. A template will only execute
......
package templates
import (
"bytes"
"net/http"
"net/http/httptest"
"sync"
"testing"
"github.com/mholt/caddy/caddyhttp/httpserver"
......@@ -28,6 +30,7 @@ func TestTemplates(t *testing.T) {
},
Root: "./testdata",
FileSys: http.Dir("./testdata"),
BufPool: &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }},
}
tmplroot := Templates{
......@@ -43,6 +46,7 @@ func TestTemplates(t *testing.T) {
},
Root: "./testdata",
FileSys: http.Dir("./testdata"),
BufPool: &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }},
}
// Test tmpl on /photos/test.html
......
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