mirror of https://github.com/go-gitea/gitea.git
Use raw Wiki links for non-renderable Wiki files (#30273)
In Wiki pages, short-links created to local Wiki files were always expanded as regular Wiki Links. In particular, if a link wanted to point to a file that Gitea doesn't know how to render (e.g, a .zip file), a user following the link would be silently redirected to the Wiki's home page. This change makes short-links* in Wiki pages be expanded to raw wiki links, so these local wiki files may be accessed without manually accessing their URL. * only short-links ending in a file extension that isn't renderable are affected. Closes #27121. Signed-off-by: Rafael Girão <rafael.s.girao@tecnico.ulisboa.pt> Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
parent
50099d7af4
commit
c1f76aea45
|
@ -709,7 +709,8 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
|
|
||||||
name += tail
|
name += tail
|
||||||
image := false
|
image := false
|
||||||
switch ext := filepath.Ext(link); ext {
|
ext := filepath.Ext(link)
|
||||||
|
switch ext {
|
||||||
// fast path: empty string, ignore
|
// fast path: empty string, ignore
|
||||||
case "":
|
case "":
|
||||||
// leave image as false
|
// leave image as false
|
||||||
|
@ -767,12 +768,27 @@ func shortLinkProcessor(ctx *RenderContext, node *html.Node) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !absoluteLink {
|
if !absoluteLink {
|
||||||
|
var base string
|
||||||
if ctx.IsWiki {
|
if ctx.IsWiki {
|
||||||
link = util.URLJoin(ctx.Links.WikiLink(), link)
|
switch ext {
|
||||||
|
case "":
|
||||||
|
// no file extension, create a regular wiki link
|
||||||
|
base = ctx.Links.WikiLink()
|
||||||
|
default:
|
||||||
|
// we have a file extension:
|
||||||
|
// return a regular wiki link if it's a renderable file (extension),
|
||||||
|
// raw link otherwise
|
||||||
|
if Type(link) != "" {
|
||||||
|
base = ctx.Links.WikiLink()
|
||||||
} else {
|
} else {
|
||||||
link = util.URLJoin(ctx.Links.SrcLink(), link)
|
base = ctx.Links.WikiRawLink()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
base = ctx.Links.SrcLink()
|
||||||
|
}
|
||||||
|
link = util.URLJoin(base, link)
|
||||||
|
}
|
||||||
childNode.Type = html.TextNode
|
childNode.Type = html.TextNode
|
||||||
childNode.Data = name
|
childNode.Data = name
|
||||||
}
|
}
|
||||||
|
|
|
@ -427,6 +427,10 @@ func TestRender_ShortLinks(t *testing.T) {
|
||||||
otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg")
|
otherImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+Other.jpg")
|
||||||
encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg")
|
encodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "Link+%23.jpg")
|
||||||
notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
|
notencodedImgurlWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "some", "path", "Link+#.jpg")
|
||||||
|
renderableFileURL := util.URLJoin(tree, "markdown_file.md")
|
||||||
|
renderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "markdown_file.md")
|
||||||
|
unrenderableFileURL := util.URLJoin(tree, "file.zip")
|
||||||
|
unrenderableFileURLWiki := util.URLJoin(markup.TestRepoURL, "wiki", "raw", "file.zip")
|
||||||
favicon := "http://google.com/favicon.ico"
|
favicon := "http://google.com/favicon.ico"
|
||||||
|
|
||||||
test(
|
test(
|
||||||
|
@ -481,6 +485,14 @@ func TestRender_ShortLinks(t *testing.T) {
|
||||||
"[[Link]] [[Other Link]] [[Link?]]",
|
"[[Link]] [[Other Link]] [[Link?]]",
|
||||||
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
|
`<p><a href="`+url+`" rel="nofollow">Link</a> <a href="`+otherURL+`" rel="nofollow">Other Link</a> <a href="`+encodedURL+`" rel="nofollow">Link?</a></p>`,
|
||||||
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`)
|
`<p><a href="`+urlWiki+`" rel="nofollow">Link</a> <a href="`+otherURLWiki+`" rel="nofollow">Other Link</a> <a href="`+encodedURLWiki+`" rel="nofollow">Link?</a></p>`)
|
||||||
|
test(
|
||||||
|
"[[markdown_file.md]]",
|
||||||
|
`<p><a href="`+renderableFileURL+`" rel="nofollow">markdown_file.md</a></p>`,
|
||||||
|
`<p><a href="`+renderableFileURLWiki+`" rel="nofollow">markdown_file.md</a></p>`)
|
||||||
|
test(
|
||||||
|
"[[file.zip]]",
|
||||||
|
`<p><a href="`+unrenderableFileURL+`" rel="nofollow">file.zip</a></p>`,
|
||||||
|
`<p><a href="`+unrenderableFileURLWiki+`" rel="nofollow">file.zip</a></p>`)
|
||||||
test(
|
test(
|
||||||
"[[Link #.jpg]]",
|
"[[Link #.jpg]]",
|
||||||
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`,
|
`<p><a href="`+encodedImgurl+`" rel="nofollow"><img src="`+encodedImgurl+`" title="Link #.jpg" alt="Link #.jpg"/></a></p>`,
|
||||||
|
|
|
@ -653,9 +653,9 @@ space</p>
|
||||||
Expected: `<p>space @mention-user<br/>
|
Expected: `<p>space @mention-user<br/>
|
||||||
/just/a/path.bin<br/>
|
/just/a/path.bin<br/>
|
||||||
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
||||||
<a href="/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
<a href="/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
||||||
<a href="/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/path/file" alt="local image"/></a><br/>
|
<a href="/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/wiki/raw/path/file" alt="local image"/></a><br/>
|
||||||
|
@ -711,9 +711,9 @@ space</p>
|
||||||
Expected: `<p>space @mention-user<br/>
|
Expected: `<p>space @mention-user<br/>
|
||||||
/just/a/path.bin<br/>
|
/just/a/path.bin<br/>
|
||||||
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
||||||
<a href="https://gitea.io/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="https://gitea.io/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="https://gitea.io/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="https://gitea.io/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="https://gitea.io/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
<a href="https://gitea.io/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
||||||
<a href="https://gitea.io/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/path/file" alt="local image"/></a><br/>
|
<a href="https://gitea.io/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="https://gitea.io/wiki/raw/path/file" alt="local image"/></a><br/>
|
||||||
|
@ -769,9 +769,9 @@ space</p>
|
||||||
Expected: `<p>space @mention-user<br/>
|
Expected: `<p>space @mention-user<br/>
|
||||||
/just/a/path.bin<br/>
|
/just/a/path.bin<br/>
|
||||||
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
||||||
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
||||||
|
@ -829,9 +829,9 @@ space</p>
|
||||||
Expected: `<p>space @mention-user<br/>
|
Expected: `<p>space @mention-user<br/>
|
||||||
/just/a/path.bin<br/>
|
/just/a/path.bin<br/>
|
||||||
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
||||||
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
||||||
|
@ -889,9 +889,9 @@ space</p>
|
||||||
Expected: `<p>space @mention-user<br/>
|
Expected: `<p>space @mention-user<br/>
|
||||||
/just/a/path.bin<br/>
|
/just/a/path.bin<br/>
|
||||||
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
||||||
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
||||||
|
@ -951,9 +951,9 @@ space</p>
|
||||||
Expected: `<p>space @mention-user<br/>
|
Expected: `<p>space @mention-user<br/>
|
||||||
/just/a/path.bin<br/>
|
/just/a/path.bin<br/>
|
||||||
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
<a href="https://example.com/file.bin" rel="nofollow">https://example.com/file.bin</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/file.bin" rel="nofollow">local link</a><br/>
|
<a href="/relative/path/wiki/raw/file.bin" rel="nofollow">local link</a><br/>
|
||||||
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
<a href="https://example.com" rel="nofollow">remote link</a><br/>
|
||||||
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/image.jpg" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/image.jpg" alt="local image"/></a><br/>
|
||||||
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
<a href="/relative/path/wiki/raw/path/file" target="_blank" rel="nofollow noopener"><img src="/relative/path/wiki/raw/path/file" alt="local image"/></a><br/>
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
package markdown
|
package markdown
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/markup"
|
"code.gitea.io/gitea/modules/markup"
|
||||||
giteautil "code.gitea.io/gitea/modules/util"
|
giteautil "code.gitea.io/gitea/modules/util"
|
||||||
|
|
||||||
|
@ -18,7 +20,16 @@ func (g *ASTTransformer) transformLink(ctx *markup.RenderContext, v *ast.Link, r
|
||||||
if !isAnchorFragment && !markup.IsFullURLBytes(link) {
|
if !isAnchorFragment && !markup.IsFullURLBytes(link) {
|
||||||
base := ctx.Links.Base
|
base := ctx.Links.Base
|
||||||
if ctx.IsWiki {
|
if ctx.IsWiki {
|
||||||
|
if filepath.Ext(string(link)) == "" {
|
||||||
|
// This link doesn't have a file extension - assume a regular wiki link
|
||||||
base = ctx.Links.WikiLink()
|
base = ctx.Links.WikiLink()
|
||||||
|
} else if markup.Type(string(link)) != "" {
|
||||||
|
// If it's a file type we can render, use a regular wiki link
|
||||||
|
base = ctx.Links.WikiLink()
|
||||||
|
} else {
|
||||||
|
// Otherwise, use a raw link instead
|
||||||
|
base = ctx.Links.WikiRawLink()
|
||||||
|
}
|
||||||
} else if ctx.Links.HasBranchInfo() {
|
} else if ctx.Links.HasBranchInfo() {
|
||||||
base = ctx.Links.SrcLink()
|
base = ctx.Links.SrcLink()
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,6 +202,7 @@ func TestWikiRaw(t *testing.T) {
|
||||||
for filepath, filetype := range map[string]string{
|
for filepath, filetype := range map[string]string{
|
||||||
"jpeg.jpg": "image/jpeg",
|
"jpeg.jpg": "image/jpeg",
|
||||||
"images/jpeg.jpg": "image/jpeg",
|
"images/jpeg.jpg": "image/jpeg",
|
||||||
|
"files/Non-Renderable-File.zip": "application/octet-stream",
|
||||||
"Page With Spaced Name": "text/plain; charset=utf-8",
|
"Page With Spaced Name": "text/plain; charset=utf-8",
|
||||||
"Page-With-Spaced-Name": "text/plain; charset=utf-8",
|
"Page-With-Spaced-Name": "text/plain; charset=utf-8",
|
||||||
"Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo
|
"Page With Spaced Name.md": "", // there is no "Page With Spaced Name.md" in repo
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
xťŹKnÄ Dłć죱ÁvóEQ˛Ę~nĐ@3Fňđ‰r”\,dŽ<64>^”TĄŇSµĎŹGj|žĹK+DÜĘŕ˘
$2`ĺ4ÇÉY«”Y”u{‡Xho\Źŕ‚u4E;k- P4<>Q^Hł84Ŕđlk.ü†iă_©ü|gţVžv¨Ă=ĚŤüž|Î-U—q8Ú;—ZJµč,ý<>Nnô_<C3B4>Ő”ę0Ůaě3ľçýŇż TĐmÄ·ěqă1mÄŘŤb˝ňµµŁ^ÇńžÚzşˇ/ďůŇá_Ö5ŐzR'-'É~étl˝
|
Binary file not shown.
Binary file not shown.
|
@ -1 +1 @@
|
||||||
0dca5bd9b5d7ef937710e056f575e86c0184ba85
|
a5bbc0fd39a696feabed2d4cccaf05abbcaf3b02
|
||||||
|
|
|
@ -45,6 +45,7 @@ func TestRepoCloneWiki(t *testing.T) {
|
||||||
assertFileExist(t, filepath.Join(dstPath, "Page-With-Image.md"))
|
assertFileExist(t, filepath.Join(dstPath, "Page-With-Image.md"))
|
||||||
assertFileExist(t, filepath.Join(dstPath, "Page-With-Spaced-Name.md"))
|
assertFileExist(t, filepath.Join(dstPath, "Page-With-Spaced-Name.md"))
|
||||||
assertFileExist(t, filepath.Join(dstPath, "images"))
|
assertFileExist(t, filepath.Join(dstPath, "images"))
|
||||||
|
assertFileExist(t, filepath.Join(dstPath, "files/Non-Renderable-File.zip"))
|
||||||
assertFileExist(t, filepath.Join(dstPath, "jpeg.jpg"))
|
assertFileExist(t, filepath.Join(dstPath, "jpeg.jpg"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue