Browse Source

templates: Use text/template; add experimental notice to docs

Using html/template.HTML like we were doing before caused nested include
to be HTML-escaped, which breaks sites. Now we do not escape any of the
output; template input is usually trusted, and if it's not, users should
employ escaping actions within their templates to keep it safe. The docs
already said this.
master
Matthew Holt 5 years ago
parent
commit
437d5095a6
No known key found for this signature in database GPG Key ID: 2A349DD577D586A5
  1. 2
      modules/caddyhttp/templates/templates.go
  2. 20
      modules/caddyhttp/templates/tplcontext.go
  3. 3
      modules/caddyhttp/templates/tplcontext_test.go

2
modules/caddyhttp/templates/templates.go

@ -33,6 +33,8 @@ func init() {
// The syntax is documented in the Go standard library's
// [text/template package](https://golang.org/pkg/text/template/).
//
// ⚠️ Template functions/actions are still experimental, so they are subject to change.
//
// [All Sprig functions](https://masterminds.github.io/sprig/) are supported.
//
// In addition to the standard functions and Sprig functions, Caddy adds

20
modules/caddyhttp/templates/tplcontext.go

@ -17,7 +17,6 @@ package templates
import (
"bytes"
"fmt"
"html/template"
"io"
"net"
"net/http"
@ -25,6 +24,7 @@ import (
"strconv"
"strings"
"sync"
"text/template"
"github.com/Masterminds/sprig/v3"
"github.com/alecthomas/chroma/formatters/html"
@ -57,7 +57,7 @@ func (c templateContext) OriginalReq() http.Request {
// Note that included files are NOT escaped, so you should only include
// trusted files. If it is not trusted, be sure to use escaping functions
// in your template.
func (c templateContext) funcInclude(filename string, args ...interface{}) (template.HTML, error) {
func (c templateContext) funcInclude(filename string, args ...interface{}) (string, error) {
if c.Root == nil {
return "", fmt.Errorf("root file system not specified")
}
@ -84,14 +84,14 @@ func (c templateContext) funcInclude(filename string, args ...interface{}) (temp
return "", err
}
return template.HTML(bodyBuf.String()), nil
return bodyBuf.String(), nil
}
// funcHTTPInclude returns the body of a virtual (lightweight) request
// to the given URI on the same server. Note that included bodies
// are NOT escaped, so you should only include trusted resources.
// If it is not trusted, be sure to use escaping functions yourself.
func (c templateContext) funcHTTPInclude(uri string) (template.HTML, error) {
func (c templateContext) funcHTTPInclude(uri string) (string, error) {
// prevent virtual request loops by counting how many levels
// deep we are; and if we get too deep, return an error
recursionCount := 1
@ -132,7 +132,7 @@ func (c templateContext) funcHTTPInclude(uri string) (template.HTML, error) {
return "", err
}
return template.HTML(buf.String()), nil
return buf.String(), nil
}
func (c templateContext) executeTemplateInBuffer(tplName string, buf *bytes.Buffer) error {
@ -231,7 +231,7 @@ func (c templateContext) funcStripHTML(s string) string {
// funcMarkdown renders the markdown body as HTML. The resulting
// HTML is NOT escaped so that it can be rendered as HTML.
func (c templateContext) funcMarkdown(input interface{}) (template.HTML, error) {
func (c templateContext) funcMarkdown(input interface{}) (string, error) {
inputStr := toString(input)
md := goldmark.New(
@ -259,7 +259,7 @@ func (c templateContext) funcMarkdown(input interface{}) (template.HTML, error)
md.Convert([]byte(inputStr), buf)
return template.HTML(buf.String()), nil
return buf.String(), nil
}
// splitFrontMatter parses front matter out from the beginning of input,
@ -338,14 +338,12 @@ func toString(input interface{}) string {
switch v := input.(type) {
case string:
return v
case template.HTML:
return string(v)
case fmt.Stringer:
return v.String()
case error:
return v.Error()
default:
return fmt.Sprintf("%s", input)
return fmt.Sprintf("%v", input)
}
}
@ -357,6 +355,6 @@ var bufPool = sync.Pool{
// at time of writing, sprig.FuncMap() makes a copy, thus
// involves iterating the whole map, so do it just once
var sprigFuncMap = sprig.FuncMap()
var sprigFuncMap = sprig.TxtFuncMap()
const recursionPreventionHeader = "Caddy-Templates-Include"

3
modules/caddyhttp/templates/tplcontext_test.go

@ -31,7 +31,6 @@ package templates
import (
"bytes"
"fmt"
"html/template"
"io/ioutil"
"net/http"
"os"
@ -48,7 +47,7 @@ func TestMarkdown(t *testing.T) {
for i, test := range []struct {
body string
expect template.HTML
expect string
}{
{
body: "- str1\n- str2\n",

Loading…
Cancel
Save