diff --git a/CHANGELOG.md b/CHANGELOG.md index aa7f8847fd..44f771cc32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ Changelog for NeoFS Node - Policer removes redundant local shard copies that could remain on disk forever (#3908) - Treat only HALTed main transactions as successfully executed, retry the rest (#3868) - `different object owner and session issuer` for stored objects (#3929) +- SearchV2 method returning zero result instead of "bad request" error for incorrect numeric filters (#3934) ### Changed - `object search` CLI command is now the same as `object searchv2` (#3931) diff --git a/pkg/core/object/metadata.go b/pkg/core/object/metadata.go index 06ae994a25..829b254628 100644 --- a/pkg/core/object/metadata.go +++ b/pkg/core/object/metadata.go @@ -709,9 +709,9 @@ func PreprocessSearchQuery(fs object.SearchFilters, attrs []string, cursor strin if blindlyProcess(fs) { return nil, nil, ErrUnreachableQuery } - ofs, ok := parseIntFilters(fs) - if !ok { - return nil, nil, ErrUnreachableQuery + ofs, err := parseIntFilters(fs) + if err != nil { + return nil, nil, err } if oidSorted { @@ -773,7 +773,7 @@ func blindlyProcess(fs object.SearchFilters) bool { return false } -func parseIntFilters(fs object.SearchFilters) ([]SearchFilter, bool) { +func parseIntFilters(fs object.SearchFilters) ([]SearchFilter, error) { ofs := make([]SearchFilter, len(fs)) for i := range fs { ofs[i].SearchFilter = fs[i] @@ -784,16 +784,22 @@ func parseIntFilters(fs object.SearchFilters) ([]SearchFilter, bool) { } n, ok := new(big.Int).SetString(val, 10) if !ok { - return nil, false + return nil, fmt.Errorf("non-integer value in numeric filter number %d", i) } if c := n.Cmp(maxUint256); c >= 0 { - if c > 0 || m == object.MatchNumGT { - return nil, false + if c > 0 { + return nil, fmt.Errorf("too big integer in numeric filter number %d", i) + } + if m == object.MatchNumGT { + return nil, ErrUnreachableQuery } ofs[i].AutoMatch = m == object.MatchNumLE } else if c = n.Cmp(maxUint256Neg); c <= 0 { - if c < 0 || m == object.MatchNumLT { - return nil, false + if c < 0 { + return nil, fmt.Errorf("too low integer in numeric filter number %d", i) + } + if m == object.MatchNumLT { + return nil, ErrUnreachableQuery } ofs[i].AutoMatch = m == object.MatchNumGE } @@ -805,7 +811,7 @@ func parseIntFilters(fs object.SearchFilters) ([]SearchFilter, bool) { } // TODO: #1148 there are more auto-cases (like <=X AND >=X, X), cover more here } - return ofs, true + return ofs, nil } // BigIntBytes returns integer's raw representation. Int must belong to diff --git a/pkg/services/object/acl/v2/service.go b/pkg/services/object/acl/v2/service.go index a1dbb2365c..1b95553033 100644 --- a/pkg/services/object/acl/v2/service.go +++ b/pkg/services/object/acl/v2/service.go @@ -463,23 +463,9 @@ func (b Service) HeadRequestToInfo(request *protoobject.HeadRequest) (RequestInf return b.findRequestInfo(request, cnr, acl.OpObjectHead, sessionSDK.VerbObjectHead, sessionv2.VerbObjectHead, *obj) } -// SearchRequestToInfo resolves RequestInfo from the request to check it using -// [ACLChecker]. -func (b Service) SearchRequestToInfo(request *protoobject.SearchRequest) (RequestInfo, error) { - return b.searchRequestToInfo(request) -} - // SearchV2RequestToInfo resolves RequestInfo from the request to check it using // [ACLChecker]. func (b Service) SearchV2RequestToInfo(request *protoobject.SearchV2Request) (RequestInfo, error) { - return b.searchRequestToInfo(request) -} - -// unifies V1 and V2 search request processing. -func (b Service) searchRequestToInfo(request interface { - GetMetaHeader() *protosession.RequestMetaHeader - GetVerifyHeader() *protosession.RequestVerificationHeader -}) (RequestInfo, error) { id, err := getContainerIDFromRequest(request) if err != nil { return RequestInfo{}, err diff --git a/pkg/services/object/acl/v2/service_test.go b/pkg/services/object/acl/v2/service_test.go index 65e55ca535..a5842ac2c7 100644 --- a/pkg/services/object/acl/v2/service_test.go +++ b/pkg/services/object/acl/v2/service_test.go @@ -198,23 +198,6 @@ func TestService_GetRequestToInfo_BearerTokenIssuer(t *testing.T) { }) } -func TestService_SearchRequestToInfo_BearerTokenIssuer(t *testing.T) { - testBearerTokenIssuer(t, (*aclsvc.Service).SearchRequestToInfo, func(t *testing.T, signer neofscrypto.Signer, cnrID cid.ID, meta *protosession.RequestMetaHeader) *protoobject.SearchRequest { - req := &protoobject.SearchRequest{ - Body: &protoobject.SearchRequest_Body{ - ContainerId: cnrID.ProtoMessage(), - }, - MetaHeader: meta, - } - - var err error - req.VerifyHeader, err = neofscrypto.SignRequestWithBuffer(signer, req, nil) - require.NoError(t, err) - - return req - }) -} - func TestService_SearchV2RequestToInfo_BearerTokenIssuer(t *testing.T) { testBearerTokenIssuer(t, (*aclsvc.Service).SearchV2RequestToInfo, func(t *testing.T, signer neofscrypto.Signer, cnrID cid.ID, meta *protosession.RequestMetaHeader) *protoobject.SearchV2Request { req := &protoobject.SearchV2Request{ diff --git a/pkg/services/object/server.go b/pkg/services/object/server.go index 170e1450ff..cc3da1577d 100644 --- a/pkg/services/object/server.go +++ b/pkg/services/object/server.go @@ -159,7 +159,6 @@ type ACLInfoExtractor interface { HashRequestToInfo(*protoobject.GetRangeHashRequest) (aclsvc.RequestInfo, error) GetRequestToInfo(*protoobject.GetRequest) (aclsvc.RequestInfo, error) RangeRequestToInfo(*protoobject.GetRangeRequest) (aclsvc.RequestInfo, error) - SearchRequestToInfo(*protoobject.SearchRequest) (aclsvc.RequestInfo, error) SearchV2RequestToInfo(*protoobject.SearchV2Request) (aclsvc.RequestInfo, error) } @@ -2049,7 +2048,9 @@ func (s *Server) ProcessSearch(ctx context.Context, req *protoobject.SearchV2Req if errors.Is(err, objectcore.ErrUnreachableQuery) { return nil, nil, nil } - return nil, nil, err + var bad = new(apistatus.BadRequest) + bad.SetMessage(err.Error()) + return nil, nil, bad } var cID cid.ID diff --git a/pkg/util/meta/test/metatest.go b/pkg/util/meta/test/metatest.go index 18eaffe506..2cbc5ede73 100644 --- a/pkg/util/meta/test/metatest.go +++ b/pkg/util/meta/test/metatest.go @@ -1057,7 +1057,7 @@ func _assertSearchResultWithLimit(t testing.TB, db DB, cnr cid.ID, fs object.Sea ofs, cursor, err := objectcore.PreprocessSearchQuery(fs, attrs, strCursor) if err != nil { if len(all) == 0 { - require.ErrorIs(t, err, objectcore.ErrUnreachableQuery) + require.Error(t, err) } else { require.NoError(t, err) }