Files
alkhttp/Cargo.toml
T
glm-5.3-flash 5971c0a0d6 fuzz: adopt fuzzing (wave 1) + fix the SSE dribble quadratic (FWD-20)
Adopt the alk*/fuzzing posture (alkcall 0.8.1 precedent) — the dep
bump this ride-along builds on was 4005517:

- docs/plans/fuzzing.md: the four-target plan (sse_parser,
  ws_chunk_framing this session; spec_import + the stateful wave
  later), the infrastructure blueprint, and the corpus/campaign
  policies (§3's table tracks progress)
- fuzz/ workspace (the sibling layout): nightly-pinned subtree,
  stable fuzz/shared invariant library (corpus replay = the standing
  fuzz gate), detached runner (never a foreground child of an agent
  session), JSON dict, deterministic seed generator; 80 committed seeds
- two wave-1 targets: sse_parser (SseParser::feed + the FWD-17
  envelope mapping — the parser every subscription forwards through)
  and ws_chunk_framing (WriteChunkWalk, the write pump's chunk walk)
- crate-side surfacing: SseParser/SseEvent/sse_event_envelope are pub
  behind the adapters::forward::fuzzing re-export hub; the write
  pump's inline chunk loop extracted as WriteChunkWalk (pump byte
  behavior unchanged — 441 tests green); retained_bytes() diagnostic
  (the alktunnels/alksocks posture)
- root Cargo.toml gains the explicit [workspace] table with
  fuzz/ excluded (auto-discovery would pull the nightly-consumed
  dev-deps into the stable build — the alkcall trap); fuzz/ joins the
  publish exclude list
- AGENTS.md verification checklist gains the corpus-replay line

FWD-20 fix, found by driving the new sse_parser harness: feed()
rescanned the whole reassembly buffer per feed — a dribble-fed
subscription (one unterminated line over many small chunks) cost
quadratic CPU (1 MiB dribble ≈ minutes per connection, unbounded
total). Line assembly now walks only the arriving chunk: the buffer
holds just the current line, the scan never revisits drained bytes.
1 MiB dribble: ~5 min (quadratic) → 21 ms (linear). Regression test
sse_parser_dribble_feeds_do_not_rescan_the_buffer.

Verification: cargo test 441 passed; cargo test --all-features ok;
clippy --all-targets -- -D warnings (main + fuzz/shared) clean;
fmt --check (main, fuzz, fuzz/shared) clean; cargo fuzz build clean;
corpus replay (cargo test --manifest-path fuzz/shared/Cargo.toml) 80
seeds green.

Refs: alkcall docs/research/fuzzing.md (§7.9 posture), alksocks
08a3694 (the sibling wave-1 shape), docs/plans/fuzzing.md §2
2026-09-29 08:32:29 +00:00

122 lines
4.6 KiB
TOML

[package]
name = "alkhttp"
version = "0.5.0"
edition = "2021"
rust-version = "1.88"
license = "MIT OR Apache-2.0"
description = "HTTP interface for the alk stack: serves HTTP/1.1 + HTTP/2 on standard ALPNs (with WebSocket upgrade carrying the channels protocol) and hosts the HTTP-backed call-protocol adapters"
readme = "README.md"
repository = "https://git.alk.dev/alkdev/alkhttp"
keywords = ["http", "websocket", "rpc", "openapi", "mcp"]
categories = ["network-programming", "web-programming", "asynchronous"]
exclude = [".opencode/", "AGENTS.md", "docs/", "tasks/", "scripts/", "fuzz/"]
[lib]
name = "alkhttp"
[workspace]
members = ["."]
exclude = ["fuzz"]
[features]
default = ["server", "client", "h2", "http1"]
# Producer side: the axum `Router` host (gateway routes, /healthz,
# /openapi.json, /mcp, the WS upgrade path) and the hyper connection
# driver. `openapi` rides along because /openapi.json is part of the
# default surface (ADR-042/045); `http1` rides along so the hyper
# auto-builder always has at least one protocol compiled.
server = ["dep:axum", "dep:hyper", "dep:hyper-util", "dep:uuid", "openapi", "http1"]
# Consumer side: the shared outbound client host and the HTTP-backed
# import adapters (`from_jsonschema`, `from_openapi` with `openapi`,
# `from_mcp` with `mcp`).
client = ["dep:arc-swap", "dep:httpdate", "dep:percent-encoding", "dep:reqwest", "dep:reqwest-middleware", "dep:reqwest-retry", "dep:url", "openapi"]
# Shared OpenAPI document model: `from_openapi` parsing (client side)
# and the `to_openapi` gateway projection (server side).
openapi = ["dep:yaml_serde"]
# MCP adapters: `from_mcp` needs `client`, `to_mcp` needs `server`.
mcp = ["dep:rmcp"]
# WebSocket transport (from_wss consumer; tungstenite flavor of the
# WS ↔ byte-stream adapter).
wss = ["dep:tokio-tungstenite"]
# Test-only WS client helpers (downstream deployment tests); implies
# `server` — the helpers live with the upgrade path.
test-support = ["server", "dep:tokio-tungstenite"]
# HTTP protocol features of the server connection driver (ADR-001).
h2 = ["server", "dep:hyper", "hyper-util/http2", "hyper/http2"]
http1 = ["server", "dep:hyper", "hyper-util/http1", "hyper/http1"]
[dependencies]
alkcall = { version = "0.8.1", features = ["gateway"] }
arc-swap = { version = "1", optional = true }
axum = { version = "0.8", optional = true, features = ["ws"] }
bytes = "1"
futures = "0.3"
http = "1"
httpdate = { version = "1", optional = true }
hyper = { version = "1", optional = true, features = ["server"] }
hyper-util = { version = "0.1", optional = true, features = ["server", "service", "tokio"] }
jsonschema = { version = "0.46", default-features = false }
parking_lot = "0.12"
percent-encoding = { version = "2", optional = true }
reqwest = { version = "0.13", optional = true, default-features = false, features = ["json", "stream", "rustls"] }
reqwest-middleware = { version = "0.5", optional = true }
reqwest-retry = { version = "0.9", optional = true }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-util", "net", "fs", "time", "sync"] }
tokio-tungstenite = { version = "0.29", optional = true, default-features = false, features = ["connect", "rustls-tls-webpki-roots", "handshake"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
async-trait = "0.1"
tracing = "0.1"
thiserror = "2"
uuid = { version = "1", optional = true, features = ["v4"] }
url = { version = "2", optional = true }
yaml_serde = { version = "0.10", optional = true }
rmcp = { version = "1.8", optional = true, default-features = false, features = [
"client",
"server",
"transport-streamable-http-client-reqwest",
"transport-streamable-http-server",
] }
[dev-dependencies]
http-body-util = "0.1"
tower = { version = "0.5", features = ["util"] }
tokio-tungstenite = { version = "0.29", default-features = false, features = ["connect"] }
openapiv3 = "2"
rcgen = "0.14"
tokio-rustls = "0.26"
rustls = { version = "0.23", default-features = false, features = ["aws_lc_rs", "std", "tls12"] }
rustls-pki-types = "1"
uuid = { version = "1", features = ["v4"] }
[[test]]
name = "ws_upgrade_session"
required-features = ["test-support"]
[[test]]
name = "ws_overlay_ops"
required-features = ["test-support"]
[[test]]
name = "from_mcp_integration"
required-features = ["server", "client", "mcp"]
[[test]]
name = "full_surface"
required-features = ["server", "client", "openapi", "mcp", "test-support"]
[[test]]
name = "client_config_reload"
required-features = ["client"]
[[test]]
name = "client_tls"
required-features = ["client"]
[[test]]
name = "retry_after_budget"
required-features = ["client"]
[[test]]
name = "retry_policy_wire"
required-features = ["client"]