mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-17 04:36:50 +00:00
* s3: accept raw semicolons in query strings Go's url.ParseQuery drops any key=value pair containing a raw ';'. A presigned PUT that signs content-type carries X-Amz-SignedHeaders=content-type%3Bhost; when a client or proxy decodes the %3B, the parameter vanished and the upload failed with MissingFields, while AWS accepts the raw ';' as query data. Re-encode it before routing so the pair survives parsing and signature verification. * iam, iceberg: recover raw-semicolon query pairs on the other listeners The standalone IAM API verifies SigV4 with a canonical query recomputed from the parsed query, and Iceberg REST warehouse/parent values may legally contain ';'. Move the normalization middleware to util/http and attach it to both routers.
46 lines
1.6 KiB
Go
46 lines
1.6 KiB
Go
package s3api
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
|
util_http "github.com/seaweedfs/seaweedfs/weed/util/http"
|
|
)
|
|
|
|
// A presigned URL that signs content-type carries
|
|
// X-Amz-SignedHeaders=content-type%3Bhost. Some clients and proxies decode
|
|
// the %3B into a raw ';', which RFC 3986 permits in a query string and AWS
|
|
// accepts, but Go's url.ParseQuery drops the whole pair — verification then
|
|
// fails with MissingFields. The router middleware re-encodes the ';' so the
|
|
// parameter survives.
|
|
func TestPresignedPutSignedContentTypeWithRawSemicolon(t *testing.T) {
|
|
iam := newTestIAM()
|
|
|
|
req, err := newTestRequest(http.MethodPut, "http://127.0.0.1:9000/bucket/key.png", 0, nil)
|
|
if err != nil {
|
|
t.Fatalf("newTestRequest: %v", err)
|
|
}
|
|
req.Header.Set("Content-Type", "image/png")
|
|
if err := preSignV4WithHeaders(iam, req, "AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", 600, []string{"host", "content-type"}); err != nil {
|
|
t.Fatalf("preSignV4WithHeaders: %v", err)
|
|
}
|
|
req.URL.RawQuery = strings.ReplaceAll(req.URL.RawQuery, "%3B", ";")
|
|
|
|
if _, errCode := iam.reqSignatureV4Verify(req); errCode == s3err.ErrNone {
|
|
t.Fatal("raw-semicolon query unexpectedly verified without normalization")
|
|
}
|
|
|
|
errCode := s3err.ErrInternalError
|
|
handler := util_http.EscapeSemicolonsInQuery(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
_, errCode = iam.reqSignatureV4Verify(r)
|
|
}))
|
|
handler.ServeHTTP(httptest.NewRecorder(), req)
|
|
|
|
if errCode != s3err.ErrNone {
|
|
t.Fatalf("expected ErrNone through semicolon-normalizing middleware, got %v", errCode)
|
|
}
|
|
}
|