Skip to content

Commit 5cc8a1a

Browse files
committed
Ensure that plain files are rendered correctly even when containing ambiguous characters
As recognised in go-gitea#21841 the rendering of plain text files is somewhat incorrect when there are ambiguous characters as the html code is double escaped. In fact there are several more problems here. We have a residual isRenderedHTML which is actually simply escaping the file - not rendering it. This is badly named and gives the wrong impression. There is also unusual behaviour whether the file is called a Readme or not and there is no way to get to the source code if the file is called README. In reality what should happen is different depending on whether the file is being rendered a README at the bottom of the directory view or not. 1. If it is rendered as a README on a directory - it should simply be escaped and rendered as `<pre>` text. 2. If it is rendered as a file then it should be rendered as source code. This PR therefore does: 1. Rename IsRenderedHTML to IsRenderedPlainText 2. Readme files rendered at the bottom of the directory are rendered without line numbers 3. Otherwise plain text files are rendered as source code. Replace go-gitea#21841 Signed-off-by: Andrew Thornton <[email protected]>
1 parent 0e46499 commit 5cc8a1a

File tree

4 files changed

+40
-22
lines changed

4 files changed

+40
-22
lines changed

modules/charset/escape.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package charset
99

1010
import (
11+
"bufio"
1112
"io"
1213
"strings"
1314

@@ -43,6 +44,35 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.
4344
return streamer.escaped, err
4445
}
4546

47+
// EscapeControlStringReader escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string
48+
func EscapeControlStringReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
49+
bufRd := bufio.NewReader(reader)
50+
outputStream := &HTMLStreamerWriter{Writer: writer}
51+
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
52+
53+
for {
54+
line, rdErr := bufRd.ReadString('\n')
55+
if len(line) > 0 {
56+
if err := streamer.Text(line); err != nil {
57+
streamer.escaped.HasError = true
58+
log.Error("Error whilst escaping: %v", err)
59+
return streamer.escaped, err
60+
}
61+
}
62+
if rdErr != nil {
63+
if rdErr != io.EOF {
64+
err = rdErr
65+
}
66+
break
67+
}
68+
if err := streamer.SelfClosingTag("br"); err != nil {
69+
streamer.escaped.HasError = true
70+
return streamer.escaped, err
71+
}
72+
}
73+
return streamer.escaped, err
74+
}
75+
4676
// EscapeControlString escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string
4777
func EscapeControlString(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
4878
sb := &strings.Builder{}

routers/web/repo/view.go

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
gocontext "context"
1010
"encoding/base64"
1111
"fmt"
12-
gotemplate "html/template"
1312
"io"
1413
"net/http"
1514
"net/url"
@@ -341,15 +340,13 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
341340
if err != nil {
342341
log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.name, ctx.Repo.Repository, err)
343342
buf := &bytes.Buffer{}
344-
ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale)
345-
ctx.Data["FileContent"] = strings.ReplaceAll(
346-
gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
347-
)
343+
ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
344+
ctx.Data["FileContent"] = buf.String()
348345
}
349346
} else {
350-
ctx.Data["IsRenderedHTML"] = true
347+
ctx.Data["IsRenderedPlainText"] = true
351348
buf := &bytes.Buffer{}
352-
ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, &charset.BreakWriter{Writer: buf}, ctx.Locale, charset.RuneNBSP)
349+
ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
353350
if err != nil {
354351
log.Error("Read failed: %v", err)
355352
}
@@ -527,15 +524,6 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
527524
}
528525
// to prevent iframe load third-party url
529526
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'")
530-
} else if readmeExist && !shouldRenderSource {
531-
buf := &bytes.Buffer{}
532-
ctx.Data["IsRenderedHTML"] = true
533-
534-
ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale)
535-
536-
ctx.Data["FileContent"] = strings.ReplaceAll(
537-
gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
538-
)
539527
} else {
540528
buf, _ := io.ReadAll(rd)
541529

templates/repo/settings/lfs_file.tmpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@
1717
</h4>
1818
<div class="ui attached table unstackable segment">
1919
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
20-
<div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsRenderedHTML}} plain-text{{else if .IsTextFile}} code-view{{end}}">
20+
<div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsRenderedPlainText}} plain-text{{else if .IsTextFile}} code-view{{end}}">
2121
{{if .IsMarkup}}
2222
{{if .FileContent}}{{.FileContent | Safe}}{{end}}
23-
{{else if .IsRenderedHTML}}
24-
<pre>{{if .FileContent}}{{.FileContent | Str2html}}{{end}}</pre>
23+
{{else if .IsRenderedPlainText}}
24+
<pre>{{if .FileContent}}{{.FileContent | Safe}}{{end}}</pre>
2525
{{else if not .IsTextFile}}
2626
<div class="view-raw ui center">
2727
{{if .IsImageFile}}

templates/repo/view_file.tmpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@
6161
{{if not (or .IsMarkup .IsRenderedHTML)}}
6262
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
6363
{{end}}
64-
<div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsRenderedHTML}} plain-text{{else if .IsTextSource}} code-view{{end}}">
64+
<div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsRenderedPlainText}} plain-text{{else if .IsTextSource}} code-view{{end}}">
6565
{{if .IsMarkup}}
6666
{{if .FileContent}}{{.FileContent | Safe}}{{end}}
67-
{{else if .IsRenderedHTML}}
68-
<pre>{{if .FileContent}}{{.FileContent | Str2html}}{{end}}</pre>
67+
{{else if .IsRenderedPlainText}}
68+
<pre>{{if .FileContent}}{{.FileContent | Safe}}{{end}}</pre>
6969
{{else if not .IsTextSource}}
7070
<div class="view-raw ui center">
7171
{{if .IsImageFile}}

0 commit comments

Comments
 (0)