1use super::compat::{AllowStd, Direction};
15use super::deflate::PerMessageDeflate;
16use crate::http::error::Error;
17use bytes::{Bytes, BytesMut};
18use futures_util::{Sink, SinkExt, Stream};
19use hyper::header::HeaderValue;
20use hyper_util::rt::TokioIo;
21use std::collections::VecDeque;
22use std::future::poll_fn;
23use std::pin::Pin;
24use std::task::{Context, Poll};
25use tokio_util::sync::PollSender;
26use tungstenite::Error as WsError;
27use tungstenite::protocol::WebSocketConfig;
28use tungstenite::protocol::frame::coding::{Control, Data as OpData, OpCode};
29use tungstenite::protocol::frame::{CloseFrame, Frame, FrameSocket, Utf8Bytes};
30
31pub use tungstenite::Message;
32
33type Io = AllowStd<TokioIo<hyper::upgrade::Upgraded>>;
34
35const SPLIT_CHANNEL_CAPACITY: usize = 32;
39
40pub struct WebSocket {
44 frames: FrameSocket<Io>,
45 protocol: Option<HeaderValue>,
46 config: WebSocketConfig,
47 deflate: Option<PerMessageDeflate>,
48 fragment: Option<Fragment>,
49 outgoing: VecDeque<Frame>,
50 flush_needed: bool,
54 sent_close: bool,
55 closed: bool,
56}
57
58struct Fragment {
59 opcode: OpData,
60 compressed: bool,
61 buffer: BytesMut,
62}
63
64impl std::fmt::Debug for WebSocket {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("WebSocket").finish_non_exhaustive()
67 }
68}
69
70fn protocol_error(err: &WsError) -> Error {
71 Error::Internal(err.to_string())
72}
73
74fn unmask(data: &mut [u8], mask: [u8; 4]) {
78 let mask8 = u64::from_ne_bytes([
79 mask[0], mask[1], mask[2], mask[3], mask[0], mask[1], mask[2], mask[3],
80 ]);
81 let mut chunks8 = data.chunks_exact_mut(8);
82 for chunk in &mut chunks8 {
83 let word =
84 u64::from_ne_bytes([
85 chunk[0], chunk[1], chunk[2], chunk[3], chunk[4], chunk[5], chunk[6], chunk[7],
86 ]) ^ mask8;
87 chunk.copy_from_slice(&word.to_ne_bytes());
88 }
89
90 let mask4 = u32::from_ne_bytes(mask);
91 let mut chunks4 = chunks8.into_remainder().chunks_exact_mut(4);
92 for chunk in &mut chunks4 {
93 let word = u32::from_ne_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]) ^ mask4;
94 chunk.copy_from_slice(&word.to_ne_bytes());
95 }
96
97 for (i, byte) in chunks4.into_remainder().iter_mut().enumerate() {
98 *byte ^= mask[i % 4];
99 }
100}
101
102fn parse_close(payload: &[u8]) -> Result<Option<CloseFrame>, Error> {
103 match payload.len() {
104 0 => Ok(None),
105 1 => Err(Error::Internal("invalid WebSocket close frame".to_string())),
106 _ => {
107 let code = u16::from_be_bytes([payload[0], payload[1]]);
108 let reason = std::str::from_utf8(&payload[2..])
109 .map_err(|_| Error::Internal("WebSocket close reason is not UTF-8".to_string()))?;
110 Ok(Some(CloseFrame { code: code.into(), reason: reason.to_string().into() }))
111 }
112 }
113}
114
115fn poll_io<T>(
118 frames: &mut FrameSocket<Io>,
119 direction: &Direction,
120 cx: &Context<'_>,
121 f: impl FnOnce(&mut FrameSocket<Io>) -> Result<T, WsError>,
122) -> Poll<Result<T, WsError>> {
123 frames.get_mut().register(direction, cx);
124 match f(frames) {
125 Ok(value) => Poll::Ready(Ok(value)),
126 Err(WsError::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => Poll::Pending,
127 Err(err) => Poll::Ready(Err(err)),
128 }
129}
130
131impl WebSocket {
132 pub(super) fn new(
133 io: TokioIo<hyper::upgrade::Upgraded>,
134 protocol: Option<HeaderValue>,
135 config: WebSocketConfig,
136 deflate: Option<PerMessageDeflate>,
137 ) -> Self {
138 Self {
139 frames: FrameSocket::new(AllowStd::new(io)),
140 protocol,
141 config,
142 deflate,
143 fragment: None,
144 outgoing: VecDeque::new(),
145 flush_needed: false,
146 sent_close: false,
147 closed: false,
148 }
149 }
150
151 fn poll_drain_outgoing(&mut self, cx: &Context<'_>) -> Poll<Result<(), WsError>> {
155 while let Some(frame) = self.outgoing.pop_front() {
156 match poll_io(&mut self.frames, &Direction::Write, cx, |fs| fs.write(frame)) {
157 Poll::Ready(Ok(())) => self.flush_needed = true,
158 other => return other,
159 }
160 }
161 if !self.flush_needed {
162 return Poll::Ready(Ok(()));
163 }
164 match poll_io(&mut self.frames, &Direction::Write, cx, FrameSocket::flush) {
165 Poll::Ready(Ok(())) => {
166 self.flush_needed = false;
167 Poll::Ready(Ok(()))
168 }
169 other => other,
170 }
171 }
172
173 fn finish_message(
174 &mut self,
175 opcode: OpData,
176 compressed: bool,
177 payload: Bytes,
178 ) -> Result<Option<Message>, Error> {
179 let bytes = if compressed {
180 let deflate = self.deflate.as_mut().ok_or_else(|| {
181 Error::Internal("RSV1 set but permessage-deflate was not negotiated".to_string())
182 })?;
183 Bytes::from(deflate.decompress(&payload, self.config.max_message_size)?)
184 } else {
185 payload
186 };
187 match opcode {
188 OpData::Text => {
189 let text = Utf8Bytes::try_from(bytes)
190 .map_err(|e| Error::Internal(format!("invalid UTF-8 in text message: {e}")))?;
191 Ok(Some(Message::Text(text)))
192 }
193 OpData::Binary => Ok(Some(Message::Binary(bytes))),
194 OpData::Continue | OpData::Reserved(_) => unreachable!("caller only passes Text/Binary"),
195 }
196 }
197
198 fn handle_frame(&mut self, frame: Frame) -> Result<Option<Message>, Error> {
199 let header = frame.header().clone();
200 let raw = frame.into_payload();
201 let payload = if let Some(mask) = header.mask {
202 let mut buf = raw.try_into_mut().unwrap_or_else(|shared| BytesMut::from(&shared[..]));
206 unmask(&mut buf, mask);
207 buf.freeze()
208 } else if self.config.accept_unmasked_frames {
209 raw
210 } else {
211 return Err(Error::Internal(
212 "received an unmasked frame from the client".to_string(),
213 ));
214 };
215
216 match header.opcode {
217 OpCode::Control(Control::Ping) => {
218 self.outgoing.push_back(Frame::pong(payload.clone()));
219 Ok(Some(Message::Ping(payload)))
220 }
221 OpCode::Control(Control::Pong) => Ok(Some(Message::Pong(payload))),
222 OpCode::Control(Control::Close) => {
223 let close_frame = parse_close(&payload)?;
224 if !self.sent_close {
225 self.outgoing.push_back(Frame::close(close_frame.clone()));
226 self.sent_close = true;
227 }
228 self.closed = true;
229 Ok(Some(Message::Close(close_frame)))
230 }
231 OpCode::Control(Control::Reserved(code)) => Err(Error::Internal(format!(
232 "received reserved WebSocket control opcode {code}"
233 ))),
234 OpCode::Data(data @ (OpData::Text | OpData::Binary)) => {
235 if self.fragment.is_some() {
236 return Err(Error::Internal(
237 "received a new data frame while a fragmented message was in progress"
238 .to_string(),
239 ));
240 }
241 if header.is_final {
242 self.finish_message(data, header.rsv1, payload)
243 } else {
244 let buffer =
245 payload.try_into_mut().unwrap_or_else(|shared| BytesMut::from(&shared[..]));
246 self.fragment = Some(Fragment { opcode: data, compressed: header.rsv1, buffer });
247 Ok(None)
248 }
249 }
250 OpCode::Data(OpData::Continue) => {
251 let fragment = self.fragment.as_mut().ok_or_else(|| {
252 Error::Internal("received a continuation frame with no message in progress".to_string())
253 })?;
254 fragment.buffer.extend_from_slice(&payload);
255 if let Some(max) = self.config.max_message_size
256 && fragment.buffer.len() > max
257 {
258 return Err(Error::Internal(
259 "WebSocket message exceeds the configured maximum size".to_string(),
260 ));
261 }
262 if header.is_final {
263 let Fragment { opcode, compressed, buffer } =
264 self.fragment.take().unwrap_or_else(|| unreachable!());
265 self.finish_message(opcode, compressed, buffer.freeze())
266 } else {
267 Ok(None)
268 }
269 }
270 OpCode::Data(OpData::Reserved(code)) => {
271 Err(Error::Internal(format!("received reserved WebSocket data opcode {code}")))
272 }
273 }
274 }
275
276 fn poll_recv(&mut self, cx: &Context<'_>) -> Poll<Option<Result<Message, Error>>> {
277 loop {
278 match self.poll_drain_outgoing(cx) {
279 Poll::Ready(Ok(())) => {}
280 Poll::Ready(Err(err)) => {
281 self.closed = true;
282 return Poll::Ready(Some(Err(protocol_error(&err))));
283 }
284 Poll::Pending => return Poll::Pending,
285 }
286 if self.closed {
287 return Poll::Ready(None);
288 }
289
290 let max_frame_size = self.config.max_frame_size;
291 let frame = match poll_io(&mut self.frames, &Direction::Read, cx, |fs| {
292 fs.read(max_frame_size)
293 }) {
294 Poll::Ready(Ok(Some(frame))) => frame,
295 Poll::Ready(Ok(None)) => {
296 self.closed = true;
297 return Poll::Ready(None);
298 }
299 Poll::Ready(Err(err)) => {
300 self.closed = true;
301 return Poll::Ready(Some(Err(protocol_error(&err))));
302 }
303 Poll::Pending => return Poll::Pending,
304 };
305
306 match self.handle_frame(frame) {
307 Ok(Some(msg)) => return Poll::Ready(Some(Ok(msg))),
308 Ok(None) => {}
309 Err(err) => {
310 self.closed = true;
311 return Poll::Ready(Some(Err(err)));
312 }
313 }
314 }
315 }
316
317 fn queue_data(&mut self, opcode: OpData, payload: Bytes) -> Result<(), Error> {
318 let compressed = match &mut self.deflate {
319 Some(deflate) => deflate.compress_if_smaller(&payload)?,
320 None => None,
321 };
322 let (rsv1, bytes) =
323 compressed.map_or_else(move || (false, payload), |c| (true, Bytes::from(c)));
324 let mut frame = Frame::message(bytes, OpCode::Data(opcode), true);
325 frame.header_mut().rsv1 = rsv1;
326 self.outgoing.push_back(frame);
327 Ok(())
328 }
329
330 fn queue_message(&mut self, msg: Message) -> Result<(), Error> {
331 match msg {
332 Message::Text(text) => self.queue_data(OpData::Text, Bytes::from(text)),
333 Message::Binary(data) => self.queue_data(OpData::Binary, data),
334 Message::Ping(data) => {
335 self.outgoing.push_back(Frame::ping(data));
336 Ok(())
337 }
338 Message::Pong(data) => {
339 self.outgoing.push_back(Frame::pong(data));
340 Ok(())
341 }
342 Message::Close(frame) => {
343 self.outgoing.push_back(Frame::close(frame));
344 self.sent_close = true;
345 Ok(())
346 }
347 Message::Frame(frame) => {
348 self.outgoing.push_back(frame);
349 Ok(())
350 }
351 }
352 }
353
354 pub async fn recv(&mut self) -> Option<Result<Message, Error>> {
356 poll_fn(|cx| self.poll_recv(cx)).await
357 }
358
359 pub async fn send(&mut self, msg: Message) -> Result<(), Error> {
366 self.queue_message(msg)?;
367 poll_fn(|cx| self.poll_drain_outgoing(cx)).await.map_err(|e| protocol_error(&e))
368 }
369
370 pub async fn flush(&mut self) -> Result<(), Error> {
377 poll_fn(|cx| self.poll_drain_outgoing(cx)).await.map_err(|e| protocol_error(&e))
378 }
379
380 pub async fn close(mut self) -> Result<(), Error> {
386 if !self.sent_close {
387 self.outgoing.push_back(Frame::close(None));
388 self.sent_close = true;
389 }
390 poll_fn(|cx| self.poll_drain_outgoing(cx)).await.map_err(|e| protocol_error(&e))
391 }
392
393 #[must_use]
395 pub const fn protocol(&self) -> Option<&HeaderValue> {
396 self.protocol.as_ref()
397 }
398
399 pub fn split(
407 self,
408 ) -> (
409 impl Sink<Message, Error = Error> + Send,
410 impl Stream<Item = Result<Message, Error>> + Send,
411 ) {
412 let (out_tx, mut out_rx) = tokio::sync::mpsc::channel::<Message>(SPLIT_CHANNEL_CAPACITY);
413 let (in_tx, in_rx) =
414 tokio::sync::mpsc::channel::<Result<Message, Error>>(SPLIT_CHANNEL_CAPACITY);
415
416 tokio::spawn(async move {
417 let mut socket = self;
418 loop {
419 tokio::select! {
420 incoming = socket.recv() => {
421 match incoming {
422 Some(msg) => {
423 if in_tx.send(msg).await.is_err() {
424 break;
425 }
426 }
427 None => break,
428 }
429 }
430 outgoing = out_rx.recv() => {
431 match outgoing {
432 Some(msg) => {
433 if socket.send(msg).await.is_err() {
434 break;
435 }
436 }
437 None => break,
438 }
439 }
440 }
441 }
442 });
443
444 (PollSender::new(out_tx).sink_map_err(map_poll_sender_err), SplitStream { rx: in_rx })
445 }
446}
447
448fn map_poll_sender_err<T>(_: tokio_util::sync::PollSendError<T>) -> Error {
449 Error::Internal("WebSocket connection closed".to_string())
450}
451
452struct SplitStream {
453 rx: tokio::sync::mpsc::Receiver<Result<Message, Error>>,
454}
455
456impl Stream for SplitStream {
457 type Item = Result<Message, Error>;
458
459 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
460 self.rx.poll_recv(cx)
461 }
462}