Skip to content

fix: apply the rate limiter to /autocompleter - #138

Open
souta-lab wants to merge 2 commits into
sahenjp:mainfrom
souta-lab:fix/a04-autocompleter-rate-limit
Open

souta-lab wants to merge 2 commits into
sahenjp:mainfrom
souta-lab:fix/a04-autocompleter-rate-limit

Conversation

@souta-lab

Copy link
Copy Markdown
Contributor

Summary

Apply the shared rate limiter to /autocompleter, the remaining endpoint called out in A04 of docs/AUDIT-2026-11-02.md. The /research part of A04 was fixed in #54, but /autocompleter still never called the limiter while making outbound requests to its configured backends.

Root cause

autocompleter in src/web/handlers.rs had no ClientAddr extractor parameter and never called state.limiter.check(...), unlike /search and /research. With the limiter enabled, /search returns 429 once the budget is spent while /autocompleter kept answering — and each answer can fan out to external autocomplete backends, iterating over the comma-separated backend list from the request.

Changes

  • src/web/handlers.rs: autocompleter now takes the same peer: ClientAddr extractor as search_get/research and runs the existing limiter_response(&state, state.limiter.check(peer.0, &headers, "json")) check immediately after the empty-query early return — before preferences, query parsing and any backend fetch. This is a straight transplant of the pattern already used by /research (which also passes "json"); src/web/limiter.rs is unchanged.
  • tests/integration.rs: new test autocompleter_is_rate_limited, modelled on the existing research_and_search_share_limits_before_outbound_requests. With limiter_max = 1 and backend=none (so the allowed request makes no outbound call), the first request returns 200 with [] and the second returns 429 with a Retry-After header. The test fails on unmodified main (the second request returns 200).

Scope is deliberately limited to the limiter. The audit also mentions bounding the number of backend candidates tried and an overall deadline for the autocompleter; both need values chosen, so they are left out here rather than smuggled into a pattern transplant. Happy to add them in a follow-up if wanted.

No dependencies, configuration, or response fields change. With the limiter disabled (the default), behaviour is unchanged.

Verification

Linux x86_64, Rust 1.99.1 (proxy environment variables excluded from the test process for the loopback fixtures, as in #52):

  • New test: cargo test --test integration autocompleter_is_rate_limited — 1 passed. With the handler change reverted, the same test fails (second request returns 200 instead of 429), confirming it covers the bug.
  • cargo test --test integration: 26 passed, 2 failed. The failures are raw_content_honors_a_configured_limit_above_eight_thousand_characters and raw_content_uses_only_the_explicit_language_and_separates_cached_variants, which fail identically on unmodified main in this sandbox (Japanese content extraction returns null; same environment family as the tests/pdf_pages.rs failure noted in fix: parse the LLM query array as JSON instead of splitting on commas #134/fix: validate timeout_limit at the HTTP entry point instead of panicking on inf #135) and are unrelated to this change.
  • cargo test --lib web::: 36 passed.
  • cargo fmt --all -- --check: passed.
  • cargo clippy --all-targets -- -D warnings: passed.

Limitations

Other platforms are left to CI. The test asserts the 429 response; that no backend fetch happens before the check follows from the check's placement (the autocomplete backend URLs are hardcoded to public hosts, so unlike the /research test there is no local fake to count outbound calls against).

Related

Addresses the remaining /autocompleter part of A04 in the existing audit.

AI assistance: implementation and tests.

@souta-lab
souta-lab requested a review from sahenjp as a code owner November 11, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant