From df7054759e93045301ef043ed426223ec623ef61 Mon Sep 17 00:00:00 2001 From: Mingluan Mu Date: Wed, 30 Sep 2026 18:32:11 +0800 Subject: [PATCH 1/2] fix(s3): sign content type for direct uploads - Include the inferred MIME type in presigned PutObject requests - Return the signed Content-Type header for frontend uploads Co-authored-by: Codex <267193182+codex@users.noreply.github.com> --- drivers/s3/driver.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/s3/driver.go b/drivers/s3/driver.go index 711f46ab5e..4876eb7562 100644 --- a/drivers/s3/driver.go +++ b/drivers/s3/driver.go @@ -229,9 +229,11 @@ func (d *S3) GetDirectUploadInfo(ctx context.Context, _ string, dstDir model.Obj return nil, errs.NotImplement } path := getKey(stdpath.Join(dstDir.GetPath(), fileName), false) + contentType := utils.GetMimeType(fileName) req, _ := d.directUploadClient.PutObjectRequest(&s3.PutObjectInput{ - Bucket: &d.Bucket, - Key: &path, + Bucket: &d.Bucket, + Key: &path, + ContentType: &contentType, }) if req == nil { return nil, fmt.Errorf("failed to create PutObject request") @@ -243,6 +245,7 @@ func (d *S3) GetDirectUploadInfo(ctx context.Context, _ string, dstDir model.Obj return &model.HttpDirectUploadInfo{ UploadURL: link, Method: "PUT", + Headers: map[string]string{"Content-Type": contentType}, }, nil } From 21aa31904e2dfd6e0b3217ec843c5f162bc9694d Mon Sep 17 00:00:00 2001 From: Mingluan Mu Date: Sun, 4 Oct 2026 12:55:45 +0800 Subject: [PATCH 2/2] fix(drivers/s3): use client content type for direct uploads - Accept and validate the client-provided direct upload media type - Pass the type to the S3 signer through a typed context key - Default missing types to application/octet-stream Co-authored-by: Codex <267193182+codex@users.noreply.github.com> --- drivers/s3/driver.go | 6 +++++- internal/conf/const.go | 1 + server/handles/direct_upload.go | 20 +++++++++++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/s3/driver.go b/drivers/s3/driver.go index 4876eb7562..253d3c0a38 100644 --- a/drivers/s3/driver.go +++ b/drivers/s3/driver.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/OpenListTeam/OpenList/v4/internal/conf" "github.com/OpenListTeam/OpenList/v4/internal/driver" "github.com/OpenListTeam/OpenList/v4/internal/errs" "github.com/OpenListTeam/OpenList/v4/internal/model" @@ -229,7 +230,10 @@ func (d *S3) GetDirectUploadInfo(ctx context.Context, _ string, dstDir model.Obj return nil, errs.NotImplement } path := getKey(stdpath.Join(dstDir.GetPath(), fileName), false) - contentType := utils.GetMimeType(fileName) + contentType, _ := ctx.Value(conf.DirectUploadContentTypeKey).(string) + if contentType == "" { + contentType = "application/octet-stream" + } req, _ := d.directUploadClient.PutObjectRequest(&s3.PutObjectInput{ Bucket: &d.Bucket, Key: &path, diff --git a/internal/conf/const.go b/internal/conf/const.go index 2193d3d9d3..9a0f11a449 100644 --- a/internal/conf/const.go +++ b/internal/conf/const.go @@ -197,4 +197,5 @@ const ( PathKey SharingIDKey SkipHookKey + DirectUploadContentTypeKey ) diff --git a/server/handles/direct_upload.go b/server/handles/direct_upload.go index b016f028c2..221b1afa45 100644 --- a/server/handles/direct_upload.go +++ b/server/handles/direct_upload.go @@ -1,6 +1,8 @@ package handles import ( + "context" + "mime" "net/url" stdpath "path" @@ -15,10 +17,11 @@ import ( ) type FsGetDirectUploadInfoReq struct { - Path string `json:"path" form:"path"` - FileName string `json:"file_name" form:"file_name"` - FileSize int64 `json:"file_size" form:"file_size"` - Tool string `json:"tool" form:"tool"` + Path string `json:"path" form:"path"` + FileName string `json:"file_name" form:"file_name"` + FileSize int64 `json:"file_size" form:"file_size"` + ContentType string `json:"content_type" form:"content_type"` + Tool string `json:"tool" form:"tool"` } // FsGetDirectUploadInfo returns the direct upload info if supported by the driver @@ -91,7 +94,14 @@ func FsGetDirectUploadInfo(c *gin.Context) { return } } - directUploadInfo, err := fs.GetDirectUploadInfo(c, req.Tool, path, req.FileName, req.FileSize, overwrite) + if req.ContentType != "" { + if _, _, err := mime.ParseMediaType(req.ContentType); err != nil { + common.ErrorResp(c, err, 400) + return + } + } + ctx := context.WithValue(c, conf.DirectUploadContentTypeKey, req.ContentType) + directUploadInfo, err := fs.GetDirectUploadInfo(ctx, req.Tool, path, req.FileName, req.FileSize, overwrite) if err != nil { if !overwrite && errs.IsObjectAlreadyExists(err) { common.ErrorStrResp(c, "file exists", 403)