Skip to content
Open
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
5 changes: 5 additions & 0 deletions src/web/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,12 +487,17 @@ fn results_page(
pub async fn autocompleter(
State(state): State<AppState>,
Query(params): Query<AutocompleteParams>,
peer: ClientAddr,
headers: HeaderMap,
) -> Response {
let query = params.q.clone().unwrap_or_default();
if query.trim().is_empty() {
return axum::Json(Vec::<String>::new()).into_response();
}
if let Some(response) = limiter_response(&state, state.limiter.check(peer.0, &headers, "json"))
{
return response;
}
let preferences = preferences_of(&headers, &state);
let parsed = SearchQuery::parse(
&query,
Expand Down
20 changes: 20 additions & 0 deletions tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,26 @@ async fn research_and_search_share_limits_before_outbound_requests() {
server.abort();
}

#[tokio::test]
async fn autocompleter_is_rate_limited() {
let base_url = start_fake_engine().await;
let mut settings = settings_for(&base_url);
settings.server.limiter = LimiterSettings::Enabled(true);
settings.server.limiter_max = 1;
settings.server.limiter_window = 60;
let app = app(settings);

// `backend=none` keeps the allowed request from reaching any backend.
let uri = "/autocompleter?q=rust&backend=none";
let (status, body, _) = get_uri(&app, uri).await;
assert_eq!(status, StatusCode::OK);
assert_eq!(body, "[]");

let (status, _, headers) = get_uri(&app, uri).await;
assert_eq!(status, StatusCode::TOO_MANY_REQUESTS);
assert!(headers.contains_key(header::RETRY_AFTER));
}

/// The JSON payload the fake YaCy engine answers with.
const YACY_RESPONSE: &str = r#"{
"channels": [{
Expand Down
Loading