[#108] Add different expiration header formats

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2021-11-26 15:44:07 +03:00 committed by Alex Vanin
parent 06be798111
commit cd0633cda0
5 changed files with 279 additions and 0 deletions

View file

@ -2,7 +2,11 @@ package uploader
import (
"bytes"
"fmt"
"strconv"
"time"
"github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/valyala/fasthttp"
"go.uber.org/zap"
)
@ -10,6 +14,10 @@ import (
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-")}
@ -68,3 +76,60 @@ func filterHeaders(l *zap.Logger, header *fasthttp.RequestHeader) map[string]str
return result
}
func prepareExpirationHeader(headers map[string]string, epochDurations *epochDurations) error {
expirationInEpoch := headers[object.SysAttributeExpEpoch]
if timeRFC3339, ok := headers[expirationRFC3339Attr]; ok {
expTime, err := time.Parse(time.RFC3339, timeRFC3339)
if err != nil {
return fmt.Errorf("couldn't parse value %s of header %s", timeRFC3339, expirationRFC3339Attr)
}
now := time.Now().UTC()
if expTime.Before(now) {
return fmt.Errorf("value %s of header %s must be in the future", timeRFC3339, expirationRFC3339Attr)
}
updateExpirationHeader(headers, epochDurations, expTime.Sub(now))
delete(headers, expirationRFC3339Attr)
}
if timestamp, ok := headers[expirationTimestampAttr]; ok {
value, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return fmt.Errorf("couldn't parse value %s of header %s", timestamp, expirationTimestampAttr)
}
expTime := time.Unix(value, 0)
now := time.Now()
if expTime.Before(now) {
return fmt.Errorf("value %s of header %s must be in the future", timestamp, expirationTimestampAttr)
}
updateExpirationHeader(headers, epochDurations, expTime.Sub(now))
delete(headers, expirationTimestampAttr)
}
if duration, ok := headers[expirationDurationAttr]; ok {
expDuration, err := time.ParseDuration(duration)
if err != nil {
return fmt.Errorf("couldn't parse value %s of header %s", duration, expirationDurationAttr)
}
if expDuration <= 0 {
return fmt.Errorf("value %s of header %s must be positive", expDuration, expirationDurationAttr)
}
updateExpirationHeader(headers, epochDurations, expDuration)
delete(headers, expirationDurationAttr)
}
if expirationInEpoch != "" {
headers[object.SysAttributeExpEpoch] = expirationInEpoch
}
return nil
}
func updateExpirationHeader(headers map[string]string, durations *epochDurations, expDuration time.Duration) {
epochDuration := durations.msPerBlock * int64(durations.blockPerEpoch)
numEpoch := expDuration.Milliseconds() / epochDuration
headers[object.SysAttributeExpEpoch] = strconv.FormatInt(int64(durations.currentEpoch)+numEpoch, 10)
}