feat: adds x-amz-tagging-count support for HeadObject

Closes #1346

`GetObject` and `HeadObject` return the `x-amz-tagging-count` header in the response, which specifies the number of tags associated with the object. This was already supported for `GetObject`, but missing for `HeadObject`. This implementation adds support for `HeadObject` in `azure` and `posix` and updates the integration tests to cover this functionality for `GetObject`.
This commit is contained in:
niksis02
2025-11-05 19:51:56 +04:00
parent 59312f880f
commit 77459720ba
6 changed files with 35 additions and 0 deletions

View File

@@ -583,6 +583,11 @@ func (az *Azure) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3
}
}
if resp.TagCount != nil {
tagcount := int32(*resp.TagCount)
result.TagCount = &tagcount
}
return result, nil
}

View File

@@ -4026,6 +4026,16 @@ func (p *Posix) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3.
}
}
var tagCount *int32
tags, err := p.getAttrTags(bucket, object, versionId)
if err != nil && !errors.Is(err, s3err.GetAPIError(s3err.ErrBucketTaggingNotFound)) {
return nil, err
}
if tags != nil {
tc := int32(len(tags))
tagCount = &tc
}
return &s3.HeadObjectOutput{
ContentLength: &length,
AcceptRanges: backend.GetPtrFromString("bytes"),
@@ -4050,6 +4060,7 @@ func (p *Posix) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3.
ChecksumSHA256: checksums.SHA256,
ChecksumCRC64NVME: checksums.CRC64NVME,
ChecksumType: cType,
TagCount: tagCount,
}, nil
}

View File

@@ -150,6 +150,7 @@ func (c S3ApiController) HeadObject(ctx *fiber.Ctx) (*Response, error) {
"x-amz-storage-class": utils.ConvertToStringPtr(res.StorageClass),
"x-amz-checksum-type": utils.ConvertToStringPtr(res.ChecksumType),
"x-amz-object-lock-retain-until-date": utils.FormatDatePtrToString(res.ObjectLockRetainUntilDate, time.RFC3339),
"x-amz-tagging-count": utils.ConvertPtrToStringPtr(res.TagCount),
},
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,

View File

@@ -147,6 +147,7 @@ func TestS3ApiController_HeadObject(t *testing.T) {
"x-amz-checksum-type": nil,
"x-amz-object-lock-retain-until-date": nil,
"Last-Modified": nil,
"x-amz-tagging-count": nil,
"Content-Type": utils.GetStringPtr("application/xml"),
"Content-Length": utils.GetStringPtr("100"),
},

View File

@@ -527,6 +527,7 @@ func GetObject_success(s *S3Conf) error {
Expires: &expires,
CacheControl: &cacheControl,
Metadata: meta,
Tagging: getPtr("key=value&key1=val1"),
}, s3client)
if err != nil {
return err
@@ -577,6 +578,13 @@ func GetObject_success(s *S3Conf) error {
return fmt.Errorf("expected the object metadata to be %v, instead got %v",
meta, out.Metadata)
}
var tagCount int32
if out.TagCount != nil {
tagCount = *out.TagCount
}
if tagCount != 2 {
return fmt.Errorf("expected tag count to be 2, instead got %v", tagCount)
}
bdy, err := io.ReadAll(out.Body)
if err != nil {

View File

@@ -566,6 +566,7 @@ func HeadObject_success(s *S3Conf) error {
ContentLanguage: &cLang,
CacheControl: &cacheControl,
Expires: &expires,
Tagging: getPtr("key=value"),
}, s3client)
if err != nil {
return err
@@ -620,6 +621,14 @@ func HeadObject_success(s *S3Conf) error {
return fmt.Errorf("expected the storage class to be %v, instead got %v",
types.StorageClassStandard, out.StorageClass)
}
tagCount := int32(0)
if out.TagCount != nil {
tagCount = *out.TagCount
}
if tagCount != 1 {
return fmt.Errorf("expected the tagcount to be 1, instead got %v", tagCount)
}
return nil
})