mirror of
https://github.com/versity/versitygw.git
synced 2026-01-09 13:03:09 +00:00
fix: fixes the LastModified date formatting in CopyObject result.
Fixes #1276 Creates the custom `s3response.CopyObjectOutput` type to handle the `LastModified` date property formatting correctly. It uses `time.RFC3339` to format the date to match the format that s3 uses.
This commit is contained in:
@@ -823,14 +823,14 @@ func (az *Azure) DeleteObjects(ctx context.Context, input *s3.DeleteObjectsInput
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInput) (*s3.CopyObjectOutput, error) {
|
||||
func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInput) (s3response.CopyObjectOutput, error) {
|
||||
dstClient, err := az.getBlobClient(*input.Bucket, *input.Key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
if strings.Join([]string{*input.Bucket, *input.Key}, "/") == *input.CopySource {
|
||||
if input.MetadataDirective != types.MetadataDirectiveReplace {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidCopyDest)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidCopyDest)
|
||||
}
|
||||
|
||||
// Set object meta http headers
|
||||
@@ -842,7 +842,7 @@ func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInpu
|
||||
BlobContentType: input.ContentType,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
|
||||
meta := input.Metadata
|
||||
@@ -857,14 +857,14 @@ func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInpu
|
||||
// Set object metadata
|
||||
_, err = dstClient.SetMetadata(ctx, parseMetadata(meta), nil)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
|
||||
// Set object legal hold
|
||||
if input.ObjectLockLegalHoldStatus != "" {
|
||||
err = az.PutObjectLegalHold(ctx, *input.Bucket, *input.Key, "", input.ObjectLockLegalHoldStatus == types.ObjectLockLegalHoldStatusOn)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
}
|
||||
// Set object retention
|
||||
@@ -878,11 +878,11 @@ func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInpu
|
||||
|
||||
retParsed, err := json.Marshal(retention)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse object retention: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("parse object retention: %w", err)
|
||||
}
|
||||
err = az.PutObjectRetention(ctx, *input.Bucket, *input.Key, "", true, retParsed)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -890,16 +890,16 @@ func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInpu
|
||||
if input.TaggingDirective == types.TaggingDirectiveReplace {
|
||||
tags, err := backend.ParseObjectTags(getString(input.Tagging))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
_, err = dstClient.SetTags(ctx, tags, nil)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
return &s3.CopyObjectOutput{
|
||||
CopyObjectResult: &types.CopyObjectResult{
|
||||
return s3response.CopyObjectOutput{
|
||||
CopyObjectResult: &s3response.CopyObjectResult{
|
||||
LastModified: res.LastModified,
|
||||
ETag: (*string)(res.ETag),
|
||||
},
|
||||
@@ -908,13 +908,13 @@ func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInpu
|
||||
|
||||
srcBucket, srcObj, _, err := backend.ParseCopySource(*input.CopySource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
|
||||
// Get the source object
|
||||
downloadResp, err := az.client.DownloadStream(ctx, srcBucket, srcObj, nil)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
|
||||
pInput := s3response.PutObjectInput{
|
||||
@@ -952,28 +952,28 @@ func (az *Azure) CopyObject(ctx context.Context, input s3response.CopyObjectInpu
|
||||
// Create the destination object
|
||||
resp, err := az.PutObject(ctx, pInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
|
||||
// Copy the object tagging, if tagging directive is "COPY"
|
||||
if input.TaggingDirective == types.TaggingDirectiveCopy {
|
||||
srcClient, err := az.getBlobClient(srcBucket, srcObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
res, err := srcClient.GetTags(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
|
||||
_, err = dstClient.SetTags(ctx, parseAzTags(res.BlobTagSet), nil)
|
||||
if err != nil {
|
||||
return nil, azureErrToS3Err(err)
|
||||
return s3response.CopyObjectOutput{}, azureErrToS3Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
return &s3.CopyObjectOutput{
|
||||
CopyObjectResult: &types.CopyObjectResult{
|
||||
return s3response.CopyObjectOutput{
|
||||
CopyObjectResult: &s3response.CopyObjectResult{
|
||||
ETag: &resp.ETag,
|
||||
},
|
||||
}, nil
|
||||
|
||||
@@ -65,7 +65,7 @@ type Backend interface {
|
||||
GetObject(context.Context, *s3.GetObjectInput) (*s3.GetObjectOutput, error)
|
||||
GetObjectAcl(context.Context, *s3.GetObjectAclInput) (*s3.GetObjectAclOutput, error)
|
||||
GetObjectAttributes(context.Context, *s3.GetObjectAttributesInput) (s3response.GetObjectAttributesResponse, error)
|
||||
CopyObject(context.Context, s3response.CopyObjectInput) (*s3.CopyObjectOutput, error)
|
||||
CopyObject(context.Context, s3response.CopyObjectInput) (s3response.CopyObjectOutput, error)
|
||||
ListObjects(context.Context, *s3.ListObjectsInput) (s3response.ListObjectsResult, error)
|
||||
ListObjectsV2(context.Context, *s3.ListObjectsV2Input) (s3response.ListObjectsV2Result, error)
|
||||
DeleteObject(context.Context, *s3.DeleteObjectInput) (*s3.DeleteObjectOutput, error)
|
||||
@@ -200,8 +200,8 @@ func (BackendUnsupported) GetObjectAcl(context.Context, *s3.GetObjectAclInput) (
|
||||
func (BackendUnsupported) GetObjectAttributes(context.Context, *s3.GetObjectAttributesInput) (s3response.GetObjectAttributesResponse, error) {
|
||||
return s3response.GetObjectAttributesResponse{}, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) CopyObject(context.Context, s3response.CopyObjectInput) (*s3.CopyObjectOutput, error) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
func (BackendUnsupported) CopyObject(context.Context, s3response.CopyObjectInput) (s3response.CopyObjectOutput, error) {
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
}
|
||||
func (BackendUnsupported) ListObjects(context.Context, *s3.ListObjectsInput) (s3response.ListObjectsResult, error) {
|
||||
return s3response.ListObjectsResult{}, s3err.GetAPIError(s3err.ErrNotImplemented)
|
||||
|
||||
@@ -3855,51 +3855,51 @@ func (p *Posix) GetObjectAttributes(ctx context.Context, input *s3.GetObjectAttr
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput) (*s3.CopyObjectOutput, error) {
|
||||
func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput) (s3response.CopyObjectOutput, error) {
|
||||
if input.Bucket == nil {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidBucketName)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidBucketName)
|
||||
}
|
||||
if input.Key == nil {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidCopyDest)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidCopyDest)
|
||||
}
|
||||
if input.CopySource == nil {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidCopySource)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidCopySource)
|
||||
}
|
||||
if input.ExpectedBucketOwner == nil {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidRequest)
|
||||
}
|
||||
|
||||
srcBucket, srcObject, srcVersionId, err := backend.ParseCopySource(*input.CopySource)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
dstBucket := *input.Bucket
|
||||
dstObject := *input.Key
|
||||
|
||||
_, err = os.Stat(srcBucket)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stat bucket: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
vStatus, err := p.getBucketVersioningStatus(ctx, srcBucket)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
vEnabled := p.isBucketVersioningEnabled(vStatus)
|
||||
|
||||
if srcVersionId != "" {
|
||||
if !p.versioningEnabled() || !vEnabled {
|
||||
return nil, s3err.GetAPIError(s3err.ErrInvalidVersionId)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidVersionId)
|
||||
}
|
||||
vId, err := p.meta.RetrieveAttribute(nil, srcBucket, srcObject, versionIdKey)
|
||||
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return nil, fmt.Errorf("get src object version id: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("get src object version id: %w", err)
|
||||
}
|
||||
|
||||
if string(vId) != srcVersionId {
|
||||
@@ -3910,37 +3910,37 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
|
||||
_, err = os.Stat(dstBucket)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchBucket)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stat bucket: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("stat bucket: %w", err)
|
||||
}
|
||||
|
||||
objPath := joinPathWithTrailer(srcBucket, srcObject)
|
||||
f, err := os.Open(objPath)
|
||||
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
|
||||
if p.versioningEnabled() && vEnabled {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchVersion)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchVersion)
|
||||
}
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if errors.Is(err, syscall.ENAMETOOLONG) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrKeyTooLong)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrKeyTooLong)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open object: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("open object: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stat object: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("stat object: %w", err)
|
||||
}
|
||||
if strings.HasSuffix(srcObject, "/") && !fi.IsDir() {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if !strings.HasSuffix(srcObject, "/") && fi.IsDir() {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
|
||||
mdmap := make(map[string]string)
|
||||
@@ -3958,7 +3958,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
dstObjdPath := joinPathWithTrailer(dstBucket, dstObject)
|
||||
if dstObjdPath == objPath {
|
||||
if input.MetadataDirective == types.MetadataDirectiveCopy {
|
||||
return &s3.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidCopyDest)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrInvalidCopyDest)
|
||||
}
|
||||
|
||||
// Delete the object metadata
|
||||
@@ -3966,7 +3966,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
err := p.meta.DeleteAttribute(dstBucket, dstObject,
|
||||
fmt.Sprintf("%v.%v", metaHdr, k))
|
||||
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return nil, fmt.Errorf("delete user metadata: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("delete user metadata: %w", err)
|
||||
}
|
||||
}
|
||||
// Store the new metadata
|
||||
@@ -3974,13 +3974,13 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
err := p.meta.StoreAttribute(nil, dstBucket, dstObject,
|
||||
fmt.Sprintf("%v.%v", metaHdr, k), []byte(v))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("set user attr %q: %w", k, err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("set user attr %q: %w", k, err)
|
||||
}
|
||||
}
|
||||
|
||||
checksums, err := p.retrieveChecksums(nil, dstBucket, dstObject)
|
||||
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return nil, fmt.Errorf("get obj checksums: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("get obj checksums: %w", err)
|
||||
}
|
||||
|
||||
chType = checksums.Type
|
||||
@@ -3991,18 +3991,18 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
if checksums.Algorithm != input.ChecksumAlgorithm {
|
||||
f, err := os.Open(dstObjdPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("open obj file: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("open obj file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
hashReader, err := utils.NewHashReader(f, "", utils.HashType(strings.ToLower(string(input.ChecksumAlgorithm))))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("initialize hash reader: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("initialize hash reader: %w", err)
|
||||
}
|
||||
|
||||
_, err = hashReader.Read(nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read err: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("read err: %w", err)
|
||||
}
|
||||
|
||||
checksums = s3response.Checksum{}
|
||||
@@ -4032,7 +4032,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
|
||||
err = p.storeChecksums(f, dstBucket, dstObject, checksums)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("store checksum: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("store checksum: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4041,7 +4041,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
etag = string(b)
|
||||
vId, _ := p.meta.RetrieveAttribute(nil, dstBucket, dstObject, versionIdKey)
|
||||
if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
version = backend.GetPtrFromString(string(vId))
|
||||
|
||||
@@ -4056,18 +4056,18 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
Expires: input.Expires,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
|
||||
if input.TaggingDirective == types.TaggingDirectiveReplace {
|
||||
tags, err := backend.ParseObjectTags(getString(input.Tagging))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
|
||||
err = p.PutObjectTagging(ctx, dstBucket, dstObject, tags)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -4075,7 +4075,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
|
||||
checksums, err := p.retrieveChecksums(f, srcBucket, srcObject)
|
||||
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return nil, fmt.Errorf("get obj checksum: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("get obj checksum: %w", err)
|
||||
}
|
||||
|
||||
// If any checksum algorithm is provided, replace, otherwise
|
||||
@@ -4121,7 +4121,7 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
|
||||
res, err := p.PutObject(ctx, putObjectInput)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return s3response.CopyObjectOutput{}, err
|
||||
}
|
||||
|
||||
// copy the source object tagging after the destination object
|
||||
@@ -4129,12 +4129,12 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
if input.TaggingDirective == types.TaggingDirectiveCopy {
|
||||
tagging, err := p.meta.RetrieveAttribute(nil, srcBucket, srcObject, tagHdr)
|
||||
if err != nil && !errors.Is(err, meta.ErrNoSuchKey) {
|
||||
return nil, fmt.Errorf("get source object tagging: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("get source object tagging: %w", err)
|
||||
}
|
||||
if err == nil {
|
||||
err := p.meta.StoreAttribute(nil, dstBucket, dstObject, tagHdr, tagging)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("set destination object tagging: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("set destination object tagging: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4151,11 +4151,11 @@ func (p *Posix) CopyObject(ctx context.Context, input s3response.CopyObjectInput
|
||||
|
||||
fi, err = os.Stat(dstObjdPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("stat dst object: %w", err)
|
||||
return s3response.CopyObjectOutput{}, fmt.Errorf("stat dst object: %w", err)
|
||||
}
|
||||
|
||||
return &s3.CopyObjectOutput{
|
||||
CopyObjectResult: &types.CopyObjectResult{
|
||||
return s3response.CopyObjectOutput{
|
||||
CopyObjectResult: &s3response.CopyObjectResult{
|
||||
ETag: &etag,
|
||||
LastModified: backend.GetTimePtr(fi.ModTime()),
|
||||
ChecksumCRC32: crc32,
|
||||
|
||||
@@ -1089,9 +1089,9 @@ func (s *S3Proxy) GetObjectAttributes(ctx context.Context, input *s3.GetObjectAt
|
||||
}, handleError(err)
|
||||
}
|
||||
|
||||
func (s *S3Proxy) CopyObject(ctx context.Context, input s3response.CopyObjectInput) (*s3.CopyObjectOutput, error) {
|
||||
func (s *S3Proxy) CopyObject(ctx context.Context, input s3response.CopyObjectInput) (s3response.CopyObjectOutput, error) {
|
||||
if *input.Bucket == s.metaBucket {
|
||||
return nil, s3err.GetAPIError(s3err.ErrAccessDenied)
|
||||
return s3response.CopyObjectOutput{}, s3err.GetAPIError(s3err.ErrAccessDenied)
|
||||
}
|
||||
if input.CacheControl != nil && *input.CacheControl == "" {
|
||||
input.CacheControl = nil
|
||||
@@ -1227,7 +1227,33 @@ func (s *S3Proxy) CopyObject(ctx context.Context, input s3response.CopyObjectInp
|
||||
StorageClass: input.StorageClass,
|
||||
TaggingDirective: input.TaggingDirective,
|
||||
})
|
||||
return out, handleError(err)
|
||||
if err != nil {
|
||||
return s3response.CopyObjectOutput{}, handleError(err)
|
||||
}
|
||||
if out.CopyObjectResult == nil {
|
||||
out.CopyObjectResult = &types.CopyObjectResult{}
|
||||
}
|
||||
return s3response.CopyObjectOutput{
|
||||
BucketKeyEnabled: out.BucketKeyEnabled,
|
||||
CopyObjectResult: &s3response.CopyObjectResult{
|
||||
ChecksumCRC32: out.CopyObjectResult.ChecksumCRC32,
|
||||
ChecksumCRC32C: out.CopyObjectResult.ChecksumCRC32C,
|
||||
ChecksumCRC64NVME: out.CopyObjectResult.ChecksumCRC64NVME,
|
||||
ChecksumSHA1: out.CopyObjectResult.ChecksumSHA1,
|
||||
ChecksumSHA256: out.CopyObjectResult.ChecksumSHA256,
|
||||
ChecksumType: out.CopyObjectResult.ChecksumType,
|
||||
ETag: out.CopyObjectResult.ETag,
|
||||
LastModified: out.CopyObjectResult.LastModified,
|
||||
},
|
||||
CopySourceVersionId: out.CopySourceVersionId,
|
||||
Expiration: out.Expiration,
|
||||
SSECustomerAlgorithm: out.SSECustomerAlgorithm,
|
||||
SSECustomerKeyMD5: out.SSECustomerKeyMD5,
|
||||
SSEKMSEncryptionContext: out.SSEKMSEncryptionContext,
|
||||
SSEKMSKeyId: out.SSEKMSKeyId,
|
||||
ServerSideEncryption: out.ServerSideEncryption,
|
||||
VersionId: out.VersionId,
|
||||
}, handleError(err)
|
||||
}
|
||||
|
||||
func (s *S3Proxy) ListObjects(ctx context.Context, input *s3.ListObjectsInput) (s3response.ListObjectsResult, error) {
|
||||
|
||||
@@ -32,7 +32,7 @@ var _ backend.Backend = &BackendMock{}
|
||||
// CompleteMultipartUploadFunc: func(contextMoqParam context.Context, completeMultipartUploadInput *s3.CompleteMultipartUploadInput) (s3response.CompleteMultipartUploadResult, string, error) {
|
||||
// panic("mock out the CompleteMultipartUpload method")
|
||||
// },
|
||||
// CopyObjectFunc: func(contextMoqParam context.Context, copyObjectInput s3response.CopyObjectInput) (*s3.CopyObjectOutput, error) {
|
||||
// CopyObjectFunc: func(contextMoqParam context.Context, copyObjectInput s3response.CopyObjectInput) (s3response.CopyObjectOutput, error) {
|
||||
// panic("mock out the CopyObject method")
|
||||
// },
|
||||
// CreateBucketFunc: func(contextMoqParam context.Context, createBucketInput *s3.CreateBucketInput, defaultACL []byte) error {
|
||||
@@ -202,7 +202,7 @@ type BackendMock struct {
|
||||
CompleteMultipartUploadFunc func(contextMoqParam context.Context, completeMultipartUploadInput *s3.CompleteMultipartUploadInput) (s3response.CompleteMultipartUploadResult, string, error)
|
||||
|
||||
// CopyObjectFunc mocks the CopyObject method.
|
||||
CopyObjectFunc func(contextMoqParam context.Context, copyObjectInput s3response.CopyObjectInput) (*s3.CopyObjectOutput, error)
|
||||
CopyObjectFunc func(contextMoqParam context.Context, copyObjectInput s3response.CopyObjectInput) (s3response.CopyObjectOutput, error)
|
||||
|
||||
// CreateBucketFunc mocks the CreateBucket method.
|
||||
CreateBucketFunc func(contextMoqParam context.Context, createBucketInput *s3.CreateBucketInput, defaultACL []byte) error
|
||||
@@ -940,7 +940,7 @@ func (mock *BackendMock) CompleteMultipartUploadCalls() []struct {
|
||||
}
|
||||
|
||||
// CopyObject calls CopyObjectFunc.
|
||||
func (mock *BackendMock) CopyObject(contextMoqParam context.Context, copyObjectInput s3response.CopyObjectInput) (*s3.CopyObjectOutput, error) {
|
||||
func (mock *BackendMock) CopyObject(contextMoqParam context.Context, copyObjectInput s3response.CopyObjectInput) (s3response.CopyObjectOutput, error) {
|
||||
if mock.CopyObjectFunc == nil {
|
||||
panic("BackendMock.CopyObjectFunc: method is nil but Backend.CopyObject was just called")
|
||||
}
|
||||
|
||||
@@ -974,9 +974,9 @@ func TestS3ApiController_PutActions(t *testing.T) {
|
||||
PutObjectAclFunc: func(context.Context, *s3.PutObjectAclInput) error {
|
||||
return nil
|
||||
},
|
||||
CopyObjectFunc: func(context.Context, s3response.CopyObjectInput) (*s3.CopyObjectOutput, error) {
|
||||
return &s3.CopyObjectOutput{
|
||||
CopyObjectResult: &types.CopyObjectResult{},
|
||||
CopyObjectFunc: func(context.Context, s3response.CopyObjectInput) (s3response.CopyObjectOutput, error) {
|
||||
return s3response.CopyObjectOutput{
|
||||
CopyObjectResult: &s3response.CopyObjectResult{},
|
||||
}, nil
|
||||
},
|
||||
PutObjectFunc: func(context.Context, s3response.PutObjectInput) (s3response.PutObjectOutput, error) {
|
||||
|
||||
@@ -344,23 +344,42 @@ type CanonicalUser struct {
|
||||
DisplayName string
|
||||
}
|
||||
|
||||
type CopyObjectOutput struct {
|
||||
BucketKeyEnabled *bool
|
||||
CopyObjectResult *CopyObjectResult
|
||||
CopySourceVersionId *string
|
||||
Expiration *string
|
||||
SSECustomerAlgorithm *string
|
||||
SSECustomerKeyMD5 *string
|
||||
SSEKMSEncryptionContext *string
|
||||
SSEKMSKeyId *string
|
||||
ServerSideEncryption types.ServerSideEncryption
|
||||
VersionId *string
|
||||
}
|
||||
|
||||
type CopyObjectResult struct {
|
||||
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CopyObjectResult" json:"-"`
|
||||
LastModified time.Time
|
||||
ETag string
|
||||
CopySourceVersionId string `xml:"-"`
|
||||
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ CopyObjectResult" json:"-"`
|
||||
ChecksumCRC32 *string
|
||||
ChecksumCRC32C *string
|
||||
ChecksumCRC64NVME *string
|
||||
ChecksumSHA1 *string
|
||||
ChecksumSHA256 *string
|
||||
ChecksumType types.ChecksumType
|
||||
ETag *string
|
||||
LastModified *time.Time
|
||||
}
|
||||
|
||||
func (r CopyObjectResult) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
|
||||
type Alias CopyObjectResult
|
||||
aux := &struct {
|
||||
LastModified string `xml:"LastModified"`
|
||||
LastModified string `xml:"LastModified,omitempty"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(&r),
|
||||
}
|
||||
|
||||
aux.LastModified = r.LastModified.UTC().Format(iso8601TimeFormat)
|
||||
if r.LastModified != nil {
|
||||
aux.LastModified = r.LastModified.UTC().Format(time.RFC3339)
|
||||
}
|
||||
|
||||
return e.EncodeElement(aux, start)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user