Files
seaweedfs/weed/server/common_test.go
T
qzhello fb168e2a36 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
2026-06-23 20:20:11 -07:00

115 lines
3.0 KiB
Go

package weed_server
import (
"bytes"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestParseURL(t *testing.T) {
if vid, fid, _, _, _ := parseURLPath("/1,06dfa8a684"); true {
if vid != "1" {
t.Errorf("fail to parse vid: %s", vid)
}
if fid != "06dfa8a684" {
t.Errorf("fail to parse fid: %s", fid)
}
}
if vid, fid, _, _, _ := parseURLPath("/1,06dfa8a684_1"); true {
if vid != "1" {
t.Errorf("fail to parse vid: %s", vid)
}
if fid != "06dfa8a684_1" {
t.Errorf("fail to parse fid: %s", fid)
}
if sepIndex := strings.LastIndex(fid, "_"); sepIndex > 0 {
fid = fid[:sepIndex]
}
if fid != "06dfa8a684" {
t.Errorf("fail to parse fid: %s", fid)
}
}
}
func TestWriteJsonNoJSONP(t *testing.T) {
// callback= must be ignored; response is always application/json with nosniff.
cases := []string{"", "myCb", "<script>alert(1)</script>"}
for _, cb := range cases {
t.Run("callback="+cb, func(t *testing.T) {
url := "/x"
if cb != "" {
url += "?callback=" + cb
}
r := httptest.NewRequest(http.MethodGet, url, nil)
w := httptest.NewRecorder()
if err := writeJson(w, r, http.StatusOK, map[string]string{"k": "v"}); err != nil {
t.Fatalf("writeJson: %v", err)
}
if w.Code != http.StatusOK {
t.Errorf("status: got %d want 200", w.Code)
}
if got := w.Header().Get("Content-Type"); got != "application/json" {
t.Errorf("Content-Type: got %q want application/json", got)
}
if got := w.Header().Get("X-Content-Type-Options"); got != "nosniff" {
t.Errorf("X-Content-Type-Options: got %q want nosniff", got)
}
if got := w.Body.String(); got != `{"k":"v"}` {
t.Errorf("body: got %q want %q", got, `{"k":"v"}`)
}
})
}
}
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
}