mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-23 22:27:38 -05:00
context: add Push action
Signed-off-by: Tw <tw19881113@gmail.com>
This commit is contained in:
parent
aa7ecb02af
commit
761a32a080
4 changed files with 66 additions and 7 deletions
|
@ -29,6 +29,20 @@ type Context struct {
|
||||||
Req *http.Request
|
Req *http.Request
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
Args []interface{} // defined by arguments to .Include
|
Args []interface{} // defined by arguments to .Include
|
||||||
|
|
||||||
|
// just used for adding preload links for server push
|
||||||
|
responseHeader http.Header
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContextWithHeader creates a context with given response header.
|
||||||
|
//
|
||||||
|
// To plugin developer:
|
||||||
|
// The returned context's exported fileds remain empty,
|
||||||
|
// you should then initialize them if you want.
|
||||||
|
func NewContextWithHeader(rh http.Header) Context {
|
||||||
|
return Context{
|
||||||
|
responseHeader: rh,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include returns the contents of filename relative to the site root.
|
// Include returns the contents of filename relative to the site root.
|
||||||
|
@ -410,6 +424,15 @@ func (c Context) RandomString(minLen, maxLen int) string {
|
||||||
return string(result)
|
return string(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Push adds a preload link in response header for server push
|
||||||
|
func (c Context) Push(link string) string {
|
||||||
|
if c.responseHeader == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
c.responseHeader.Add("Link", "<"+link+">; rel=preload")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// buffer pool for .Include context actions
|
// buffer pool for .Include context actions
|
||||||
var includeBufs = sync.Pool{
|
var includeBufs = sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -731,8 +732,9 @@ func initTestContext() (Context, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Context{}, err
|
return Context{}, err
|
||||||
}
|
}
|
||||||
|
res := httptest.NewRecorder()
|
||||||
|
|
||||||
return Context{Root: http.Dir(os.TempDir()), Req: request}, nil
|
return Context{Root: http.Dir(os.TempDir()), responseHeader: res.Header(), Req: request}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getContextOrFail(t *testing.T) Context {
|
func getContextOrFail(t *testing.T) Context {
|
||||||
|
@ -874,3 +876,35 @@ func TestFiles(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPush(t *testing.T) {
|
||||||
|
for name, c := range map[string]struct {
|
||||||
|
input string
|
||||||
|
expectLinks []string
|
||||||
|
}{
|
||||||
|
"oneLink": {
|
||||||
|
input: `{{.Push "/test.css"}}`,
|
||||||
|
expectLinks: []string{"</test.css>; rel=preload"},
|
||||||
|
},
|
||||||
|
"multipleLinks": {
|
||||||
|
input: `{{.Push "/test1.css"}} {{.Push "/test2.css"}}`,
|
||||||
|
expectLinks: []string{"</test1.css>; rel=preload", "</test2.css>; rel=preload"},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
c := c
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
ctx := getContextOrFail(t)
|
||||||
|
tmpl, err := template.New("").Parse(c.input)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
err = tmpl.Execute(ioutil.Discard, ctx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if got := ctx.responseHeader["Link"]; !reflect.DeepEqual(got, c.expectLinks) {
|
||||||
|
t.Errorf("Result not match: expect %v, but got %v", c.expectLinks, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -133,11 +133,10 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
|
||||||
}
|
}
|
||||||
lastModTime = latest(lastModTime, fs.ModTime())
|
lastModTime = latest(lastModTime, fs.ModTime())
|
||||||
|
|
||||||
ctx := httpserver.Context{
|
ctx := httpserver.NewContextWithHeader(w.Header())
|
||||||
Root: md.FileSys,
|
ctx.Root = md.FileSys
|
||||||
Req: r,
|
ctx.Req = r
|
||||||
URL: r.URL,
|
ctx.URL = r.URL
|
||||||
}
|
|
||||||
html, err := cfg.Markdown(title(fpath), f, dirents, ctx)
|
html, err := cfg.Markdown(title(fpath), f, dirents, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return http.StatusInternalServerError, err
|
return http.StatusInternalServerError, err
|
||||||
|
|
|
@ -34,7 +34,10 @@ func (t Templates) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
|
||||||
for _, ext := range rule.Extensions {
|
for _, ext := range rule.Extensions {
|
||||||
if reqExt == ext {
|
if reqExt == ext {
|
||||||
// Create execution context
|
// Create execution context
|
||||||
ctx := httpserver.Context{Root: t.FileSys, Req: r, URL: r.URL}
|
ctx := httpserver.NewContextWithHeader(w.Header())
|
||||||
|
ctx.Root = t.FileSys
|
||||||
|
ctx.Req = r
|
||||||
|
ctx.URL = r.URL
|
||||||
|
|
||||||
// New template
|
// New template
|
||||||
templateName := filepath.Base(fpath)
|
templateName := filepath.Base(fpath)
|
||||||
|
|
Loading…
Reference in a new issue