mirror of
https://github.com/minio/minio.git
synced 2025-04-10 06:30:07 -04:00
fix: perform CopyObject under more conditions (#9879)
- x-amz-storage-class specified CopyObject should proceed regardless, its not a precondition - sourceVersionID is specified CopyObject should proceed regardless, its not a precondition
This commit is contained in:
parent
53f0cc1340
commit
67062840c1
@ -768,9 +768,6 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
// Note that url.Parse does the unescaping
|
// Note that url.Parse does the unescaping
|
||||||
cpSrcPath = u.Path
|
cpSrcPath = u.Path
|
||||||
}
|
}
|
||||||
if vid == "" {
|
|
||||||
vid = strings.TrimSpace(r.Header.Get(xhttp.AmzCopySourceVersionID))
|
|
||||||
}
|
|
||||||
|
|
||||||
srcBucket, srcObject := path2BucketObject(cpSrcPath)
|
srcBucket, srcObject := path2BucketObject(cpSrcPath)
|
||||||
// If source object is empty or bucket is empty, reply back invalid copy source.
|
// If source object is empty or bucket is empty, reply back invalid copy source.
|
||||||
@ -884,11 +881,8 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
|
|
||||||
var chStorageClass bool
|
var chStorageClass bool
|
||||||
if dstSc != "" {
|
if dstSc != "" {
|
||||||
sc, ok := srcInfo.UserDefined[xhttp.AmzStorageClass]
|
chStorageClass = true
|
||||||
if (ok && dstSc != sc) || (srcInfo.StorageClass != dstSc) {
|
srcInfo.metadataOnly = false
|
||||||
chStorageClass = true
|
|
||||||
srcInfo.metadataOnly = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var reader io.Reader
|
var reader io.Reader
|
||||||
@ -1121,7 +1115,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
// if encryption is enabled we do not need explicit "REPLACE" metadata to
|
// if encryption is enabled we do not need explicit "REPLACE" metadata to
|
||||||
// be enabled as well - this is to allow for key-rotation.
|
// be enabled as well - this is to allow for key-rotation.
|
||||||
if !isDirectiveReplace(r.Header.Get(xhttp.AmzMetadataDirective)) && !isDirectiveReplace(r.Header.Get(xhttp.AmzTagDirective)) &&
|
if !isDirectiveReplace(r.Header.Get(xhttp.AmzMetadataDirective)) && !isDirectiveReplace(r.Header.Get(xhttp.AmzTagDirective)) &&
|
||||||
srcInfo.metadataOnly && !crypto.IsEncrypted(srcInfo.UserDefined) {
|
srcInfo.metadataOnly && !crypto.IsEncrypted(srcInfo.UserDefined) && srcOpts.VersionID == "" {
|
||||||
// If x-amz-metadata-directive is not set to REPLACE then we need
|
// If x-amz-metadata-directive is not set to REPLACE then we need
|
||||||
// to error out if source and destination are same.
|
// to error out if source and destination are same.
|
||||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidCopyDest), r.URL, guessIsBrowserReq(r))
|
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrInvalidCopyDest), r.URL, guessIsBrowserReq(r))
|
||||||
@ -1181,6 +1175,12 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
|
|||||||
encodedSuccessResponse := encodeResponse(response)
|
encodedSuccessResponse := encodeResponse(response)
|
||||||
|
|
||||||
setPutObjHeaders(w, objInfo, false)
|
setPutObjHeaders(w, objInfo, false)
|
||||||
|
// We must not use the http.Header().Set method here because some (broken)
|
||||||
|
// clients expect the x-amz-copy-source-version-id header key to be literally
|
||||||
|
// "x-amz-copy-source-version-id"- not in canonicalized form, preserve it.
|
||||||
|
if srcOpts.VersionID != "" {
|
||||||
|
w.Header()[strings.ToLower(xhttp.AmzCopySourceVersionID)] = []string{srcOpts.VersionID}
|
||||||
|
}
|
||||||
|
|
||||||
// Write success response.
|
// Write success response.
|
||||||
writeSuccessResponseXML(w, encodedSuccessResponse)
|
writeSuccessResponseXML(w, encodedSuccessResponse)
|
||||||
|
@ -1578,15 +1578,14 @@ func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName stri
|
|||||||
|
|
||||||
// test cases with inputs and expected result for Copy Object.
|
// test cases with inputs and expected result for Copy Object.
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
bucketName string
|
bucketName string
|
||||||
copySourceHeader string // data for "X-Amz-Copy-Source" header. Contains the object to be copied in the URL.
|
copySourceHeader string // data for "X-Amz-Copy-Source" header. Contains the object to be copied in the URL.
|
||||||
copySourceVersionID string // data for "X-Amz-Copy-Source-Version-Id" header.
|
copySourceRange string // data for "X-Amz-Copy-Source-Range" header, contains the byte range offsets of data to be copied.
|
||||||
copySourceRange string // data for "X-Amz-Copy-Source-Range" header, contains the byte range offsets of data to be copied.
|
uploadID string // uploadID of the transaction.
|
||||||
uploadID string // uploadID of the transaction.
|
invalidPartNumber bool // Sets an invalid multipart.
|
||||||
invalidPartNumber bool // Sets an invalid multipart.
|
maximumPartNumber bool // Sets a maximum parts.
|
||||||
maximumPartNumber bool // Sets a maximum parts.
|
accessKey string
|
||||||
accessKey string
|
secretKey string
|
||||||
secretKey string
|
|
||||||
// expected output.
|
// expected output.
|
||||||
expectedRespStatus int
|
expectedRespStatus int
|
||||||
}{
|
}{
|
||||||
@ -1768,26 +1767,6 @@ func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName stri
|
|||||||
secretKey: credentials.SecretKey,
|
secretKey: credentials.SecretKey,
|
||||||
expectedRespStatus: http.StatusBadRequest,
|
expectedRespStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// Test case - 16, copy part 1 from from newObject1 with null X-Amz-Copy-Source-Version-Id
|
|
||||||
{
|
|
||||||
bucketName: bucketName,
|
|
||||||
uploadID: uploadID,
|
|
||||||
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
|
|
||||||
copySourceVersionID: "null",
|
|
||||||
accessKey: credentials.AccessKey,
|
|
||||||
secretKey: credentials.SecretKey,
|
|
||||||
expectedRespStatus: http.StatusOK,
|
|
||||||
},
|
|
||||||
// Test case - 16, copy part 1 from from newObject1 with non null X-Amz-Copy-Source-Version-Id
|
|
||||||
{
|
|
||||||
bucketName: bucketName,
|
|
||||||
uploadID: uploadID,
|
|
||||||
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
|
|
||||||
copySourceVersionID: "17", // invalid id
|
|
||||||
accessKey: credentials.AccessKey,
|
|
||||||
secretKey: credentials.SecretKey,
|
|
||||||
expectedRespStatus: http.StatusBadRequest,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
@ -1810,9 +1789,6 @@ func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName stri
|
|||||||
if testCase.copySourceHeader != "" {
|
if testCase.copySourceHeader != "" {
|
||||||
req.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader)
|
req.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader)
|
||||||
}
|
}
|
||||||
if testCase.copySourceVersionID != "" {
|
|
||||||
req.Header.Set("X-Amz-Copy-Source-Version-Id", testCase.copySourceVersionID)
|
|
||||||
}
|
|
||||||
if testCase.copySourceRange != "" {
|
if testCase.copySourceRange != "" {
|
||||||
req.Header.Set("X-Amz-Copy-Source-Range", testCase.copySourceRange)
|
req.Header.Set("X-Amz-Copy-Source-Range", testCase.copySourceRange)
|
||||||
}
|
}
|
||||||
@ -1933,7 +1909,6 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
|
|||||||
bucketName string
|
bucketName string
|
||||||
newObjectName string // name of the newly copied object.
|
newObjectName string // name of the newly copied object.
|
||||||
copySourceHeader string // data for "X-Amz-Copy-Source" header. Contains the object to be copied in the URL.
|
copySourceHeader string // data for "X-Amz-Copy-Source" header. Contains the object to be copied in the URL.
|
||||||
copySourceVersionID string // data for "X-Amz-Copy-Source-Version-Id" header.
|
|
||||||
copyModifiedHeader string // data for "X-Amz-Copy-Source-If-Modified-Since" header
|
copyModifiedHeader string // data for "X-Amz-Copy-Source-If-Modified-Since" header
|
||||||
copyUnmodifiedHeader string // data for "X-Amz-Copy-Source-If-Unmodified-Since" header
|
copyUnmodifiedHeader string // data for "X-Amz-Copy-Source-If-Unmodified-Since" header
|
||||||
metadataGarbage bool
|
metadataGarbage bool
|
||||||
@ -2162,26 +2137,6 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
|
|||||||
secretKey: credentials.SecretKey,
|
secretKey: credentials.SecretKey,
|
||||||
expectedRespStatus: http.StatusBadRequest,
|
expectedRespStatus: http.StatusBadRequest,
|
||||||
},
|
},
|
||||||
// Test case - 19, copy metadata from newObject1 with null X-Amz-Copy-Source-Version-Id
|
|
||||||
{
|
|
||||||
bucketName: bucketName,
|
|
||||||
newObjectName: "newObject1",
|
|
||||||
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
|
|
||||||
copySourceVersionID: "null",
|
|
||||||
accessKey: credentials.AccessKey,
|
|
||||||
secretKey: credentials.SecretKey,
|
|
||||||
expectedRespStatus: http.StatusOK,
|
|
||||||
},
|
|
||||||
// Test case - 20, copy metadata from newObject1 with non null X-Amz-Copy-Source-Version-Id
|
|
||||||
{
|
|
||||||
bucketName: bucketName,
|
|
||||||
newObjectName: "newObject1",
|
|
||||||
copySourceHeader: url.QueryEscape(SlashSeparator + bucketName + SlashSeparator + objectName),
|
|
||||||
copySourceVersionID: "17",
|
|
||||||
accessKey: credentials.AccessKey,
|
|
||||||
secretKey: credentials.SecretKey,
|
|
||||||
expectedRespStatus: http.StatusBadRequest,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, testCase := range testCases {
|
for i, testCase := range testCases {
|
||||||
@ -2200,9 +2155,6 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
|
|||||||
if testCase.copySourceHeader != "" {
|
if testCase.copySourceHeader != "" {
|
||||||
req.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader)
|
req.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader)
|
||||||
}
|
}
|
||||||
if testCase.copySourceVersionID != "" {
|
|
||||||
req.Header.Set("X-Amz-Copy-Source-Version-Id", testCase.copySourceVersionID)
|
|
||||||
}
|
|
||||||
if testCase.copyModifiedHeader != "" {
|
if testCase.copyModifiedHeader != "" {
|
||||||
req.Header.Set("X-Amz-Copy-Source-If-Modified-Since", testCase.copyModifiedHeader)
|
req.Header.Set("X-Amz-Copy-Source-If-Modified-Since", testCase.copyModifiedHeader)
|
||||||
}
|
}
|
||||||
@ -2259,9 +2211,6 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string,
|
|||||||
if testCase.copySourceHeader != "" {
|
if testCase.copySourceHeader != "" {
|
||||||
reqV2.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader)
|
reqV2.Header.Set("X-Amz-Copy-Source", testCase.copySourceHeader)
|
||||||
}
|
}
|
||||||
if testCase.copySourceVersionID != "" {
|
|
||||||
reqV2.Header.Set("X-Amz-Copy-Source-Version-Id", testCase.copySourceVersionID)
|
|
||||||
}
|
|
||||||
if testCase.copyModifiedHeader != "" {
|
if testCase.copyModifiedHeader != "" {
|
||||||
reqV2.Header.Set("X-Amz-Copy-Source-If-Modified-Since", testCase.copyModifiedHeader)
|
reqV2.Header.Set("X-Amz-Copy-Source-If-Modified-Since", testCase.copyModifiedHeader)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user