Added the Context to the browse directive

Moved the Context type to middleware and exported it.
Users can use .Include and others in browse directive templating
Created test for the templates directive.
This commit is contained in:
Maxime 2015-07-17 20:07:24 +02:00
parent fcf2622c26
commit f536bc94b2
10 changed files with 165 additions and 32 deletions

View File

@ -2,8 +2,8 @@ package setup
import (
"fmt"
"html/template"
"io/ioutil"
"text/template"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/browse"

View File

@ -5,13 +5,13 @@ package browse
import (
"bytes"
"errors"
"html/template"
"net/http"
"net/url"
"os"
"path"
"sort"
"strings"
"text/template"
"time"
"github.com/dustin/go-humanize"
@ -51,6 +51,8 @@ type Listing struct {
// And which order
Order string
middleware.Context
}
// FileInfo is the info about a particular file or directory
@ -135,8 +137,9 @@ var IndexPages = []string{
"default.htm",
}
func directoryListing(files []os.FileInfo, urlPath string, canGoUp bool) (Listing, error) {
func directoryListing(files []os.FileInfo, r *http.Request, canGoUp bool, root string) (Listing, error) {
var fileinfos []FileInfo
var urlPath = r.URL.Path
for _, f := range files {
name := f.Name()
@ -168,6 +171,11 @@ func directoryListing(files []os.FileInfo, urlPath string, canGoUp bool) (Listin
Path: urlPath,
CanGoUp: canGoUp,
Items: fileinfos,
Context: middleware.Context{
Root: http.Dir(root),
Req: r,
URL: r.URL,
},
}, nil
}
@ -222,7 +230,7 @@ func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
}
}
// Assemble listing of directory contents
listing, err := directoryListing(files, r.URL.Path, canGoUp)
listing, err := directoryListing(files, r, canGoUp, b.Root)
if err != nil { // directory isn't browsable
continue
}

View File

@ -1,4 +1,4 @@
package templates
package middleware
import (
"bytes"
@ -8,23 +8,22 @@ import (
"net/url"
"text/template"
"time"
"github.com/mholt/caddy/middleware"
)
// This file contains the context and functions available for
// use in the templates.
// context is the context with which templates are executed.
type context struct {
root http.FileSystem
req *http.Request
type Context struct {
Root http.FileSystem
Req *http.Request
// This is used to access information about the URL.
URL *url.URL
}
// Include returns the contents of filename relative to the site root
func (c context) Include(filename string) (string, error) {
file, err := c.root.Open(filename)
func (c Context) Include(filename string) (string, error) {
file, err := c.Root.Open(filename)
if err != nil {
return "", err
}
@ -50,13 +49,13 @@ func (c context) Include(filename string) (string, error) {
}
// Date returns the current timestamp in the specified format
func (c context) Date(format string) string {
func (c Context) Date(format string) string {
return time.Now().Format(format)
}
// Cookie gets the value of a cookie with name name.
func (c context) Cookie(name string) string {
cookies := c.req.Cookies()
func (c Context) Cookie(name string) string {
cookies := c.Req.Cookies()
for _, cookie := range cookies {
if cookie.Name == name {
return cookie.Value
@ -66,15 +65,15 @@ func (c context) Cookie(name string) string {
}
// Header gets the value of a request header with field name.
func (c context) Header(name string) string {
return c.req.Header.Get(name)
func (c Context) Header(name string) string {
return c.Req.Header.Get(name)
}
// IP gets the (remote) IP address of the client making the request.
func (c context) IP() string {
ip, _, err := net.SplitHostPort(c.req.RemoteAddr)
func (c Context) IP() string {
ip, _, err := net.SplitHostPort(c.Req.RemoteAddr)
if err != nil {
return c.req.RemoteAddr
return c.Req.RemoteAddr
}
return ip
}
@ -82,14 +81,14 @@ func (c context) IP() string {
// URI returns the raw, unprocessed request URI (including query
// string and hash) obtained directly from the Request-Line of
// the HTTP request.
func (c context) URI() string {
return c.req.RequestURI
func (c Context) URI() string {
return c.Req.RequestURI
}
// Host returns the hostname portion of the Host header
// from the HTTP request.
func (c context) Host() (string, error) {
host, _, err := net.SplitHostPort(c.req.Host)
func (c Context) Host() (string, error) {
host, _, err := net.SplitHostPort(c.Req.Host)
if err != nil {
return "", err
}
@ -97,8 +96,8 @@ func (c context) Host() (string, error) {
}
// Port returns the port portion of the Host header if specified.
func (c context) Port() (string, error) {
_, port, err := net.SplitHostPort(c.req.Host)
func (c Context) Port() (string, error) {
_, port, err := net.SplitHostPort(c.Req.Host)
if err != nil {
return "", err
}
@ -106,12 +105,12 @@ func (c context) Port() (string, error) {
}
// Method returns the method (GET, POST, etc.) of the request.
func (c context) Method() string {
return c.req.Method
func (c Context) Method() string {
return c.Req.Method
}
// PathMatches returns true if the path portion of the request
// URL matches pattern.
func (c context) PathMatches(pattern string) bool {
return middleware.Path(c.req.URL.Path).Matches(pattern)
func (c Context) PathMatches(pattern string) bool {
return Path(c.Req.URL.Path).Matches(pattern)
}

View File

@ -0,0 +1 @@
<h1>Header title</h1>

View File

@ -0,0 +1 @@
<h1>Header title</h1>

View File

@ -0,0 +1 @@
<!DOCTYPE html><html><head><title>img</title></head><body>{{.Include "header.html"}}</body></html>

View File

@ -0,0 +1 @@
<!DOCTYPE html><html><head><title>test page</title></head><body>{{.Include "../header.html"}}</body></html>

View File

@ -0,0 +1 @@
<!DOCTYPE html><html><head><title>root</title></head><body>{{.Include "header.html"}}</body></html>

View File

@ -31,7 +31,7 @@ func (t Templates) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
for _, ext := range rule.Extensions {
if reqExt == ext {
// Create execution context
ctx := context{root: t.FileSys, req: r, URL: r.URL}
ctx := middleware.Context{Root: t.FileSys, Req: r, URL: r.URL}
// Build the template
tpl, err := template.ParseFiles(filepath.Join(t.Root, fpath))

View File

@ -0,0 +1,121 @@
package templates
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/mholt/caddy/middleware"
)
func Test(t *testing.T) {
tmpl := Templates{
Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
return 0, nil
}),
Rules: []Rule{
Rule{
Extensions: []string{".html"},
IndexFiles: []string{"index.html"},
Path: "/photos",
},
Rule{
Extensions: []string{".html", ".htm"},
IndexFiles: []string{"index.html", "index.htm"},
Path: "/images",
},
},
Root: ".",
FileSys: http.Dir("."),
}
tmplroot := Templates{
Next: middleware.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (int, error) {
return 0, nil
}),
Rules: []Rule{
Rule{
Extensions: []string{".html"},
IndexFiles: []string{"index.html"},
Path: "/",
},
},
Root: ".",
FileSys: http.Dir("."),
}
/*
* 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)
}
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)
}
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 tmplroot on /root.html
*/
req, err = http.NewRequest("GET", "/root.html", nil)
if err != nil {
t.Fatalf("Could not create HTTP request: %v", err)
}
rec = httptest.NewRecorder()
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)
}
}