[#79] Fix panic on get empty object

Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
Denis Kirillov 2022-10-18 12:49:06 +03:00 committed by Alex Vanin
parent e79189045e
commit 8d83320120
3 changed files with 136 additions and 17 deletions

View file

@ -83,7 +83,9 @@ func runTestInContainer(rootCtx context.Context, t *testing.T, key *keys.Private
aioImage := "nspccdev/neofs-aio-testcontainer:" aioImage := "nspccdev/neofs-aio-testcontainer:"
versions := []string{ versions := []string{
"0.29.0", "0.29.0",
//"latest", "0.30.0",
"0.32.0",
"latest",
} }
for _, version := range versions { for _, version := range versions {
@ -607,6 +609,25 @@ func restObjectGet(ctx context.Context, t *testing.T, p *pool.Pool, ownerID *use
contentData, err = base64.StdEncoding.DecodeString(objInfo.Payload) contentData, err = base64.StdEncoding.DecodeString(objInfo.Payload)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, content[:rangeLength], contentData) require.Equal(t, content[:rangeLength], contentData)
// check empty object
objID2 := createObject(ctx, t, p, ownerID, cnrID, map[string]string{}, []byte{})
query2 := make(url.Values)
query2.Add(walletConnectQuery, strconv.FormatBool(useWalletConnect))
request2, err := http.NewRequest(http.MethodGet, testHost+"/v1/objects/"+cnrID.EncodeToString()+"/"+objID2.EncodeToString()+"?"+query2.Encode(), nil)
require.NoError(t, err)
prepareCommonHeaders(request2.Header, bearerToken)
objInfo2 := &models.ObjectInfo{}
doRequest(t, httpClient, request2, http.StatusOK, objInfo2)
require.Equal(t, cnrID.EncodeToString(), *objInfo2.ContainerID)
require.Equal(t, objID2.EncodeToString(), *objInfo2.ObjectID)
require.Equal(t, ownerID.EncodeToString(), *objInfo2.OwnerID)
require.Equal(t, 0, len(objInfo2.Attributes))
require.Equal(t, int64(0), *objInfo2.ObjectSize)
} }
func restObjectGetFullBearer(ctx context.Context, t *testing.T, p *pool.Pool, ownerID *user.ID, cnrID cid.ID) { func restObjectGetFullBearer(ctx context.Context, t *testing.T, p *pool.Pool, ownerID *user.ID, cnrID cid.ID) {

View file

@ -142,28 +142,26 @@ func (a *API) GetObjectInfo(params operations.GetObjectInfoParams, principal *mo
} }
} }
var prmRange pool.PrmObjectRange if objInfo.PayloadSize() == 0 {
prmRange.SetAddress(addr) return operations.NewGetObjectInfoOK().WithPayload(&resp)
prmRange.UseBearer(btoken) }
var offset, length uint64 offset, length, err := prepareOffsetLength(params, objInfo.PayloadSize())
if params.RangeOffset != nil || params.RangeLength != nil { if err != nil {
if params.RangeOffset == nil || params.RangeLength == nil { errResp := a.logAndGetErrorResponse("invalid range param", err)
errResp := a.logAndGetErrorResponse("invalid range param", errors.New("both offset and length musded")) return errorResponse.WithPayload(errResp)
return errorResponse.WithPayload(errResp)
}
offset = uint64(*params.RangeOffset)
length = uint64(*params.RangeLength)
} else {
length = objInfo.PayloadSize()
} }
prmRange.SetOffset(offset)
prmRange.SetLength(length)
if uint64(*params.MaxPayloadSize) < length { if uint64(*params.MaxPayloadSize) < length {
return operations.NewGetObjectInfoOK().WithPayload(&resp) return operations.NewGetObjectInfoOK().WithPayload(&resp)
} }
var prmRange pool.PrmObjectRange
prmRange.SetAddress(addr)
prmRange.UseBearer(btoken)
prmRange.SetOffset(offset)
prmRange.SetLength(length)
rangeRes, err := a.pool.ObjectRange(ctx, prmRange) rangeRes, err := a.pool.ObjectRange(ctx, prmRange)
if err != nil { if err != nil {
errResp := a.logAndGetErrorResponse("range object", err) errResp := a.logAndGetErrorResponse("range object", err)
@ -436,3 +434,26 @@ func prepareBearerToken(bt *BearerToken, isWalletConnect, isFullToken bool) (bea
return btoken, nil return btoken, nil
} }
func prepareOffsetLength(params operations.GetObjectInfoParams, objSize uint64) (uint64, uint64, error) {
var offset, length uint64
if params.RangeOffset != nil || params.RangeLength != nil {
if params.RangeOffset == nil || params.RangeLength == nil {
return 0, 0, errors.New("both offset and length must be provided")
}
offset = uint64(*params.RangeOffset)
length = uint64(*params.RangeLength)
} else {
length = objSize
}
if offset >= objSize {
return 0, 0, fmt.Errorf("offset '%d' must be less than object size '%d'", offset, objSize)
}
if offset+length > objSize {
return 0, 0, fmt.Errorf("end of range '%d' must be less or equal object size '%d'", offset+length, objSize)
}
return offset, length, nil
}

77
handlers/objects_test.go Normal file
View file

@ -0,0 +1,77 @@
package handlers
import (
"testing"
"github.com/nspcc-dev/neofs-rest-gw/gen/restapi/operations"
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
"github.com/stretchr/testify/require"
)
func TestPrepareOffset(t *testing.T) {
for _, tc := range []struct {
err bool
expectedOffset uint64
expectedLength uint64
params operations.GetObjectInfoParams
objSize uint64
}{
{
params: operations.GetObjectInfoParams{
RangeLength: util.NewInteger(1),
RangeOffset: util.NewInteger(0),
},
objSize: 1,
expectedOffset: 0,
expectedLength: 1,
},
{
params: operations.GetObjectInfoParams{
RangeLength: util.NewInteger(3),
RangeOffset: util.NewInteger(1),
},
objSize: 5,
expectedOffset: 1,
expectedLength: 3,
},
{
objSize: 1,
expectedOffset: 0,
expectedLength: 1,
},
{
err: true,
params: operations.GetObjectInfoParams{
RangeLength: util.NewInteger(1),
RangeOffset: nil,
},
},
{
err: true,
params: operations.GetObjectInfoParams{
RangeLength: nil,
RangeOffset: util.NewInteger(1),
},
},
{
err: true,
params: operations.GetObjectInfoParams{
RangeLength: util.NewInteger(1),
RangeOffset: util.NewInteger(0),
},
objSize: 0,
},
} {
t.Run("", func(t *testing.T) {
offset, length, err := prepareOffsetLength(tc.params, tc.objSize)
if tc.err {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, tc.expectedOffset, offset)
require.Equal(t, tc.expectedLength, length)
})
}
}