Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ansi/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (e *ImageElement) Render(w io.Writer, ctx RenderContext) error {
}
if len(e.URL) > 0 {
el := &BaseElement{
Token: resolveRelativeURL(e.BaseURL, e.URL),
Token: resolveURL(e.BaseURL, e.URL),
Prefix: " ",
Style: ctx.options.Styles.Image,
}
Expand Down
2 changes: 1 addition & 1 deletion ansi/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (e *LinkElement) Render(w io.Writer, ctx RenderContext) error {
}

el := &BaseElement{
Token: resolveRelativeURL(e.BaseURL, e.URL),
Token: resolveURL(e.BaseURL, e.URL),
Prefix: pre,
Style: style,
}
Expand Down
4 changes: 1 addition & 3 deletions ansi/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package ansi
import (
"io"
"net/url"
"strings"

"github.com/muesli/termenv"
east "github.com/yuin/goldmark-emoji/ast"
Expand Down Expand Up @@ -150,15 +149,14 @@ func isChild(node ast.Node) bool {
return false
}

func resolveRelativeURL(baseURL string, rel string) string {
func resolveURL(baseURL string, rel string) string {
u, err := url.Parse(rel)
if err != nil {
return rel
}
if u.IsAbs() {
return rel
}
u.Path = strings.TrimPrefix(u.Path, "/")

base, err := url.Parse(baseURL)
if err != nil {
Expand Down
62 changes: 62 additions & 0 deletions ansi/renderer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,65 @@ func TestRendererIssues(t *testing.T) {
}
}
}

func TestUrlResolver(t *testing.T) {
// resolveURL should be compliant with https://tools.ietf.org/html/rfc3986#section-5.2.2

host := "https://example.com"
host2 := "https://elpmaxe.moc"

assertEqual(t, resolveURL("a/b", "/c/d"), "/c/d")
assertEqual(t, resolveURL("a/b", "./c/d"), "/a/c/d")
assertEqual(t, resolveURL("a/b", "../c/d"), "/c/d")
assertEqual(t, resolveURL("a/b/", "./c/d"), "/a/b/c/d")
assertEqual(t, resolveURL("a/b/", "c/d"), "/a/b/c/d")
assertEqual(t, resolveURL("a/b/", host2+"/c/d"), host2+"/c/d")

assertEqual(t, resolveURL("/a/b", "/c/d"), "/c/d")
assertEqual(t, resolveURL("/a/b", "./c/d"), "/a/c/d")
assertEqual(t, resolveURL("/a/b", "../c/d"), "/c/d")
assertEqual(t, resolveURL("/a/b/", "./c/d"), "/a/b/c/d")
assertEqual(t, resolveURL("/a/b/", "c/d"), "/a/b/c/d")
assertEqual(t, resolveURL("/a/b/", host2+"/c/d"), host2+"/c/d")

assertEqual(t, resolveURL(host+"/a/b", "/c/d"), host+"/c/d")
assertEqual(t, resolveURL(host+"/a/b", "./c/d"), host+"/a/c/d")
assertEqual(t, resolveURL(host+"/a/b", "../c/d"), host+"/c/d")
assertEqual(t, resolveURL(host+"/a/b/", "./c/d"), host+"/a/b/c/d")
assertEqual(t, resolveURL(host+"/a/b/", "c/d"), host+"/a/b/c/d")
assertEqual(t, resolveURL(host+"/a/b/", host2+"/c/d"), host2+"/c/d")
}

func TestUrlResolverForLocalFiles(t *testing.T) {
base := "/home/foobar/project/"
assertEqual(t,
resolveURL(base, "/assets/logo.png"),
"/home/foobar/project/assets/logo.png")
}

func TestUrlResolverForGitforgeUsage(t *testing.T) {
// in git-forges like github & gitea, URLs are often written relative,
// where the repo-url (`gitea.com/gitea/tea`) treated as reference.
// The base URL needs to be treated with a trailing slash, acting as a "directory",
// requiring preprocessing of the URLs by applications (appending trailing slash to base URL).
base := "https://gitea.com/gitea/tea/"
assertEqual(t,
resolveURL(base, "src/branch/master/modules/print/markdown.go"),
"https://gitea.com/gitea/tea/src/branch/master/modules/print/markdown.go")

base = "https://raw.githubusercontent.com/foo/bar/master/"
assertEqual(t,
resolveURL(base, "/assets/logo.png"),
"https://raw.githubusercontent.com/foo/bar/master/assets/logo.png")

base = "https://raw.githubusercontent.com/foo/bar/master/some/dir/"
assertEqual(t,
resolveURL(base, "/assets/logo.png"),
"https://raw.githubusercontent.com/foo/bar/master/assets/logo.png")
}

func assertEqual(t *testing.T, value interface{}, expected interface{}) {
if value != expected {
t.Errorf("Expected '%v', but got '%v'", expected, value)
}
}