Skip to content

fix(proxy): allocation-free host matching in the request hot path#99

Merged
GordonBeeming merged 1 commit intomainfrom
gb/proxy-host-normalize-perf
Apr 9, 2026
Merged

fix(proxy): allocation-free host matching in the request hot path#99
GordonBeeming merged 1 commit intomainfrom
gb/proxy-host-normalize-perf

Conversation

@GordonBeeming
Copy link
Copy Markdown
Owner

Summary

  • Replaces the normalize_host -> String helper with host_matches(&str, &str) -> bool that uses str::strip_suffix('.') + eq_ignore_ascii_case.
  • Zero allocations per call. Same semantics — API.GITHUB.COM, api.github.com., and api.github.com all still match each other.
  • Both call sites updated: check_host_allowed and check_request.

Why

normalize_host(&rule.host) allocated a fresh String for every rule on every incoming request, which is a meaningful amount of allocator churn for a proxy on the request hot path. Caught by copilot-pull-request-reviewer in two inline threads on #98 (thread 1, thread 2) — both threads went unanswered at #98 merge time because autopilot's idle baseline was anchored to lastCommit instead of max(lastCommit, readyForReviewAt). The skill has been updated to wait the full 15-minute safety cap from readyForReviewAt, and this PR is the actual code fix the reviewer asked for.

Test plan

  • cargo build --release clean
  • Manual: rule listing api.github.com accepts a request to API.GITHUB.COM
  • Manual: same rule accepts api.github.com. (trailing dot)
  • Manual: rule listing evil.com blocks good.com

Refs #98

The previous normalize_host helper allocated a fresh String for every
rule on every request via .to_ascii_lowercase(). In a proxy that sits
on the request hot path that meant N + 1 String allocations per
incoming connection (one for the request host, one per rule for the
.find() closure). Caught by copilot-pull-request-reviewer in two
review threads on PR #98.

Fix: replace normalize_host with a host_matches helper that does

  - strip a single trailing '.' on each side via str::strip_suffix
    (slice operation, no copy)
  - eq_ignore_ascii_case for the case-fold comparison (byte-by-byte,
    no copy)

Zero allocations per call. Same semantics as before:
"API.GITHUB.COM" matches "api.github.com" matches "api.github.com.".

Both call sites updated (check_host_allowed and check_request).

Refs #98

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: GitButler <gitbutler@gitbutler.com>
@GordonBeeming GordonBeeming marked this pull request as ready for review April 9, 2026 03:53
Copilot AI review requested due to automatic review settings April 9, 2026 03:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes per-request hostname normalization allocations in the proxy hot path by switching from a normalize_host(&str) -> String helper to an allocation-free host_matches(&str, &str) -> bool comparison that is case-insensitive and ignores a single trailing dot.

Changes:

  • Replaced normalize_host (allocating String) with host_matches using strip_suffix('.') + eq_ignore_ascii_case.
  • Updated both host-allowlist lookup call sites (check_host_allowed and check_request) to use host_matches.

@GordonBeeming GordonBeeming merged commit 4b8fb59 into main Apr 9, 2026
35 checks passed
@GordonBeeming GordonBeeming deleted the gb/proxy-host-normalize-perf branch April 9, 2026 04:01
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.

2 participants