[#79] Fix panic on get empty object
Signed-off-by: Denis Kirillov <denis@nspcc.ru>
This commit is contained in:
parent
e79189045e
commit
8d83320120
3 changed files with 136 additions and 17 deletions
|
@ -83,7 +83,9 @@ func runTestInContainer(rootCtx context.Context, t *testing.T, key *keys.Private
|
|||
aioImage := "nspccdev/neofs-aio-testcontainer:"
|
||||
versions := []string{
|
||||
"0.29.0",
|
||||
//"latest",
|
||||
"0.30.0",
|
||||
"0.32.0",
|
||||
"latest",
|
||||
}
|
||||
|
||||
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)
|
||||
require.NoError(t, err)
|
||||
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) {
|
||||
|
|
|
@ -142,28 +142,26 @@ func (a *API) GetObjectInfo(params operations.GetObjectInfoParams, principal *mo
|
|||
}
|
||||
}
|
||||
|
||||
var prmRange pool.PrmObjectRange
|
||||
prmRange.SetAddress(addr)
|
||||
prmRange.UseBearer(btoken)
|
||||
|
||||
var offset, length uint64
|
||||
if params.RangeOffset != nil || params.RangeLength != nil {
|
||||
if params.RangeOffset == nil || params.RangeLength == nil {
|
||||
errResp := a.logAndGetErrorResponse("invalid range param", errors.New("both offset and length musded"))
|
||||
return errorResponse.WithPayload(errResp)
|
||||
}
|
||||
offset = uint64(*params.RangeOffset)
|
||||
length = uint64(*params.RangeLength)
|
||||
} else {
|
||||
length = objInfo.PayloadSize()
|
||||
if objInfo.PayloadSize() == 0 {
|
||||
return operations.NewGetObjectInfoOK().WithPayload(&resp)
|
||||
}
|
||||
|
||||
offset, length, err := prepareOffsetLength(params, objInfo.PayloadSize())
|
||||
if err != nil {
|
||||
errResp := a.logAndGetErrorResponse("invalid range param", err)
|
||||
return errorResponse.WithPayload(errResp)
|
||||
}
|
||||
prmRange.SetOffset(offset)
|
||||
prmRange.SetLength(length)
|
||||
|
||||
if uint64(*params.MaxPayloadSize) < length {
|
||||
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)
|
||||
if err != nil {
|
||||
errResp := a.logAndGetErrorResponse("range object", err)
|
||||
|
@ -436,3 +434,26 @@ func prepareBearerToken(bt *BearerToken, isWalletConnect, isFullToken bool) (bea
|
|||
|
||||
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
77
handlers/objects_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
Reference in a new issue