|
|
|
@ -51,6 +51,14 @@ func setGetRespHeaders(w http.ResponseWriter, reqParams url.Values) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// http Header "x-amz-content-sha256" == "UNSIGNED-PAYLOAD" indicates that the
|
|
|
|
|
// client did not calculate sha256 of the payload. Hence we skip calculating sha256.
|
|
|
|
|
// We also skip calculating sha256 for presigned requests without "x-amz-content-sha256" header.
|
|
|
|
|
func skipSHA256Calculation(r *http.Request) bool { |
|
|
|
|
shaHeader := r.Header.Get("X-Amz-Content-Sha256") |
|
|
|
|
return isRequestUnsignedPayload(r) || (isRequestPresignedSignatureV4(r) && shaHeader == "") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// errAllowableNotFound - For an anon user, return 404 if have ListBucket, 403 otherwise
|
|
|
|
|
// this is in keeping with the permissions sections of the docs of both:
|
|
|
|
|
// HEAD Object: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectHEAD.html
|
|
|
|
@ -594,6 +602,28 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req |
|
|
|
|
// Create anonymous object.
|
|
|
|
|
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, r.Body, metadata) |
|
|
|
|
case authTypePresigned, authTypeSigned: |
|
|
|
|
validateRegion := true // Validate region.
|
|
|
|
|
|
|
|
|
|
if skipSHA256Calculation(r) { |
|
|
|
|
// Either sha256-header is "UNSIGNED-PAYLOAD" or this is a presigned PUT
|
|
|
|
|
// request without sha256-header.
|
|
|
|
|
var s3Error APIErrorCode |
|
|
|
|
if isRequestSignatureV4(r) { |
|
|
|
|
s3Error = doesSignatureMatch(unsignedPayload, r, validateRegion) |
|
|
|
|
} else if isRequestPresignedSignatureV4(r) { |
|
|
|
|
s3Error = doesPresignedSignatureMatch(unsignedPayload, r, validateRegion) |
|
|
|
|
} |
|
|
|
|
if s3Error != ErrNone { |
|
|
|
|
if s3Error == ErrSignatureDoesNotMatch { |
|
|
|
|
err = errSignatureMismatch |
|
|
|
|
} else { |
|
|
|
|
err = fmt.Errorf("%v", getAPIError(s3Error)) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
md5Sum, err = api.ObjectAPI.PutObject(bucket, object, size, r.Body, metadata) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Sha256 of payload has to be calculated and matched with what was sent in the header.
|
|
|
|
|
// Initialize a pipe for data pipe line.
|
|
|
|
|
reader, writer := io.Pipe() |
|
|
|
|
var wg = &sync.WaitGroup{} |
|
|
|
@ -613,7 +643,6 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
shaPayload := shaWriter.Sum(nil) |
|
|
|
|
validateRegion := true // Validate region.
|
|
|
|
|
var s3Error APIErrorCode |
|
|
|
|
if isRequestSignatureV4(r) { |
|
|
|
|
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion) |
|
|
|
@ -640,6 +669,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req |
|
|
|
|
// Wait for all the routines to finish.
|
|
|
|
|
wg.Wait() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if err != nil { |
|
|
|
|
errorIf(err, "Unable to create an object.") |
|
|
|
|
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path) |
|
|
|
@ -765,6 +795,28 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
|
hexMD5 := hex.EncodeToString(md5Bytes) |
|
|
|
|
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, hexMD5) |
|
|
|
|
case authTypePresigned, authTypeSigned: |
|
|
|
|
validateRegion := true // Validate region.
|
|
|
|
|
|
|
|
|
|
if skipSHA256Calculation(r) { |
|
|
|
|
// Either sha256-header is "UNSIGNED-PAYLOAD" or this is a presigned
|
|
|
|
|
// request without sha256-header.
|
|
|
|
|
var s3Error APIErrorCode |
|
|
|
|
if isRequestSignatureV4(r) { |
|
|
|
|
s3Error = doesSignatureMatch(unsignedPayload, r, validateRegion) |
|
|
|
|
} else if isRequestPresignedSignatureV4(r) { |
|
|
|
|
s3Error = doesPresignedSignatureMatch(unsignedPayload, r, validateRegion) |
|
|
|
|
} |
|
|
|
|
if s3Error != ErrNone { |
|
|
|
|
if s3Error == ErrSignatureDoesNotMatch { |
|
|
|
|
err = errSignatureMismatch |
|
|
|
|
} else { |
|
|
|
|
err = fmt.Errorf("%v", getAPIError(s3Error)) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
md5SumHex := hex.EncodeToString(md5Bytes) |
|
|
|
|
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, r.Body, md5SumHex) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Initialize a pipe for data pipe line.
|
|
|
|
|
reader, writer := io.Pipe() |
|
|
|
|
var wg = &sync.WaitGroup{} |
|
|
|
@ -784,7 +836,6 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
shaPayload := shaWriter.Sum(nil) |
|
|
|
|
validateRegion := true // Validate region.
|
|
|
|
|
var s3Error APIErrorCode |
|
|
|
|
if isRequestSignatureV4(r) { |
|
|
|
|
s3Error = doesSignatureMatch(hex.EncodeToString(shaPayload), r, validateRegion) |
|
|
|
@ -810,6 +861,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
|
// Wait for all the routines to finish.
|
|
|
|
|
wg.Wait() |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if err != nil { |
|
|
|
|
errorIf(err, "Unable to create object part.") |
|
|
|
|
// Verify if the underlying error is signature mismatch.
|
|
|
|
|