diff options
author | coldWater <254244460@qq.com> | 2024-03-14 10:51:55 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-14 02:51:55 +0000 |
commit | e79a807a8461a73bd66146d816f635b66e198c89 (patch) | |
tree | 032858dd999f08e3710563485975cdf5a16113ef /modules | |
parent | bbef5fc5c304d8e9cef110bffa44a0e4bcf028fb (diff) | |
download | gitea-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.go | 57 | ||||
-rw-r--r-- | modules/markup/csv/csv_test.go | 10 |
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("&") + case `'`: + _, err = tmpBlock.WriteString("'") // "'" is shorter than "'" and apos was not in HTML until HTML5. + case `<`: + _, err = tmpBlock.WriteString("<") + case `>`: + _, err = tmpBlock.WriteString(">") + case `"`: + _, err = tmpBlock.WriteString(""") // """ is shorter than """. + 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,<a>\n2,<b></pre>" + assert.Equal(t, want, buf.String()) + }) } |