Commit f536bc94 authored by Maxime's avatar Maxime

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.
parent fcf2622c
...@@ -2,8 +2,8 @@ package setup ...@@ -2,8 +2,8 @@ package setup
import ( import (
"fmt" "fmt"
"html/template"
"io/ioutil" "io/ioutil"
"text/template"
"github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/browse" "github.com/mholt/caddy/middleware/browse"
......
...@@ -5,13 +5,13 @@ package browse ...@@ -5,13 +5,13 @@ package browse
import ( import (
"bytes" "bytes"
"errors" "errors"
"html/template"
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"path" "path"
"sort" "sort"
"strings" "strings"
"text/template"
"time" "time"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
...@@ -51,6 +51,8 @@ type Listing struct { ...@@ -51,6 +51,8 @@ type Listing struct {
// And which order // And which order
Order string Order string
middleware.Context
} }
// FileInfo is the info about a particular file or directory // FileInfo is the info about a particular file or directory
...@@ -135,8 +137,9 @@ var IndexPages = []string{ ...@@ -135,8 +137,9 @@ var IndexPages = []string{
"default.htm", "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 fileinfos []FileInfo
var urlPath = r.URL.Path
for _, f := range files { for _, f := range files {
name := f.Name() name := f.Name()
...@@ -168,6 +171,11 @@ func directoryListing(files []os.FileInfo, urlPath string, canGoUp bool) (Listin ...@@ -168,6 +171,11 @@ func directoryListing(files []os.FileInfo, urlPath string, canGoUp bool) (Listin
Path: urlPath, Path: urlPath,
CanGoUp: canGoUp, CanGoUp: canGoUp,
Items: fileinfos, Items: fileinfos,
Context: middleware.Context{
Root: http.Dir(root),
Req: r,
URL: r.URL,
},
}, nil }, nil
} }
...@@ -222,7 +230,7 @@ func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) { ...@@ -222,7 +230,7 @@ func (b Browse) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
} }
} }
// Assemble listing of directory contents // 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 if err != nil { // directory isn't browsable
continue continue
} }
......
package templates package middleware
import ( import (
"bytes" "bytes"
...@@ -8,23 +8,22 @@ import ( ...@@ -8,23 +8,22 @@ import (
"net/url" "net/url"
"text/template" "text/template"
"time" "time"
"github.com/mholt/caddy/middleware"
) )
// This file contains the context and functions available for // This file contains the context and functions available for
// use in the templates. // use in the templates.
// context is the context with which templates are executed. // context is the context with which templates are executed.
type context struct { type Context struct {
root http.FileSystem Root http.FileSystem
req *http.Request Req *http.Request
URL *url.URL // This is used to access information about the URL.
URL *url.URL
} }
// Include returns the contents of filename relative to the site root // Include returns the contents of filename relative to the site root
func (c context) Include(filename string) (string, error) { func (c Context) Include(filename string) (string, error) {
file, err := c.root.Open(filename) file, err := c.Root.Open(filename)
if err != nil { if err != nil {
return "", err return "", err
} }
...@@ -50,13 +49,13 @@ func (c context) Include(filename string) (string, error) { ...@@ -50,13 +49,13 @@ func (c context) Include(filename string) (string, error) {
} }
// Date returns the current timestamp in the specified format // 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) return time.Now().Format(format)
} }
// Cookie gets the value of a cookie with name name. // Cookie gets the value of a cookie with name name.
func (c context) Cookie(name string) string { func (c Context) Cookie(name string) string {
cookies := c.req.Cookies() cookies := c.Req.Cookies()
for _, cookie := range cookies { for _, cookie := range cookies {
if cookie.Name == name { if cookie.Name == name {
return cookie.Value return cookie.Value
...@@ -66,15 +65,15 @@ func (c context) Cookie(name string) string { ...@@ -66,15 +65,15 @@ func (c context) Cookie(name string) string {
} }
// Header gets the value of a request header with field name. // Header gets the value of a request header with field name.
func (c context) Header(name string) string { func (c Context) Header(name string) string {
return c.req.Header.Get(name) return c.Req.Header.Get(name)
} }
// IP gets the (remote) IP address of the client making the request. // IP gets the (remote) IP address of the client making the request.
func (c context) IP() string { func (c Context) IP() string {
ip, _, err := net.SplitHostPort(c.req.RemoteAddr) ip, _, err := net.SplitHostPort(c.Req.RemoteAddr)
if err != nil { if err != nil {
return c.req.RemoteAddr return c.Req.RemoteAddr
} }
return ip return ip
} }
...@@ -82,14 +81,14 @@ func (c context) IP() string { ...@@ -82,14 +81,14 @@ func (c context) IP() string {
// URI returns the raw, unprocessed request URI (including query // URI returns the raw, unprocessed request URI (including query
// string and hash) obtained directly from the Request-Line of // string and hash) obtained directly from the Request-Line of
// the HTTP request. // the HTTP request.
func (c context) URI() string { func (c Context) URI() string {
return c.req.RequestURI return c.Req.RequestURI
} }
// Host returns the hostname portion of the Host header // Host returns the hostname portion of the Host header
// from the HTTP request. // from the HTTP request.
func (c context) Host() (string, error) { func (c Context) Host() (string, error) {
host, _, err := net.SplitHostPort(c.req.Host) host, _, err := net.SplitHostPort(c.Req.Host)
if err != nil { if err != nil {
return "", err return "", err
} }
...@@ -97,8 +96,8 @@ func (c context) Host() (string, error) { ...@@ -97,8 +96,8 @@ func (c context) Host() (string, error) {
} }
// Port returns the port portion of the Host header if specified. // Port returns the port portion of the Host header if specified.
func (c context) Port() (string, error) { func (c Context) Port() (string, error) {
_, port, err := net.SplitHostPort(c.req.Host) _, port, err := net.SplitHostPort(c.Req.Host)
if err != nil { if err != nil {
return "", err return "", err
} }
...@@ -106,12 +105,12 @@ func (c context) Port() (string, error) { ...@@ -106,12 +105,12 @@ func (c context) Port() (string, error) {
} }
// Method returns the method (GET, POST, etc.) of the request. // Method returns the method (GET, POST, etc.) of the request.
func (c context) Method() string { func (c Context) Method() string {
return c.req.Method return c.Req.Method
} }
// PathMatches returns true if the path portion of the request // PathMatches returns true if the path portion of the request
// URL matches pattern. // URL matches pattern.
func (c context) PathMatches(pattern string) bool { func (c Context) PathMatches(pattern string) bool {
return middleware.Path(c.req.URL.Path).Matches(pattern) return Path(c.Req.URL.Path).Matches(pattern)
} }
<!DOCTYPE html><html><head><title>img</title></head><body>{{.Include "header.html"}}</body></html>
<!DOCTYPE html><html><head><title>test page</title></head><body>{{.Include "../header.html"}}</body></html>
<!DOCTYPE html><html><head><title>root</title></head><body>{{.Include "header.html"}}</body></html>
...@@ -31,7 +31,7 @@ func (t Templates) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error ...@@ -31,7 +31,7 @@ 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 := context{root: t.FileSys, req: r, URL: r.URL} ctx := middleware.Context{Root: t.FileSys, Req: r, URL: r.URL}
// Build the template // Build the template
tpl, err := template.ParseFiles(filepath.Join(t.Root, fpath)) tpl, err := template.ParseFiles(filepath.Join(t.Root, fpath))
......
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)
}
}
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