From d508676138f37cee25f15eeb078524f3ce25d94a Mon Sep 17 00:00:00 2001 From: coldWater Date: Wed, 13 Mar 2024 14:08:26 +0800 Subject: [PATCH 1/2] Refactor --- modules/markup/csv/csv.go | 57 ++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go index 12458e954ade..f0b2bc134e15 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("
"); 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("
")
+	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.WriteString(scan.Text())
 		}
-		if _, err := tmpBlock.WriteString("
"); err != nil { + if err != nil { return err } - return tmpBlock.Flush() } - rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, bytes.NewReader(rawBytes)) + _, err = tmpBlock.WriteString("
") + 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 } From 40efea97017b968e66e55e86c81c4d1149557667 Mon Sep 17 00:00:00 2001 From: coldWater Date: Wed, 13 Mar 2024 16:32:12 +0800 Subject: [PATCH 2/2] add ut --- modules/markup/csv/csv.go | 2 +- modules/markup/csv/csv_test.go | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go index f0b2bc134e15..570c4f47041d 100644 --- a/modules/markup/csv/csv.go +++ b/modules/markup/csv/csv.go @@ -117,7 +117,7 @@ func (Renderer) fallbackRender(input io.Reader, tmpBlock *bufio.Writer) error { case `"`: _, err = tmpBlock.WriteString(""") // """ is shorter than """. default: - _, err = tmpBlock.WriteString(scan.Text()) + _, err = tmpBlock.Write(scan.Bytes()) } if err != nil { return err diff --git a/modules/markup/csv/csv_test.go b/modules/markup/csv/csv_test.go index 8c07184b21ee..3d12be477c74 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,\n2,"), bufio.NewWriter(&buf)) + assert.NoError(t, err) + want := "
1,<a>\n2,<b>
" + assert.Equal(t, want, buf.String()) + }) }