summaryrefslogtreecommitdiffstats
path: root/markup
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-03-09 18:26:32 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-03-09 22:30:10 +0100
commit5697348e1732a5f64ee7467283eb0335f2ec36e8 (patch)
treeaf121a9de0890e66f9edde46fd4f084a750b3f6f /markup
parentf98e570b17d99e0ca7a6e6792a4c741cfc8b81e8 (diff)
markup/goldmark: Default to https for linkify
Fixes #9639
Diffstat (limited to 'markup')
-rw-r--r--markup/goldmark/convert.go2
-rw-r--r--markup/goldmark/goldmark_config/config.go24
-rw-r--r--markup/goldmark/integration_test.go67
-rw-r--r--markup/goldmark/render_hooks.go31
4 files changed, 105 insertions, 19 deletions
diff --git a/markup/goldmark/convert.go b/markup/goldmark/convert.go
index 4c1641a0b..9442ee9e7 100644
--- a/markup/goldmark/convert.go
+++ b/markup/goldmark/convert.go
@@ -94,7 +94,7 @@ func newMarkdown(pcfg converter.ProviderConfig) goldmark.Markdown {
var (
extensions = []goldmark.Extender{
- newLinks(),
+ newLinks(cfg),
newTocExtension(rendererOptions),
}
parserOptions []parser.Option
diff --git a/markup/goldmark/goldmark_config/config.go b/markup/goldmark/goldmark_config/config.go
index 82b8d9630..a3238091b 100644
--- a/markup/goldmark/goldmark_config/config.go
+++ b/markup/goldmark/goldmark_config/config.go
@@ -23,13 +23,14 @@ const (
// DefaultConfig holds the default Goldmark configuration.
var Default = Config{
Extensions: Extensions{
- Typographer: true,
- Footnote: true,
- DefinitionList: true,
- Table: true,
- Strikethrough: true,
- Linkify: true,
- TaskList: true,
+ Typographer: true,
+ Footnote: true,
+ DefinitionList: true,
+ Table: true,
+ Strikethrough: true,
+ Linkify: true,
+ LinkifyProtocol: "https",
+ TaskList: true,
},
Renderer: Renderer{
Unsafe: false,
@@ -57,10 +58,11 @@ type Extensions struct {
DefinitionList bool
// GitHub flavored markdown
- Table bool
- Strikethrough bool
- Linkify bool
- TaskList bool
+ Table bool
+ Strikethrough bool
+ Linkify bool
+ LinkifyProtocol string
+ TaskList bool
}
type Renderer struct {
diff --git a/markup/goldmark/integration_test.go b/markup/goldmark/integration_test.go
index 89cd5bbb6..d8f218b31 100644
--- a/markup/goldmark/integration_test.go
+++ b/markup/goldmark/integration_test.go
@@ -423,3 +423,70 @@ title: "p1"
<img src="b.jpg" alt="&quot;a&quot;">
`)
}
+
+func TestLinkifyProtocol(t *testing.T) {
+ t.Parallel()
+
+ runTest := func(protocol string, withHook bool) *hugolib.IntegrationTestBuilder {
+
+ files := `
+-- config.toml --
+[markup.goldmark]
+[markup.goldmark.extensions]
+linkify = true
+linkifyProtocol = "PROTOCOL"
+-- content/p1.md --
+---
+title: "p1"
+---
+Link no procol: www.example.org
+Link http procol: http://www.example.org
+Link https procol: https://www.example.org
+
+-- layouts/_default/single.html --
+{{ .Content }}
+`
+ files = strings.ReplaceAll(files, "PROTOCOL", protocol)
+
+ if withHook {
+ files += `-- layouts/_default/_markup/render-link.html --
+<a href="{{ .Destination | safeURL }}">{{ .Text | safeHTML }}</a>`
+ }
+
+ return hugolib.NewIntegrationTestBuilder(
+ hugolib.IntegrationTestConfig{
+ T: t,
+ TxtarString: files,
+ },
+ ).Build()
+
+ }
+
+ for _, withHook := range []bool{false, true} {
+
+ b := runTest("https", withHook)
+
+ b.AssertFileContent("public/p1/index.html",
+ "Link no procol: <a href=\"https://www.example.org\">www.example.org</a>",
+ "Link http procol: <a href=\"http://www.example.org\">http://www.example.org</a>",
+ "Link https procol: <a href=\"https://www.example.org\">https://www.example.org</a></p>",
+ )
+
+ b = runTest("http", withHook)
+
+ b.AssertFileContent("public/p1/index.html",
+ "Link no procol: <a href=\"http://www.example.org\">www.example.org</a>",
+ "Link http procol: <a href=\"http://www.example.org\">http://www.example.org</a>",
+ "Link https procol: <a href=\"https://www.example.org\">https://www.example.org</a></p>",
+ )
+
+ b = runTest("gopher", withHook)
+
+ b.AssertFileContent("public/p1/index.html",
+ "Link no procol: <a href=\"gopher://www.example.org\">www.example.org</a>",
+ "Link http procol: <a href=\"http://www.example.org\">http://www.example.org</a>",
+ "Link https procol: <a href=\"https://www.example.org\">https://www.example.org</a></p>",
+ )
+
+ }
+}
diff --git a/markup/goldmark/render_hooks.go b/markup/goldmark/render_hooks.go
index 138a60d26..a22030f54 100644
--- a/markup/goldmark/render_hooks.go
+++ b/markup/goldmark/render_hooks.go
@@ -18,6 +18,7 @@ import (
"strings"
"github.com/gohugoio/hugo/markup/converter/hooks"
+ "github.com/gohugoio/hugo/markup/goldmark/goldmark_config"
"github.com/gohugoio/hugo/markup/goldmark/internal/render"
"github.com/gohugoio/hugo/markup/internal/attributes"
@@ -30,8 +31,9 @@ import (
var _ renderer.SetOptioner = (*hookedRenderer)(nil)
-func newLinkRenderer() renderer.NodeRenderer {
+func newLinkRenderer(cfg goldmark_config.Config) renderer.NodeRenderer {
r := &hookedRenderer{
+ linkifyProtocol: []byte(cfg.Extensions.LinkifyProtocol),
Config: html.Config{
Writer: html.DefaultWriter,
},
@@ -39,8 +41,8 @@ func newLinkRenderer() renderer.NodeRenderer {
return r
}
-func newLinks() goldmark.Extender {
- return &links{}
+func newLinks(cfg goldmark_config.Config) goldmark.Extender {
+ return &links{cfg: cfg}
}
type linkContext struct {
@@ -105,6 +107,7 @@ func (ctx headingContext) PlainText() string {
}
type hookedRenderer struct {
+ linkifyProtocol []byte
html.Config
}
@@ -279,7 +282,7 @@ func (r *hookedRenderer) renderAutoLink(w util.BufWriter, source []byte, node as
return r.renderAutoLinkDefault(w, source, node, entering)
}
- url := string(n.URL(source))
+ url := string(r.autoLinkURL(n, source))
label := string(n.Label(source))
if n.AutoLinkType == ast.AutoLinkEmail && !strings.HasPrefix(strings.ToLower(url), "mailto:") {
url = "mailto:" + url
@@ -310,8 +313,9 @@ func (r *hookedRenderer) renderAutoLinkDefault(w util.BufWriter, source []byte,
if !entering {
return ast.WalkContinue, nil
}
+
_, _ = w.WriteString(`<a href="`)
- url := n.URL(source)
+ url := r.autoLinkURL(n, source)
label := n.Label(source)
if n.AutoLinkType == ast.AutoLinkEmail && !bytes.HasPrefix(bytes.ToLower(url), []byte("mailto:")) {
_, _ = w.WriteString("mailto:")
@@ -329,6 +333,17 @@ func (r *hookedRenderer) renderAutoLinkDefault(w util.BufWriter, source []byte,
return ast.WalkContinue, nil
}
+func (r *hookedRenderer) autoLinkURL(n *ast.AutoLink, source []byte) []byte {
+ url := n.URL(source)
+ if len(n.Protocol) > 0 && !bytes.Equal(n.Protocol, r.linkifyProtocol) {
+ // The CommonMark spec says "http" is the correct protocol for links,
+ // but this doesn't make much sense (the fact that they should care about the rendered output).
+ // Note that n.Protocol is not set if protocol is provided by user.
+ url = append(r.linkifyProtocol, url[len(n.Protocol):]...)
+ }
+ return url
+}
+
func (r *hookedRenderer) renderHeading(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
n := node.(*ast.Heading)
var hr hooks.HeadingRenderer
@@ -394,11 +409,13 @@ func (r *hookedRenderer) renderHeadingDefault(w util.BufWriter, source []byte, n
return ast.WalkContinue, nil
}
-type links struct{}
+type links struct {
+ cfg goldmark_config.Config
+}
// Extend implements goldmark.Extender.
func (e *links) Extend(m goldmark.Markdown) {
m.Renderer().AddOptions(renderer.WithNodeRenderers(
- util.Prioritized(newLinkRenderer(), 100),
+ util.Prioritized(newLinkRenderer(e.cfg), 100),
))
}