|
|
@ -369,7 +369,6 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req |
|
|
|
objInfo.UserDefined = objectlock.FilterObjectLockMetadata(objInfo.UserDefined, getRetPerms != ErrNone, legalHoldPerms != ErrNone) |
|
|
|
objInfo.UserDefined = objectlock.FilterObjectLockMetadata(objInfo.UserDefined, getRetPerms != ErrNone, legalHoldPerms != ErrNone) |
|
|
|
|
|
|
|
|
|
|
|
if objectAPI.IsEncryptionSupported() { |
|
|
|
if objectAPI.IsEncryptionSupported() { |
|
|
|
objInfo.UserDefined = CleanMinioInternalMetadataKeys(objInfo.UserDefined) |
|
|
|
|
|
|
|
if _, err = DecryptObjectInfo(&objInfo, r.Header); err != nil { |
|
|
|
if _, err = DecryptObjectInfo(&objInfo, r.Header); err != nil { |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
@ -545,7 +544,6 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re |
|
|
|
writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) |
|
|
|
writeErrorResponseHeadersOnly(w, toAPIError(ctx, err)) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
objInfo.UserDefined = CleanMinioInternalMetadataKeys(objInfo.UserDefined) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Set encryption response headers
|
|
|
|
// Set encryption response headers
|
|
|
@ -1820,8 +1818,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Read compression metadata preserved in the init multipart for the decision.
|
|
|
|
// Read compression metadata preserved in the init multipart for the decision.
|
|
|
|
_, compressPart := li.UserDefined[ReservedMetadataPrefix+"compression"] |
|
|
|
_, isCompressed := li.UserDefined[ReservedMetadataPrefix+"compression"] |
|
|
|
isCompressed := compressPart |
|
|
|
|
|
|
|
// Compress only if the compression is enabled during initial multipart.
|
|
|
|
// Compress only if the compression is enabled during initial multipart.
|
|
|
|
if isCompressed { |
|
|
|
if isCompressed { |
|
|
|
s2c := newS2CompressReader(gr) |
|
|
|
s2c := newS2CompressReader(gr) |
|
|
@ -1838,24 +1835,18 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
rawReader := srcInfo.Reader |
|
|
|
|
|
|
|
pReader := NewPutObjReader(rawReader, nil, nil) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isEncrypted := false |
|
|
|
|
|
|
|
var objectEncryptionKey crypto.ObjectKey |
|
|
|
|
|
|
|
if objectAPI.IsEncryptionSupported() && !isCompressed { |
|
|
|
|
|
|
|
li, lerr := objectAPI.ListObjectParts(ctx, dstBucket, dstObject, uploadID, 0, 1, dstOpts) |
|
|
|
|
|
|
|
if lerr != nil { |
|
|
|
|
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, lerr), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
li.UserDefined = CleanMinioInternalMetadataKeys(li.UserDefined) |
|
|
|
|
|
|
|
dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, li.UserDefined) |
|
|
|
dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, li.UserDefined) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
if crypto.IsEncrypted(li.UserDefined) { |
|
|
|
|
|
|
|
|
|
|
|
rawReader := srcInfo.Reader |
|
|
|
|
|
|
|
pReader := NewPutObjReader(rawReader, nil, nil) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isEncrypted := crypto.IsEncrypted(li.UserDefined) |
|
|
|
|
|
|
|
var objectEncryptionKey crypto.ObjectKey |
|
|
|
|
|
|
|
if objectAPI.IsEncryptionSupported() && !isCompressed && isEncrypted { |
|
|
|
if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) { |
|
|
|
if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) { |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
@ -1864,7 +1855,6 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
isEncrypted = true |
|
|
|
|
|
|
|
var key []byte |
|
|
|
var key []byte |
|
|
|
if crypto.SSEC.IsRequested(r.Header) { |
|
|
|
if crypto.SSEC.IsRequested(r.Header) { |
|
|
|
key, err = ParseSSECustomerRequest(r) |
|
|
|
key, err = ParseSSECustomerRequest(r) |
|
|
@ -1895,7 +1885,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt |
|
|
|
} |
|
|
|
} |
|
|
|
pReader = NewPutObjReader(rawReader, srcInfo.Reader, &objectEncryptionKey) |
|
|
|
pReader = NewPutObjReader(rawReader, srcInfo.Reader, &objectEncryptionKey) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
srcInfo.PutObjReader = pReader |
|
|
|
srcInfo.PutObjReader = pReader |
|
|
|
// Copy source object to destination, if source and destination
|
|
|
|
// Copy source object to destination, if source and destination
|
|
|
|
// object is same then only metadata is updated.
|
|
|
|
// object is same then only metadata is updated.
|
|
|
@ -2062,11 +2052,11 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Read compression metadata preserved in the init multipart for the decision.
|
|
|
|
// Read compression metadata preserved in the init multipart for the decision.
|
|
|
|
_, compressPart := li.UserDefined[ReservedMetadataPrefix+"compression"] |
|
|
|
_, isCompressed := li.UserDefined[ReservedMetadataPrefix+"compression"] |
|
|
|
|
|
|
|
|
|
|
|
isCompressed := false |
|
|
|
if objectAPI.IsCompressionSupported() && isCompressed { |
|
|
|
if objectAPI.IsCompressionSupported() && compressPart { |
|
|
|
|
|
|
|
actualReader, err := hash.NewReader(reader, size, md5hex, sha256hex, actualSize, globalCLIContext.StrictS3Compat) |
|
|
|
actualReader, err := hash.NewReader(reader, size, md5hex, sha256hex, actualSize, globalCLIContext.StrictS3Compat) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
@ -2080,7 +2070,6 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
size = -1 // Since compressed size is un-predictable.
|
|
|
|
size = -1 // Since compressed size is un-predictable.
|
|
|
|
md5hex = "" // Do not try to verify the content.
|
|
|
|
md5hex = "" // Do not try to verify the content.
|
|
|
|
sha256hex = "" |
|
|
|
sha256hex = "" |
|
|
|
isCompressed = true |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
hashReader, err := hash.NewReader(reader, size, md5hex, sha256hex, actualSize, globalCLIContext.StrictS3Compat) |
|
|
|
hashReader, err := hash.NewReader(reader, size, md5hex, sha256hex, actualSize, globalCLIContext.StrictS3Compat) |
|
|
@ -2091,23 +2080,14 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
rawReader := hashReader |
|
|
|
rawReader := hashReader |
|
|
|
pReader := NewPutObjReader(rawReader, nil, nil) |
|
|
|
pReader := NewPutObjReader(rawReader, nil, nil) |
|
|
|
|
|
|
|
|
|
|
|
isEncrypted := false |
|
|
|
isEncrypted := crypto.IsEncrypted(li.UserDefined) |
|
|
|
var objectEncryptionKey crypto.ObjectKey |
|
|
|
var objectEncryptionKey crypto.ObjectKey |
|
|
|
if objectAPI.IsEncryptionSupported() && !isCompressed { |
|
|
|
if objectAPI.IsEncryptionSupported() && !isCompressed && isEncrypted { |
|
|
|
var li ListPartsInfo |
|
|
|
|
|
|
|
li, err = objectAPI.ListObjectParts(ctx, bucket, object, uploadID, 0, 1, ObjectOptions{}) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
li.UserDefined = CleanMinioInternalMetadataKeys(li.UserDefined) |
|
|
|
|
|
|
|
if crypto.IsEncrypted(li.UserDefined) { |
|
|
|
|
|
|
|
if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) { |
|
|
|
if !crypto.SSEC.IsRequested(r.Header) && crypto.SSEC.IsEncrypted(li.UserDefined) { |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrSSEMultipartEncrypted), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
isEncrypted = true // to detect SSE-S3 encryption
|
|
|
|
|
|
|
|
opts, err = putOpts(ctx, r, bucket, object, li.UserDefined) |
|
|
|
opts, err = putOpts(ctx, r, bucket, object, li.UserDefined) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
@ -2152,7 +2132,6 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http |
|
|
|
} |
|
|
|
} |
|
|
|
pReader = NewPutObjReader(rawReader, hashReader, &objectEncryptionKey) |
|
|
|
pReader = NewPutObjReader(rawReader, hashReader, &objectEncryptionKey) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
putObjectPart := objectAPI.PutObjectPart |
|
|
|
putObjectPart := objectAPI.PutObjectPart |
|
|
|
|
|
|
|
|
|
|
@ -2249,29 +2228,24 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidMaxParts), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidMaxParts), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var opts ObjectOptions |
|
|
|
var opts ObjectOptions |
|
|
|
listPartsInfo, err := objectAPI.ListObjectParts(ctx, bucket, object, uploadID, partNumberMarker, maxParts, opts) |
|
|
|
listPartsInfo, err := objectAPI.ListObjectParts(ctx, bucket, object, uploadID, partNumberMarker, maxParts, opts) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var ssec bool |
|
|
|
var ssec bool |
|
|
|
if objectAPI.IsEncryptionSupported() { |
|
|
|
if objectAPI.IsEncryptionSupported() && crypto.IsEncrypted(listPartsInfo.UserDefined) { |
|
|
|
var li ListPartsInfo |
|
|
|
|
|
|
|
li, err = objectAPI.ListObjectParts(ctx, bucket, object, uploadID, 0, 1, opts) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if crypto.IsEncrypted(li.UserDefined) { |
|
|
|
|
|
|
|
var key []byte |
|
|
|
var key []byte |
|
|
|
if crypto.SSEC.IsEncrypted(li.UserDefined) { |
|
|
|
if crypto.SSEC.IsEncrypted(listPartsInfo.UserDefined) { |
|
|
|
ssec = true |
|
|
|
ssec = true |
|
|
|
} |
|
|
|
} |
|
|
|
var objectEncryptionKey []byte |
|
|
|
var objectEncryptionKey []byte |
|
|
|
if crypto.S3.IsEncrypted(li.UserDefined) { |
|
|
|
if crypto.S3.IsEncrypted(listPartsInfo.UserDefined) { |
|
|
|
// Calculating object encryption key
|
|
|
|
// Calculating object encryption key
|
|
|
|
objectEncryptionKey, err = decryptObjectInfo(key, bucket, object, li.UserDefined) |
|
|
|
objectEncryptionKey, err = decryptObjectInfo(key, bucket, object, listPartsInfo.UserDefined) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL, guessIsBrowserReq(r)) |
|
|
|
return |
|
|
|
return |
|
|
@ -2285,7 +2259,6 @@ func (api objectAPIHandlers) ListObjectPartsHandler(w http.ResponseWriter, r *ht |
|
|
|
} |
|
|
|
} |
|
|
|
listPartsInfo.Parts = parts |
|
|
|
listPartsInfo.Parts = parts |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
response := generateListPartsResponse(listPartsInfo, encodingType) |
|
|
|
response := generateListPartsResponse(listPartsInfo, encodingType) |
|
|
|
encodedSuccessResponse := encodeResponse(response) |
|
|
|
encodedSuccessResponse := encodeResponse(response) |
|
|
|