Go · 1953 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package repo
4
5 import (
6 "bytes"
7 "io"
8 "net/url"
9 "path"
10 "strings"
11
12 "golang.org/x/net/html"
13 )
14
15 func codeRouteBase(owner, repoName, route, ref, dir string) string {
16 base := "/" + url.PathEscape(owner) + "/" + url.PathEscape(repoName) + "/" + route + "/" + escapePathSegments(ref)
17 if dir != "" {
18 base += "/" + escapePathSegments(dir)
19 }
20 return base
21 }
22
23 func rewriteMarkdownRelativeURLs(fragment, linkBase, linkRoot, imageBase, imageRoot string) string {
24 if fragment == "" {
25 return ""
26 }
27 z := html.NewTokenizer(strings.NewReader(fragment))
28 var out bytes.Buffer
29 for {
30 tt := z.Next()
31 if tt == html.ErrorToken {
32 if z.Err() == io.EOF {
33 return out.String()
34 }
35 return fragment
36 }
37 tok := z.Token()
38 switch tt {
39 case html.StartTagToken, html.SelfClosingTagToken:
40 rewriteMarkdownTokenURLs(&tok, linkBase, linkRoot, imageBase, imageRoot)
41 }
42 out.WriteString(tok.String())
43 }
44 }
45
46 func rewriteMarkdownTokenURLs(tok *html.Token, linkBase, linkRoot, imageBase, imageRoot string) {
47 switch tok.Data {
48 case "a":
49 rewriteAttr(tok, "href", linkBase, linkRoot)
50 case "img":
51 rewriteAttr(tok, "src", imageBase, imageRoot)
52 }
53 }
54
55 func rewriteAttr(tok *html.Token, key, base, root string) {
56 for i := range tok.Attr {
57 if tok.Attr[i].Key == key {
58 tok.Attr[i].Val = rewriteRelativeMarkdownURL(tok.Attr[i].Val, base, root)
59 }
60 }
61 }
62
63 func rewriteRelativeMarkdownURL(raw, base, root string) string {
64 if raw == "" || base == "" || root == "" || strings.TrimSpace(raw) != raw {
65 return raw
66 }
67 if strings.HasPrefix(raw, "#") || strings.HasPrefix(raw, "//") {
68 return raw
69 }
70 u, err := url.Parse(raw)
71 if err != nil || u.IsAbs() || u.Host != "" || strings.HasPrefix(u.Path, "/") || u.Path == "" {
72 return raw
73 }
74 next := path.Clean(path.Clean(base) + "/" + u.Path)
75 if next != root && !strings.HasPrefix(next, root+"/") {
76 return raw
77 }
78 u.Path = next
79 u.RawPath = ""
80 return u.String()
81 }
82