frostfs-node/pkg/services/object/acl/eacl/v2/headers.go
Evgenii Stratonikov b24589b62d [#1386] eacl/v2: Use raw structs where possible
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
2022-05-20 12:04:10 +03:00

246 lines
5.6 KiB
Go

package v2
import (
"errors"
"fmt"
"github.com/nspcc-dev/neofs-api-go/v2/acl"
objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object"
refsV2 "github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-api-go/v2/session"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
eaclSDK "github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/object"
objectSDKAddress "github.com/nspcc-dev/neofs-sdk-go/object/address"
objectSDKID "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/owner"
sessionSDK "github.com/nspcc-dev/neofs-sdk-go/session"
)
type Option func(*cfg)
type cfg struct {
storage ObjectStorage
msg xHeaderSource
addr *objectSDKAddress.Address
}
type ObjectStorage interface {
Head(*objectSDKAddress.Address) (*object.Object, error)
}
type Request interface {
GetMetaHeader() *session.RequestMetaHeader
}
type Response interface {
GetMetaHeader() *session.ResponseMetaHeader
}
type headerSource struct {
requestHeaders []eaclSDK.Header
objectHeaders []eaclSDK.Header
}
func defaultCfg() *cfg {
return &cfg{
storage: new(localStorage),
}
}
func NewMessageHeaderSource(opts ...Option) (eaclSDK.TypedHeaderSource, error) {
cfg := defaultCfg()
for i := range opts {
opts[i](cfg)
}
if cfg.msg == nil {
return nil, errors.New("message is not provided")
}
objHdrs, err := cfg.objectHeaders()
if err != nil {
return nil, err
}
return headerSource{
objectHeaders: objHdrs,
requestHeaders: requestHeaders(cfg.msg),
}, nil
}
func (h headerSource) HeadersOfType(typ eaclSDK.FilterHeaderType) ([]eaclSDK.Header, bool) {
switch typ {
default:
return nil, true
case eaclSDK.HeaderFromRequest:
return h.requestHeaders, true
case eaclSDK.HeaderFromObject:
return h.objectHeaders, true
}
}
func requestHeaders(msg xHeaderSource) []eaclSDK.Header {
xHdrs := msg.GetXHeaders()
res := make([]eaclSDK.Header, 0, len(xHdrs))
for i := range xHdrs {
res = append(res, sessionSDK.NewXHeaderFromV2(&xHdrs[i]))
}
return res
}
func (h *cfg) objectHeaders() ([]eaclSDK.Header, error) {
switch m := h.msg.(type) {
default:
panic(fmt.Sprintf("unexpected message type %T", h.msg))
case requestXHeaderSource:
switch req := m.req.(type) {
case *objectV2.GetRequest:
return h.localObjectHeaders(h.addr)
case *objectV2.HeadRequest:
return h.localObjectHeaders(h.addr)
case
*objectV2.GetRangeRequest,
*objectV2.GetRangeHashRequest,
*objectV2.DeleteRequest:
return addressHeaders(h.addr), nil
case *objectV2.PutRequest:
if v, ok := req.GetBody().GetObjectPart().(*objectV2.PutObjectPartInit); ok {
oV2 := new(objectV2.Object)
oV2.SetObjectID(v.GetObjectID())
oV2.SetHeader(v.GetHeader())
if h.addr == nil {
idV2 := v.GetObjectID()
var id objectSDKID.ID
if idV2 != nil {
if err := id.ReadFromV2(*idV2); err != nil {
return nil, fmt.Errorf("can't parse object ID: %w", err)
}
}
cnrV2 := v.GetHeader().GetContainerID()
var cnr cid.ID
if cnrV2 != nil {
if err := cnr.ReadFromV2(*cnrV2); err != nil {
return nil, fmt.Errorf("can't parse container ID: %w", err)
}
}
h.addr = new(objectSDKAddress.Address)
h.addr.SetContainerID(cnr)
h.addr.SetObjectID(id)
}
hs := headersFromObject(object.NewFromV2(oV2), h.addr)
return hs, nil
}
case *objectV2.SearchRequest:
cnrV2 := req.GetBody().GetContainerID()
var cnr cid.ID
if cnrV2 != nil {
if err := cnr.ReadFromV2(*cnrV2); err != nil {
return nil, fmt.Errorf("can't parse container ID: %w", err)
}
}
return []eaclSDK.Header{cidHeader(cnr)}, nil
}
case responseXHeaderSource:
switch resp := m.resp.(type) {
default:
hs, _ := h.localObjectHeaders(h.addr)
return hs, nil
case *objectV2.GetResponse:
if v, ok := resp.GetBody().GetObjectPart().(*objectV2.GetObjectPartInit); ok {
oV2 := new(objectV2.Object)
oV2.SetObjectID(v.GetObjectID())
oV2.SetHeader(v.GetHeader())
return headersFromObject(object.NewFromV2(oV2), h.addr), nil
}
case *objectV2.HeadResponse:
oV2 := new(objectV2.Object)
var hdr *objectV2.Header
switch v := resp.GetBody().GetHeaderPart().(type) {
case *objectV2.ShortHeader:
hdr = new(objectV2.Header)
id, _ := h.addr.ContainerID()
var idV2 refsV2.ContainerID
id.WriteToV2(&idV2)
hdr.SetContainerID(&idV2)
hdr.SetVersion(v.GetVersion())
hdr.SetCreationEpoch(v.GetCreationEpoch())
hdr.SetOwnerID(v.GetOwnerID())
hdr.SetObjectType(v.GetObjectType())
hdr.SetPayloadLength(v.GetPayloadLength())
case *objectV2.HeaderWithSignature:
hdr = v.GetHeader()
}
oV2.SetHeader(hdr)
return headersFromObject(object.NewFromV2(oV2), h.addr), nil
}
}
return nil, nil
}
func (h *cfg) localObjectHeaders(addr *objectSDKAddress.Address) ([]eaclSDK.Header, error) {
obj, err := h.storage.Head(addr)
if err != nil {
// Still parse addressHeaders, because the errors is ignored in some places.
return addressHeaders(addr), err
}
return headersFromObject(obj, addr), nil
}
func cidHeader(idCnr cid.ID) sysObjHdr {
return sysObjHdr{
k: acl.FilterObjectContainerID,
v: idCnr.String(),
}
}
func oidHeader(oid objectSDKID.ID) sysObjHdr {
return sysObjHdr{
k: acl.FilterObjectID,
v: oid.String(),
}
}
func ownerIDHeader(ownerID *owner.ID) sysObjHdr {
return sysObjHdr{
k: acl.FilterObjectOwnerID,
v: ownerID.String(),
}
}
func addressHeaders(addr *objectSDKAddress.Address) []eaclSDK.Header {
cnr, _ := addr.ContainerID()
res := make([]eaclSDK.Header, 1, 2)
res[0] = cidHeader(cnr)
if oid, ok := addr.ObjectID(); ok {
res = append(res, oidHeader(oid))
}
return res
}