From f536bc94b2e26cd1640d6361cee38977c0f98930 Mon Sep 17 00:00:00 2001 From: Maxime Date: Fri, 17 Jul 2015 20:07:24 +0200 Subject: [PATCH] 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. --- config/setup/browse.go | 2 +- middleware/browse/browse.go | 14 ++- middleware/{templates => }/context.go | 53 +++++------ middleware/templates/header.html | 1 + middleware/templates/images/header.html | 1 + middleware/templates/images/img.htm | 1 + middleware/templates/photos/test.html | 1 + middleware/templates/root.html | 1 + middleware/templates/templates.go | 2 +- middleware/templates/templates_test.go | 121 ++++++++++++++++++++++++ 10 files changed, 165 insertions(+), 32 deletions(-) rename middleware/{templates => }/context.go (63%) create mode 100644 middleware/templates/header.html create mode 100644 middleware/templates/images/header.html create mode 100644 middleware/templates/images/img.htm create mode 100644 middleware/templates/photos/test.html create mode 100644 middleware/templates/root.html create mode 100644 middleware/templates/templates_test.go diff --git a/config/setup/browse.go b/config/setup/browse.go index 7db8b40ac..a98ec313d 100644 --- a/config/setup/browse.go +++ b/config/setup/browse.go @@ -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" diff --git a/middleware/browse/browse.go b/middleware/browse/browse.go index c0090acd6..5caeb5ac5 100644 --- a/middleware/browse/browse.go +++ b/middleware/browse/browse.go @@ -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 } diff --git a/middleware/templates/context.go b/middleware/context.go similarity index 63% rename from middleware/templates/context.go rename to middleware/context.go index 4f125c991..508ec6042 100644 --- a/middleware/templates/context.go +++ b/middleware/context.go @@ -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 - URL *url.URL +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) } diff --git a/middleware/templates/header.html b/middleware/templates/header.html new file mode 100644 index 000000000..9c96e0e37 --- /dev/null +++ b/middleware/templates/header.html @@ -0,0 +1 @@ +

Header title

diff --git a/middleware/templates/images/header.html b/middleware/templates/images/header.html new file mode 100644 index 000000000..9c96e0e37 --- /dev/null +++ b/middleware/templates/images/header.html @@ -0,0 +1 @@ +

Header title

diff --git a/middleware/templates/images/img.htm b/middleware/templates/images/img.htm new file mode 100644 index 000000000..865a73809 --- /dev/null +++ b/middleware/templates/images/img.htm @@ -0,0 +1 @@ +img{{.Include "header.html"}} diff --git a/middleware/templates/photos/test.html b/middleware/templates/photos/test.html new file mode 100644 index 000000000..e2e95e133 --- /dev/null +++ b/middleware/templates/photos/test.html @@ -0,0 +1 @@ +test page{{.Include "../header.html"}} diff --git a/middleware/templates/root.html b/middleware/templates/root.html new file mode 100644 index 000000000..e1720e726 --- /dev/null +++ b/middleware/templates/root.html @@ -0,0 +1 @@ +root{{.Include "header.html"}} diff --git a/middleware/templates/templates.go b/middleware/templates/templates.go index fc4f8242e..a699d0026 100644 --- a/middleware/templates/templates.go +++ b/middleware/templates/templates.go @@ -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)) diff --git a/middleware/templates/templates_test.go b/middleware/templates/templates_test.go new file mode 100644 index 000000000..a519de99e --- /dev/null +++ b/middleware/templates/templates_test.go @@ -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 := `test page

Header title

+ +` + + 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 = `img

Header title

+ +` + + 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 = `root

Header title

+ +` + + if respBody != expectedBody { + t.Fatalf("Test: the expected body %v is different from the response one: %v", expectedBody, respBody) + } +}