Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document how to close a stream correctly #1493

Merged
merged 10 commits into from
Mar 1, 2023
43 changes: 43 additions & 0 deletions quinn/src/recv_stream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,51 @@ use crate::{
/// - A variant of [`ReadError`] has been yielded by a read call
/// - [`stop()`] was called explicitly
///
/// # Closing a stream
///
/// When a stream is expected to be closed gracefully the sender should call
/// [`SendStream::finish`]. However there is no guarantee the connected [`RecvStream`] will
/// receive the "finished" notification in the same QUIC frame as the last frame which
/// carried data.
///
/// Even if the application layer logic already knows it read all the data because it does
/// its own framing, it should still read until it reaches the end of the [`RecvStream`].
/// Otherwise it risks inadvertently calling [`RecvStream::stop`] if it drops the stream.
/// And calling [`RecvStream::stop`] could result in the connected [`SendStream::finish`]
/// call failing with a [`WriteError::Stopped`] error.
///
/// For example if exactly 10 bytes are to be read, you still need to explicitly read the
/// end of the stream:
///
/// ```no_run
/// # use quinn::{SendStream, RecvStream};
/// # async fn func(
/// # mut send_stream: SendStream,
/// # mut recv_stream: RecvStream,
/// # ) -> anyhow::Result<()>
/// # {
/// // In the sending task
/// send_stream.write(&b"0123456789"[..]).await?;
/// send_stream.finish().await?;
///
/// // In the receiving task
/// let mut buf = [0u8; 10];
/// let data = recv_stream.read_exact(&mut buf).await?;
/// if recv_stream.read_to_end(0).await.is_err() {
/// recv_stream.stop(0u8.into()).ok();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, of course this call is impossible because read_to_end takes ownership. Perhaps we should change it to take &mut self...

/// }
/// # Ok(())
/// # }
/// ```
///
/// Note that in this example the receiver sends an error to the sender if it received some
/// unexpected data, interrupting any further attempts to send data. But crucially only
/// after it attempted to read the end of the stream.
///
/// [`ReadError`]: crate::ReadError
/// [`stop()`]: RecvStream::stop
/// [`SendStream::finish`]: crate::SendStream::finish
/// [`WriteError::Stopped`]: crate::WriteError::Stopped
#[derive(Debug)]
pub struct RecvStream {
conn: ConnectionRef,
Expand Down