Skip to main content

RequestStream

Struct RequestStream 

Source
pub struct RequestStream {
    send: FramedSendStream,
    recv: FramedRecvStream,
    request_id: VarInt,
    kind: RequestKind,
    draft: DraftVersion,
    stream_id: u64,
    cancelled: bool,
    finished: bool,
    origin: RequestOrigin,
    responded: bool,
}
Expand description

One request and its answer, on a bidirectional stream of their own.

Draft-17 Section 3.3 moved requests off the control plane: each request is the first message on a bidirectional stream it opens, and the response comes back on that same stream. Responses carry no request id on this draft — the stream is the correlation, which is why this handle exists and why a bare request id is no longer enough to find an answer.

§Reading and writing go through the connection

This handle owns both halves of the stream but not the session, so the endpoint state machine and the observer stay where they were. Read a response with Connection::recv_on_request_stream, write a follow-up with Connection::send_on_request_stream, and cancel with Connection::cancel_request_stream.

cancel and peer_cancelled are on the handle because they touch the stream and nothing else, and Drop needs the first of them. Neither moves the endpoint’s record of the request, which is why the connection carries a pair of its own.

§Dropping this cancels the request

A dropped handle resets the send half and sends STOP_SENDING on the receive half, both with REQUEST_CANCELLED, unless the stream was already cancelled or finished. Letting the default drop stand would send a FIN instead, telling the peer the request ended cleanly when it was abandoned.

The consequence is sharp and worth stating: a live subscription’s request stream must be held for the subscription’s life, because PUBLISH_DONE arrives on it. Keeping only request_id and letting the handle fall out of scope cancels the subscription.

What a drop cannot do is say so at the endpoint. Drop holds the stream and not the session, so the request stays where it was in the endpoint’s record while the stream it travelled on is gone. Call Connection::cancel_request_stream wherever that record matters.

§Which side opened it changes what this handle does

origin says whether this endpoint opened the stream or accepted it, and three behaviours turn on it: reads dispatch as responses or as follow-ups to the peer’s request, the respond_* helpers refuse a stream this endpoint opened, and Drop resets with REQUEST_UNANSWERED rather than REQUEST_CANCELLED. Everything else — cancel, peer_cancelled, finish, Connection::send_on_request_stream — is the same in both directions. Draft-17 Section 3.3.1 is explicit that a cancel is available to both: “Senders cancel requests if the response is no longer of interest; Receivers cancel requests if they are unable to or choose not to respond.”

All fields are private so the shape can grow without breaking callers.

Fields§

§send: FramedSendStream§recv: FramedRecvStream§request_id: VarInt§kind: RequestKind§draft: DraftVersion§stream_id: u64§cancelled: bool§finished: bool§origin: RequestOrigin§responded: bool

Whether a respond_* helper has written a response on this stream. True on a RequestOrigin::Peer stream from the response written on it, and on a RequestOrigin::Local one from the answer to an update the peer sent, which is the only response this endpoint writes on a stream of its own.

Implementations§

Source§

impl RequestStream

Source

pub fn request_id(&self) -> VarInt

The request id the endpoint allocated for this request.

Useful for logging and for endpoint calls that still take one. It is not enough to find the response: draft-17 responses carry no request id, so only this stream identifies them.

Source

pub fn kind(&self) -> RequestKind

Which of the six request types opened this stream.

Source

pub fn stream_id(&self) -> u64

The transport-level stream identifier, the same one ClientEvent::StreamOpened reports for data streams.

Source

pub fn draft(&self) -> DraftVersion

The draft version this stream is framed for.

Source

pub fn origin(&self) -> RequestOrigin

Which side opened this stream.

RequestOrigin::Peer means this endpoint owes a response and the respond_* helpers apply; RequestOrigin::Local means it is waiting for one.

Source

pub fn responded(&self) -> bool

Whether a response has been written on this stream by one of the respond_* helpers.

On a RequestOrigin::Local stream this says an update the peer sent was answered here, not that the request itself was: that one is answered by the peer.

Source

pub fn is_cancelled(&self) -> bool

Whether cancel has already run on this handle.

Says nothing about the peer: a peer reset is learned from peer_cancelled or from the next read.

Source

pub fn cancel(&mut self, code: u64) -> Result<(), ConnectionError>

Cancel the request by resetting the stream, handing the peer code.

Draft-17 removed UNSUBSCRIBE and FETCH_CANCEL: resetting the request stream is how a request is withdrawn. Both halves are shut — a QUIC bidirectional stream has two independent halves, so resetting only the send half would leave the peer free to keep writing a response nobody will read. The send half is reset with code and the receive half is stopped with the same value.

REQUEST_CANCELLED is the ordinary choice. The parameter is a plain u64 rather than a draft enum because draft-17’s registry for these values is titled “Data Stream Reset Error Codes” and a request stream is not a data stream; a caller who wants a typed value has DataStreamResetErrorCode::as_u64.

This is the stream and nothing else. The endpoint’s record of the request does not move, so a response already in flight is still accepted after this returns. Connection::cancel_request_stream does both and is what a caller holding a connection should reach for; this stays because Drop has no connection to reach.

Idempotent, and it retires the Drop behaviour: a cancelled handle does nothing further when it goes out of scope. Errors from a stream that was already reset or stopped are swallowed for the same reason — the request is cancelled either way.

§Errors

ConnectionError::Transport carrying TransportError::Write if code is outside the QUIC varint range (0..2^62). Nothing is sent in that case, and the handle is not marked cancelled, so a caller can retry with a representable code.

Source

pub async fn peer_cancelled(&mut self) -> Result<Option<u64>, ConnectionError>

Wait for the peer to cancel this request, consuming nothing.

A caller applying backpressure is deliberately not calling Connection::recv_on_request_stream, which is the only other place a peer reset surfaces — so without this the abandonment goes unobserved for as long as the backpressure lasts. This grants no flow-control credit and is cancel-safe.

Returns Ok(Some(code)) with the peer’s application error code, or Ok(None) meaning no reset is observable, now or ever — stop asking. A caller that re-polls after Ok(None) spins.

Like cancel, this records nothing at the endpoint. Connection::peer_cancelled_on_request_stream is the same wait with the record attached.

On WebTransport this always answers Ok(None): wtransport exposes no reset-only observable, so a WebTransport caller learns of a peer cancel on its next read and not before.

Source

pub async fn finish(&mut self) -> Result<(), ConnectionError>

Finish the send half cleanly, leaving the receive half open.

Whether a requester may FIN before its response arrives is not settled by anything this implementation can check, so no request helper calls this and the default is to leave the send half open for the request’s life. It is offered for a caller that knows its peer.

A finished handle, like a cancelled one, does nothing further on Drop.

Trait Implementations§

Source§

impl Drop for RequestStream

Source§

fn drop(&mut self)

Reset the request unless it was already cancelled or finished.

See the type-level note: the default drop would FIN the send half, which claims a clean end for a request the caller walked away from.

The code says which walking away it was. A stream this endpoint opened is cancelled — REQUEST_CANCELLED — which is the requester act draft-17 Section 3.3.1 describes. A stream the peer opened is reset with REQUEST_UNANSWERED whether or not a response was already written: before one, the request was never served; after one, the obligations that follow it are still outstanding.

Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more