diff --git a/weed/s3api/s3api_object_handlers.go b/weed/s3api/s3api_object_handlers.go index 610daef9f..ca02e1d1c 100644 --- a/weed/s3api/s3api_object_handlers.go +++ b/weed/s3api/s3api_object_handlers.go @@ -40,7 +40,7 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request) bucket, object := getBucketAndObject(r) - _, err := validateContentMd5(r.Header) + contentMd5, err := validateContentMd5(r.Header) if err != nil { writeErrorResponse(w, s3err.ErrInvalidDigest, r.URL) return @@ -81,6 +81,11 @@ func (s3a *S3ApiServer) PutObjectHandler(w http.ResponseWriter, r *http.Request) } setEtag(w, etag) + + if len(contentMd5) != 0 && fmt.Sprintf("%x", contentMd5) != etag { + writeErrorResponse(w, s3err.ErrBadDigest, r.URL) + return + } } writeSuccessResponseEmpty(w) diff --git a/weed/s3api/s3api_object_multipart_handlers.go b/weed/s3api/s3api_object_multipart_handlers.go index 4ddb24e31..6900eebc8 100644 --- a/weed/s3api/s3api_object_multipart_handlers.go +++ b/weed/s3api/s3api_object_multipart_handlers.go @@ -182,6 +182,13 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ return } + // get Content-Md5 sent by client and verify if valid + contentMd5, err := validateContentMd5(r.Header) + if err != nil { + writeErrorResponse(w, s3err.ErrInvalidDigest, r.URL) + return + } + dataReader := r.Body if s3a.iam.isEnabled() { rAuthType := getRequestAuthType(r) @@ -213,6 +220,11 @@ func (s3a *S3ApiServer) PutObjectPartHandler(w http.ResponseWriter, r *http.Requ setEtag(w, etag) + if len(contentMd5) != 0 && fmt.Sprintf("%x", contentMd5) != etag { + writeErrorResponse(w, s3err.ErrBadDigest, r.URL) + return + } + writeSuccessResponseEmpty(w) } diff --git a/weed/s3api/s3err/s3api_errors.go b/weed/s3api/s3err/s3api_errors.go index a3f7bb25e..5f8064936 100644 --- a/weed/s3api/s3err/s3api_errors.go +++ b/weed/s3api/s3err/s3api_errors.go @@ -45,6 +45,7 @@ const ( ErrNone ErrorCode = iota ErrAccessDenied ErrMethodNotAllowed + ErrBadDigest ErrBucketNotEmpty ErrBucketAlreadyExists ErrBucketAlreadyOwnedByYou @@ -109,6 +110,11 @@ var errorCodeResponse = map[ErrorCode]APIError{ Description: "The specified method is not allowed against this resource.", HTTPStatusCode: http.StatusMethodNotAllowed, }, + ErrBadDigest: { + Code: "BadDigest", + Description: "The Content-Md5 you specified did not match what we received.", + HTTPStatusCode: http.StatusBadRequest, + }, ErrBucketNotEmpty: { Code: "BucketNotEmpty", Description: "The bucket you tried to delete is not empty",