Fail with error when double-rendering text in markdownify/RenderString

This commit prevents the most commons case of infinite recursion in link render hooks when the `linkify` option is enabled (see below). This is always a user error, but getting a `stack overflow` (the current stack limit in Go is 1 GB on 64-bit, 250 MB on 32-bit) error isn't very helpful. This fix will not prevent all such errors, though, but we may do better once #9570 is in place.

So, these will fail:

```
<a href="{{ .Destination | safeURL }}" >{{ .Text | markdownify }}</a>
<a href="{{ .Destination | safeURL }}" >{{ .Text | .Page.RenderString }}</a>
```

`.Text` is already rendered to `HTML`. The above needs to be rewritten to:

```
<a href="{{ .Destination | safeURL }}" >{{ .Text | safeHTML }}</a>
<a href="{{ .Destination | safeURL }}" >{{ .Text | safeHTML }}</a>
```

Fixes #8959
This commit is contained in:
Bjørn Erik Pedersen
2022-03-10 08:19:03 +01:00
committed by GitHub
parent 5697348e17
commit 4e14cf7607
7 changed files with 122 additions and 20 deletions

View File

@@ -18,6 +18,7 @@ import (
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/common/types/hstring"
"github.com/gohugoio/hugo/identity"
"github.com/gohugoio/hugo/markup/internal/attributes"
)
@@ -32,7 +33,7 @@ type LinkContext interface {
Page() interface{}
Destination() string
Title() string
Text() string
Text() hstring.RenderedString
PlainText() string
}
@@ -75,7 +76,7 @@ type HeadingContext interface {
// Anchor is the HTML id assigned to the heading.
Anchor() string
// Text is the rendered (HTML) heading text, excluding the heading marker.
Text() string
Text() hstring.RenderedString
// PlainText is the unrendered version of Text.
PlainText() string

View File

@@ -18,6 +18,8 @@ import (
"strings"
"testing"
qt "github.com/frankban/quicktest"
"github.com/gohugoio/hugo/hugolib"
)
@@ -395,6 +397,49 @@ FENCE
}
}
// Iisse #8959
func TestHookInfiniteRecursion(t *testing.T) {
t.Parallel()
for _, renderFunc := range []string{"markdownify", ".Page.RenderString"} {
t.Run(renderFunc, func(t *testing.T) {
files := `
-- config.toml --
-- layouts/_default/_markup/render-link.html --
<a href="{{ .Destination | safeURL }}">{{ .Text | RENDERFUNC }}</a>
-- layouts/_default/single.html --
{{ .Content }}
-- content/p1.md --
---
title: "p1"
---
https://example.org
a@b.com
`
files = strings.ReplaceAll(files, "RENDERFUNC", renderFunc)
b, err := hugolib.NewIntegrationTestBuilder(
hugolib.IntegrationTestConfig{
T: t,
TxtarString: files,
},
).BuildE()
b.Assert(err, qt.IsNotNil)
b.Assert(err.Error(), qt.Contains, "text is already rendered, repeating it may cause infinite recursion")
})
}
}
// Issue 9594
func TestQuotesInImgAltAttr(t *testing.T) {
t.Parallel()

View File

@@ -17,6 +17,7 @@ import (
"bytes"
"strings"
"github.com/gohugoio/hugo/common/types/hstring"
"github.com/gohugoio/hugo/markup/converter/hooks"
"github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
@@ -49,7 +50,7 @@ type linkContext struct {
page interface{}
destination string
title string
text string
text hstring.RenderedString
plainText string
}
@@ -65,7 +66,7 @@ func (ctx linkContext) Page() interface{} {
return ctx.page
}
func (ctx linkContext) Text() string {
func (ctx linkContext) Text() hstring.RenderedString {
return ctx.text
}
@@ -81,7 +82,7 @@ type headingContext struct {
page interface{}
level int
anchor string
text string
text hstring.RenderedString
plainText string
*attributes.AttributesHolder
}
@@ -98,7 +99,7 @@ func (ctx headingContext) Anchor() string {
return ctx.anchor
}
func (ctx headingContext) Text() string {
func (ctx headingContext) Text() hstring.RenderedString {
return ctx.text
}
@@ -156,7 +157,7 @@ func (r *hookedRenderer) renderImage(w util.BufWriter, source []byte, node ast.N
page: ctx.DocumentContext().Document,
destination: string(n.Destination),
title: string(n.Title),
text: string(text),
text: hstring.RenderedString(text),
plainText: string(n.Text(source)),
},
)
@@ -226,7 +227,7 @@ func (r *hookedRenderer) renderLink(w util.BufWriter, source []byte, node ast.No
page: ctx.DocumentContext().Document,
destination: string(n.Destination),
title: string(n.Title),
text: string(text),
text: hstring.RenderedString(text),
plainText: string(n.Text(source)),
},
)
@@ -293,7 +294,7 @@ func (r *hookedRenderer) renderAutoLink(w util.BufWriter, source []byte, node as
linkContext{
page: ctx.DocumentContext().Document,
destination: url,
text: label,
text: hstring.RenderedString(label),
plainText: label,
},
)
@@ -381,7 +382,7 @@ func (r *hookedRenderer) renderHeading(w util.BufWriter, source []byte, node ast
page: ctx.DocumentContext().Document,
level: n.Level,
anchor: string(anchor),
text: string(text),
text: hstring.RenderedString(text),
plainText: string(n.Text(source)),
AttributesHolder: attributes.New(n.Attributes(), attributes.AttributesOwnerGeneral),
},