summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2022-09-01 21:15:20 -0600
committerMatthew Holt <mholt@users.noreply.github.com>2022-09-01 21:15:44 -0600
commit73d4a8ba02292491fca289b324e89ef8c62fd435 (patch)
treedf0ce2fd72c75b03490c28686402f3f67d9e9eea /modules
parent7d5108d132d3bccfd8d83bc3fc2dbc46afde20ae (diff)
map: Coerce val to string, fix #4987
Also prevent infinite recursion, and enforce placeholder syntax.
Diffstat (limited to 'modules')
-rw-r--r--modules/caddyhttp/map/caddyfile.go10
-rw-r--r--modules/caddyhttp/map/map.go26
-rw-r--r--modules/caddyhttp/templates/tplcontext.go17
3 files changed, 27 insertions, 26 deletions
diff --git a/modules/caddyhttp/map/caddyfile.go b/modules/caddyhttp/map/caddyfile.go
index f38aff7..9cc7d8c 100644
--- a/modules/caddyhttp/map/caddyfile.go
+++ b/modules/caddyhttp/map/caddyfile.go
@@ -27,10 +27,10 @@ func init() {
// parseCaddyfile sets up the map handler from Caddyfile tokens. Syntax:
//
-// map [<matcher>] <source> <destinations...> {
-// [~]<input> <outputs...>
-// default <defaults...>
-// }
+// map [<matcher>] <source> <destinations...> {
+// [~]<input> <outputs...>
+// default <defaults...>
+// }
//
// If the input value is prefixed with a tilde (~), then the input will be parsed as a
// regular expression.
@@ -76,7 +76,7 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)
continue
}
- // every other line maps one input to one or more outputs
+ // every line maps an input value to one or more outputs
in := h.Val()
var outs []any
for h.NextArg() {
diff --git a/modules/caddyhttp/map/map.go b/modules/caddyhttp/map/map.go
index bbc1249..d41806d 100644
--- a/modules/caddyhttp/map/map.go
+++ b/modules/caddyhttp/map/map.go
@@ -62,6 +62,9 @@ func (Handler) CaddyModule() caddy.ModuleInfo {
// Provision sets up h.
func (h *Handler) Provision(_ caddy.Context) error {
for j, dest := range h.Destinations {
+ if strings.Count(dest, "{") != 1 || !strings.HasPrefix(dest, "{") {
+ return fmt.Errorf("destination must be a placeholder and only a placeholder")
+ }
h.Destinations[j] = strings.Trim(dest, "{}")
}
@@ -106,6 +109,16 @@ func (h *Handler) Validate() error {
}
seen[input] = i
+ // prevent infinite recursion
+ for _, out := range m.Outputs {
+ for _, dest := range h.Destinations {
+ if strings.Contains(caddy.ToString(out), dest) ||
+ strings.Contains(m.Input, dest) {
+ return fmt.Errorf("mapping %d requires value of {%s} to define value of {%s}: infinite recursion", i, dest, dest)
+ }
+ }
+ }
+
// ensure mappings have 1:1 output-to-destination correspondence
nOut := len(m.Outputs)
if nOut != nDest {
@@ -135,21 +148,22 @@ func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhtt
if output == nil {
continue
}
+ outputStr := caddy.ToString(output)
+
+ // evaluate regular expression if configured
if m.re != nil {
var result []byte
matches := m.re.FindStringSubmatchIndex(input)
if matches == nil {
continue
}
- result = m.re.ExpandString(result, output.(string), input, matches)
+ result = m.re.ExpandString(result, outputStr, input, matches)
return string(result), true
}
+
+ // otherwise simple string comparison
if input == m.Input {
- if outputStr, ok := output.(string); ok {
- // NOTE: if the output has a placeholder that has the same key as the input, this is infinite recursion
- return repl.ReplaceAll(outputStr, ""), true
- }
- return output, true
+ return repl.ReplaceAll(outputStr, ""), true
}
}
diff --git a/modules/caddyhttp/templates/tplcontext.go b/modules/caddyhttp/templates/tplcontext.go
index 96a341c..f681399 100644
--- a/modules/caddyhttp/templates/tplcontext.go
+++ b/modules/caddyhttp/templates/tplcontext.go
@@ -305,7 +305,7 @@ func (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 (TemplateContext) funcMarkdown(input any) (string, error) {
- inputStr := toString(input)
+ inputStr := caddy.ToString(input)
md := goldmark.New(
goldmark.WithExtensions(
@@ -341,7 +341,7 @@ func (TemplateContext) funcMarkdown(input any) (string, error) {
// and returns the separated key-value pairs and the body/content. input
// must be a "stringy" value.
func (TemplateContext) funcSplitFrontMatter(input any) (parsedMarkdownDoc, error) {
- meta, body, err := extractFrontMatter(toString(input))
+ meta, body, err := extractFrontMatter(caddy.ToString(input))
if err != nil {
return parsedMarkdownDoc{}, err
}
@@ -465,19 +465,6 @@ func (h WrappedHeader) Del(field string) string {
return ""
}
-func toString(input any) string {
- switch v := input.(type) {
- case string:
- return v
- case fmt.Stringer:
- return v.String()
- case error:
- return v.Error()
- default:
- return fmt.Sprintf("%v", input)
- }
-}
-
var bufPool = sync.Pool{
New: func() any {
return new(bytes.Buffer)