mirror of
https://github.com/typesense/typesense.git
synced 2025-05-17 20:22:32 +08:00
Validate group limit & other numerical parameters of search.
This commit is contained in:
parent
8c42d5da7b
commit
0cdd58e86c
@ -151,8 +151,18 @@ struct StringUtils {
|
||||
}
|
||||
|
||||
char * p ;
|
||||
strtoull(s.c_str(), &p, 10);
|
||||
return (*p == 0);
|
||||
unsigned long long ull = strtoull(s.c_str(), &p, 10);
|
||||
return (*p == 0) && ull <= std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
|
||||
static bool is_uint32_t(const std::string &s) {
|
||||
if(s.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char * p ;
|
||||
unsigned long ul = strtoul(s.c_str(), &p, 10);
|
||||
return (*p == 0) && ul <= std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
static void toupper(std::string& str) {
|
||||
|
@ -394,6 +394,10 @@ Option<nlohmann::json> Collection::search(const std::string & query, const std::
|
||||
return Option<nlohmann::json>(400, "No search fields specified for the query.");
|
||||
}
|
||||
|
||||
if(group_limit == 0 || group_limit >= 100) {
|
||||
return Option<nlohmann::json>(400, "Value of `group_limit` is invalid.");
|
||||
}
|
||||
|
||||
std::vector<uint32_t> excluded_ids;
|
||||
std::map<size_t, std::vector<uint32_t>> include_ids; // position => list of IDs
|
||||
populate_overrides(query, pinned_hits, hidden_hits, include_ids, excluded_ids);
|
||||
|
@ -301,42 +301,42 @@ bool get_search(http_req & req, http_res & res) {
|
||||
}
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[DROP_TOKENS_THRESHOLD])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[DROP_TOKENS_THRESHOLD])) {
|
||||
res.set_400("Parameter `" + std::string(DROP_TOKENS_THRESHOLD) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[TYPO_TOKENS_THRESHOLD])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[TYPO_TOKENS_THRESHOLD])) {
|
||||
res.set_400("Parameter `" + std::string(TYPO_TOKENS_THRESHOLD) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[NUM_TYPOS])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[NUM_TYPOS])) {
|
||||
res.set_400("Parameter `" + std::string(NUM_TYPOS) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[PER_PAGE])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[PER_PAGE])) {
|
||||
res.set_400("Parameter `" + std::string(PER_PAGE) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[PAGE])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[PAGE])) {
|
||||
res.set_400("Parameter `" + std::string(PAGE) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[MAX_FACET_VALUES])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[MAX_FACET_VALUES])) {
|
||||
res.set_400("Parameter `" + std::string(MAX_FACET_VALUES) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[SNIPPET_THRESHOLD])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[SNIPPET_THRESHOLD])) {
|
||||
res.set_400("Parameter `" + std::string(SNIPPET_THRESHOLD) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!StringUtils::is_uint64_t(req.params[GROUP_LIMIT])) {
|
||||
if(!StringUtils::is_uint32_t(req.params[GROUP_LIMIT])) {
|
||||
res.set_400("Parameter `" + std::string(GROUP_LIMIT) + "` must be an unsigned integer.");
|
||||
return false;
|
||||
}
|
||||
@ -441,19 +441,19 @@ bool get_search(http_req & req, http_res & res) {
|
||||
|
||||
Option<nlohmann::json> result_op = collection->search(req.params[QUERY], search_fields, filter_str, facet_fields,
|
||||
sort_fields, std::stoi(req.params[NUM_TYPOS]),
|
||||
static_cast<size_t>(std::stoi(req.params[PER_PAGE])),
|
||||
static_cast<size_t>(std::stoi(req.params[PAGE])),
|
||||
static_cast<size_t>(std::stol(req.params[PER_PAGE])),
|
||||
static_cast<size_t>(std::stol(req.params[PAGE])),
|
||||
token_order, prefix, drop_tokens_threshold,
|
||||
include_fields, exclude_fields,
|
||||
static_cast<size_t>(std::stoi(req.params[MAX_FACET_VALUES])),
|
||||
static_cast<size_t>(std::stol(req.params[MAX_FACET_VALUES])),
|
||||
req.params[FACET_QUERY],
|
||||
static_cast<size_t>(std::stoi(req.params[SNIPPET_THRESHOLD])),
|
||||
static_cast<size_t>(std::stol(req.params[SNIPPET_THRESHOLD])),
|
||||
req.params[HIGHLIGHT_FULL_FIELDS],
|
||||
typo_tokens_threshold,
|
||||
pinned_hits,
|
||||
hidden_hits,
|
||||
group_by_fields,
|
||||
static_cast<size_t>(std::stoi(req.params[GROUP_LIMIT]))
|
||||
static_cast<size_t>(std::stol(req.params[GROUP_LIMIT]))
|
||||
);
|
||||
|
||||
uint64_t timeMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
|
@ -222,6 +222,27 @@ TEST_F(CollectionGroupingTest, GroupingCompoundKey) {
|
||||
|
||||
ASSERT_EQ(1, (int) res["facet_counts"][0]["counts"][3]["count"]);
|
||||
ASSERT_STREQ("Zeta", res["facet_counts"][0]["counts"][3]["value"].get<std::string>().c_str());
|
||||
|
||||
// respect min and max grouping limit (greater than 0 and less than 99)
|
||||
auto res_op = coll_group->search("*", {}, "", {"brand"}, {}, 0, 50, 1, FREQUENCY,
|
||||
false, Index::DROP_TOKENS_THRESHOLD,
|
||||
spp::sparse_hash_set<std::string>(),
|
||||
spp::sparse_hash_set<std::string>(), 10, "brand: omeg", 30,
|
||||
"", 10,
|
||||
{}, {}, {"rating"}, 100);
|
||||
|
||||
ASSERT_FALSE(res_op.ok());
|
||||
ASSERT_STREQ("Value of `group_limit` is invalid.", res_op.error().c_str());
|
||||
|
||||
res_op = coll_group->search("*", {}, "", {"brand"}, {}, 0, 50, 1, FREQUENCY,
|
||||
false, Index::DROP_TOKENS_THRESHOLD,
|
||||
spp::sparse_hash_set<std::string>(),
|
||||
spp::sparse_hash_set<std::string>(), 10, "brand: omeg", 30,
|
||||
"", 10,
|
||||
{}, {}, {"rating"}, 0);
|
||||
|
||||
ASSERT_FALSE(res_op.ok());
|
||||
ASSERT_STREQ("Value of `group_limit` is invalid.", res_op.error().c_str());
|
||||
}
|
||||
|
||||
TEST_F(CollectionGroupingTest, GroupingWithGropLimitOfOne) {
|
||||
|
@ -54,3 +54,8 @@ TEST(StringUtilsTest, HMAC) {
|
||||
std::string digest1 = StringUtils::hmac("KeyVal", "{\"filter_by\": \"user_id:1080\"}");
|
||||
ASSERT_STREQ("IvjqWNZ5M5ElcvbMoXj45BxkQrZG4ZKEaNQoRioCx2s=", digest1.c_str());
|
||||
}
|
||||
|
||||
TEST(StringUtilsTest, UInt32Validation) {
|
||||
std::string big_num = "99999999999999999999999999999999";
|
||||
ASSERT_FALSE(StringUtils::is_uint32_t(big_num));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user