Skip to content

Add advanced proxying features: rate limiting, CPU-aware balancing, source address forwarding, HTTP/2 ALPN#6

Merged
kriszyp merged 23 commits into
mainfrom
test-harper
May 13, 2026
Merged

Add advanced proxying features: rate limiting, CPU-aware balancing, source address forwarding, HTTP/2 ALPN#6
kriszyp merged 23 commits into
mainfrom
test-harper

Conversation

@kriszyp
Copy link
Copy Markdown
Member

@kriszyp kriszyp commented Apr 18, 2026

Summary

  • Per-route rate limiting (maxConnectionsPerSecond, burst): route-wide token bucket to prevent one route from starving others. Connections dropped silently when exhausted.
  • Per-upstream CPU utilisation monitoring: UDS upstreams can declare a Linux pid/tid; symphony samples /proc/{pid}/task/{tid}/stat every 250ms and incorporates measured CPU utilisation as a secondary tiebreaker in socket selection (score = active_connections × 1000 + cpu_util_permille).
  • Source address forwarding (sourceAddressHeader): per-route choice of PROXY Protocol v1 (default for UDS), X-Forwarded-For header injection (for backends that don't support PROXY Protocol), or none (default for TCP).
  • HTTP/2 ALPN (http2): opt-in per route/resolveConnection. When true, advertises ['h2', 'http/1.1'] in TLS ALPN so clients negotiate HTTP/2; raw H2 frames flow through copy_bidirectional unchanged — no HTTP parsing. Requires terminateTls: true. Default false (backward compatible).

Purpose

Harper's UDS workers run in separate threads and processes. These features allow symphony to:

  • Enforce fairness between routes under load
  • Route new connections to less-loaded threads using real CPU utilisation data
  • Propagate the real client IP to upstream servers that need it
  • Support HTTP/2 negotiation transparently for upstreams that serve h2

Areas for attention

  • CPU monitoring (balancer.rs): update_cpu_stats() uses fixed-point arithmetic and CAS stores on AtomicU32/AtomicU64 per slot. The /proc read is blocking I/O done on a tokio worker thread (250ms interval); it's short-lived but it's not offloaded to a blocking thread pool. Low risk at 250ms cadence.
  • X-Forwarded-For injection (http_proxy.rs): peeks at the first bytes of the request to find the end of the request line, then splices in the header. This is a best-effort parse — it expects well-formed HTTP/1.x. Malformed or HTTP/2 requests on a non-http2 route skip the header insertion.
  • TlsConfigCache key now includes (cert_sha256, mtls_sha256, http2). Routes sharing cert + mTLS but differing in ALPN get distinct ServerConfig instances — correct, but worth confirming the hash covers all relevant config.
  • resolveConnection + http2: Gemini review flagged that the resolution path originally hardcoded http2=false. Fixed in the ALPN commit — JsResolveRoute now carries http2 and threads it through build_resolved_route.

🤖 Generated with Claude Code

kriszyp and others added 23 commits April 17, 2026 19:41
- Add __test__/harper-integration.spec.ts: starts a real Harper instance with
  TLS + UDS mirroring, reads metadata YAML, configures SymphonyProxy to
  terminate TLS and route through UDS sockets, then verifies HTTP responses.
- Fix loadAddon() in ts/proxy.ts: try both one and two levels up from __dirname
  so the native addon is found in both production (dist/) and test (dist-test/ts/)
  build layouts.
- Add test:integration script and harper/yaml devDependencies in package.json.
- Add integration-test CI job that checks out and builds harper-pro, then runs
  the integration test with HARPER_INTEGRATION_TEST_INSTALL_SCRIPT.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces a sourceAddressHeader route option with three modes:
  - 'proxyProtocol' (default for UDS): send PROXY v1 header before data
  - 'xForwardedFor': read the first HTTP chunk, insert X-Forwarded-For
    after the request line, then copy the rest verbatim — no per-request
    parsing overhead on keep-alive connections
  - 'none' (default for TCP): no source address forwarding

This enables Bun backends (which lack PROXY protocol support) to receive
the real client IP via X-Forwarded-For over UDS upstreams.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a row to the RouteConfig reference table and a new "Source address
forwarding" section explaining all three modes, with examples for the
PROXY protocol (HarperDB/nginx) and X-Forwarded-For (Bun) use cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e, and configure TLS session resumption

- **package.json**: Added `benchmark`, `benchmark:throughput`, and `diagnostic:keepalive` scripts for testing and diagnostics.
- **proxy.rs**: Introduced multi-threaded runtime (`tokio::runtime::Runtime`) to distribute proxy tasks across CPU cores, improving connection handling.
- **tls.rs**: Configured TLS session resumption with support for both TLS 1.2 and 1.3, reducing handshake latency for resumed sessions.
…ifact publishing

- **package.json**: Remove `build` step from `prepublishOnly` script.
- **Cargo.toml**: Disable default `rustls` and `tokio-rustls` features; enable logging and TLS 1.2 support.
- **release.yml**: Refactor artifact handling and npm publishing, publishing platform-specific packages separately via `napi`.
Updates CI and release workflows to use `--ignore-scripts` flag instead of `--omit=optional` for npm ci, preventing execution of install scripts during dependency installation.
…workflows

Updates CI and release workflows to upgrade npm globally before running `npm ci`, ensuring consistent dependency installation on macOS runners.
…e workflows

Updates macOS and Linux workflow steps to use `npm install --ignore-scripts` instead of upgrading npm and running `npm ci`, simplifying dependency installation across all runners.
…optionalDependencies

Updates the release workflow to manually populate `optionalDependencies` in package.json by reading platform package metadata from the `npm/` directory, replacing the previous `napi prepublish` command. Also upgrades npm to latest version before installing dependencies.
…e workflow

Replaces `npm ci` with `npm install -g npm@latest && npm install --ignore-scripts` to ensure npm is upgraded before dependency installation, aligning with other workflow changes.
Adds an `http2` boolean field to RouteConfig and ResolveRoute. When true,
symphony advertises ['h2', 'http/1.1'] in the TLS ALPN extension so clients
can negotiate HTTP/2. Raw H2 frames flow through copy_bidirectional to the
upstream unchanged — no HTTP parsing or translation. Default: false.

TlsConfigCache key extended to include the http2 flag so routes sharing the
same cert but differing in ALPN get distinct ServerConfig instances.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kriszyp kriszyp changed the title Test harper Add advanced proxying features: rate limiting, CPU-aware balancing, source address forwarding, HTTP/2 ALPN May 5, 2026
@kriszyp kriszyp merged commit e72b220 into main May 13, 2026
5 of 10 checks passed
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