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) } }