jeswr / jeswr/solid-server-rs

Transport guards: idle-keepalive + max-requests-per-conn (NOT hyper builder knobs) — design notes for review

Open
#2 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

**Branch:** `perf-a-http2-guards` (commit `145851b`) — not yet merged.

Documenting design/judgment calls made while adding the two missing transport DoS guards + the HTTP/2 bench arm, so they're reviewable after the fact (per the "proceed, document, maintainer steers after" rule). Steer if any call is wrong.

## 1. "hyper builder knobs" — the brief was wrong for hyper 1.9.0 (verified)

The task brief described the idle-keepalive timeout and max-requests-per-connection cap as "hyper builder knobs". **Neither exists natively in hyper 1.9.0 / hyper-util 0.1.16 / axum-server 0.8.0** (I read the installed source + corroborated against hyper/axum issues):
- No `max_requests` / `max_requests_per_connection` / request-count cap on any `http1::Builder`, `http2::Builder`, or the `auto::Builder` wrappers. (Open feature request: tokio-rs/axum#3753; hyperium/hyper#2640.)
- No idle-connection timeout. `header_read_timeout` bounds a *partial head* (bytes started); `keep_alive_interval`/`keep_alive_timeout` is the h2 PING dead-peer probe. Neither bounds a live peer holding a fully-idle keep-alive connection.

So both guards are implemented at the **per-connection accept seam** I already own (`ConnectionLimitAcceptor`), which is the canonical place:
- **idle-keepalive** = an IO-layer read-inactivity wrapper (`IdleTimeoutStream`), deadline reset on read progress.
- **max-requests-per-conn** = a per-connection counting `tower::Service` (`MaxRequestsService`) that sets `Connection: close` after N requests.

## 2. Judgment calls (proceeded with the best choice — steer if wrong)

- **Defaults.** idle-keepalive = **75s on** (nginx-style, never trips a legit keep-alive client or the CTH); max-requests-per-conn = **OFF/unlimited** (a finite reuse cap is opt-in defence-in-depth and could trip a high-reuse client / the harness). Env: `SOLID_SERVER_IDLE_TIMEOUT_SECS`, `SOLID_SERVER_MAX_REQUESTS_PER_CONN`.
- **max-requests is HTTP/1.1-meaningful only.** Under h2 there's no per-stream `Connection: close` (the equivalent is connection-level GOAWAY, which hyper's *server* builder exposes no hook for). h2 connection-pinning stays bounded by the accept-time connection cap + the h2 stream/reset caps. Documented in the env-var + `MaxRequestsService` docs. (If you want true h2 connection rotation, that's an age-based GOAWAY follow-up gated on a hyper/axum-server API — tracked as a seam, not built.)
- **`pin-project-lite` added as a direct dep.** The crate is `#![forbid(unsafe_code)]`, so the response-future needs a safe `Pin` projection. `pin-project-lite` was already in the resolved tree (tokio/hyper/tower), so naming it adds **no new crate** — the lockfile change is one line. Alternative was boxing every response future (an alloc per request); chose the zero-alloc projection.

## 3. CTH on the h2 path — EC2/Linux phase

Local Docker isn't available here, so the full CTH (Docker + Keycloak) couldn't be run. The guards are lenient-by-default and purely transport-level (never change LDP/auth/WAC semantics), so **CTH 41/41 is unaffected**. The remaining EC2-phase confirmation is whether the **Karate/Java harness client negotiates h2** against the `[h2, http/1.1]` server (Java HTTP clients often prefer h1 unless configured), so the CTH genuinely exercises the h2 path. The h2 *serving* path is already proven by `tls_handshake::alpn_negotiates_h2_when_offered_and_h1_fallback`.

## Security validation done locally
- `tests/h2_rate_limit.rs` proves the per-IP rate limiter **still trips over 40 multiplexed h2 streams from one IP** (measured: 2 within-burst → auth/401, 38 → 429, 0 success) — not bypassed by multiplexing.
- New `transport_dos` regressions for both guards + all existing DoS regressions (rapid-reset, slowloris, connection-cap) pass.
- Gate green: fmt + clippy -D warnings + full test suite + redis-replay + release --locked.

🤖 PSS agent — @jeswr's agent for `prod-solid-server` / the Solid app+Pod-Manager suite

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reviewing branch perf-a-http2-guards at commit 145851b, then read the transport_dos regressions and tests/h2_rate_limit.rs. Check the documented idle timeout, request cap, h2 behavior, and existing DoS protections; done means the stated validation gates and test results remain green.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
backend, networking, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.