mirror of
https://github.com/minio/minio.git
synced 2026-02-04 18:00:15 -05:00
feat: add support for GetObjectAttributes API (#18732)
This commit is contained in:
@@ -689,6 +689,155 @@ func (api objectAPIHandlers) getObjectHandler(ctx context.Context, objectAPI Obj
|
||||
})
|
||||
}
|
||||
|
||||
// GetObjectAttributes ...
|
||||
func (api objectAPIHandlers) getObjectAttributesHandler(ctx context.Context, objectAPI ObjectLayer, bucket, object string, w http.ResponseWriter, r *http.Request) {
|
||||
opts, valid := getAndValidateAttributesOpts(ctx, w, r, bucket, object)
|
||||
if !valid {
|
||||
return
|
||||
}
|
||||
|
||||
var s3Error APIErrorCode
|
||||
if opts.VersionID != "" {
|
||||
s3Error = checkRequestAuthType(ctx, r, policy.GetObjectVersionAttributesAction, bucket, object)
|
||||
if s3Error == ErrNone {
|
||||
s3Error = checkRequestAuthType(ctx, r, policy.GetObjectVersionAction, bucket, object)
|
||||
}
|
||||
} else {
|
||||
s3Error = checkRequestAuthType(ctx, r, policy.GetObjectAttributesAction, bucket, object)
|
||||
if s3Error == ErrNone {
|
||||
s3Error = checkRequestAuthType(ctx, r, policy.GetObjectAction, bucket, object)
|
||||
}
|
||||
}
|
||||
|
||||
if s3Error != ErrNone {
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(s3Error), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
objInfo, err := objectAPI.GetObjectInfo(ctx, bucket, object, opts)
|
||||
if err != nil {
|
||||
s3Error = checkRequestAuthType(ctx, r, policy.ListBucketAction, bucket, object)
|
||||
if s3Error == ErrNone {
|
||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
writeErrorResponse(ctx, w, errorCodes.ToAPIErr(ErrAccessDenied), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = DecryptObjectInfo(&objInfo, r); err != nil {
|
||||
writeErrorResponseHeadersOnly(w, toAPIError(ctx, err))
|
||||
return
|
||||
}
|
||||
|
||||
if checkPreconditions(ctx, w, r, objInfo, opts) {
|
||||
return
|
||||
}
|
||||
|
||||
OA := new(getObjectAttributesResponse)
|
||||
|
||||
if opts.Versioned {
|
||||
w.Header().Set(xhttp.AmzVersionID, objInfo.VersionID)
|
||||
}
|
||||
|
||||
lastModified := objInfo.ModTime.UTC().Format(http.TimeFormat)
|
||||
w.Header().Set(xhttp.LastModified, lastModified)
|
||||
w.Header().Del(xhttp.ContentType)
|
||||
|
||||
if _, ok := opts.ObjectAttributes[xhttp.Checksum]; ok {
|
||||
chkSums := objInfo.decryptChecksums(0)
|
||||
// AWS does not appear to append part number on this API call.
|
||||
switch {
|
||||
case chkSums["CRC32"] != "":
|
||||
OA.Checksum = new(objectAttributesChecksum)
|
||||
OA.Checksum.ChecksumCRC32 = strings.Split(chkSums["CRC32"], "-")[0]
|
||||
case chkSums["CRC32C"] != "":
|
||||
OA.Checksum = new(objectAttributesChecksum)
|
||||
OA.Checksum.ChecksumCRC32C = strings.Split(chkSums["CRC32C"], "-")[0]
|
||||
case chkSums["SHA256"] != "":
|
||||
OA.Checksum = new(objectAttributesChecksum)
|
||||
OA.Checksum.ChecksumSHA1 = strings.Split(chkSums["SHA1"], "-")[0]
|
||||
case chkSums["SHA1"] != "":
|
||||
OA.Checksum = new(objectAttributesChecksum)
|
||||
OA.Checksum.ChecksumSHA256 = strings.Split(chkSums["SHA256"], "-")[0]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if _, ok := opts.ObjectAttributes[xhttp.ETag]; ok {
|
||||
OA.ETag = objInfo.ETag
|
||||
}
|
||||
|
||||
if _, ok := opts.ObjectAttributes[xhttp.ObjectSize]; ok {
|
||||
OA.ObjectSize, _ = objInfo.GetActualSize()
|
||||
}
|
||||
|
||||
if _, ok := opts.ObjectAttributes[xhttp.StorageClass]; ok {
|
||||
OA.StorageClass = objInfo.StorageClass
|
||||
}
|
||||
|
||||
objInfo.decryptPartsChecksums()
|
||||
|
||||
if _, ok := opts.ObjectAttributes[xhttp.ObjectParts]; ok {
|
||||
OA.ObjectParts = new(objectAttributesParts)
|
||||
OA.ObjectParts.PartNumberMarker = opts.PartNumberMarker
|
||||
|
||||
OA.ObjectParts.MaxParts = opts.MaxParts
|
||||
partsLength := len(objInfo.Parts)
|
||||
OA.ObjectParts.PartsCount = partsLength
|
||||
|
||||
if opts.MaxParts > -1 {
|
||||
for i, v := range objInfo.Parts {
|
||||
if v.Number <= opts.PartNumberMarker {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(OA.ObjectParts.Parts) == opts.MaxParts {
|
||||
break
|
||||
}
|
||||
|
||||
OA.ObjectParts.NextPartNumberMarker = v.Number
|
||||
OA.ObjectParts.Parts = append(OA.ObjectParts.Parts, &objectAttributesPart{
|
||||
ChecksumSHA1: objInfo.Parts[i].Checksums["SHA1"],
|
||||
ChecksumSHA256: objInfo.Parts[i].Checksums["SHA256"],
|
||||
ChecksumCRC32: objInfo.Parts[i].Checksums["CRC32"],
|
||||
ChecksumCRC32C: objInfo.Parts[i].Checksums["CRC32C"],
|
||||
PartNumber: objInfo.Parts[i].Number,
|
||||
Size: objInfo.Parts[i].Size,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if OA.ObjectParts.NextPartNumberMarker != partsLength {
|
||||
OA.ObjectParts.IsTruncated = true
|
||||
}
|
||||
}
|
||||
|
||||
outBytes, err := xml.Marshal(OA)
|
||||
if err != nil {
|
||||
writeErrorResponseHeadersOnly(w, toAPIError(ctx, err))
|
||||
}
|
||||
|
||||
writeResponse(
|
||||
w,
|
||||
200,
|
||||
append([]byte(`<?xml version="1.0" encoding="UTF-8"?>`), outBytes...),
|
||||
mimeXML,
|
||||
)
|
||||
|
||||
sendEvent(eventArgs{
|
||||
EventName: event.ObjectAccessedAttributes,
|
||||
BucketName: bucket,
|
||||
Object: objInfo,
|
||||
ReqParams: extractReqParams(r),
|
||||
RespElements: extractRespElements(w),
|
||||
UserAgent: r.UserAgent(),
|
||||
Host: handlers.GetSourceIP(r),
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetObjectHandler - GET Object
|
||||
// ----------
|
||||
// This implementation of the GET operation retrieves object. To use GET,
|
||||
@@ -1043,6 +1192,30 @@ func (api objectAPIHandlers) headObjectHandler(ctx context.Context, objectAPI Ob
|
||||
})
|
||||
}
|
||||
|
||||
// GetObjectAttributesHandles - GET Object
|
||||
// -----------
|
||||
// This operation retrieves metadata and part metadata from an object without returning the object itself.
|
||||
func (api objectAPIHandlers) GetObjectAttributesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := newContext(r, w, "GetObjectAttributes")
|
||||
defer logger.AuditLog(ctx, w, r, mustGetClaimsFromToken(r))
|
||||
|
||||
objectAPI := api.ObjectAPI()
|
||||
if objectAPI == nil {
|
||||
writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrServerNotInitialized))
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
bucket := vars["bucket"]
|
||||
object, err := unescapePath(vars["object"])
|
||||
if err != nil {
|
||||
writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL)
|
||||
return
|
||||
}
|
||||
|
||||
api.getObjectAttributesHandler(ctx, objectAPI, bucket, object, w, r)
|
||||
}
|
||||
|
||||
// HeadObjectHandler - HEAD Object
|
||||
// -----------
|
||||
// The HEAD operation retrieves metadata from an object without returning the object itself.
|
||||
|
||||
Reference in New Issue
Block a user