From 822c7aa4362c14f7e98704551635214b6645adeb Mon Sep 17 00:00:00 2001 From: s0u7a Date: Wed, 11 Nov 2026 09:11:37 +0000 Subject: [PATCH] fix: apply the rate limiter to /autocompleter --- src/web/handlers.rs | 5 +++++ tests/integration.rs | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/web/handlers.rs b/src/web/handlers.rs index ffd0794..b65e8af 100644 --- a/src/web/handlers.rs +++ b/src/web/handlers.rs @@ -487,12 +487,17 @@ fn results_page( pub async fn autocompleter( State(state): State, Query(params): Query, + peer: ClientAddr, headers: HeaderMap, ) -> Response { let query = params.q.clone().unwrap_or_default(); if query.trim().is_empty() { return axum::Json(Vec::::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, diff --git a/tests/integration.rs b/tests/integration.rs index 5592e74..a97f8f7 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -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": [{