2015-07-17 13:07:24 -05:00
|
|
|
package middleware
|
2015-04-18 10:57:51 -05:00
|
|
|
|
|
|
|
import (
|
2015-06-30 19:20:36 -05:00
|
|
|
"bytes"
|
2015-04-18 10:57:51 -05:00
|
|
|
"io/ioutil"
|
2015-04-18 12:31:59 -05:00
|
|
|
"net"
|
2015-04-18 10:57:51 -05:00
|
|
|
"net/http"
|
2015-04-18 12:31:59 -05:00
|
|
|
"net/url"
|
2015-07-29 18:40:11 -05:00
|
|
|
"strings"
|
2015-06-30 19:20:36 -05:00
|
|
|
"text/template"
|
2015-04-18 12:08:41 -05:00
|
|
|
"time"
|
2015-04-18 10:57:51 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
// This file contains the context and functions available for
|
|
|
|
// use in the templates.
|
|
|
|
|
2015-07-29 18:40:11 -05:00
|
|
|
// Context is the context with which Caddy templates are executed.
|
2015-07-17 13:07:24 -05:00
|
|
|
type Context struct {
|
|
|
|
Root http.FileSystem
|
|
|
|
Req *http.Request
|
|
|
|
// This is used to access information about the URL.
|
|
|
|
URL *url.URL
|
2015-04-18 10:57:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Include returns the contents of filename relative to the site root
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) Include(filename string) (string, error) {
|
|
|
|
file, err := c.Root.Open(filename)
|
2015-04-18 10:57:51 -05:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2015-07-01 12:36:37 -05:00
|
|
|
defer file.Close()
|
2015-06-30 19:20:36 -05:00
|
|
|
|
2015-04-18 10:57:51 -05:00
|
|
|
body, err := ioutil.ReadAll(file)
|
2015-06-30 19:20:36 -05:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
tpl, err := template.New(filename).Parse(string(body))
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
err = tpl.Execute(&buf, c)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf.String(), nil
|
2015-04-18 10:57:51 -05:00
|
|
|
}
|
2015-04-18 12:08:41 -05:00
|
|
|
|
2015-07-29 18:40:11 -05:00
|
|
|
// Now returns the current timestamp in the specified format.
|
|
|
|
func (c Context) Now(format string) string {
|
2015-04-18 12:08:41 -05:00
|
|
|
return time.Now().Format(format)
|
|
|
|
}
|
|
|
|
|
2015-08-05 09:27:13 -05:00
|
|
|
// NowDate returns the current date/time that can be used
|
|
|
|
// in other time functions.
|
|
|
|
func (c Context) NowDate() time.Time {
|
|
|
|
return time.Now()
|
|
|
|
}
|
|
|
|
|
2015-04-18 12:08:41 -05:00
|
|
|
// Cookie gets the value of a cookie with name name.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) Cookie(name string) string {
|
|
|
|
cookies := c.Req.Cookies()
|
2015-04-18 12:08:41 -05:00
|
|
|
for _, cookie := range cookies {
|
|
|
|
if cookie.Name == name {
|
|
|
|
return cookie.Value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
// Header gets the value of a request header with field name.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) Header(name string) string {
|
|
|
|
return c.Req.Header.Get(name)
|
2015-04-18 12:08:41 -05:00
|
|
|
}
|
|
|
|
|
2015-05-05 16:49:22 -05:00
|
|
|
// IP gets the (remote) IP address of the client making the request.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) IP() string {
|
|
|
|
ip, _, err := net.SplitHostPort(c.Req.RemoteAddr)
|
2015-05-05 16:49:22 -05:00
|
|
|
if err != nil {
|
2015-07-17 13:07:24 -05:00
|
|
|
return c.Req.RemoteAddr
|
2015-05-05 16:49:22 -05:00
|
|
|
}
|
|
|
|
return ip
|
2015-04-18 12:08:41 -05:00
|
|
|
}
|
2015-04-18 12:31:59 -05:00
|
|
|
|
|
|
|
// URI returns the raw, unprocessed request URI (including query
|
|
|
|
// string and hash) obtained directly from the Request-Line of
|
|
|
|
// the HTTP request.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) URI() string {
|
|
|
|
return c.Req.RequestURI
|
2015-04-18 12:31:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Host returns the hostname portion of the Host header
|
|
|
|
// from the HTTP request.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) Host() (string, error) {
|
|
|
|
host, _, err := net.SplitHostPort(c.Req.Host)
|
2015-04-18 12:31:59 -05:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return host, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Port returns the port portion of the Host header if specified.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) Port() (string, error) {
|
|
|
|
_, port, err := net.SplitHostPort(c.Req.Host)
|
2015-04-18 12:31:59 -05:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return port, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Method returns the method (GET, POST, etc.) of the request.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) Method() string {
|
|
|
|
return c.Req.Method
|
2015-04-18 12:31:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// PathMatches returns true if the path portion of the request
|
|
|
|
// URL matches pattern.
|
2015-07-17 13:07:24 -05:00
|
|
|
func (c Context) PathMatches(pattern string) bool {
|
|
|
|
return Path(c.Req.URL.Path).Matches(pattern)
|
2015-04-18 12:31:59 -05:00
|
|
|
}
|
2015-07-29 18:40:11 -05:00
|
|
|
|
|
|
|
// Truncate truncates the input string to the given length. If
|
|
|
|
// input is shorter than length, the entire string is returned.
|
|
|
|
func (c Context) Truncate(input string, length int) string {
|
|
|
|
if len(input) > length {
|
|
|
|
return input[:length]
|
|
|
|
}
|
|
|
|
return input
|
|
|
|
}
|
|
|
|
|
2015-09-17 17:23:30 -05:00
|
|
|
// StripHTML returns s without HTML tags. It is fairly naive
|
|
|
|
// but works with most valid HTML inputs.
|
|
|
|
func (c Context) StripHTML(s string) string {
|
|
|
|
var buf bytes.Buffer
|
|
|
|
var inTag, inQuotes bool
|
|
|
|
var tagStart int
|
|
|
|
for i, ch := range s {
|
|
|
|
if inTag {
|
|
|
|
if ch == '>' && !inQuotes {
|
|
|
|
inTag = false
|
|
|
|
} else if ch == '<' && !inQuotes {
|
|
|
|
// false start
|
|
|
|
buf.WriteString(s[tagStart:i])
|
|
|
|
tagStart = i
|
|
|
|
} else if ch == '"' {
|
|
|
|
inQuotes = !inQuotes
|
|
|
|
}
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if ch == '<' {
|
|
|
|
inTag = true
|
|
|
|
tagStart = i
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
buf.WriteRune(ch)
|
|
|
|
}
|
|
|
|
if inTag {
|
|
|
|
// false start
|
|
|
|
buf.WriteString(s[tagStart:])
|
|
|
|
inTag = false
|
|
|
|
}
|
|
|
|
return buf.String()
|
|
|
|
}
|
|
|
|
|
2015-09-16 22:30:56 -05:00
|
|
|
// StripExt returns the input string without the extension,
|
|
|
|
// which is the suffix starting with the final '.' character
|
|
|
|
// but not before the final path separator ('/') character.
|
|
|
|
// If there is no extension, the whole input is returned.
|
|
|
|
func (c Context) StripExt(path string) string {
|
|
|
|
for i := len(path) - 1; i >= 0 && path[i] != '/'; i-- {
|
|
|
|
if path[i] == '.' {
|
|
|
|
return path[:i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return path
|
|
|
|
}
|
|
|
|
|
2015-07-29 18:40:11 -05:00
|
|
|
// Replace replaces instances of find in input with replacement.
|
|
|
|
func (c Context) Replace(input, find, replacement string) string {
|
|
|
|
return strings.Replace(input, find, replacement, -1)
|
|
|
|
}
|