Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions rust/crates/cloudsearch-index/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ use tokio::{

const MAX_FIELDS_PER_INDEX: usize = 1000;
const MERGE_TRIGGER_DOCUMENT_COUNT: usize = 8;
const MAX_SEARCH_SIZE: usize = 10_000;
const MAX_SEARCH_OFFSET: usize = 1_000_000;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MergePlan {
Expand Down Expand Up @@ -825,8 +827,8 @@ impl IndexHandle {
});
}

let from = request.from.unwrap_or(0);
let size = request.size.unwrap_or(total);
let from = request.from.unwrap_or(0).min(MAX_SEARCH_OFFSET);
let size = request.size.unwrap_or(total).min(MAX_SEARCH_SIZE);

let hits = scored
.into_iter()
Expand Down Expand Up @@ -915,6 +917,22 @@ impl IndexHandle {
)));
}

if let Some(size) = request.size
&& size > MAX_SEARCH_SIZE
{
return Err(CloudSearchError::InvalidSearchRequest(format!(
"size ({size}) exceeds maximum allowed value ({MAX_SEARCH_SIZE})"
)));
}

if let Some(from) = request.from
&& from > MAX_SEARCH_OFFSET
{
return Err(CloudSearchError::InvalidSearchRequest(format!(
"from ({from}) exceeds maximum allowed value ({MAX_SEARCH_OFFSET})"
)));
}

if let Some(aggs) = &request.aggs {
for (name, agg) in aggs {
match agg {
Expand Down
58 changes: 58 additions & 0 deletions rust/crates/cloudsearch-index/tests/coverage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,61 @@ async fn validate_search_request_rejects_nested_bool_with_object_field() {
"nested bool with object sort field should be rejected"
);
}

#[tokio::test]
async fn validate_search_request_rejects_size_exceeding_max() {
let temp_dir = TempDir::new().expect("temp dir");
let catalog = Arc::new(IndexCatalog::new(temp_dir.path()));
catalog.initialize().await.expect("init catalog");
let _metadata = catalog
.create_index(
"test",
CreateIndexRequest {
settings: IndexSettings::default(),
..Default::default()
},
)
.await
.expect("create index");
let handle = catalog.open_index("test").await.expect("open index");

let request = SearchRequest {
size: Some(100_000),
..Default::default()
};

let result = handle.validate_search_request(&request);
assert!(
result.is_err(),
"size exceeding MAX_SEARCH_SIZE should be rejected"
);
}

#[tokio::test]
async fn validate_search_request_rejects_from_exceeding_max() {
let temp_dir = TempDir::new().expect("temp dir");
let catalog = Arc::new(IndexCatalog::new(temp_dir.path()));
catalog.initialize().await.expect("init catalog");
let _metadata = catalog
.create_index(
"test",
CreateIndexRequest {
settings: IndexSettings::default(),
..Default::default()
},
)
.await
.expect("create index");
let handle = catalog.open_index("test").await.expect("open index");

let request = SearchRequest {
from: Some(2_000_000),
..Default::default()
};

let result = handle.validate_search_request(&request);
assert!(
result.is_err(),
"from exceeding MAX_SEARCH_OFFSET should be rejected"
);
}