[#111] Move attributes to a separate file

Signed-off-by: Angira Kekteeva <kira@nspcc.ru>
This commit is contained in:
Angira Kekteeva 2021-11-30 10:22:05 +03:00 committed by Alex Vanin
parent 79501077ff
commit dbbc9e05cf
6 changed files with 52 additions and 47 deletions

View file

@ -14,6 +14,7 @@ import (
"github.com/nspcc-dev/neofs-http-gw/response" "github.com/nspcc-dev/neofs-http-gw/response"
"github.com/nspcc-dev/neofs-http-gw/tokens" "github.com/nspcc-dev/neofs-http-gw/tokens"
"github.com/nspcc-dev/neofs-http-gw/utils"
"github.com/nspcc-dev/neofs-sdk-go/client" "github.com/nspcc-dev/neofs-sdk-go/client"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/object" "github.com/nspcc-dev/neofs-sdk-go/object"
@ -152,7 +153,7 @@ func (r request) receiveFile(clnt pool.Object, objectAddress *object.Address) {
if !isValidToken(key) || !isValidValue(val) { if !isValidToken(key) || !isValidValue(val) {
continue continue
} }
r.Response.Header.Set("X-Attribute-"+key, val) r.Response.Header.Set(utils.UserAttributeHeaderPrefix+key, val)
switch key { switch key {
case object.AttributeFileName: case object.AttributeFileName:
filename = val filename = val

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neofs-http-gw/response" "github.com/nspcc-dev/neofs-http-gw/response"
"github.com/nspcc-dev/neofs-http-gw/tokens" "github.com/nspcc-dev/neofs-http-gw/tokens"
"github.com/nspcc-dev/neofs-http-gw/utils"
"github.com/nspcc-dev/neofs-sdk-go/client" "github.com/nspcc-dev/neofs-sdk-go/client"
"github.com/nspcc-dev/neofs-sdk-go/object" "github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/pool" "github.com/nspcc-dev/neofs-sdk-go/pool"
@ -40,7 +41,7 @@ func (r request) headObject(clnt pool.Object, objectAddress *object.Address) {
if !isValidToken(key) || !isValidValue(val) { if !isValidToken(key) || !isValidValue(val) {
continue continue
} }
r.Response.Header.Set("X-Attribute-"+key, val) r.Response.Header.Set(utils.UserAttributeHeaderPrefix+key, val)
switch key { switch key {
case object.AttributeTimestamp: case object.AttributeTimestamp:
value, err := strconv.ParseInt(val, 10, 64) value, err := strconv.ParseInt(val, 10, 64)

View file

@ -7,24 +7,16 @@ import (
"time" "time"
"github.com/nspcc-dev/neofs-api-go/v2/object" "github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/nspcc-dev/neofs-http-gw/utils"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
"go.uber.org/zap" "go.uber.org/zap"
) )
const (
userAttributeHeaderPrefix = "X-Attribute-"
systemAttributePrefix = "__NEOFS__"
expirationDurationAttr = systemAttributePrefix + "EXPIRATION_DURATION"
expirationTimestampAttr = systemAttributePrefix + "EXPIRATION_TIMESTAMP"
expirationRFC3339Attr = systemAttributePrefix + "EXPIRATION_RFC3339"
)
var neofsAttributeHeaderPrefixes = [...][]byte{[]byte("Neofs-"), []byte("NEOFS-"), []byte("neofs-")} var neofsAttributeHeaderPrefixes = [...][]byte{[]byte("Neofs-"), []byte("NEOFS-"), []byte("neofs-")}
func systemTranslator(key, prefix []byte) []byte { func systemTranslator(key, prefix []byte) []byte {
// replace specified prefix with `__NEOFS__` // replace specified prefix with `__NEOFS__`
key = bytes.Replace(key, prefix, []byte(systemAttributePrefix), 1) key = bytes.Replace(key, prefix, []byte(utils.SystemAttributePrefix), 1)
// replace `-` with `_` // replace `-` with `_`
key = bytes.ReplaceAll(key, []byte("-"), []byte("_")) key = bytes.ReplaceAll(key, []byte("-"), []byte("_"))
@ -35,7 +27,7 @@ func systemTranslator(key, prefix []byte) []byte {
func filterHeaders(l *zap.Logger, header *fasthttp.RequestHeader) map[string]string { func filterHeaders(l *zap.Logger, header *fasthttp.RequestHeader) map[string]string {
result := make(map[string]string) result := make(map[string]string)
prefix := []byte(userAttributeHeaderPrefix) prefix := []byte(utils.UserAttributeHeaderPrefix)
header.VisitAll(func(key, val []byte) { header.VisitAll(func(key, val []byte) {
// checks that key and val not empty // checks that key and val not empty
@ -80,45 +72,45 @@ func filterHeaders(l *zap.Logger, header *fasthttp.RequestHeader) map[string]str
func prepareExpirationHeader(headers map[string]string, epochDurations *epochDurations) error { func prepareExpirationHeader(headers map[string]string, epochDurations *epochDurations) error {
expirationInEpoch := headers[object.SysAttributeExpEpoch] expirationInEpoch := headers[object.SysAttributeExpEpoch]
if timeRFC3339, ok := headers[expirationRFC3339Attr]; ok { if timeRFC3339, ok := headers[utils.ExpirationRFC3339Attr]; ok {
expTime, err := time.Parse(time.RFC3339, timeRFC3339) expTime, err := time.Parse(time.RFC3339, timeRFC3339)
if err != nil { if err != nil {
return fmt.Errorf("couldn't parse value %s of header %s", timeRFC3339, expirationRFC3339Attr) return fmt.Errorf("couldn't parse value %s of header %s", timeRFC3339, utils.ExpirationRFC3339Attr)
} }
now := time.Now().UTC() now := time.Now().UTC()
if expTime.Before(now) { if expTime.Before(now) {
return fmt.Errorf("value %s of header %s must be in the future", timeRFC3339, expirationRFC3339Attr) return fmt.Errorf("value %s of header %s must be in the future", timeRFC3339, utils.ExpirationRFC3339Attr)
} }
updateExpirationHeader(headers, epochDurations, expTime.Sub(now)) updateExpirationHeader(headers, epochDurations, expTime.Sub(now))
delete(headers, expirationRFC3339Attr) delete(headers, utils.ExpirationRFC3339Attr)
} }
if timestamp, ok := headers[expirationTimestampAttr]; ok { if timestamp, ok := headers[utils.ExpirationTimestampAttr]; ok {
value, err := strconv.ParseInt(timestamp, 10, 64) value, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil { if err != nil {
return fmt.Errorf("couldn't parse value %s of header %s", timestamp, expirationTimestampAttr) return fmt.Errorf("couldn't parse value %s of header %s", timestamp, utils.ExpirationTimestampAttr)
} }
expTime := time.Unix(value, 0) expTime := time.Unix(value, 0)
now := time.Now() now := time.Now()
if expTime.Before(now) { if expTime.Before(now) {
return fmt.Errorf("value %s of header %s must be in the future", timestamp, expirationTimestampAttr) return fmt.Errorf("value %s of header %s must be in the future", timestamp, utils.ExpirationTimestampAttr)
} }
updateExpirationHeader(headers, epochDurations, expTime.Sub(now)) updateExpirationHeader(headers, epochDurations, expTime.Sub(now))
delete(headers, expirationTimestampAttr) delete(headers, utils.ExpirationTimestampAttr)
} }
if duration, ok := headers[expirationDurationAttr]; ok { if duration, ok := headers[utils.ExpirationDurationAttr]; ok {
expDuration, err := time.ParseDuration(duration) expDuration, err := time.ParseDuration(duration)
if err != nil { if err != nil {
return fmt.Errorf("couldn't parse value %s of header %s", duration, expirationDurationAttr) return fmt.Errorf("couldn't parse value %s of header %s", duration, utils.ExpirationDurationAttr)
} }
if expDuration <= 0 { if expDuration <= 0 {
return fmt.Errorf("value %s of header %s must be positive", expDuration, expirationDurationAttr) return fmt.Errorf("value %s of header %s must be positive", expDuration, utils.ExpirationDurationAttr)
} }
updateExpirationHeader(headers, epochDurations, expDuration) updateExpirationHeader(headers, epochDurations, expDuration)
delete(headers, expirationDurationAttr) delete(headers, utils.ExpirationDurationAttr)
} }
if expirationInEpoch != "" { if expirationInEpoch != "" {

View file

@ -6,7 +6,7 @@ import (
"time" "time"
"github.com/nspcc-dev/neofs-api-go/v2/object" "github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/nspcc-dev/neofs-http-gw/utils"
"github.com/nspcc-dev/neofs-sdk-go/logger" "github.com/nspcc-dev/neofs-sdk-go/logger"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/valyala/fasthttp" "github.com/valyala/fasthttp"
@ -72,7 +72,7 @@ func TestPrepareExpirationHeader(t *testing.T) {
name: "valid epoch, valid duration", name: "valid epoch, valid duration",
headers: map[string]string{ headers: map[string]string{
object.SysAttributeExpEpoch: epoch, object.SysAttributeExpEpoch: epoch,
expirationDurationAttr: duration, utils.ExpirationDurationAttr: duration,
}, },
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: epoch}, expected: map[string]string{object.SysAttributeExpEpoch: epoch},
@ -81,7 +81,7 @@ func TestPrepareExpirationHeader(t *testing.T) {
name: "valid epoch, valid rfc3339", name: "valid epoch, valid rfc3339",
headers: map[string]string{ headers: map[string]string{
object.SysAttributeExpEpoch: epoch, object.SysAttributeExpEpoch: epoch,
expirationRFC3339Attr: tomorrow.Format(time.RFC3339), utils.ExpirationRFC3339Attr: tomorrow.Format(time.RFC3339),
}, },
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: epoch}, expected: map[string]string{object.SysAttributeExpEpoch: epoch},
@ -90,7 +90,7 @@ func TestPrepareExpirationHeader(t *testing.T) {
name: "valid epoch, valid timestamp sec", name: "valid epoch, valid timestamp sec",
headers: map[string]string{ headers: map[string]string{
object.SysAttributeExpEpoch: epoch, object.SysAttributeExpEpoch: epoch,
expirationTimestampAttr: timestampSec, utils.ExpirationTimestampAttr: timestampSec,
}, },
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: epoch}, expected: map[string]string{object.SysAttributeExpEpoch: epoch},
@ -99,7 +99,7 @@ func TestPrepareExpirationHeader(t *testing.T) {
name: "valid epoch, valid timestamp milli", name: "valid epoch, valid timestamp milli",
headers: map[string]string{ headers: map[string]string{
object.SysAttributeExpEpoch: epoch, object.SysAttributeExpEpoch: epoch,
expirationTimestampAttr: timestampMilli, utils.ExpirationTimestampAttr: timestampMilli,
}, },
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: epoch}, expected: map[string]string{object.SysAttributeExpEpoch: epoch},
@ -108,57 +108,57 @@ func TestPrepareExpirationHeader(t *testing.T) {
name: "valid epoch, valid timestamp nano", name: "valid epoch, valid timestamp nano",
headers: map[string]string{ headers: map[string]string{
object.SysAttributeExpEpoch: epoch, object.SysAttributeExpEpoch: epoch,
expirationTimestampAttr: timestampNano, utils.ExpirationTimestampAttr: timestampNano,
}, },
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: epoch}, expected: map[string]string{object.SysAttributeExpEpoch: epoch},
}, },
{ {
name: "valid timestamp sec", name: "valid timestamp sec",
headers: map[string]string{expirationTimestampAttr: timestampSec}, headers: map[string]string{utils.ExpirationTimestampAttr: timestampSec},
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: defaultExpEpoch}, expected: map[string]string{object.SysAttributeExpEpoch: defaultExpEpoch},
}, },
{ {
name: "valid duration", name: "valid duration",
headers: map[string]string{expirationDurationAttr: duration}, headers: map[string]string{utils.ExpirationDurationAttr: duration},
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: defaultExpEpoch}, expected: map[string]string{object.SysAttributeExpEpoch: defaultExpEpoch},
}, },
{ {
name: "valid rfc3339", name: "valid rfc3339",
headers: map[string]string{expirationRFC3339Attr: tomorrow.Format(time.RFC3339)}, headers: map[string]string{utils.ExpirationRFC3339Attr: tomorrow.Format(time.RFC3339)},
durations: defaultDurations, durations: defaultDurations,
expected: map[string]string{object.SysAttributeExpEpoch: defaultExpEpoch}, expected: map[string]string{object.SysAttributeExpEpoch: defaultExpEpoch},
}, },
{ {
name: "invalid timestamp sec", name: "invalid timestamp sec",
headers: map[string]string{expirationTimestampAttr: "abc"}, headers: map[string]string{utils.ExpirationTimestampAttr: "abc"},
err: true, err: true,
}, },
{ {
name: "invalid timestamp sec zero", name: "invalid timestamp sec zero",
headers: map[string]string{expirationTimestampAttr: "0"}, headers: map[string]string{utils.ExpirationTimestampAttr: "0"},
err: true, err: true,
}, },
{ {
name: "invalid duration", name: "invalid duration",
headers: map[string]string{expirationDurationAttr: "1d"}, headers: map[string]string{utils.ExpirationDurationAttr: "1d"},
err: true, err: true,
}, },
{ {
name: "invalid duration negative", name: "invalid duration negative",
headers: map[string]string{expirationDurationAttr: "-5h"}, headers: map[string]string{utils.ExpirationDurationAttr: "-5h"},
err: true, err: true,
}, },
{ {
name: "invalid rfc3339", name: "invalid rfc3339",
headers: map[string]string{expirationRFC3339Attr: "abc"}, headers: map[string]string{utils.ExpirationRFC3339Attr: "abc"},
err: true, err: true,
}, },
{ {
name: "invalid rfc3339 zero", name: "invalid rfc3339 zero",
headers: map[string]string{expirationRFC3339Attr: time.RFC3339}, headers: map[string]string{utils.ExpirationRFC3339Attr: time.RFC3339},
err: true, err: true,
}, },
} { } {

View file

@ -11,6 +11,7 @@ import (
"github.com/nspcc-dev/neofs-http-gw/response" "github.com/nspcc-dev/neofs-http-gw/response"
"github.com/nspcc-dev/neofs-http-gw/tokens" "github.com/nspcc-dev/neofs-http-gw/tokens"
"github.com/nspcc-dev/neofs-http-gw/utils"
"github.com/nspcc-dev/neofs-sdk-go/client" "github.com/nspcc-dev/neofs-sdk-go/client"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id" cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/netmap" "github.com/nspcc-dev/neofs-sdk-go/netmap"
@ -220,8 +221,8 @@ func getEpochDurations(ctx context.Context, p pool.Pool) (*epochDurations, error
} }
func needParseExpiration(headers map[string]string) bool { func needParseExpiration(headers map[string]string) bool {
_, ok1 := headers[expirationDurationAttr] _, ok1 := headers[utils.ExpirationDurationAttr]
_, ok2 := headers[expirationRFC3339Attr] _, ok2 := headers[utils.ExpirationRFC3339Attr]
_, ok3 := headers[expirationTimestampAttr] _, ok3 := headers[utils.ExpirationTimestampAttr]
return ok1 || ok2 || ok3 return ok1 || ok2 || ok3
} }

10
utils/attributes.go Normal file
View file

@ -0,0 +1,10 @@
package utils
const (
UserAttributeHeaderPrefix = "X-Attribute-"
SystemAttributePrefix = "__NEOFS__"
ExpirationDurationAttr = SystemAttributePrefix + "EXPIRATION_DURATION"
ExpirationTimestampAttr = SystemAttributePrefix + "EXPIRATION_TIMESTAMP"
ExpirationRFC3339Attr = SystemAttributePrefix + "EXPIRATION_RFC3339"
)