From f07ba2c5aabfb41fd52b54b04e44a57d2495d907 Mon Sep 17 00:00:00 2001 From: "steve.wei" Date: Sat, 27 Dec 2025 05:15:17 +0800 Subject: [PATCH] fix: support standard HTTP headers in S3 multipart upload (#7884) Co-authored-by: Chris Lu --- weed/s3api/s3_metadata_util.go | 19 +++++++++++++++++++ weed/s3api/s3api_object_handlers_multipart.go | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/weed/s3api/s3_metadata_util.go b/weed/s3api/s3_metadata_util.go index 37363752a..b11ce147a 100644 --- a/weed/s3api/s3_metadata_util.go +++ b/weed/s3api/s3_metadata_util.go @@ -34,6 +34,25 @@ func ParseS3Metadata(r *http.Request, existing map[string][]byte, isReplace bool metadata["Content-Encoding"] = []byte(ce) } + // Other Standard HTTP headers defined in https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html + standardHeaders := []string{ + "Cache-Control", + "Content-Disposition", + "Content-Language", + "Expires", + } + for _, header := range standardHeaders { + if value := r.Header.Get(header); value != "" { + metadata[header] = []byte(value) + } + } + + // Handle Response-Content-Disposition (used in presigned URLs) + // This should be stored as Content-Disposition + if rcd := r.Header.Get("Response-Content-Disposition"); rcd != "" { + metadata["Content-Disposition"] = []byte(rcd) + } + // Object tagging if tags := r.Header.Get(s3_constants.AmzObjectTagging); tags != "" { // Use url.ParseQuery for robust parsing and automatic URL decoding diff --git a/weed/s3api/s3api_object_handlers_multipart.go b/weed/s3api/s3api_object_handlers_multipart.go index becbd9bf9..7fcebef38 100644 --- a/weed/s3api/s3api_object_handlers_multipart.go +++ b/weed/s3api/s3api_object_handlers_multipart.go @@ -12,10 +12,12 @@ import ( "net/url" "strconv" "strings" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/s3" "github.com/google/uuid" + "github.com/pquerna/cachecontrol/cacheobject" "github.com/seaweedfs/seaweedfs/weed/glog" "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants" @@ -64,6 +66,22 @@ func (s3a *S3ApiServer) NewMultipartUploadHandler(w http.ResponseWriter, r *http return } + // Validate Cache-Control header format if present + if r.Header.Get("Cache-Control") != "" { + if _, err := cacheobject.ParseRequestCacheControl(r.Header.Get("Cache-Control")); err != nil { + s3err.WriteErrorResponse(w, r, s3err.ErrInvalidDigest) + return + } + } + + // Validate Expires header format if present + if r.Header.Get("Expires") != "" { + if _, err := time.Parse(http.TimeFormat, r.Header.Get("Expires")); err != nil { + s3err.WriteErrorResponse(w, r, s3err.ErrMalformedDate) + return + } + } + createMultipartUploadInput := &s3.CreateMultipartUploadInput{ Bucket: aws.String(bucket), Key: objectKey(aws.String(object)),