From a0cbc3d8beb7e9bb774b6be30fc89cc1ea9ea352 Mon Sep 17 00:00:00 2001 From: Leonard Lyubich Date: Wed, 16 Feb 2022 20:14:24 +0300 Subject: [PATCH] [#131] client: Return `io.ErrUnexpectedEOF` on cut object payload Make `ObjectReader` / `ObjectRangeReader` to track number of bytes read and return: * `io.ErrUnexpectedEOF` if the stream finished by the server before the last byte of the payload was read. * an error if more object payload size bytes was read. Signed-off-by: Leonard Lyubich --- client/object_get.go | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/client/object_get.go b/client/object_get.go index 5c8646ce..a8b68acc 100644 --- a/client/object_get.go +++ b/client/object_get.go @@ -107,6 +107,8 @@ type ObjectReader struct { bodyResp v2object.GetResponseBody tailPayload []byte + + remainingPayloadLen int } // UseKey specifies private key to sign the requests. @@ -147,6 +149,8 @@ func (x *ObjectReader) ReadHeader(dst *object.Object) bool { objv2.SetHeader(partInit.GetHeader()) objv2.SetSignature(partInit.GetSignature()) + x.remainingPayloadLen = int(objv2.GetHeader().GetPayloadLength()) + *dst = *object.NewFromV2(&objv2) // need smth better return true @@ -208,6 +212,8 @@ func (x *ObjectReader) close(ignoreEOF bool) (*ResObjectGet, error) { if x.ctxCall.err != nil { if !errors.Is(x.ctxCall.err, io.EOF) { return nil, x.ctxCall.err + } else if x.remainingPayloadLen > 0 { + return nil, io.ErrUnexpectedEOF } else if !ignoreEOF { return nil, io.EOF } @@ -239,11 +245,17 @@ func (x *ObjectReader) Read(p []byte) (int, error) { res, err := x.close(false) if err != nil { return n, err - } else if !x.ctxCall.resolveAPIFailures { - return n, apistatus.ErrFromStatus(res.Status()) } + + return n, apistatus.ErrFromStatus(res.Status()) } + if n > x.remainingPayloadLen { + return n, errors.New("payload size overflow") + } + + x.remainingPayloadLen -= n + return n, nil } @@ -497,6 +509,8 @@ type ObjectRangeReader struct { bodyResp v2object.GetRangeResponseBody tailPayload []byte + + remainingPayloadLen int } // UseKey specifies private key to sign the requests. @@ -572,6 +586,8 @@ func (x *ObjectRangeReader) close(ignoreEOF bool) (*ResObjectRange, error) { if x.ctxCall.err != nil { if !errors.Is(x.ctxCall.err, io.EOF) { return nil, x.ctxCall.err + } else if x.remainingPayloadLen > 0 { + return nil, io.ErrUnexpectedEOF } else if !ignoreEOF { return nil, io.EOF } @@ -603,11 +619,17 @@ func (x *ObjectRangeReader) Read(p []byte) (int, error) { res, err := x.close(false) if err != nil { return n, err - } else if !x.ctxCall.resolveAPIFailures { - return n, apistatus.ErrFromStatus(res.Status()) } + + return n, apistatus.ErrFromStatus(res.Status()) } + if n > x.remainingPayloadLen { + return n, errors.New("payload range size overflow") + } + + x.remainingPayloadLen -= n + return n, nil } @@ -677,6 +699,8 @@ func (c *Client) ObjectRangeInit(ctx context.Context, prm PrmObjectRange) (*Obje stream *rpcapi.ObjectRangeResponseReader ) + r.remainingPayloadLen = int(prm.ln) + ctx, r.cancelCtxStream = context.WithCancel(ctx) resp.SetBody(&r.bodyResp)