Skip to main content

Reader

Struct Reader 

Source
pub struct Reader { /* private fields */ }
Expand description

The receiving half of a split request stream.

Implementations§

Source§

impl Reader

Source

pub async fn recv_data(&mut self) -> Result<Option<Bytes>, StreamError>

Reads the next chunk of body data.

Ok(None) means the peer finished its sending side – for a CONNECT tunnel, the client’s FIN.

Cancel-safe: every byte read is accounted for in self before this returns, so a caller may poll it inside a select! with a timeout, which is exactly what a UDP session does.

Source

pub async fn reset_by_peer(&mut self) -> StreamError

Resolves when the peer resets this stream, with the reset as an error.

Self::recv_data already reports a reset – it is the Err a read fails with – but only to a caller that is reading. A CONNECT tunnel spends much of its life not reading: with a chunk in hand and a target that has stopped taking bytes, the pump is parked in a write instead, and nothing there watches the request stream. This is what such a write can select on.

It reports only a reset, and never resolves for any other ending. A clean FIN and a stream this endpoint stopped both belong to the reading half, which is where a caller meets them; ending the wait here would turn one of them into an abort.

§Why not quinn::RecvStream::received_reset

Because it borrows a slot it never gives back, and quinn asserts on that slot being empty. quinn keeps one waker per stream for whoever is waiting to read, and exactly three things take an entry out of it: a StreamEvent::Readable for that stream, a RecvStream::stop while the stream still exists at the protocol layer, and RecvStream::drop while all_data_read is still false. A read that succeeds does not, so an entry outlives every later read of the bytes it was waiting for. That call writes into the slot on every poll that finds no reset, and a select! which drops the arm leaves it behind.

In release builds that is a leak – one waker per tunnel, held until the connection closes, keeping the finished task’s cell alive with it. In debug builds it is a panic, because RecvStream::drop debug-asserts the slot is empty once the stream has been read to its end. An ordinary upload trips it: the client sends chunk after chunk with its FIN behind them, the pump is parked writing chunk k while k+1 onwards are already buffered, and every one of those iterations leaves another waker behind. Nothing becomes readable after the FIN, so the last one is never cleared, and the clean end of the stream then panics the tunnel’s task inside a destructor.

So the wait is built on the zero-length read alone, which registers only through quinn’s own read path. That kind of entry is safe to abandon: quinn takes it out again the moment the stream becomes readable, and a stream cannot reach its end without becoming readable first, so there is never one left when the reading half meets the FIN.

§What that costs

A zero-length read parks only while the stream has nothing to give. With bytes already buffered it returns at once – which is precisely the state a stalled upload sits in – so the wait there is a poll on a timer rather than a wake-up, and RESET_PEEK_INTERVAL – 250 ms, documented where it is defined – bounds how late the reset is noticed. A reset that arrives while nothing is buffered needs no timer: it wakes the parked read at once, as any read error would.

Cancel-safe, so a select! may poll it and drop it repeatedly.

Source

pub fn stop_receiving(&mut self, code: Code)

Asks the peer to stop sending on this stream.

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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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