Skip to main content

ProxyHook

Trait ProxyHook 

Source
pub trait ProxyHook: Send + Sync {
    // Provided methods
    fn interest(&self) -> Interest { ... }
    fn on_control_message(
        &self,
        _cx: &FrameCtx<'_>,
        _msg: &AnyControlMessage,
        _raw: &[u8],
    ) -> Action { ... }
    fn on_stream_open(&self, _cx: &StreamCtx<'_>) -> StreamAction { ... }
    fn on_stream_header(
        &self,
        _cx: &StreamCtx<'_>,
        _header: &DataStreamHeaderKind,
    ) -> StreamAction { ... }
    fn on_object(&self, _cx: &ObjectCtx<'_>, _raw: &[u8]) -> Action { ... }
    fn on_datagram(
        &self,
        _cx: &FrameCtx<'_>,
        _header: Option<&AnyDatagramHeader>,
        _raw: &[u8],
    ) -> Action { ... }
    fn on_stream_end(&self, _cx: &StreamCtx<'_>, _end: StreamEnd) -> Action { ... }
}
Expand description

Decide what happens to frames, objects, datagrams and streams.

Every method is synchronous and defaulted, so Arc<dyn ProxyHook> stays dyn-compatible and an observing-only implementation is impl ProxyHook for MyHook {}. There is no async fn in the trait and no async-trait dependency. Cases that genuinely need to await an external signal use Action::Hold, so a hook never stalls a read loop: timing is expressed as data and executed by the engine, where it is precise, attributable and bounded.

Provided Methods§

Source

fn interest(&self) -> Interest

What this hook wants the proxy to parse.

Sampled once, at session start, and cached. Interest::NONE keeps the zero-parse byte-pump path bit-for-bit on all three forwarding paths.

Source

fn on_control_message( &self, _cx: &FrameCtx<'_>, _msg: &AnyControlMessage, _raw: &[u8], ) -> Action

Called before forwarding a control message.

Fires only when Interest::CONTROL is set: without it the control stream takes the forward-first path, where the bytes are already in flight by the time they are parsed and a return value would be unexecutable.

raw is the frame’s original wire bytes — type, scope, length prefix and payload.

Source

fn on_stream_open(&self, _cx: &StreamCtx<'_>) -> StreamAction

Called after a unidirectional stream is accepted and before the peer stream is opened. Stream identity only — see StreamCtx.

Fires only when Interest::STREAMS is set. Under any other interest the decision point between accept_uni() and open_uni() is not armed and the stream is forwarded. The gate is spelled out because otherwise it is undefined whether an Interest::NONE session calls a hook method at all: it does not, on this method or any other.

Source

fn on_stream_header( &self, _cx: &StreamCtx<'_>, _header: &DataStreamHeaderKind, ) -> StreamAction

Called once the data stream’s header has been framed and before its bytes are forwarded.

This is where track-targeted decisions belong: header carries the track alias, group and publisher priority.

Fires only when Interest::STREAMS is set. STREAMS includes Interest::OBJECTS structurally, so declaring STREAMS alone is sufficient and puts the stream on the framed path — which it must be, because there is no header without framing. Declaring OBJECTS alone frames the stream but does not call this method.

Source

fn on_object(&self, _cx: &ObjectCtx<'_>, _raw: &[u8]) -> Action

Called before forwarding one complete object.

Fires only when Interest::OBJECTS is set (and therefore also under Interest::STREAMS, which includes it). Attaching an event observer does not turn this on: an observer makes the proxy frame objects, so that ProxyEvent::Object can fire, but a hook that declared no object interest is never asked and never has a returned Action honoured. Framing and consulting the hook are separate decisions.

raw is the object’s exact wire bytes as they will be forwarded, framing and payload; cx.meta.payload_len bytes at the end of it are the payload. Action::ReplacePayload replaces that trailing region. As they will be forwarded is load-bearing after an elide: when a previous object on this stream was elided on a delta-encoding draft, the framer has already rewritten this object’s leading Object ID varint, so raw is what goes on the wire and raw.len() - cx.meta.payload_len is still the payload offset. cx.meta.object_id is the absolute ID either way.

Not called for objects the framer could not address: an object larger than FramerConfig::max_buffered_object_bytes, or any object on a stream the framer has stopped parsing. Those are reported as ProxyEvent::Impairment instead, so “nothing matched” and “never parsed” are distinguishable.

Source

fn on_datagram( &self, _cx: &FrameCtx<'_>, _header: Option<&AnyDatagramHeader>, _raw: &[u8], ) -> Action

Called before forwarding a datagram.

Fires only when Interest::DATAGRAMS is set.

header is None when the datagram’s header did not decode. The hook is still called, so Action::Drop on malformed traffic is expressible. raw is the whole datagram.

Action::ReplacePayload is available here only when the payload’s start is derivable: not on draft-14, whose AnyDatagramHeader decode consumes the payload; not on a status datagram, which has no payload slot; and not when header is None. In those three cases it is refused with Refusal::PayloadNotDelimited and the datagram is forwarded unchanged. cx.caps answers this before you ask for it.

Source

fn on_stream_end(&self, _cx: &StreamCtx<'_>, _end: StreamEnd) -> Action

Called when a forwarded stream ends, for any reason.

Fires when Interest::STREAMS is set, on data streams and on the control stream — cx.is_control_stream says which rules apply, and it must, because Action::ResetStream is illegal on a control stream on every draft and is refused there with Refusal::ControlStreamResetIllegal. On drafts 17-19 that flag is also true for a bidirectional request stream, which runs under the same rules; see StreamCtx::is_control_stream for why and for what it costs.

Three actions are honoured here: Action::Pass, Action::ResetStream (data streams only) and Action::CloseSession (both, because a close is session-scoped and no site can be the wrong one for it — it is the documented escalation for a control stream, where a reset is a protocol violation). Everything else is refused with Refusal::WrongSite. To delay a stream’s end, delay its last object.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§