Skip to main content

conmonrs/streaming_server/spdy/
stream.rs

1//! The streams of a connection, split into the halves the protocols on
2//! top use.
3
4use super::{
5    Live, Queued, QueuedData, Shared,
6    frame::{Frame, Headers},
7};
8use crate::streaming_server::budget::Held;
9use anyhow::{Result, anyhow, bail};
10use bytes::Bytes;
11use std::sync::{
12    Arc,
13    atomic::{AtomicBool, Ordering},
14};
15use tokio::{select, sync::mpsc};
16use tokio_util::sync::{CancellationToken, WaitForCancellationFutureOwned};
17
18/// A stream the client opened and the server accepted.
19pub(crate) struct Stream {
20    pub(super) headers: Headers,
21    pub(super) receiver: StreamReceiver,
22    pub(super) sender: StreamSender,
23}
24
25impl Stream {
26    /// The headers the client opened the stream with.
27    pub(crate) fn headers(&self) -> &Headers {
28        &self.headers
29    }
30
31    /// The ID of the stream.
32    pub(crate) fn id(&self) -> u32 {
33        self.sender.id
34    }
35
36    /// Whether the stream got reset or the connection ended.
37    pub(crate) fn is_reset(&self) -> bool {
38        self.receiver.is_reset()
39    }
40
41    /// Resolves once the stream got reset or the connection ended, also
42    /// after the stream got dropped.
43    pub(crate) fn reset_watch(&self) -> WaitForCancellationFutureOwned {
44        self.receiver.reset.clone().cancelled_owned()
45    }
46
47    /// Split the stream into the data of the client and the sending side,
48    /// to use both at the same time.
49    pub(crate) fn split(self) -> (StreamReceiver, StreamSender) {
50        (self.receiver, self.sender)
51    }
52
53    /// Send data, see [`StreamSender::send`].
54    #[cfg(test)]
55    pub(crate) async fn send(&mut self, data: Bytes) -> Result<()> {
56        self.sender.send(data).await
57    }
58
59    /// Close the sending side, see [`StreamSender::close`].
60    #[cfg(test)]
61    pub(crate) async fn close(&mut self) -> Result<()> {
62        self.sender.close().await
63    }
64}
65
66/// The data the client sends on a stream.
67pub(crate) struct StreamReceiver {
68    pub(super) data: mpsc::Receiver<Held>,
69    pub(super) reset: CancellationToken,
70    pub(super) remote_closed: Arc<AtomicBool>,
71    pub(super) _live: Arc<Live>,
72}
73
74impl StreamReceiver {
75    /// The next data, `None` once the client closed its side, the stream got
76    /// reset or the connection ended.
77    pub(crate) async fn recv(&mut self) -> Option<Bytes> {
78        self.data.recv().await.map(Held::into_bytes)
79    }
80
81    /// The next data like [`Self::recv`], which still counts against the
82    /// budget of the connection while it is held.
83    pub(crate) async fn recv_held(&mut self) -> Option<Held> {
84        self.data.recv().await
85    }
86
87    /// Whether the stream got reset or the connection ended.
88    pub(crate) fn is_reset(&self) -> bool {
89        self.reset.is_cancelled()
90    }
91
92    /// Whether the client closed its side, also if the stream got reset or
93    /// the connection ended afterwards.
94    pub(crate) fn is_closed_by_client(&self) -> bool {
95        self.remote_closed.load(Ordering::Acquire)
96    }
97}
98
99/// The sending side of a stream. Dropping it without closing it resets the
100/// stream.
101pub(crate) struct StreamSender {
102    pub(super) id: u32,
103    pub(super) shared: Arc<Shared>,
104    pub(super) reset: CancellationToken,
105
106    /// The frames of the stream in the data queue.
107    pub(super) queued: Arc<Queued>,
108    pub(super) closed: bool,
109    pub(super) _live: Arc<Live>,
110}
111
112impl StreamSender {
113    /// Send data in a single frame, at most
114    /// [`MAX_DATA_FRAME_LEN`](super::frame::MAX_DATA_FRAME_LEN) bytes. Fails
115    /// once the stream got reset or the connection ended.
116    #[expect(
117        clippy::needless_pass_by_ref_mut,
118        reason = "one send at a time keeps the frames in order"
119    )]
120    pub(crate) async fn send(&mut self, data: Bytes) -> Result<()> {
121        if self.closed {
122            bail!("SPDY stream {} is closed", self.id);
123        }
124        self.queue(false, data).await
125    }
126
127    /// Queue a data frame for the writer.
128    async fn queue(&self, fin: bool, data: Bytes) -> Result<()> {
129        self.queued.add();
130        let mut unqueued = Unqueued {
131            sender: self,
132            queued: false,
133        };
134        let frame = QueuedData {
135            frame: Frame::Data {
136                stream_id: self.id,
137                fin,
138                data,
139            },
140            queued: self.queued.clone(),
141        };
142        select! {
143            biased;
144            () = self.reset.cancelled() => bail!("SPDY stream {} got reset", self.id),
145            result = self.shared.data.send(frame) => {
146                result.map_err(|_| anyhow!("SPDY connection closed"))?;
147                unqueued.queued = true;
148                Ok(())
149            }
150        }
151    }
152
153    /// Close the sending side after the data sent before. A close which got
154    /// cancelled leaves the stream to its drop, which resets it.
155    pub(crate) async fn close(&mut self) -> Result<()> {
156        if self.closed {
157            return Ok(());
158        }
159        let result = self.queue(true, Bytes::new()).await;
160        self.closed = true;
161        self.shared.local_closed(self.id);
162        result
163    }
164
165    /// Reset the stream, both sides end. The data queued for the stream
166    /// before goes out first. Users reset a stream by dropping it without
167    /// closing it, the tests also directly.
168    pub(super) fn reset(&mut self) {
169        self.closed = true;
170        if !self.reset.is_cancelled() && self.queued.reset() {
171            self.shared.queue_reset(self.id);
172        }
173        self.shared.remove(self.id);
174    }
175
176    /// Resolves once the client reset the stream or the connection ended.
177    pub(crate) async fn reset_by_peer(&self) {
178        self.reset.cancelled().await;
179    }
180
181    /// Whether the stream got reset or the connection ended.
182    pub(crate) fn is_reset(&self) -> bool {
183        self.reset.is_cancelled()
184    }
185}
186
187impl Drop for StreamSender {
188    fn drop(&mut self) {
189        if !self.closed {
190            self.reset();
191        }
192    }
193}
194
195/// Takes back the count of a frame which did not make it into the data
196/// queue, also when its send got cancelled.
197struct Unqueued<'a> {
198    sender: &'a StreamSender,
199    queued: bool,
200}
201
202impl Drop for Unqueued<'_> {
203    fn drop(&mut self) {
204        if !self.queued && self.sender.queued.remove() {
205            self.sender.shared.queue_reset(self.sender.id);
206        }
207    }
208}