aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorcoldWater <254244460@qq.com>2024-03-14 10:51:55 +0800
committerGitHub <noreply@github.com>2024-03-14 02:51:55 +0000
commite79a807a8461a73bd66146d816f635b66e198c89 (patch)
tree032858dd999f08e3710563485975cdf5a16113ef /modules
parentbbef5fc5c304d8e9cef110bffa44a0e4bcf028fb (diff)
downloadgitea-e79a807a8461a73bd66146d816f635b66e198c89.tar.gz
gitea-e79a807a8461a73bd66146d816f635b66e198c89.zip
Refactor markup/csv: don't read all to memory (#29760)
Diffstat (limited to 'modules')
-rw-r--r--modules/markup/csv/csv.go57
-rw-r--r--modules/markup/csv/csv_test.go10
2 files changed, 55 insertions, 12 deletions
diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go
index 12458e954a..570c4f4704 100644
--- a/modules/markup/csv/csv.go
+++ b/modules/markup/csv/csv.go
@@ -77,29 +77,62 @@ func writeField(w io.Writer, element, class, field string) error {
}
// Render implements markup.Renderer
-func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
+func (r Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
tmpBlock := bufio.NewWriter(output)
+ maxSize := setting.UI.CSV.MaxFileSize
- // FIXME: don't read all to memory
- rawBytes, err := io.ReadAll(input)
+ if maxSize == 0 {
+ return r.tableRender(ctx, input, tmpBlock)
+ }
+
+ rawBytes, err := io.ReadAll(io.LimitReader(input, maxSize+1))
if err != nil {
return err
}
- if setting.UI.CSV.MaxFileSize != 0 && setting.UI.CSV.MaxFileSize < int64(len(rawBytes)) {
- if _, err := tmpBlock.WriteString("<pre>"); err != nil {
- return err
- }
- if _, err := tmpBlock.WriteString(html.EscapeString(string(rawBytes))); err != nil {
- return err
+ if int64(len(rawBytes)) <= maxSize {
+ return r.tableRender(ctx, bytes.NewReader(rawBytes), tmpBlock)
+ }
+ return r.fallbackRender(io.MultiReader(bytes.NewReader(rawBytes), input), tmpBlock)
+}
+
+func (Renderer) fallbackRender(input io.Reader, tmpBlock *bufio.Writer) error {
+ _, err := tmpBlock.WriteString("<pre>")
+ if err != nil {
+ return err
+ }
+
+ scan := bufio.NewScanner(input)
+ scan.Split(bufio.ScanRunes)
+ for scan.Scan() {
+ switch scan.Text() {
+ case `&`:
+ _, err = tmpBlock.WriteString("&amp;")
+ case `'`:
+ _, err = tmpBlock.WriteString("&#39;") // "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
+ case `<`:
+ _, err = tmpBlock.WriteString("&lt;")
+ case `>`:
+ _, err = tmpBlock.WriteString("&gt;")
+ case `"`:
+ _, err = tmpBlock.WriteString("&#34;") // "&#34;" is shorter than "&quot;".
+ default:
+ _, err = tmpBlock.Write(scan.Bytes())
}
- if _, err := tmpBlock.WriteString("</pre>"); err != nil {
+ if err != nil {
return err
}
- return tmpBlock.Flush()
}
- rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, bytes.NewReader(rawBytes))
+ _, err = tmpBlock.WriteString("</pre>")
+ if err != nil {
+ return err
+ }
+ return tmpBlock.Flush()
+}
+
+func (Renderer) tableRender(ctx *markup.RenderContext, input io.Reader, tmpBlock *bufio.Writer) error {
+ rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, input)
if err != nil {
return err
}
diff --git a/modules/markup/csv/csv_test.go b/modules/markup/csv/csv_test.go
index 8c07184b21..3d12be477c 100644
--- a/modules/markup/csv/csv_test.go
+++ b/modules/markup/csv/csv_test.go
@@ -4,6 +4,8 @@
package markup
import (
+ "bufio"
+ "bytes"
"strings"
"testing"
@@ -29,4 +31,12 @@ func TestRenderCSV(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, v, buf.String())
}
+
+ t.Run("fallbackRender", func(t *testing.T) {
+ var buf bytes.Buffer
+ err := render.fallbackRender(strings.NewReader("1,<a>\n2,<b>"), bufio.NewWriter(&buf))
+ assert.NoError(t, err)
+ want := "<pre>1,&lt;a&gt;\n2,&lt;b&gt;</pre>"
+ assert.Equal(t, want, buf.String())
+ })
}