mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-29 20:24:11 +08:00
4b1b329edb
* templates: Execute template loaded by later middlewares This is the beginning of an attempt to make the staticfiles file server the only middleware that hits the disk and loads content. This may have unknown implications. But the goal is to reduce duplication without sacrificing performance. (We now call ServeContent here.) This change loses about 15% of the req/sec of the old way of doing it, but this way is arguably more correct since the file server is good at serving static files; duplicating that logic in every middleware that needs to hit the disk is not practical. * httpserver: Introduce ResponseRecorder as per Tw's suggestions It implements io.ReaderFrom and has some allocation-reducing optimizations baked into it * templates: Increase execution speed by ~10-15% after perf regression By using httpserver.ResponseBuffer, we can reduce allocations and still get what we want. It's a little tricky but it works so far.
148 lines
4.1 KiB
Go
148 lines
4.1 KiB
Go
package templates
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
|
"github.com/mholt/caddy/caddyhttp/staticfiles"
|
|
)
|
|
|
|
func TestTemplates(t *testing.T) {
|
|
siteRoot := "./testdata"
|
|
tmpl := Templates{
|
|
Next: staticfiles.FileServer{Root: http.Dir(siteRoot)},
|
|
Rules: []Rule{
|
|
{
|
|
Extensions: []string{".html"},
|
|
IndexFiles: []string{"index.html"},
|
|
Path: "/photos",
|
|
},
|
|
{
|
|
Extensions: []string{".html", ".htm"},
|
|
IndexFiles: []string{"index.html", "index.htm"},
|
|
Path: "/images",
|
|
Delims: [2]string{"{%", "%}"},
|
|
},
|
|
},
|
|
Root: siteRoot,
|
|
FileSys: http.Dir(siteRoot),
|
|
BufPool: &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }},
|
|
}
|
|
|
|
tmplroot := Templates{
|
|
Next: staticfiles.FileServer{Root: http.Dir(siteRoot)},
|
|
Rules: []Rule{
|
|
{
|
|
Extensions: []string{".html"},
|
|
IndexFiles: []string{"index.html"},
|
|
Path: "/",
|
|
},
|
|
},
|
|
Root: siteRoot,
|
|
FileSys: http.Dir(siteRoot),
|
|
BufPool: &sync.Pool{New: func() interface{} { return new(bytes.Buffer) }},
|
|
}
|
|
|
|
// Test tmpl on /photos/test.html
|
|
req, err := http.NewRequest("GET", "/photos/test.html", nil)
|
|
if err != nil {
|
|
t.Fatalf("Test: Could not create HTTP request: %v", err)
|
|
}
|
|
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
|
|
|
|
rec := httptest.NewRecorder()
|
|
|
|
tmpl.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
|
|
}
|
|
|
|
respBody := rec.Body.String()
|
|
expectedBody := `<!DOCTYPE html><html><head><title>test page</title></head><body><h1>Header title</h1>
|
|
</body></html>
|
|
`
|
|
|
|
if respBody != expectedBody {
|
|
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
|
|
}
|
|
|
|
// Test tmpl on /images/img.htm
|
|
req, err = http.NewRequest("GET", "/images/img.htm", nil)
|
|
if err != nil {
|
|
t.Fatalf("Could not create HTTP request: %v", err)
|
|
}
|
|
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
|
|
|
|
rec = httptest.NewRecorder()
|
|
|
|
tmpl.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
|
|
}
|
|
|
|
respBody = rec.Body.String()
|
|
expectedBody = `<!DOCTYPE html><html><head><title>img</title></head><body><h1>Header title</h1>
|
|
</body></html>
|
|
`
|
|
|
|
if respBody != expectedBody {
|
|
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
|
|
}
|
|
|
|
// Test tmpl on /images/img2.htm
|
|
req, err = http.NewRequest("GET", "/images/img2.htm", nil)
|
|
if err != nil {
|
|
t.Fatalf("Could not create HTTP request: %v", err)
|
|
}
|
|
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
|
|
|
|
rec = httptest.NewRecorder()
|
|
|
|
tmpl.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
|
|
}
|
|
|
|
respBody = rec.Body.String()
|
|
expectedBody = `<!DOCTYPE html><html><head><title>img</title></head><body>{{.Include "header.html"}}</body></html>
|
|
`
|
|
|
|
if respBody != expectedBody {
|
|
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
|
|
}
|
|
|
|
// Test tmplroot on /root.html
|
|
req, err = http.NewRequest("GET", "/root.html", nil)
|
|
if err != nil {
|
|
t.Fatalf("Could not create HTTP request: %v", err)
|
|
}
|
|
req = req.WithContext(context.WithValue(req.Context(), httpserver.OriginalURLCtxKey, *req.URL))
|
|
|
|
rec = httptest.NewRecorder()
|
|
|
|
// register custom function which is used in template
|
|
httpserver.TemplateFuncs["root"] = func() string { return "root" }
|
|
tmplroot.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Test: Wrong response code: %d, should be %d", rec.Code, http.StatusOK)
|
|
}
|
|
|
|
respBody = rec.Body.String()
|
|
expectedBody = `<!DOCTYPE html><html><head><title>root</title></head><body><h1>Header title</h1>
|
|
</body></html>
|
|
`
|
|
|
|
if respBody != expectedBody {
|
|
t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody)
|
|
}
|
|
}
|