Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NEW API: GetObjectAttributes #1921

Merged
merged 14 commits into from
Jan 8, 2024
129 changes: 129 additions & 0 deletions api-get-object-attributes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package minio
zveinn marked this conversation as resolved.
Show resolved Hide resolved

import (
"context"
"encoding/xml"
"net/http"
"net/url"
"time"

"github.com/minio/minio-go/v7/pkg/encrypt"
"github.com/minio/minio-go/v7/pkg/s3utils"
)

// ObjectAttributesOptions is an API call that combines
// HeadObject and ListParts.
//
// VersionID - The object version you want to attributes for
// ServerSideEncryption - The server-side encryption algorithm used when storing this object in Minio
type ObjectAttributesOptions struct {
VersionID string
ServerSideEncryption encrypt.ServerSide
}

// ObjectAttributes ...
type ObjectAttributes struct {
objectAttributesResponse
zveinn marked this conversation as resolved.
Show resolved Hide resolved
LastModified time.Time
VersionID string
}

func (o *ObjectAttributes) parseResponse(resp *http.Response) (err error) {
mod, err := parseRFC7231Time(resp.Header.Get("Last-Modified"))
if err != nil {
return err
}
o.LastModified = mod
o.VersionID = resp.Header.Get(amzVersionID)

response := new(objectAttributesResponse)
if err := xml.NewDecoder(resp.Body).Decode(response); err != nil {
return err
}
o.objectAttributesResponse = *response

return
}

type objectAttributesResponse struct {
ETag string `xml:",omitempty"`
StorageClass string
ObjectSize int
Checksum struct {
ChecksumCRC32 string `xml:",omitempty"`
ChecksumCRC32C string `xml:",omitempty"`
ChecksumSHA1 string `xml:",omitempty"`
ChecksumSHA256 string `xml:",omitempty"`
}
ObjectParts struct {
PartsCount int
Parts []*objectPart `xml:"Part"`
zveinn marked this conversation as resolved.
Show resolved Hide resolved
}
}

type objectPart struct {
ChecksumCRC32 string `xml:",omitempty"`
ChecksumCRC32C string `xml:",omitempty"`
ChecksumSHA1 string `xml:",omitempty"`
ChecksumSHA256 string `xml:",omitempty"`
PartNumber int
Size int
}

// GetObjectAttributes ...
zveinn marked this conversation as resolved.
Show resolved Hide resolved
// This API combines HeadObject and ListParts.
func (c *Client) GetObjectAttributes(ctx context.Context, bucketName, objectName string, opts ObjectAttributesOptions) (ObjectAttributes, error) {
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return ObjectAttributes{}, err
}

if err := s3utils.CheckValidObjectName(objectName); err != nil {
return ObjectAttributes{}, err
}

urlValues := make(url.Values)
urlValues.Add("attributes", "")
if opts.VersionID != "" {
urlValues.Add("versionId", opts.VersionID)
}

headers := make(http.Header)
headers.Set(amzObjectAttributes, GetObjectAttributesTags)

headers.Set(amzPartNumberMarker, "0")
headers.Set(amzMaxParts, "0")
harshavardhana marked this conversation as resolved.
Show resolved Hide resolved

if opts.ServerSideEncryption != nil {
opts.ServerSideEncryption.Marshal(headers)
}

resp, err := c.executeMethod(ctx, http.MethodGet, requestMetadata{
bucketName: bucketName,
objectName: objectName,
queryValues: urlValues,
contentSHA256Hex: emptySHA256Hex,
customHeader: headers,
})
if err != nil {
return ObjectAttributes{}, err
}

if resp.StatusCode != http.StatusOK {
ER := new(ErrorResponse)
if err := xml.NewDecoder(resp.Body).Decode(ER); err != nil {
return ObjectAttributes{}, err
}

return ObjectAttributes{}, *ER
}

defer closeResponse(resp)
zveinn marked this conversation as resolved.
Show resolved Hide resolved

OA := new(ObjectAttributes)
err = OA.parseResponse(resp)
if err != nil {
return ObjectAttributes{}, err
}

return *OA, nil
}
11 changes: 11 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,23 @@
)

const (
GetObjectAttributesTags = "ETag,Checksum,StorageClass,ObjectSize,ObjectParts"

Check failure on line 63 in constants.go

View workflow job for this annotation

GitHub Actions / Test on Go 1.20.x and ubuntu-latest

exported: exported const GetObjectAttributesTags should have comment (or a comment on this block) or be unexported (revive)

Check failure on line 63 in constants.go

View workflow job for this annotation

GitHub Actions / Test on Go 1.21.x and ubuntu-latest

exported: exported const GetObjectAttributesTags should have comment (or a comment on this block) or be unexported (revive)
)

const (

// Storage class header.
amzStorageClass = "X-Amz-Storage-Class"

// Website redirect location header
amzWebsiteRedirectLocation = "X-Amz-Website-Redirect-Location"

// GetObjectAttributes headers
amzPartNumberMarker = "X-Amz-Part-Number-Marker"
amzExpectedBucketOnwer = "X-Amz-Expected-Bucket-Owner"
amzMaxParts = "X-Amz-Max-Parts"
amzObjectAttributes = "X-Amz-Object-Attributes"

// Object Tagging headers
amzTaggingHeader = "X-Amz-Tagging"
amzTaggingHeaderDirective = "X-Amz-Tagging-Directive"
Expand Down