diff --git a/s3api/controllers/object-put.go b/s3api/controllers/object-put.go index 785e776..2b76fe4 100644 --- a/s3api/controllers/object-put.go +++ b/s3api/controllers/object-put.go @@ -354,6 +354,15 @@ func (c S3ApiController) UploadPartCopy(ctx *fiber.Ctx) (*Response, error) { }, err } + if len(ctx.Request().Body()) != 0 { + debuglogger.Logf("expected empty request body") + return &Response{ + MetaOpts: &MetaOptions{ + BucketOwner: parsedAcl.Owner, + }, + }, s3err.GetAPIError(s3err.ErrNonEmptyRequestBody) + } + if partNumber < minPartNumber || partNumber > maxPartNumber { debuglogger.Logf("invalid part number: %d", partNumber) return &Response{ @@ -490,6 +499,15 @@ func (c S3ApiController) CopyObject(ctx *fiber.Ctx) (*Response, error) { }, err } + if len(ctx.Request().Body()) != 0 { + debuglogger.Logf("expected empty request body") + return &Response{ + MetaOpts: &MetaOptions{ + BucketOwner: parsedAcl.Owner, + }, + }, s3err.GetAPIError(s3err.ErrNonEmptyRequestBody) + } + metadata := utils.GetUserMetaData(&ctx.Request().Header) if metaDirective != "" && metaDirective != types.MetadataDirectiveCopy && metaDirective != types.MetadataDirectiveReplace { diff --git a/s3api/controllers/object-put_test.go b/s3api/controllers/object-put_test.go index 6cdf7ee..95c7bfa 100644 --- a/s3api/controllers/object-put_test.go +++ b/s3api/controllers/object-put_test.go @@ -599,6 +599,27 @@ func TestS3ApiController_UploadPartCopy(t *testing.T) { err: s3err.GetAPIError(s3err.ErrInvalidCopySourceEncoding), }, }, + { + name: "non empty request body", + input: testInput{ + locals: defaultLocals, + headers: map[string]string{ + "X-Amz-Copy-Source": "bucket/object", + }, + queries: map[string]string{ + "partNumber": "2", + }, + body: []byte("body"), + }, + output: testOutput{ + response: &Response{ + MetaOpts: &MetaOptions{ + BucketOwner: "root", + }, + }, + err: s3err.GetAPIError(s3err.ErrNonEmptyRequestBody), + }, + }, { name: "invalid part number", input: testInput{ @@ -696,6 +717,7 @@ func TestS3ApiController_UploadPartCopy(t *testing.T) { locals: tt.input.locals, headers: tt.input.headers, queries: tt.input.queries, + body: tt.input.body, }) }) } @@ -817,6 +839,24 @@ func TestS3ApiController_CopyObject(t *testing.T) { err: s3err.GetAPIError(s3err.ErrInvalidCopySourceBucket), }, }, + { + name: "invalid copy source", + input: testInput{ + locals: defaultLocals, + headers: map[string]string{ + "X-Amz-Copy-Source": "bucket/object", + }, + body: []byte("body"), + }, + output: testOutput{ + response: &Response{ + MetaOpts: &MetaOptions{ + BucketOwner: "root", + }, + }, + err: s3err.GetAPIError(s3err.ErrNonEmptyRequestBody), + }, + }, { name: "invalid metadata directive", input: testInput{ @@ -999,6 +1039,7 @@ func TestS3ApiController_CopyObject(t *testing.T) { ctxInputs{ locals: tt.input.locals, headers: tt.input.headers, + body: tt.input.body, }) }) } diff --git a/s3err/s3err.go b/s3err/s3err.go index a2b1674..41898f6 100644 --- a/s3err/s3err.go +++ b/s3err/s3err.go @@ -87,6 +87,7 @@ const ( ErrInvalidPartOrder ErrInvalidCompleteMpPartNumber ErrInternalError + ErrNonEmptyRequestBody ErrInvalidCopyDest ErrInvalidCopySourceRange ErrInvalidCopySourceBucket @@ -319,6 +320,11 @@ var errorCodeResponse = map[ErrorCode]APIError{ Description: "We encountered an internal error, please try again.", HTTPStatusCode: http.StatusInternalServerError, }, + ErrNonEmptyRequestBody: { + Code: "InvalidRequest", + Description: "The request included a body. Requests of this type must not include a non-empty body.", + HTTPStatusCode: http.StatusBadRequest, + }, ErrInvalidPart: { Code: "InvalidPart", Description: "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag.",