2020-07-03 13:52:04 +00:00
|
|
|
package layer
|
|
|
|
|
|
|
|
import (
|
2021-07-28 13:27:06 +00:00
|
|
|
"context"
|
2022-05-12 16:58:11 +00:00
|
|
|
"encoding/hex"
|
2021-07-28 13:27:06 +00:00
|
|
|
"fmt"
|
2020-08-03 11:48:33 +00:00
|
|
|
"os"
|
2020-10-24 13:09:22 +00:00
|
|
|
"strconv"
|
2020-07-03 13:52:04 +00:00
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2021-07-28 13:27:06 +00:00
|
|
|
"github.com/nspcc-dev/neofs-s3-gw/api"
|
2021-09-10 06:56:56 +00:00
|
|
|
"github.com/nspcc-dev/neofs-s3-gw/api/data"
|
2021-07-28 13:27:06 +00:00
|
|
|
"github.com/nspcc-dev/neofs-s3-gw/creds/accessbox"
|
2021-11-15 12:56:16 +00:00
|
|
|
"github.com/nspcc-dev/neofs-sdk-go/object"
|
2020-07-03 13:52:04 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
2021-07-18 13:40:19 +00:00
|
|
|
// ListObjectsInfo contains common fields of data for ListObjectsV1 and ListObjectsV2.
|
2020-08-03 11:48:33 +00:00
|
|
|
ListObjectsInfo struct {
|
2021-07-18 13:40:19 +00:00
|
|
|
Prefixes []string
|
2021-09-10 06:56:56 +00:00
|
|
|
Objects []*data.ObjectInfo
|
2020-08-03 11:48:33 +00:00
|
|
|
IsTruncated bool
|
2021-07-18 13:40:19 +00:00
|
|
|
}
|
2020-08-03 11:48:33 +00:00
|
|
|
|
2021-07-18 13:40:19 +00:00
|
|
|
// ListObjectsInfoV1 holds data which ListObjectsV1 returns.
|
|
|
|
ListObjectsInfoV1 struct {
|
|
|
|
ListObjectsInfo
|
2021-06-25 12:54:25 +00:00
|
|
|
NextMarker string
|
2021-07-18 13:40:19 +00:00
|
|
|
}
|
2021-06-25 12:54:25 +00:00
|
|
|
|
2021-07-18 13:40:19 +00:00
|
|
|
// ListObjectsInfoV2 holds data which ListObjectsV2 returns.
|
|
|
|
ListObjectsInfoV2 struct {
|
|
|
|
ListObjectsInfo
|
|
|
|
NextContinuationToken string
|
2020-07-03 13:52:04 +00:00
|
|
|
}
|
2021-07-05 19:18:58 +00:00
|
|
|
|
|
|
|
// ObjectVersionInfo stores info about objects versions.
|
|
|
|
ObjectVersionInfo struct {
|
2022-05-31 15:03:58 +00:00
|
|
|
Object *data.ObjectInfo
|
|
|
|
IsLatest bool
|
|
|
|
IsUnversioned bool
|
2021-07-05 19:18:58 +00:00
|
|
|
}
|
|
|
|
|
2022-04-13 16:56:58 +00:00
|
|
|
// ListObjectVersionsInfo stores info and list of objects versions.
|
2021-07-05 19:18:58 +00:00
|
|
|
ListObjectVersionsInfo struct {
|
2021-08-18 13:48:58 +00:00
|
|
|
CommonPrefixes []string
|
2021-07-05 19:18:58 +00:00
|
|
|
IsTruncated bool
|
|
|
|
KeyMarker string
|
|
|
|
NextKeyMarker string
|
|
|
|
NextVersionIDMarker string
|
|
|
|
Version []*ObjectVersionInfo
|
2021-08-13 14:13:14 +00:00
|
|
|
DeleteMarker []*ObjectVersionInfo
|
2021-07-05 19:18:58 +00:00
|
|
|
VersionIDMarker string
|
|
|
|
}
|
2020-07-03 13:52:04 +00:00
|
|
|
)
|
|
|
|
|
2021-06-29 09:59:33 +00:00
|
|
|
// PathSeparator is a path components separator string.
|
|
|
|
const PathSeparator = string(os.PathSeparator)
|
2020-07-03 13:52:04 +00:00
|
|
|
|
2022-03-16 09:02:16 +00:00
|
|
|
func userHeaders(attrs []object.Attribute) map[string]string {
|
2020-10-19 01:04:37 +00:00
|
|
|
result := make(map[string]string, len(attrs))
|
2020-07-03 13:52:04 +00:00
|
|
|
|
2020-10-19 01:04:37 +00:00
|
|
|
for _, attr := range attrs {
|
2020-11-24 07:01:38 +00:00
|
|
|
result[attr.Key()] = attr.Value()
|
2020-07-03 13:52:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-09-10 06:56:56 +00:00
|
|
|
func objInfoFromMeta(bkt *data.BucketInfo, meta *object.Object) *data.ObjectInfo {
|
2021-08-18 13:48:58 +00:00
|
|
|
return objectInfoFromMeta(bkt, meta, "", "")
|
|
|
|
}
|
|
|
|
|
2021-09-10 06:56:56 +00:00
|
|
|
func objectInfoFromMeta(bkt *data.BucketInfo, meta *object.Object, prefix, delimiter string) *data.ObjectInfo {
|
2020-10-24 13:09:22 +00:00
|
|
|
var (
|
2021-06-29 09:59:33 +00:00
|
|
|
isDir bool
|
|
|
|
size int64
|
|
|
|
mimeType string
|
|
|
|
creation time.Time
|
|
|
|
filename = filenameFromObject(meta)
|
2020-10-24 13:09:22 +00:00
|
|
|
)
|
2020-07-03 13:52:04 +00:00
|
|
|
|
2021-06-29 09:59:33 +00:00
|
|
|
if !strings.HasPrefix(filename, prefix) {
|
2021-01-14 17:39:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-11-24 07:01:38 +00:00
|
|
|
userHeaders := userHeaders(meta.Attributes())
|
2021-06-29 09:59:33 +00:00
|
|
|
delete(userHeaders, object.AttributeFileName)
|
|
|
|
if contentType, ok := userHeaders[object.AttributeContentType]; ok {
|
|
|
|
mimeType = contentType
|
|
|
|
delete(userHeaders, object.AttributeContentType)
|
2020-10-24 13:09:22 +00:00
|
|
|
}
|
|
|
|
if val, ok := userHeaders[object.AttributeTimestamp]; !ok {
|
|
|
|
// ignore empty value
|
|
|
|
} else if dt, err := strconv.ParseInt(val, 10, 64); err == nil {
|
|
|
|
creation = time.Unix(dt, 0)
|
|
|
|
delete(userHeaders, object.AttributeTimestamp)
|
2020-07-03 13:52:04 +00:00
|
|
|
}
|
|
|
|
|
2021-06-29 09:59:33 +00:00
|
|
|
if len(delimiter) > 0 {
|
|
|
|
tail := strings.TrimPrefix(filename, prefix)
|
|
|
|
index := strings.Index(tail, delimiter)
|
|
|
|
if index >= 0 {
|
|
|
|
isDir = true
|
2021-07-07 15:49:59 +00:00
|
|
|
mimeType = ""
|
2021-06-29 09:59:33 +00:00
|
|
|
filename = prefix + tail[:index+1]
|
|
|
|
userHeaders = nil
|
|
|
|
} else {
|
2021-06-30 12:29:01 +00:00
|
|
|
size = int64(meta.PayloadSize())
|
2021-06-29 09:59:33 +00:00
|
|
|
}
|
2021-01-14 17:39:48 +00:00
|
|
|
} else {
|
2021-06-30 12:29:01 +00:00
|
|
|
size = int64(meta.PayloadSize())
|
2021-01-14 17:39:48 +00:00
|
|
|
}
|
2020-08-03 11:48:33 +00:00
|
|
|
|
2022-04-25 09:57:58 +00:00
|
|
|
objID, _ := meta.ID()
|
|
|
|
payloadChecksum, _ := meta.PayloadChecksum()
|
2021-09-10 06:56:56 +00:00
|
|
|
return &data.ObjectInfo{
|
2022-05-25 17:25:43 +00:00
|
|
|
ID: objID,
|
2021-08-27 21:33:50 +00:00
|
|
|
CID: bkt.CID,
|
|
|
|
IsDir: isDir,
|
2021-08-13 14:13:14 +00:00
|
|
|
|
|
|
|
Bucket: bkt.Name,
|
|
|
|
Name: filename,
|
|
|
|
Created: creation,
|
|
|
|
CreationEpoch: meta.CreationEpoch(),
|
|
|
|
ContentType: mimeType,
|
|
|
|
Headers: userHeaders,
|
2022-05-25 17:25:43 +00:00
|
|
|
Owner: *meta.OwnerID(),
|
2021-08-13 14:13:14 +00:00
|
|
|
Size: size,
|
2022-05-12 16:58:11 +00:00
|
|
|
HashSum: hex.EncodeToString(payloadChecksum.Value()),
|
2021-07-05 19:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-29 09:59:33 +00:00
|
|
|
func filenameFromObject(o *object.Object) string {
|
2020-11-24 07:01:38 +00:00
|
|
|
for _, attr := range o.Attributes() {
|
|
|
|
if attr.Key() == object.AttributeFileName {
|
2021-06-29 09:59:33 +00:00
|
|
|
return attr.Value()
|
2020-10-19 01:04:37 +00:00
|
|
|
}
|
2020-07-03 13:52:04 +00:00
|
|
|
}
|
2022-04-25 09:57:58 +00:00
|
|
|
objID, _ := o.ID()
|
2022-05-25 17:25:43 +00:00
|
|
|
return objID.EncodeToString()
|
2021-01-14 17:39:48 +00:00
|
|
|
}
|
2020-07-03 13:52:04 +00:00
|
|
|
|
2022-04-13 16:56:58 +00:00
|
|
|
// NameFromString splits name into a base file name and a directory path.
|
2021-01-14 17:39:48 +00:00
|
|
|
func NameFromString(name string) (string, string) {
|
|
|
|
ind := strings.LastIndex(name, PathSeparator)
|
2020-07-03 13:52:04 +00:00
|
|
|
return name[ind+1:], name[:ind+1]
|
|
|
|
}
|
2020-10-24 13:09:22 +00:00
|
|
|
|
2021-07-28 13:27:06 +00:00
|
|
|
// GetBoxData extracts accessbox.Box from context.
|
|
|
|
func GetBoxData(ctx context.Context) (*accessbox.Box, error) {
|
|
|
|
var boxData *accessbox.Box
|
|
|
|
data, ok := ctx.Value(api.BoxData).(*accessbox.Box)
|
|
|
|
if !ok || data == nil {
|
|
|
|
return nil, fmt.Errorf("couldn't get box data from context")
|
|
|
|
}
|
|
|
|
|
|
|
|
boxData = data
|
|
|
|
if boxData.Gate == nil {
|
|
|
|
boxData.Gate = &accessbox.GateData{}
|
|
|
|
}
|
|
|
|
return boxData, nil
|
|
|
|
}
|