Skip to content

Commit 581e415

Browse files
committed
Allow render HTML with css/js external links
1 parent d002e3d commit 581e415

File tree

9 files changed

+135
-1
lines changed

9 files changed

+135
-1
lines changed

modules/markup/csv/csv.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ func (Renderer) SanitizerDisabled() bool {
5151
return false
5252
}
5353

54+
// DisplayInIFrame disabled sanitize if return true
55+
func (Renderer) DisplayInIFrame() bool {
56+
return false
57+
}
58+
5459
func writeField(w io.Writer, element, class, field string) error {
5560
if _, err := io.WriteString(w, "<"); err != nil {
5661
return err

modules/markup/external/external.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ func (p *Renderer) SanitizerDisabled() bool {
5959
return p.DisableSanitizer
6060
}
6161

62+
// DisplayInIFrame disabled sanitize if return true
63+
func (p *Renderer) DisplayInIFrame() bool {
64+
return p.UseIFrame
65+
}
66+
6267
func envMark(envName string) string {
6368
if runtime.GOOS == "windows" {
6469
return "%" + envName + "%"

modules/markup/markdown/markdown.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ func (Renderer) SanitizerDisabled() bool {
226226
return false
227227
}
228228

229+
// DisplayInIFrame disabled sanitize if return true
230+
func (Renderer) DisplayInIFrame() bool {
231+
return false
232+
}
233+
229234
// Render implements markup.Renderer
230235
func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
231236
return render(ctx, input, output)

modules/markup/orgmode/orgmode.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ func (Renderer) SanitizerDisabled() bool {
5252
return false
5353
}
5454

55+
// DisplayInIFrame disabled sanitize if return true
56+
func (Renderer) DisplayInIFrame() bool {
57+
return false
58+
}
59+
5560
// Render renders orgmode rawbytes to HTML
5661
func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
5762
htmlWriter := org.NewHTMLWriter()

modules/markup/renderer.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type RenderContext struct {
4545
GitRepo *git.Repository
4646
ShaExistCache map[string]bool
4747
cancelFn func()
48+
UseIframe bool
4849
}
4950

5051
// Cancel runs any cleanup functions that have been registered for this Ctx
@@ -82,6 +83,7 @@ type Renderer interface {
8283
NeedPostProcess() bool
8384
SanitizerRules() []setting.MarkupSanitizerRule
8485
SanitizerDisabled() bool
86+
DisplayInIFrame() bool
8587
Render(ctx *RenderContext, input io.Reader, output io.Writer) error
8688
}
8789

@@ -134,6 +136,18 @@ type nopCloser struct {
134136

135137
func (nopCloser) Close() error { return nil }
136138

139+
func renderIFrame(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Writer) error {
140+
_, err := io.WriteString(output, fmt.Sprintf(`<iframe src="%s%s/%s/render/%s/%s" name="ifd"
141+
onload="this.height=ifd.document.body.scrollHeight" width="100%%" scrolling="no" frameborder="0"/>`,
142+
setting.AppURL,
143+
ctx.Metas["user"],
144+
ctx.Metas["repo"],
145+
ctx.Metas["BranchNameSubURL"],
146+
ctx.Filename,
147+
))
148+
return err
149+
}
150+
137151
func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Writer) error {
138152
var wg sync.WaitGroup
139153
var err error
@@ -212,6 +226,9 @@ func (err ErrUnsupportedRenderExtension) Error() string {
212226
func renderFile(ctx *RenderContext, input io.Reader, output io.Writer) error {
213227
extension := strings.ToLower(filepath.Ext(ctx.Filename))
214228
if renderer, ok := extRenderers[extension]; ok {
229+
if renderer.DisplayInIFrame() && ctx.UseIframe {
230+
return renderIFrame(ctx, renderer, input, output)
231+
}
215232
return render(ctx, renderer, input, output)
216233
}
217234
return ErrUnsupportedRenderExtension{extension}

modules/setting/markup.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type MarkupRenderer struct {
3030
NeedPostProcess bool
3131
MarkupSanitizerRules []MarkupSanitizerRule
3232
DisableSanitizer bool
33+
UseIFrame bool
3334
}
3435

3536
// MarkupSanitizerRule defines the policy for whitelisting attributes on
@@ -152,5 +153,6 @@ func newMarkupRenderer(name string, sec *ini.Section) {
152153
IsInputFile: sec.Key("IS_INPUT_FILE").MustBool(false),
153154
NeedPostProcess: sec.Key("NEED_POSTPROCESS").MustBool(true),
154155
DisableSanitizer: sec.Key("DISABLE_SANITIZER").MustBool(false),
156+
UseIFrame: sec.Key("USE_IFRAME").MustBool(false),
155157
})
156158
}

routers/web/repo/render.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repo
6+
7+
import (
8+
"bytes"
9+
"io"
10+
"net/http"
11+
"path"
12+
"strings"
13+
14+
"code.gitea.io/gitea/modules/charset"
15+
"code.gitea.io/gitea/modules/context"
16+
"code.gitea.io/gitea/modules/git"
17+
"code.gitea.io/gitea/modules/markup"
18+
"code.gitea.io/gitea/modules/typesniffer"
19+
"code.gitea.io/gitea/modules/util"
20+
)
21+
22+
// RenderFile renders a file by repos path
23+
func RenderFile(ctx *context.Context) {
24+
blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
25+
if err != nil {
26+
if git.IsErrNotExist(err) {
27+
ctx.NotFound("GetBlobByPath", nil)
28+
} else {
29+
ctx.ServerError("GetBlobByPath", err)
30+
}
31+
return
32+
}
33+
34+
dataRc, err := blob.DataAsync()
35+
if err != nil {
36+
ctx.ServerError("DataAsync", err)
37+
return
38+
}
39+
defer dataRc.Close()
40+
41+
buf := make([]byte, 1024)
42+
n, _ := util.ReadAtMost(dataRc, buf)
43+
buf = buf[:n]
44+
45+
st := typesniffer.DetectContentType(buf)
46+
isTextFile := st.IsText()
47+
48+
rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
49+
50+
if markupType := markup.Type(blob.Name()); markupType == "" {
51+
if isTextFile {
52+
_, err = io.Copy(ctx.Resp, rd)
53+
if err != nil {
54+
ctx.ServerError("Copy", err)
55+
}
56+
return
57+
}
58+
ctx.Error(http.StatusInternalServerError, "Unsupported file type render")
59+
return
60+
}
61+
62+
treeLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
63+
if len(ctx.Repo.TreePath) > 0 {
64+
treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
65+
}
66+
67+
var result bytes.Buffer
68+
err = markup.Render(&markup.RenderContext{
69+
Ctx: ctx,
70+
Filename: blob.Name(),
71+
URLPrefix: path.Dir(treeLink),
72+
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
73+
GitRepo: ctx.Repo.GitRepo,
74+
}, rd, &result)
75+
if err != nil {
76+
ctx.ServerError("Render", err)
77+
return
78+
}
79+
80+
_, err = charset.EscapeControlReader(strings.NewReader(result.String()), ctx.Resp)
81+
if err != nil {
82+
ctx.ServerError("EscapeControlReader", err)
83+
return
84+
}
85+
}

routers/web/repo/view.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,12 +516,15 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
516516
ctx.Data["IsMarkup"] = true
517517
ctx.Data["MarkupType"] = markupType
518518
var result strings.Builder
519+
metas := ctx.Repo.Repository.ComposeDocumentMetas()
520+
metas["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
519521
err := markup.Render(&markup.RenderContext{
520522
Ctx: ctx,
521523
Filename: blob.Name(),
522524
URLPrefix: path.Dir(treeLink),
523-
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
525+
Metas: metas,
524526
GitRepo: ctx.Repo.GitRepo,
527+
UseIframe: true,
525528
}, rd, &result)
526529
if err != nil {
527530
ctx.ServerError("Render", err)

routers/web/web.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,6 +1148,13 @@ func RegisterRoutes(m *web.Route) {
11481148
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
11491149
}, repo.MustBeNotEmpty, reqRepoCodeReader)
11501150

1151+
m.Group("/render", func() {
1152+
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RenderFile)
1153+
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RenderFile)
1154+
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RenderFile)
1155+
m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.RenderFile)
1156+
}, repo.MustBeNotEmpty, reqRepoCodeReader)
1157+
11511158
m.Group("/commits", func() {
11521159
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits)
11531160
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefCommits)

0 commit comments

Comments
 (0)