aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2022-12-19 15:51:21 +0000
committerGitHub <noreply@github.com>2022-12-19 23:51:21 +0800
commit72524adf3fd8f8ff616c9ca60ae8215991ef8f2a (patch)
tree82304f5dee4dea5a8a1783208f731da9364c492a
parent2d4083f03cbf929ad2d4b3af8f20bd5419ed53b8 (diff)
downloadgitea-72524adf3fd8f8ff616c9ca60ae8215991ef8f2a.tar.gz
gitea-72524adf3fd8f8ff616c9ca60ae8215991ef8f2a.zip
Ensure that plain files are rendered correctly even when containing ambiguous characters (#22017) (#22160)
Backport #22017 As recognised in #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 IsPlainText 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 #21841 Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
-rw-r--r--modules/charset/escape.go32
-rw-r--r--routers/web/repo/view.go20
-rw-r--r--templates/repo/settings/lfs_file.tmpl6
-rw-r--r--templates/repo/view_file.tmpl6
4 files changed, 41 insertions, 23 deletions
diff --git a/modules/charset/escape.go b/modules/charset/escape.go
index b264a569ff..e600998937 100644
--- a/modules/charset/escape.go
+++ b/modules/charset/escape.go
@@ -9,6 +9,7 @@
package charset
import (
+ "bufio"
"io"
"strings"
@@ -32,7 +33,7 @@ func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune)
return streamer.escaped, sb.String()
}
-// EscapeControlReaders escapes the unicode control sequences in a provider reader and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
+// EscapeControlReaders escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
outputStream := &HTMLStreamerWriter{Writer: writer}
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
@@ -44,6 +45,35 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.
return streamer.escaped, err
}
+// EscapeControlStringReader escapes the unicode control sequences in a provided reader of string content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
+func EscapeControlStringReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
+ bufRd := bufio.NewReader(reader)
+ outputStream := &HTMLStreamerWriter{Writer: writer}
+ streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
+
+ for {
+ line, rdErr := bufRd.ReadString('\n')
+ if len(line) > 0 {
+ if err := streamer.Text(line); err != nil {
+ streamer.escaped.HasError = true
+ log.Error("Error whilst escaping: %v", err)
+ return streamer.escaped, err
+ }
+ }
+ if rdErr != nil {
+ if rdErr != io.EOF {
+ err = rdErr
+ }
+ break
+ }
+ if err := streamer.SelfClosingTag("br"); err != nil {
+ streamer.escaped.HasError = true
+ return streamer.escaped, err
+ }
+ }
+ return streamer.escaped, err
+}
+
// EscapeControlString escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string
func EscapeControlString(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
sb := &strings.Builder{}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index d35ec48df0..293a957266 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -10,7 +10,6 @@ import (
gocontext "context"
"encoding/base64"
"fmt"
- gotemplate "html/template"
"io"
"net/http"
"net/url"
@@ -342,15 +341,13 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
if err != nil {
log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.name, ctx.Repo.Repository, err)
buf := &bytes.Buffer{}
- ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale)
- ctx.Data["FileContent"] = strings.ReplaceAll(
- gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
- )
+ ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
+ ctx.Data["FileContent"] = buf.String()
}
} else {
- ctx.Data["IsRenderedHTML"] = true
+ ctx.Data["IsPlainText"] = true
buf := &bytes.Buffer{}
- ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, &charset.BreakWriter{Writer: buf}, ctx.Locale, charset.RuneNBSP)
+ ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, buf, ctx.Locale)
if err != nil {
log.Error("Read failed: %v", err)
}
@@ -522,15 +519,6 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
// to prevent iframe load third-party url
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'")
- } else if readmeExist && !shouldRenderSource {
- buf := &bytes.Buffer{}
- ctx.Data["IsRenderedHTML"] = true
-
- ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale)
-
- ctx.Data["FileContent"] = strings.ReplaceAll(
- gotemplate.HTMLEscapeString(buf.String()), "\n", `<br>`,
- )
} else {
buf, _ := io.ReadAll(rd)
diff --git a/templates/repo/settings/lfs_file.tmpl b/templates/repo/settings/lfs_file.tmpl
index ce3c39eac2..6d20aaddef 100644
--- a/templates/repo/settings/lfs_file.tmpl
+++ b/templates/repo/settings/lfs_file.tmpl
@@ -17,11 +17,11 @@
</h4>
<div class="ui attached table unstackable segment">
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
- <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsRenderedHTML}} plain-text{{else if .IsTextFile}} code-view{{end}}">
+ <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextFile}} code-view{{end}}">
{{if .IsMarkup}}
{{if .FileContent}}{{.FileContent | Safe}}{{end}}
- {{else if .IsRenderedHTML}}
- <pre>{{if .FileContent}}{{.FileContent | Str2html}}{{end}}</pre>
+ {{else if .IsPlainText}}
+ <pre>{{if .FileContent}}{{.FileContent | Safe}}{{end}}</pre>
{{else if not .IsTextFile}}
<div class="view-raw ui center">
{{if .IsImageFile}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl
index ed2162a414..14031cec45 100644
--- a/templates/repo/view_file.tmpl
+++ b/templates/repo/view_file.tmpl
@@ -82,11 +82,11 @@
{{if not (or .IsMarkup .IsRenderedHTML)}}
{{template "repo/unicode_escape_prompt" dict "EscapeStatus" .EscapeStatus "root" $}}
{{end}}
- <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsRenderedHTML}} plain-text{{else if .IsTextSource}} code-view{{end}}">
+ <div class="file-view{{if .IsMarkup}} markup {{.MarkupType}}{{else if .IsPlainText}} plain-text{{else if .IsTextSource}} code-view{{end}}">
{{if .IsMarkup}}
{{if .FileContent}}{{.FileContent | Safe}}{{end}}
- {{else if .IsRenderedHTML}}
- <pre>{{if .FileContent}}{{.FileContent | Str2html}}{{end}}</pre>
+ {{else if .IsPlainText}}
+ <pre>{{if .FileContent}}{{.FileContent | Safe}}{{end}}</pre>
{{else if not .IsTextSource}}
<div class="view-raw ui center">
{{if .IsImageFile}}