mirror of
https://github.com/versity/versitygw.git
synced 2026-01-05 11:24:52 +00:00
feat: implements advanced routing for HeadObject and bucket PUT operations.
This commit is contained in:
@@ -2538,266 +2538,6 @@ const (
|
||||
timefmt = "Mon, 02 Jan 2006 15:04:05 GMT"
|
||||
)
|
||||
|
||||
func (c S3ApiController) HeadObject(ctx *fiber.Ctx) error {
|
||||
bucket := ctx.Params("bucket")
|
||||
acct := utils.ContextKeyAccount.Get(ctx).(auth.Account)
|
||||
isRoot := utils.ContextKeyIsRoot.Get(ctx).(bool)
|
||||
parsedAcl := utils.ContextKeyParsedAcl.Get(ctx).(auth.ACL)
|
||||
isPublicBucket := utils.ContextKeyPublicBucket.IsSet(ctx)
|
||||
partNumberQuery := int32(ctx.QueryInt("partNumber", -1))
|
||||
versionId := ctx.Query("versionId")
|
||||
objRange := ctx.Get("Range")
|
||||
key := ctx.Params("key")
|
||||
keyEnd := ctx.Params("*1")
|
||||
if keyEnd != "" {
|
||||
key = strings.Join([]string{key, keyEnd}, "/")
|
||||
}
|
||||
path := ctx.Path()
|
||||
if path[len(path)-1:] == "/" && key[len(key)-1:] != "/" {
|
||||
key = key + "/"
|
||||
}
|
||||
|
||||
var partNumber *int32
|
||||
if ctx.Request().URI().QueryArgs().Has("partNumber") {
|
||||
if partNumberQuery < 1 || partNumberQuery > 10000 {
|
||||
if c.debug {
|
||||
debuglogger.Logf("invalid part number: %d", partNumberQuery)
|
||||
}
|
||||
return SendResponse(ctx, s3err.GetAPIError(s3err.ErrInvalidPartNumber),
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
MetricsMng: c.mm,
|
||||
Action: metrics.ActionHeadObject,
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
partNumber = &partNumberQuery
|
||||
}
|
||||
|
||||
err := auth.VerifyAccess(ctx.Context(), c.be,
|
||||
auth.AccessOptions{
|
||||
Readonly: c.readonly,
|
||||
Acl: parsedAcl,
|
||||
AclPermission: auth.PermissionRead,
|
||||
IsRoot: isRoot,
|
||||
Acc: acct,
|
||||
Bucket: bucket,
|
||||
Object: key,
|
||||
Action: auth.GetObjectAction,
|
||||
IsBucketPublic: isPublicBucket,
|
||||
})
|
||||
if err != nil {
|
||||
return SendResponse(ctx, err,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
MetricsMng: c.mm,
|
||||
Action: metrics.ActionHeadObject,
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
checksumMode := types.ChecksumMode(ctx.Get("x-amz-checksum-mode"))
|
||||
if checksumMode != "" && checksumMode != types.ChecksumModeEnabled {
|
||||
if c.debug {
|
||||
debuglogger.Logf("invalid x-amz-checksum-mode header value: %v", checksumMode)
|
||||
}
|
||||
return SendResponse(ctx, s3err.GetInvalidChecksumHeaderErr("x-amz-checksum-mode"),
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
MetricsMng: c.mm,
|
||||
Action: metrics.ActionHeadObject,
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
res, err := c.be.HeadObject(ctx.Context(),
|
||||
&s3.HeadObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: &key,
|
||||
PartNumber: partNumber,
|
||||
VersionId: &versionId,
|
||||
ChecksumMode: checksumMode,
|
||||
Range: &objRange,
|
||||
})
|
||||
if err != nil {
|
||||
if res != nil {
|
||||
utils.SetResponseHeaders(ctx, []utils.CustomHeader{
|
||||
{
|
||||
Key: "x-amz-delete-marker",
|
||||
Value: "true",
|
||||
},
|
||||
{
|
||||
Key: "Last-Modified",
|
||||
Value: res.LastModified.UTC().Format(timefmt),
|
||||
},
|
||||
})
|
||||
}
|
||||
return SendResponse(ctx, err,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
MetricsMng: c.mm,
|
||||
Action: metrics.ActionHeadObject,
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
utils.SetMetaHeaders(ctx, res.Metadata)
|
||||
headers := []utils.CustomHeader{
|
||||
{
|
||||
Key: "Content-Length",
|
||||
Value: fmt.Sprint(getint64(res.ContentLength)),
|
||||
},
|
||||
{
|
||||
Key: "ETag",
|
||||
Value: getstring(res.ETag),
|
||||
},
|
||||
{
|
||||
Key: "x-amz-restore",
|
||||
Value: getstring(res.Restore),
|
||||
},
|
||||
}
|
||||
if getstring(res.AcceptRanges) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "accept-ranges",
|
||||
Value: getstring(res.AcceptRanges),
|
||||
})
|
||||
}
|
||||
if getstring(res.ContentRange) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Content-Range",
|
||||
Value: getstring(res.ContentRange),
|
||||
})
|
||||
}
|
||||
if getstring(res.ContentDisposition) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Content-Disposition",
|
||||
Value: getstring(res.ContentDisposition),
|
||||
})
|
||||
}
|
||||
if getstring(res.ContentEncoding) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Content-Encoding",
|
||||
Value: getstring(res.ContentEncoding),
|
||||
})
|
||||
}
|
||||
if getstring(res.ContentLanguage) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Content-Language",
|
||||
Value: getstring(res.ContentLanguage),
|
||||
})
|
||||
}
|
||||
if getstring(res.CacheControl) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Cache-Control",
|
||||
Value: getstring(res.CacheControl),
|
||||
})
|
||||
}
|
||||
if getstring(res.ExpiresString) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Expires",
|
||||
Value: getstring(res.ExpiresString),
|
||||
})
|
||||
}
|
||||
if res.ObjectLockMode != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-object-lock-mode",
|
||||
Value: string(res.ObjectLockMode),
|
||||
})
|
||||
}
|
||||
if res.ObjectLockLegalHoldStatus != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-object-lock-legal-hold",
|
||||
Value: string(res.ObjectLockLegalHoldStatus),
|
||||
})
|
||||
}
|
||||
if res.ObjectLockRetainUntilDate != nil {
|
||||
retainUntilDate := res.ObjectLockRetainUntilDate.Format(time.RFC3339)
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-object-lock-retain-until-date",
|
||||
Value: retainUntilDate,
|
||||
})
|
||||
}
|
||||
if res.PartsCount != nil {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-mp-parts-count",
|
||||
Value: fmt.Sprintf("%v", *res.PartsCount),
|
||||
})
|
||||
}
|
||||
if res.LastModified != nil {
|
||||
lastmod := res.LastModified.UTC().Format(timefmt)
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Last-Modified",
|
||||
Value: lastmod,
|
||||
})
|
||||
}
|
||||
if res.StorageClass != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-storage-class",
|
||||
Value: string(res.StorageClass),
|
||||
})
|
||||
}
|
||||
switch {
|
||||
case res.ChecksumCRC32 != nil:
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-checksum-crc32",
|
||||
Value: *res.ChecksumCRC32,
|
||||
})
|
||||
case res.ChecksumCRC32C != nil:
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-checksum-crc32c",
|
||||
Value: *res.ChecksumCRC32C,
|
||||
})
|
||||
case res.ChecksumCRC64NVME != nil:
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-checksum-crc64nvme",
|
||||
Value: *res.ChecksumCRC64NVME,
|
||||
})
|
||||
case res.ChecksumSHA1 != nil:
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-checksum-sha1",
|
||||
Value: *res.ChecksumSHA1,
|
||||
})
|
||||
case res.ChecksumSHA256 != nil:
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-checksum-sha256",
|
||||
Value: *res.ChecksumSHA256,
|
||||
})
|
||||
}
|
||||
if res.ChecksumType != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-checksum-type",
|
||||
Value: string(res.ChecksumType),
|
||||
})
|
||||
}
|
||||
|
||||
contentType := getstring(res.ContentType)
|
||||
if contentType == "" {
|
||||
contentType = defaultContentType
|
||||
}
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "Content-Type",
|
||||
Value: contentType,
|
||||
})
|
||||
|
||||
if getstring(res.VersionId) != "" {
|
||||
headers = append(headers, utils.CustomHeader{
|
||||
Key: "x-amz-version-id",
|
||||
Value: getstring(res.VersionId),
|
||||
})
|
||||
}
|
||||
|
||||
utils.SetResponseHeaders(ctx, headers)
|
||||
|
||||
return SendResponse(ctx, nil,
|
||||
&MetaOpts{
|
||||
Logger: c.logger,
|
||||
MetricsMng: c.mm,
|
||||
Action: metrics.ActionHeadObject,
|
||||
BucketOwner: parsedAcl.Owner,
|
||||
})
|
||||
}
|
||||
|
||||
func (c S3ApiController) CreateActions(ctx *fiber.Ctx) error {
|
||||
bucket := ctx.Params("bucket")
|
||||
key := ctx.Params("key")
|
||||
|
||||
Reference in New Issue
Block a user