forked from TrueCloudLab/frostfs-node
[#291] object: Split validating target in two
Signed-off-by: Evgenii Stratonikov <e.stratonikov@yadro.com>
This commit is contained in:
parent
ee58b390bb
commit
35ea207df6
2 changed files with 70 additions and 58 deletions
|
@ -77,7 +77,7 @@ func (p *Streamer) initUntrustedTarget(prm *PutInitPrm) error {
|
||||||
p.relay = prm.relay
|
p.relay = prm.relay
|
||||||
|
|
||||||
// prepare untrusted-Put object target
|
// prepare untrusted-Put object target
|
||||||
p.target = &validatingTarget{
|
p.target = &validatingPreparedTarget{
|
||||||
nextTarget: p.newCommonTarget(prm),
|
nextTarget: p.newCommonTarget(prm),
|
||||||
fmt: p.fmtValidator,
|
fmt: p.fmtValidator,
|
||||||
|
|
||||||
|
@ -125,8 +125,7 @@ func (p *Streamer) initTrustedTarget(prm *PutInitPrm) error {
|
||||||
|
|
||||||
p.sessionKey = sessionKey
|
p.sessionKey = sessionKey
|
||||||
p.target = &validatingTarget{
|
p.target = &validatingTarget{
|
||||||
fmt: p.fmtValidator,
|
fmt: p.fmtValidator,
|
||||||
unpreparedObject: true,
|
|
||||||
nextTarget: transformer.NewPayloadSizeLimiter(
|
nextTarget: transformer.NewPayloadSizeLimiter(
|
||||||
p.maxPayloadSz,
|
p.maxPayloadSz,
|
||||||
containerSDK.IsHomomorphicHashingDisabled(prm.cnr),
|
containerSDK.IsHomomorphicHashingDisabled(prm.cnr),
|
||||||
|
|
|
@ -15,13 +15,18 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/tzhash/tz"
|
"git.frostfs.info/TrueCloudLab/tzhash/tz"
|
||||||
)
|
)
|
||||||
|
|
||||||
// validatingTarget validates object format and content.
|
// validatingTarget validates unprepared object format and content (streaming PUT case).
|
||||||
type validatingTarget struct {
|
type validatingTarget struct {
|
||||||
nextTarget transformer.ObjectTarget
|
nextTarget transformer.ObjectTarget
|
||||||
|
|
||||||
fmt *object.FormatValidator
|
fmt *object.FormatValidator
|
||||||
|
}
|
||||||
|
|
||||||
unpreparedObject bool
|
// validatingPreparedTarget validates prepared object format and content.
|
||||||
|
type validatingPreparedTarget struct {
|
||||||
|
nextTarget transformer.ObjectTarget
|
||||||
|
|
||||||
|
fmt *object.FormatValidator
|
||||||
|
|
||||||
hash hash.Hash
|
hash hash.Hash
|
||||||
|
|
||||||
|
@ -42,38 +47,52 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *validatingTarget) WriteHeader(ctx context.Context, obj *objectSDK.Object) error {
|
func (t *validatingTarget) WriteHeader(ctx context.Context, obj *objectSDK.Object) error {
|
||||||
|
if err := t.fmt.Validate(ctx, obj, true); err != nil {
|
||||||
|
return fmt.Errorf("(%T) coult not validate object format: %w", t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.nextTarget.WriteHeader(ctx, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *validatingTarget) Write(ctx context.Context, p []byte) (n int, err error) {
|
||||||
|
return t.nextTarget.Write(ctx, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *validatingTarget) Close(ctx context.Context) (*transformer.AccessIdentifiers, error) {
|
||||||
|
return t.nextTarget.Close(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *validatingPreparedTarget) WriteHeader(ctx context.Context, obj *objectSDK.Object) error {
|
||||||
t.payloadSz = obj.PayloadSize()
|
t.payloadSz = obj.PayloadSize()
|
||||||
chunkLn := uint64(len(obj.Payload()))
|
chunkLn := uint64(len(obj.Payload()))
|
||||||
|
|
||||||
if !t.unpreparedObject {
|
// check chunk size
|
||||||
// check chunk size
|
if chunkLn > t.payloadSz {
|
||||||
if chunkLn > t.payloadSz {
|
return ErrWrongPayloadSize
|
||||||
return ErrWrongPayloadSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// check payload size limit
|
|
||||||
if t.payloadSz > t.maxPayloadSz {
|
|
||||||
return ErrExceedingMaxSize
|
|
||||||
}
|
|
||||||
|
|
||||||
cs, csSet := obj.PayloadChecksum()
|
|
||||||
if !csSet {
|
|
||||||
return errors.New("missing payload checksum")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch typ := cs.Type(); typ {
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("(%T) unsupported payload checksum type %v", t, typ)
|
|
||||||
case checksum.SHA256:
|
|
||||||
t.hash = sha256.New()
|
|
||||||
case checksum.TZ:
|
|
||||||
t.hash = tz.New()
|
|
||||||
}
|
|
||||||
|
|
||||||
t.checksum = cs.Value()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := t.fmt.Validate(ctx, obj, t.unpreparedObject); err != nil {
|
// check payload size limit
|
||||||
|
if t.payloadSz > t.maxPayloadSz {
|
||||||
|
return ErrExceedingMaxSize
|
||||||
|
}
|
||||||
|
|
||||||
|
cs, csSet := obj.PayloadChecksum()
|
||||||
|
if !csSet {
|
||||||
|
return errors.New("missing payload checksum")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch typ := cs.Type(); typ {
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("(%T) unsupported payload checksum type %v", t, typ)
|
||||||
|
case checksum.SHA256:
|
||||||
|
t.hash = sha256.New()
|
||||||
|
case checksum.TZ:
|
||||||
|
t.hash = tz.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.checksum = cs.Value()
|
||||||
|
|
||||||
|
if err := t.fmt.Validate(ctx, obj, false); err != nil {
|
||||||
return fmt.Errorf("(%T) coult not validate object format: %w", t, err)
|
return fmt.Errorf("(%T) coult not validate object format: %w", t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,30 +101,26 @@ func (t *validatingTarget) WriteHeader(ctx context.Context, obj *objectSDK.Objec
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !t.unpreparedObject {
|
// update written bytes
|
||||||
// update written bytes
|
//
|
||||||
//
|
// Note: we MUST NOT add obj.PayloadSize() since obj
|
||||||
// Note: we MUST NOT add obj.PayloadSize() since obj
|
// can carry only the chunk of the full payload
|
||||||
// can carry only the chunk of the full payload
|
t.writtenPayload += chunkLn
|
||||||
t.writtenPayload += chunkLn
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *validatingTarget) Write(ctx context.Context, p []byte) (n int, err error) {
|
func (t *validatingPreparedTarget) Write(ctx context.Context, p []byte) (n int, err error) {
|
||||||
chunkLn := uint64(len(p))
|
chunkLn := uint64(len(p))
|
||||||
|
|
||||||
if !t.unpreparedObject {
|
// check if new chunk will overflow payload size
|
||||||
// check if new chunk will overflow payload size
|
if t.writtenPayload+chunkLn > t.payloadSz {
|
||||||
if t.writtenPayload+chunkLn > t.payloadSz {
|
return 0, ErrWrongPayloadSize
|
||||||
return 0, ErrWrongPayloadSize
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_, err = t.hash.Write(p)
|
_, err = t.hash.Write(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err = t.nextTarget.Write(ctx, p)
|
n, err = t.nextTarget.Write(ctx, p)
|
||||||
|
@ -116,16 +131,14 @@ func (t *validatingTarget) Write(ctx context.Context, p []byte) (n int, err erro
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *validatingTarget) Close(ctx context.Context) (*transformer.AccessIdentifiers, error) {
|
func (t *validatingPreparedTarget) Close(ctx context.Context) (*transformer.AccessIdentifiers, error) {
|
||||||
if !t.unpreparedObject {
|
// check payload size correctness
|
||||||
// check payload size correctness
|
if t.payloadSz != t.writtenPayload {
|
||||||
if t.payloadSz != t.writtenPayload {
|
return nil, ErrWrongPayloadSize
|
||||||
return nil, ErrWrongPayloadSize
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(t.hash.Sum(nil), t.checksum) {
|
if !bytes.Equal(t.hash.Sum(nil), t.checksum) {
|
||||||
return nil, fmt.Errorf("(%T) incorrect payload checksum", t)
|
return nil, fmt.Errorf("(%T) incorrect payload checksum", t)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return t.nextTarget.Close(ctx)
|
return t.nextTarget.Close(ctx)
|
||||||
|
|
Loading…
Reference in a new issue