Skip to content

Commit 042e9fc

Browse files
authored
Fix rendered wiki page link (#31398) (#31407)
Backport #31398 Fix #31395
1 parent e8e43a7 commit 042e9fc

File tree

11 files changed

+62
-78
lines changed

11 files changed

+62
-78
lines changed

modules/markup/html.go

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -761,10 +761,10 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
761761
if image {
762762
link = strings.ReplaceAll(link, " ", "+")
763763
} else {
764-
link = strings.ReplaceAll(link, " ", "-")
764+
link = strings.ReplaceAll(link, " ", "-") // FIXME: it should support dashes in the link, eg: "the-dash-support.-"
765765
}
766766
if !strings.Contains(link, "/") {
767-
link = url.PathEscape(link)
767+
link = url.PathEscape(link) // FIXME: it doesn't seem right and it might cause double-escaping
768768
}
769769
}
770770
if image {
@@ -796,28 +796,7 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
796796
childNode.Attr = childNode.Attr[:2]
797797
}
798798
} else {
799-
if !absoluteLink {
800-
var base string
801-
if ctx.IsWiki {
802-
switch ext {
803-
case "":
804-
// no file extension, create a regular wiki link
805-
base = ctx.Links.WikiLink()
806-
default:
807-
// we have a file extension:
808-
// return a regular wiki link if it's a renderable file (extension),
809-
// raw link otherwise
810-
if Type(link) != "" {
811-
base = ctx.Links.WikiLink()
812-
} else {
813-
base = ctx.Links.WikiRawLink()
814-
}
815-
}
816-
} else {
817-
base = ctx.Links.SrcLink()
818-
}
819-
link = util.URLJoin(base, link)
820-
}
799+
link, _ = ResolveLink(ctx, link, "")
821800
childNode.Type = html.TextNode
822801
childNode.Data = name
823802
}

modules/markup/html_link.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package markup
5+
6+
import (
7+
"path"
8+
9+
"code.gitea.io/gitea/modules/util"
10+
)
11+
12+
func ResolveLink(ctx *RenderContext, link, userContentAnchorPrefix string) (result string, resolved bool) {
13+
isAnchorFragment := link != "" && link[0] == '#'
14+
if !isAnchorFragment && !IsFullURLString(link) {
15+
linkBase := ctx.Links.Base
16+
if ctx.IsWiki {
17+
if ext := path.Ext(link); ext == "" || ext == ".-" {
18+
linkBase = ctx.Links.WikiLink() // the link is for a wiki page
19+
} else if DetectMarkupTypeByFileName(link) != "" {
20+
linkBase = ctx.Links.WikiLink() // the link is renderable as a wiki page
21+
} else {
22+
linkBase = ctx.Links.WikiRawLink() // otherwise, use a raw link instead to view&download medias
23+
}
24+
} else if ctx.Links.BranchPath != "" || ctx.Links.TreePath != "" {
25+
// if there is no BranchPath, then the link will be something like "/owner/repo/src/{the-file-path}"
26+
// and then this link will be handled by the "legacy-ref" code and be redirected to the default branch like "/owner/repo/src/branch/main/{the-file-path}"
27+
linkBase = ctx.Links.SrcLink()
28+
}
29+
link, resolved = util.URLJoin(linkBase, link), true
30+
}
31+
if isAnchorFragment && userContentAnchorPrefix != "" {
32+
link, resolved = userContentAnchorPrefix+link[1:], true
33+
}
34+
return link, resolved
35+
}

modules/markup/html_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,10 @@ func TestRender_ShortLinks(t *testing.T) {
442442
"[[Link]]",
443443
`<p><a href="`+url+`" rel="nofollow">Link</a></p>`,
444444
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a></p>`)
445+
test(
446+
"[[Link.-]]",
447+
`<p><a href="http://localhost:3000/test-owner/test-repo/src/master/Link.-" rel="nofollow">Link.-</a></p>`,
448+
`<p><a href="http://localhost:3000/test-owner/test-repo/wiki/Link.-" rel="nofollow">Link.-</a></p>`)
445449
test(
446450
"[[Link.jpg]]",
447451
`<p><a href="`+imgurl+`" rel="nofollow"><img src="`+imgurl+`" title="Link.jpg" alt="Link.jpg"/></a></p>`,

modules/markup/markdown/goldmark.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
6767
case *ast.Image:
6868
g.transformImage(ctx, v, reader)
6969
case *ast.Link:
70-
g.transformLink(ctx, v, reader)
70+
g.transformLink(ctx, v)
7171
case *ast.List:
7272
g.transformList(ctx, v, reader, rc)
7373
case *ast.Text:

modules/markup/markdown/markdown_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ [email protected]
626626
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
627627
<a href="/file.bin" rel="nofollow">local link</a><br/>
628628
<a href="https://example.com" rel="nofollow">remote link</a><br/>
629-
<a href="/src/file.bin" rel="nofollow">local link</a><br/>
629+
<a href="/file.bin" rel="nofollow">local link</a><br/>
630630
<a href="https://example.com" rel="nofollow">remote link</a><br/>
631631
<a href="/image.jpg" target="_blank" rel="nofollow noopener"><img src="/image.jpg" alt="local image"/></a><br/>
632632
<a href="/path/file" target="_blank" rel="nofollow noopener"><img src="/path/file" alt="local image"/></a><br/>
@@ -682,7 +682,7 @@ space</p>
682682
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
683683
<a href="https://gitea.io/file.bin" rel="nofollow">local link</a><br/>
684684
<a href="https://example.com" rel="nofollow">remote link</a><br/>
685-
<a href="https://gitea.io/src/file.bin" rel="nofollow">local link</a><br/>
685+
<a href="https://gitea.io/file.bin" rel="nofollow">local link</a><br/>
686686
<a href="https://example.com" rel="nofollow">remote link</a><br/>
687687
<a href="https://gitea.io/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/image.jpg" alt="local image"/></a><br/>
688688
<a href="https://gitea.io/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/path/file" alt="local image"/></a><br/>
@@ -740,7 +740,7 @@ space</p>
740740
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
741741
<a href="/relative/path/file.bin" rel="nofollow">local link</a><br/>
742742
<a href="https://example.com" rel="nofollow">remote link</a><br/>
743-
<a href="/relative/path/src/file.bin" rel="nofollow">local link</a><br/>
743+
<a href="/relative/path/file.bin" rel="nofollow">local link</a><br/>
744744
<a href="https://example.com" rel="nofollow">remote link</a><br/>
745745
<a href="/relative/path/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/image.jpg" alt="local image"/></a><br/>
746746
<a href="/relative/path/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/path/file" alt="local image"/></a><br/>
@@ -857,7 +857,7 @@ space</p>
857857
Expected: `<p>space @mention-user<br/>
858858
/just/a/path.bin<br/>
859859
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
860-
<a href="/user/repo/file.bin" rel="nofollow">local link</a><br/>
860+
<a href="/user/repo/src/sub/folder/file.bin" rel="nofollow">local link</a><br/>
861861
<a href="https://example.com" rel="nofollow">remote link</a><br/>
862862
<a href="/user/repo/src/sub/folder/file.bin" rel="nofollow">local link</a><br/>
863863
<a href="https://example.com" rel="nofollow">remote link</a><br/>
@@ -975,7 +975,7 @@ space</p>
975975
for i, c := range cases {
976976
result, err := markdown.RenderString(&markup.RenderContext{Ctx: context.Background(), Links: c.Links, IsWiki: c.IsWiki}, input)
977977
assert.NoError(t, err, "Unexpected error in testcase: %v", i)
978-
assert.Equal(t, template.HTML(c.Expected), result, "Unexpected result in testcase %v", i)
978+
assert.Equal(t, c.Expected, string(result), "Unexpected result in testcase %v", i)
979979
}
980980
}
981981

modules/markup/markdown/transform_link.go

Lines changed: 3 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,13 @@
44
package markdown
55

66
import (
7-
"path/filepath"
8-
97
"code.gitea.io/gitea/modules/markup"
10-
giteautil "code.gitea.io/gitea/modules/util"
118

129
"github.com/yuin/goldmark/ast"
13-
"github.com/yuin/goldmark/text"
1410
)
1511

16-
func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link, reader text.Reader) {
17-
// Links need their href to munged to be a real value
18-
link := v.Destination
19-
isAnchorFragment := len(link) > 0 && link[0] == '#'
20-
if !isAnchorFragment && !markup.IsFullURLBytes(link) {
21-
base := ctx.Links.Base
22-
if ctx.IsWiki {
23-
if filepath.Ext(string(link)) == "" {
24-
// This link doesn't have a file extension - assume a regular wiki link
25-
base = ctx.Links.WikiLink()
26-
} else if markup.Type(string(link)) != "" {
27-
// If it's a file type we can render, use a regular wiki link
28-
base = ctx.Links.WikiLink()
29-
} else {
30-
// Otherwise, use a raw link instead
31-
base = ctx.Links.WikiRawLink()
32-
}
33-
} else if ctx.Links.HasBranchInfo() {
34-
base = ctx.Links.SrcLink()
35-
}
36-
link = []byte(giteautil.URLJoin(base, string(link)))
37-
}
38-
if isAnchorFragment {
39-
link = []byte("#user-content-" + string(link)[1:])
12+
func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link) {
13+
if link, resolved := markup.ResolveLink(ctx, string(v.Destination), "#user-content-"); resolved {
14+
v.Destination = []byte(link)
4015
}
41-
v.Destination = link
4216
}

modules/markup/renderer.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -370,22 +370,14 @@ func renderFile(ctx *RenderContext, input io.Reader, output io.Writer) error {
370370
return ErrUnsupportedRenderExtension{extension}
371371
}
372372

373-
// Type returns if markup format via the filename
374-
func Type(filename string) string {
373+
// DetectMarkupTypeByFileName returns the possible markup format type via the filename
374+
func DetectMarkupTypeByFileName(filename string) string {
375375
if parser := GetRendererByFileName(filename); parser != nil {
376376
return parser.Name()
377377
}
378378
return ""
379379
}
380380

381-
// IsMarkupFile reports whether file is a markup type file
382-
func IsMarkupFile(name, markup string) bool {
383-
if parser := GetRendererByFileName(name); parser != nil {
384-
return parser.Name() == markup
385-
}
386-
return false
387-
}
388-
389381
func PreviewableExtensions() []string {
390382
extensions := make([]string, 0, len(extRenderers))
391383
for extension := range extRenderers {

modules/templates/util_render_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func TestRenderMarkdownToHtml(t *testing.T) {
174174
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a>
175175
<a href="/file.bin" rel="nofollow">local link</a>
176176
<a href="https://example.com" rel="nofollow">remote link</a>
177-
<a href="/src/file.bin" rel="nofollow">local link</a>
177+
<a href="/file.bin" rel="nofollow">local link</a>
178178
<a href="https://example.com" rel="nofollow">remote link</a>
179179
<a href="/image.jpg" target="_blank" rel="nofollow noopener"><img src="/image.jpg" alt="local image"/></a>
180180
<a href="https://example.com/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://example.com/image.jpg" alt="remote image"/></a>
@@ -190,7 +190,7 @@ com 88fc37a3c0a4dda553bdcfc80c178a58247f42fb mit
190190
#123
191191
space</p>
192192
`
193-
assert.EqualValues(t, expected, RenderMarkdownToHtml(context.Background(), testInput()))
193+
assert.Equal(t, expected, string(RenderMarkdownToHtml(context.Background(), testInput())))
194194
}
195195

196196
func TestRenderLabels(t *testing.T) {

routers/web/repo/render.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func RenderFile(ctx *context.Context) {
4747
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{})
4848
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
4949

50-
if markupType := markup.Type(blob.Name()); markupType == "" {
50+
if markupType := markup.DetectMarkupTypeByFileName(blob.Name()); markupType == "" {
5151
if isTextFile {
5252
_, _ = io.Copy(ctx.Resp, rd)
5353
} else {

routers/web/repo/view.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ func renderReadmeFile(ctx *context.Context, subfolder string, readmeFile *git.Tr
307307

308308
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc), charset.ConvertOpts{})
309309

310-
if markupType := markup.Type(readmeFile.Name()); markupType != "" {
310+
if markupType := markup.DetectMarkupTypeByFileName(readmeFile.Name()); markupType != "" {
311311
ctx.Data["IsMarkup"] = true
312312
ctx.Data["MarkupType"] = markupType
313313

@@ -499,7 +499,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
499499
readmeExist := util.IsReadmeFileName(blob.Name())
500500
ctx.Data["ReadmeExist"] = readmeExist
501501

502-
markupType := markup.Type(blob.Name())
502+
markupType := markup.DetectMarkupTypeByFileName(blob.Name())
503503
// If the markup is detected by custom markup renderer it should not be reset later on
504504
// to not pass it down to the render context.
505505
detected := false
@@ -606,9 +606,9 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry) {
606606
break
607607
}
608608

609-
// TODO: this logic seems strange, it duplicates with "isRepresentableAsText=true", it is not the same as "LFSFileGet" in "lfs.go"
610-
// maybe for this case, the file is a binary file, and shouldn't be rendered?
611-
if markupType := markup.Type(blob.Name()); markupType != "" {
609+
// TODO: this logic duplicates with "isRepresentableAsText=true", it is not the same as "LFSFileGet" in "lfs.go"
610+
// It is used by "external renders", markupRender will execute external programs to get rendered content.
611+
if markupType := markup.DetectMarkupTypeByFileName(blob.Name()); markupType != "" {
612612
rd := io.MultiReader(bytes.NewReader(buf), dataRc)
613613
ctx.Data["IsMarkup"] = true
614614
ctx.Data["MarkupType"] = markupType

routers/web/repo/wiki.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ func Wiki(ctx *context.Context) {
532532
}
533533

534534
wikiPath := entry.Name()
535-
if markup.Type(wikiPath) != markdown.MarkupName {
535+
if markup.DetectMarkupTypeByFileName(wikiPath) != markdown.MarkupName {
536536
ext := strings.ToUpper(filepath.Ext(wikiPath))
537537
ctx.Data["FormatWarning"] = fmt.Sprintf("%s rendering is not supported at the moment. Rendered as Markdown.", ext)
538538
}

0 commit comments

Comments
 (0)