mirror of
https://github.com/versity/versitygw.git
synced 2026-01-11 13:50:13 +00:00
Merge pull request #797 from versity/fix/getobjectattributes-mp
fix: Removed multipart upload part from GetObjectAttributes action
This commit is contained in:
@@ -24,7 +24,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@@ -1951,63 +1950,15 @@ func (p *Posix) GetObjectAttributes(ctx context.Context, input *s3.GetObjectAttr
|
||||
Bucket: input.Bucket,
|
||||
Key: input.Key,
|
||||
})
|
||||
if err == nil {
|
||||
return s3response.GetObjectAttributesResult{
|
||||
ETag: data.ETag,
|
||||
LastModified: data.LastModified,
|
||||
ObjectSize: data.ContentLength,
|
||||
StorageClass: data.StorageClass,
|
||||
VersionId: data.VersionId,
|
||||
}, nil
|
||||
}
|
||||
if !errors.Is(err, s3err.GetAPIError(s3err.ErrNoSuchKey)) {
|
||||
return s3response.GetObjectAttributesResult{}, err
|
||||
}
|
||||
|
||||
uploadId, _, err := p.retrieveUploadId(*input.Bucket, *input.Key)
|
||||
if err != nil {
|
||||
return s3response.GetObjectAttributesResult{}, err
|
||||
return s3response.GetObjectAttributesResult{}, nil
|
||||
}
|
||||
|
||||
resp, err := p.ListParts(ctx, &s3.ListPartsInput{
|
||||
Bucket: input.Bucket,
|
||||
Key: input.Key,
|
||||
UploadId: &uploadId,
|
||||
PartNumberMarker: input.PartNumberMarker,
|
||||
MaxParts: input.MaxParts,
|
||||
})
|
||||
if err != nil {
|
||||
return s3response.GetObjectAttributesResult{}, err
|
||||
}
|
||||
|
||||
parts := []types.ObjectPart{}
|
||||
|
||||
for _, p := range resp.Parts {
|
||||
if !(p.PartNumber > 0 && p.PartNumber <= math.MaxInt32) {
|
||||
return s3response.GetObjectAttributesResult{},
|
||||
s3err.GetAPIError(s3err.ErrInvalidPartNumber)
|
||||
}
|
||||
|
||||
partNumber := int32(p.PartNumber)
|
||||
size := p.Size
|
||||
|
||||
parts = append(parts, types.ObjectPart{
|
||||
Size: &size,
|
||||
PartNumber: &partNumber,
|
||||
})
|
||||
}
|
||||
|
||||
//TODO: handle PartsCount prop
|
||||
//TODO: Maybe simply calling ListParts isn't a good option
|
||||
return s3response.GetObjectAttributesResult{
|
||||
ObjectParts: &s3response.ObjectParts{
|
||||
IsTruncated: resp.IsTruncated,
|
||||
MaxParts: resp.MaxParts,
|
||||
PartNumberMarker: resp.PartNumberMarker,
|
||||
NextPartNumberMarker: resp.NextPartNumberMarker,
|
||||
Parts: parts,
|
||||
},
|
||||
StorageClass: types.StorageClassStandard,
|
||||
ETag: data.ETag,
|
||||
LastModified: data.LastModified,
|
||||
ObjectSize: data.ContentLength,
|
||||
StorageClass: data.StorageClass,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -152,8 +152,6 @@ func TestGetObjectAttributes(s *S3Conf) {
|
||||
GetObjectAttributes_non_existing_bucket(s)
|
||||
GetObjectAttributes_non_existing_object(s)
|
||||
GetObjectAttributes_existing_object(s)
|
||||
GetObjectAttributes_multipart_upload(s)
|
||||
GetObjectAttributes_multipart_upload_truncated(s)
|
||||
}
|
||||
|
||||
func TestGetObject(s *S3Conf) {
|
||||
@@ -604,8 +602,6 @@ func GetIntTests() IntTests {
|
||||
"GetObjectAttributes_non_existing_bucket": GetObjectAttributes_non_existing_bucket,
|
||||
"GetObjectAttributes_non_existing_object": GetObjectAttributes_non_existing_object,
|
||||
"GetObjectAttributes_existing_object": GetObjectAttributes_existing_object,
|
||||
"GetObjectAttributes_multipart_upload": GetObjectAttributes_multipart_upload,
|
||||
"GetObjectAttributes_multipart_upload_truncated": GetObjectAttributes_multipart_upload_truncated,
|
||||
"GetObject_non_existing_key": GetObject_non_existing_key,
|
||||
"GetObject_invalid_ranges": GetObject_invalid_ranges,
|
||||
"GetObject_with_meta": GetObject_with_meta,
|
||||
|
||||
@@ -3193,159 +3193,6 @@ func GetObjectAttributes_existing_object(s *S3Conf) error {
|
||||
})
|
||||
}
|
||||
|
||||
func GetObjectAttributes_multipart_upload(s *S3Conf) error {
|
||||
testName := "GetObjectAttributes_multipart_upload"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
obj := "my-obj"
|
||||
out, err := createMp(s3client, bucket, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parts, err := uploadParts(s3client, 5*1024*1024, 5, bucket, obj, *out.UploadId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
||||
resp, err := s3client.GetObjectAttributes(ctx, &s3.GetObjectAttributesInput{
|
||||
Bucket: &bucket,
|
||||
Key: &obj,
|
||||
ObjectAttributes: []types.ObjectAttributes{
|
||||
types.ObjectAttributesObjectParts,
|
||||
types.ObjectAttributesStorageClass,
|
||||
},
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.ObjectParts == nil {
|
||||
return fmt.Errorf("expected non nil object parts")
|
||||
}
|
||||
if resp.StorageClass != types.StorageClassStandard {
|
||||
return fmt.Errorf("expected the storage class to be %v, instead got %v", types.StorageClassStandard, resp.StorageClass)
|
||||
}
|
||||
|
||||
for i, p := range resp.ObjectParts.Parts {
|
||||
if *p.PartNumber != *parts[i].PartNumber {
|
||||
return fmt.Errorf("expected part number to be %v, instead got %v", *parts[i].PartNumber, *p.PartNumber)
|
||||
}
|
||||
if *p.Size != *parts[i].Size {
|
||||
return fmt.Errorf("expected part size to be %v, instead got %v", *parts[i].Size, *p.Size)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func GetObjectAttributes_multipart_upload_truncated(s *S3Conf) error {
|
||||
testName := "GetObjectAttributes_multipart_upload_truncated"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
obj := "my-obj"
|
||||
out, err := createMp(s3client, bucket, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
parts, err := uploadParts(s3client, 5*1024*1024, 5, bucket, obj, *out.UploadId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
maxParts := int32(3)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
||||
resp, err := s3client.GetObjectAttributes(ctx, &s3.GetObjectAttributesInput{
|
||||
Bucket: &bucket,
|
||||
Key: &obj,
|
||||
ObjectAttributes: []types.ObjectAttributes{
|
||||
types.ObjectAttributesObjectParts,
|
||||
},
|
||||
MaxParts: &maxParts,
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.ObjectParts == nil {
|
||||
return fmt.Errorf("expected non nil object parts")
|
||||
}
|
||||
if resp.ObjectParts.IsTruncated == nil {
|
||||
return fmt.Errorf("expected non nil isTruncated")
|
||||
}
|
||||
if !*resp.ObjectParts.IsTruncated {
|
||||
return fmt.Errorf("expected object parts to be truncated")
|
||||
}
|
||||
if resp.ObjectParts.MaxParts == nil {
|
||||
return fmt.Errorf("expected non nil max-parts")
|
||||
}
|
||||
if *resp.ObjectParts.MaxParts != maxParts {
|
||||
return fmt.Errorf("expected max-parts to be %v, instead got %v", maxParts, *resp.ObjectParts.MaxParts)
|
||||
}
|
||||
if resp.ObjectParts.NextPartNumberMarker == nil {
|
||||
return fmt.Errorf("expected non nil NextPartNumberMarker")
|
||||
}
|
||||
if *resp.ObjectParts.NextPartNumberMarker != fmt.Sprint(*parts[2].PartNumber) {
|
||||
return fmt.Errorf("expected NextPartNumberMarker to be %v, instead got %v", fmt.Sprint(*parts[2].PartNumber), *resp.ObjectParts.NextPartNumberMarker)
|
||||
}
|
||||
if len(resp.ObjectParts.Parts) != int(maxParts) {
|
||||
return fmt.Errorf("expected length of parts to be %v, instead got %v", maxParts, len(resp.ObjectParts.Parts))
|
||||
}
|
||||
|
||||
for i, p := range resp.ObjectParts.Parts {
|
||||
if *p.PartNumber != *parts[i].PartNumber {
|
||||
return fmt.Errorf("expected part number to be %v, instead got %v", *parts[i].PartNumber, *p.PartNumber)
|
||||
}
|
||||
if *p.Size != *parts[i].Size {
|
||||
return fmt.Errorf("expected part size to be %v, instead got %v", *parts[i].Size, *p.Size)
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel = context.WithTimeout(context.Background(), shortTimeout)
|
||||
resp, err = s3client.GetObjectAttributes(ctx, &s3.GetObjectAttributesInput{
|
||||
Bucket: &bucket,
|
||||
Key: &obj,
|
||||
ObjectAttributes: []types.ObjectAttributes{
|
||||
types.ObjectAttributesObjectParts,
|
||||
},
|
||||
PartNumberMarker: resp.ObjectParts.NextPartNumberMarker,
|
||||
})
|
||||
cancel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.ObjectParts == nil {
|
||||
return fmt.Errorf("expected non nil object parts")
|
||||
}
|
||||
if resp.ObjectParts.IsTruncated == nil {
|
||||
return fmt.Errorf("expected non nil isTruncated")
|
||||
}
|
||||
if *resp.ObjectParts.IsTruncated {
|
||||
return fmt.Errorf("expected object parts to not be truncated")
|
||||
}
|
||||
|
||||
if len(resp.ObjectParts.Parts) != len(parts)-int(maxParts) {
|
||||
return fmt.Errorf("expected length of parts to be %v, instead got %v", len(parts)-int(maxParts), len(resp.ObjectParts.Parts))
|
||||
}
|
||||
|
||||
for i, p := range resp.ObjectParts.Parts {
|
||||
if *p.PartNumber != *parts[i+int(maxParts)].PartNumber {
|
||||
return fmt.Errorf("expected part number to be %v, instead got %v", *parts[i+int(maxParts)].PartNumber, *p.PartNumber)
|
||||
}
|
||||
if *p.Size != *parts[i+int(maxParts)].Size {
|
||||
return fmt.Errorf("expected part size to be %v, instead got %v", *parts[i+int(maxParts)].Size, *p.Size)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func GetObject_non_existing_key(s *S3Conf) error {
|
||||
testName := "GetObject_non_existing_key"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
|
||||
Reference in New Issue
Block a user