From 18b03d5dc7a03e3148683feb26a5aaecfef40d30 Mon Sep 17 00:00:00 2001 From: qzhello <951012707@qq.com> Date: Wed, 24 Jun 2026 11:20:11 +0800 Subject: [PATCH] fix: avoid reading upload body when writing JSON errors (#10073) * fix(shell): correct volume.list -writable filter unit and comparison * fix(shell): correct volume.list -writable filter unit and comparison * chore(shell): fix typo in EC shard helper param names * fix(shell): use exact match for volume.balance -racks/-nodes filter The old strings.Contains-based filter quietly included any id that was a substring of the user-supplied flag value (e.g. -racks=rack10 also matched rack1). Replace it with an exact-match set parsed from the comma-separated flag value, and add regression tests for both -racks and -nodes paths. Also fix a small typo in the "remote storage" error returned by maybeMoveOneVolume. * fix(shell): use exact match for volume.balance -racks/-nodes filter The old strings.Contains-based filter quietly included any id that was a substring of the user-supplied flag value (e.g. -racks=rack10 also matched rack1). Replace it with an exact-match set parsed from the comma-separated flag value, and add regression tests for both -racks and -nodes paths. Also fix a small typo in the "remote storage" error returned by maybeMoveOneVolume. * refactor(shell): drop nil sentinel in splitCSVSet, use len() in callers * fix: avoid reading upload body when writing JSON errors --- weed/server/common.go | 2 +- weed/server/common_test.go | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/weed/server/common.go b/weed/server/common.go index 990ad6398..b8058b2a9 100644 --- a/weed/server/common.go +++ b/weed/server/common.go @@ -95,7 +95,7 @@ func writeJson(w http.ResponseWriter, r *http.Request, httpStatus int, obj inter var bytes []byte if obj != nil { - if r.FormValue("pretty") != "" { + if r.URL.Query().Get("pretty") != "" { bytes, err = json.MarshalIndent(obj, "", " ") } else { bytes, err = json.Marshal(obj) diff --git a/weed/server/common_test.go b/weed/server/common_test.go index 18d4f1135..6c65ab1af 100644 --- a/weed/server/common_test.go +++ b/weed/server/common_test.go @@ -1,6 +1,9 @@ package weed_server import ( + "bytes" + "io" + "mime/multipart" "net/http" "net/http/httptest" "strings" @@ -61,3 +64,51 @@ func TestWriteJsonNoJSONP(t *testing.T) { }) } } + +func TestWriteJsonPrettyDoesNotReadMultipartBody(t *testing.T) { + var form bytes.Buffer + mw := multipart.NewWriter(&form) + if err := mw.WriteField("pretty", "1"); err != nil { + t.Fatalf("write pretty field: %v", err) + } + part, err := mw.CreateFormFile("file", "test.txt") + if err != nil { + t.Fatalf("create form file: %v", err) + } + if _, err := part.Write([]byte("hello")); err != nil { + t.Fatalf("write form file: %v", err) + } + if err := mw.Close(); err != nil { + t.Fatalf("close multipart writer: %v", err) + } + + body := &countingReadCloser{Reader: bytes.NewReader(form.Bytes())} + r := httptest.NewRequest(http.MethodPost, "/x", body) + r.Header.Set("Content-Type", mw.FormDataContentType()) + w := httptest.NewRecorder() + + if err := writeJson(w, r, http.StatusTooManyRequests, map[string]string{"error": "busy"}); err != nil { + t.Fatalf("writeJson: %v", err) + } + + if body.reads != 0 { + t.Fatalf("writeJson read multipart body %d times", body.reads) + } + if got, want := w.Body.String(), `{"error":"busy"}`; got != want { + t.Fatalf("body: got %q want %q", got, want) + } +} + +type countingReadCloser struct { + io.Reader + reads int +} + +func (c *countingReadCloser) Read(p []byte) (int, error) { + c.reads++ + return c.Reader.Read(p) +} + +func (c *countingReadCloser) Close() error { + return nil +}