frostfs-sdk-go/eacl/filter.go

210 lines
4.8 KiB
Go

package eacl
import (
"strconv"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
)
// Filter defines check conditions if request header is matched or not. Matched
// header means that request should be processed according to ContainerEACL action.
//
// Filter is compatible with v2 acl.EACLRecord.Filter message.
type Filter struct {
from FilterHeaderType
matcher Match
key filterKey
value stringEncoder
}
type staticStringer string
type u64Stringer uint64
type filterKey struct {
typ filterKeyType
str string
}
// enumeration of reserved filter keys.
type filterKeyType int
const (
_ filterKeyType = iota
fKeyObjVersion
fKeyObjID
fKeyObjContainerID
fKeyObjOwnerID
fKeyObjCreationEpoch
fKeyObjPayloadLength
fKeyObjPayloadHash
fKeyObjType
fKeyObjHomomorphicHash
fKeyObjLast // helper, used in tests
)
func (s staticStringer) EncodeToString() string {
return string(s)
}
func (u u64Stringer) EncodeToString() string {
return strconv.FormatUint(uint64(u), 10)
}
// Value returns filtered string value.
func (f Filter) Value() string {
return f.value.EncodeToString()
}
// Matcher returns filter Match type.
func (f Filter) Matcher() Match {
return f.matcher
}
// Key returns key to the filtered header.
func (f Filter) Key() string {
return f.key.String()
}
// From returns FilterHeaderType that defined which header will be filtered.
func (f Filter) From() FilterHeaderType {
return f.from
}
// ToV2 converts Filter to v2 acl.EACLRecord.Filter message.
//
// Nil Filter converts to nil.
func (f *Filter) ToV2() *v2acl.HeaderFilter {
if f == nil {
return nil
}
filter := new(v2acl.HeaderFilter)
filter.SetValue(f.value.EncodeToString())
filter.SetKey(f.key.String())
filter.SetMatchType(f.matcher.ToV2())
filter.SetHeaderType(f.from.ToV2())
return filter
}
func (k filterKey) String() string {
switch k.typ {
default:
return k.str
case fKeyObjVersion:
return v2acl.FilterObjectVersion
case fKeyObjID:
return v2acl.FilterObjectID
case fKeyObjContainerID:
return v2acl.FilterObjectContainerID
case fKeyObjOwnerID:
return v2acl.FilterObjectOwnerID
case fKeyObjCreationEpoch:
return v2acl.FilterObjectCreationEpoch
case fKeyObjPayloadLength:
return v2acl.FilterObjectPayloadLength
case fKeyObjPayloadHash:
return v2acl.FilterObjectPayloadHash
case fKeyObjType:
return v2acl.FilterObjectType
case fKeyObjHomomorphicHash:
return v2acl.FilterObjectHomomorphicHash
}
}
func (k *filterKey) fromString(s string) {
switch s {
default:
k.typ, k.str = 0, s
case v2acl.FilterObjectVersion:
k.typ, k.str = fKeyObjVersion, ""
case v2acl.FilterObjectID:
k.typ, k.str = fKeyObjID, ""
case v2acl.FilterObjectContainerID:
k.typ, k.str = fKeyObjContainerID, ""
case v2acl.FilterObjectOwnerID:
k.typ, k.str = fKeyObjOwnerID, ""
case v2acl.FilterObjectCreationEpoch:
k.typ, k.str = fKeyObjCreationEpoch, ""
case v2acl.FilterObjectPayloadLength:
k.typ, k.str = fKeyObjPayloadLength, ""
case v2acl.FilterObjectPayloadHash:
k.typ, k.str = fKeyObjPayloadHash, ""
case v2acl.FilterObjectType:
k.typ, k.str = fKeyObjType, ""
case v2acl.FilterObjectHomomorphicHash:
k.typ, k.str = fKeyObjHomomorphicHash, ""
}
}
// NewFilter creates, initializes and returns blank Filter instance.
//
// Defaults:
// - header type: HeaderTypeUnknown;
// - matcher: MatchUnknown;
// - key: "";
// - value: "".
func NewFilter() *Filter {
return NewFilterFromV2(new(v2acl.HeaderFilter))
}
// NewFilterFromV2 converts v2 acl.EACLRecord.Filter message to Filter.
func NewFilterFromV2(filter *v2acl.HeaderFilter) *Filter {
f := new(Filter)
if filter == nil {
return f
}
f.from = FilterHeaderTypeFromV2(filter.GetHeaderType())
f.matcher = MatchFromV2(filter.GetMatchType())
f.key.fromString(filter.GetKey())
f.value = staticStringer(filter.GetValue())
return f
}
// Marshal marshals Filter into a protobuf binary form.
func (f *Filter) Marshal() ([]byte, error) {
return f.ToV2().StableMarshal(nil), nil
}
// Unmarshal unmarshals protobuf binary representation of Filter.
func (f *Filter) Unmarshal(data []byte) error {
fV2 := new(v2acl.HeaderFilter)
if err := fV2.Unmarshal(data); err != nil {
return err
}
*f = *NewFilterFromV2(fV2)
return nil
}
// MarshalJSON encodes Filter to protobuf JSON format.
func (f *Filter) MarshalJSON() ([]byte, error) {
return f.ToV2().MarshalJSON()
}
// UnmarshalJSON decodes Filter from protobuf JSON format.
func (f *Filter) UnmarshalJSON(data []byte) error {
fV2 := new(v2acl.HeaderFilter)
if err := fV2.UnmarshalJSON(data); err != nil {
return err
}
*f = *NewFilterFromV2(fV2)
return nil
}
// equalFilters compares Filter with each other.
func equalFilters(f1, f2 Filter) bool {
return f1.From() == f2.From() &&
f1.Matcher() == f2.Matcher() &&
f1.Key() == f2.Key() &&
f1.Value() == f2.Value()
}