fix(server): hyper knobs, decoy fidelity, cache + builder fixes (SRV-04..SRV-10)
- SRV-04: TokioTimer on h1+h2 builder, header_read_timeout 10s, h1 keep-alive on, h2 keep-alive 30s/10s; concurrency boundary documented - SRV-05: with_decoy rebuild keeps extra routes (clone, not take) - SRV-07: method_not_allowed_fallback serves the nginx-shaped 405 - SRV-08: UTF-8 percent-decoding, literal '+', tokio::fs syscalls - SRV-09: /openapi.json cached at construction, generic 500 body, to_openapi returns Result (expect removed) - SRV-10: ChannelsPolicy extension injection point on the WS upgrade; single token resolution via route ordering (WS layer before the router-wide auth route_layer) Verification: cargo test 265 passed; --all-features server::/to_openapi:: green; clippy + fmt clean on touched files (remaining tree noise is a parallel agent's in-flight from_mcp/from_wss/forward work)
This commit is contained in:
@@ -25,8 +25,7 @@ use super::byte_adapter::split_ws_to_bytes;
|
||||
|
||||
/// The channels session for an upgraded socket: adapt → `Connection`
|
||||
/// (identity attached) → `ChannelsAdapter::handle`. `policy` gates
|
||||
/// data-channel opens (ADR-041); the default surface uses `NoCap`
|
||||
/// (the deployment's assembly layer can pass a stricter policy).
|
||||
/// data-channel opens (ADR-041).
|
||||
pub async fn run_channels_session(
|
||||
socket: axum::extract::ws::WebSocket,
|
||||
registry: Arc<OperationRegistry>,
|
||||
@@ -115,16 +114,34 @@ impl alkcall::core::auth::IdentityProvider for NoopProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extension wrapper for the channels-policy injection point (SRV-10):
|
||||
/// a deployment inserts `ChannelsPolicy(Arc<dyn ChannelLifecyclePolicy>)`
|
||||
/// into the request extensions (a route layer on the WS route) to gate
|
||||
/// data-channel opens per identity (ADR-041). Without the extension the
|
||||
/// upgrade defaults to [`NoCap`] — the crate default for the built-in
|
||||
/// surface (POC/trusted-peer semantics); assembly layers that build
|
||||
/// their own upgrade route pass a stricter policy directly to
|
||||
/// [`run_channels_session`].
|
||||
#[derive(Clone)]
|
||||
pub struct ChannelsPolicy(pub Arc<dyn ChannelLifecyclePolicy>);
|
||||
|
||||
/// The upgrade handler. Requires the resolved identity in request
|
||||
/// extensions (stashed by [`ws_bearer_auth`]) — a WS session without
|
||||
/// an identity cannot run `AccessControl::check`.
|
||||
///
|
||||
/// The channel lifecycle policy comes from the
|
||||
/// [`ChannelsPolicy`] request extension when present, else `NoCap`.
|
||||
pub async fn ws_upgrade_handler(
|
||||
axum::extract::State(registry): axum::extract::State<Arc<OperationRegistry>>,
|
||||
axum::Extension(identity): axum::Extension<Identity>,
|
||||
policy: Option<axum::Extension<ChannelsPolicy>>,
|
||||
ws_upgrade: WebSocketUpgrade,
|
||||
) -> Response {
|
||||
let policy = policy
|
||||
.map(|axum::Extension(p)| p.0)
|
||||
.unwrap_or_else(|| Arc::new(NoCap));
|
||||
ws_upgrade.on_upgrade(move |socket| async move {
|
||||
run_channels_session(socket, registry, identity, Arc::new(NoCap)).await
|
||||
run_channels_session(socket, registry, identity, policy).await
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user