1#![deny(
42 missing_docs,
43 unused_must_use,
44 unused_mut,
45 unused_imports,
46 unused_import_braces
47)]
48
49pub use tungstenite;
50
51mod compat;
52mod handshake;
53
54#[cfg(any(
55 feature = "async-tls",
56 feature = "async-native-tls",
57 feature = "smol-native-tls",
58 feature = "futures-rustls-manual-roots",
59 feature = "futures-rustls-webpki-roots",
60 feature = "futures-rustls-native-certs",
61 feature = "futures-rustls-platform-verifier",
62 feature = "tokio-native-tls",
63 feature = "tokio-rustls-manual-roots",
64 feature = "tokio-rustls-native-certs",
65 feature = "tokio-rustls-platform-verifier",
66 feature = "tokio-rustls-webpki-roots",
67 feature = "tokio-openssl",
68))]
69pub mod stream;
70
71use std::{
72 io::{Read, Write},
73 pin::Pin,
74 sync::{Arc, Mutex, MutexGuard},
75 task::{ready, Context, Poll},
76};
77
78use compat::{cvt, AllowStd, ContextWaker};
79use futures_core::stream::{FusedStream, Stream};
80use futures_io::{AsyncRead, AsyncWrite};
81use log::*;
82
83#[cfg(feature = "handshake")]
84use tungstenite::{
85 client::IntoClientRequest,
86 handshake::{
87 client::{ClientHandshake, Response},
88 server::{Callback, NoCallback},
89 HandshakeError,
90 },
91};
92use tungstenite::{
93 error::Error as WsError,
94 protocol::{Message, Role, WebSocket, WebSocketConfig},
95};
96
97#[cfg(feature = "async-std-runtime")]
98#[deprecated = "async-std is unmaintained upstream. Please use the smol runtime instead."]
99pub mod async_std;
100#[cfg(feature = "async-tls")]
101#[deprecated(
102 note = "async-tls has not seen an update for 2 years and depends on a vulnerable version of rustls. Use futures-rustls instead."
103)]
104pub mod async_tls;
105#[cfg(feature = "gio-runtime")]
106pub mod gio;
107#[cfg(feature = "smol-runtime")]
108pub mod smol;
109#[cfg(feature = "tokio-runtime")]
110pub mod tokio;
111
112pub mod bytes;
113pub use bytes::ByteReader;
114pub use bytes::ByteWriter;
115
116use tungstenite::protocol::CloseFrame;
117
118#[cfg(feature = "handshake")]
131pub async fn client_async<'a, R, S>(
132 request: R,
133 stream: S,
134) -> Result<(WebSocketStream<S>, Response), WsError>
135where
136 R: IntoClientRequest + Unpin,
137 S: AsyncRead + AsyncWrite + Unpin,
138{
139 client_async_with_config(request, stream, None).await
140}
141
142#[cfg(feature = "handshake")]
145pub async fn client_async_with_config<'a, R, S>(
146 request: R,
147 stream: S,
148 config: Option<WebSocketConfig>,
149) -> Result<(WebSocketStream<S>, Response), WsError>
150where
151 R: IntoClientRequest + Unpin,
152 S: AsyncRead + AsyncWrite + Unpin,
153{
154 let f = handshake::client_handshake(stream, move |allow_std| {
155 let request = request.into_client_request()?;
156 let cli_handshake = ClientHandshake::start(allow_std, request, config)?;
157 cli_handshake.handshake()
158 });
159 f.await.map_err(|e| match e {
160 HandshakeError::Failure(e) => e,
161 e => WsError::Io(std::io::Error::new(
162 std::io::ErrorKind::Other,
163 e.to_string(),
164 )),
165 })
166}
167
168#[cfg(feature = "handshake")]
180pub async fn accept_async<S>(stream: S) -> Result<WebSocketStream<S>, WsError>
181where
182 S: AsyncRead + AsyncWrite + Unpin,
183{
184 accept_hdr_async(stream, NoCallback).await
185}
186
187#[cfg(feature = "handshake")]
190pub async fn accept_async_with_config<S>(
191 stream: S,
192 config: Option<WebSocketConfig>,
193) -> Result<WebSocketStream<S>, WsError>
194where
195 S: AsyncRead + AsyncWrite + Unpin,
196{
197 accept_hdr_async_with_config(stream, NoCallback, config).await
198}
199
200#[cfg(feature = "handshake")]
206pub async fn accept_hdr_async<S, C>(stream: S, callback: C) -> Result<WebSocketStream<S>, WsError>
207where
208 S: AsyncRead + AsyncWrite + Unpin,
209 C: Callback + Unpin,
210{
211 accept_hdr_async_with_config(stream, callback, None).await
212}
213
214#[cfg(feature = "handshake")]
217pub async fn accept_hdr_async_with_config<S, C>(
218 stream: S,
219 callback: C,
220 config: Option<WebSocketConfig>,
221) -> Result<WebSocketStream<S>, WsError>
222where
223 S: AsyncRead + AsyncWrite + Unpin,
224 C: Callback + Unpin,
225{
226 let f = handshake::server_handshake(stream, move |allow_std| {
227 tungstenite::accept_hdr_with_config(allow_std, callback, config)
228 });
229 f.await.map_err(|e| match e {
230 HandshakeError::Failure(e) => e,
231 e => WsError::Io(std::io::Error::new(
232 std::io::ErrorKind::Other,
233 e.to_string(),
234 )),
235 })
236}
237
238#[derive(Debug)]
248pub struct WebSocketStream<S> {
249 inner: WebSocket<AllowStd<S>>,
250 #[cfg(feature = "futures-03-sink")]
251 closing: bool,
252 ended: bool,
253 ready: bool,
258}
259
260impl<S> WebSocketStream<S> {
261 pub async fn from_raw_socket(stream: S, role: Role, config: Option<WebSocketConfig>) -> Self
264 where
265 S: AsyncRead + AsyncWrite + Unpin,
266 {
267 handshake::without_handshake(stream, move |allow_std| {
268 WebSocket::from_raw_socket(allow_std, role, config)
269 })
270 .await
271 }
272
273 pub async fn from_partially_read(
276 stream: S,
277 part: Vec<u8>,
278 role: Role,
279 config: Option<WebSocketConfig>,
280 ) -> Self
281 where
282 S: AsyncRead + AsyncWrite + Unpin,
283 {
284 handshake::without_handshake(stream, move |allow_std| {
285 WebSocket::from_partially_read(allow_std, part, role, config)
286 })
287 .await
288 }
289
290 pub(crate) fn new(ws: WebSocket<AllowStd<S>>) -> Self {
291 Self {
292 inner: ws,
293 #[cfg(feature = "futures-03-sink")]
294 closing: false,
295 ended: false,
296 ready: true,
297 }
298 }
299
300 fn with_context<F, R>(&mut self, ctx: Option<(ContextWaker, &mut Context<'_>)>, f: F) -> R
301 where
302 F: FnOnce(&mut WebSocket<AllowStd<S>>) -> R,
303 AllowStd<S>: Read + Write,
304 {
305 #[cfg(feature = "verbose-logging")]
306 trace!("{}:{} WebSocketStream.with_context", file!(), line!());
307 if let Some((kind, ctx)) = ctx {
308 self.inner.get_mut().set_waker(kind, ctx.waker());
309 }
310 f(&mut self.inner)
311 }
312
313 pub fn into_inner(self) -> S {
315 self.inner.into_inner().into_inner()
316 }
317
318 pub fn get_ref(&self) -> &S
320 where
321 S: AsyncRead + AsyncWrite + Unpin,
322 {
323 self.inner.get_ref().get_ref()
324 }
325
326 pub fn get_mut(&mut self) -> &mut S
328 where
329 S: AsyncRead + AsyncWrite + Unpin,
330 {
331 self.inner.get_mut().get_mut()
332 }
333
334 pub fn get_config(&self) -> &WebSocketConfig {
336 self.inner.get_config()
337 }
338
339 pub async fn close(&mut self, msg: Option<CloseFrame>) -> Result<(), WsError>
341 where
342 S: AsyncRead + AsyncWrite + Unpin,
343 {
344 self.send(Message::Close(msg)).await
345 }
346
347 pub fn split(self) -> (WebSocketSender<S>, WebSocketReceiver<S>) {
350 let shared = Arc::new(Shared(Mutex::new(self)));
351 let sender = WebSocketSender {
352 shared: shared.clone(),
353 };
354
355 let receiver = WebSocketReceiver { shared };
356 (sender, receiver)
357 }
358
359 pub fn reunite(
364 sender: WebSocketSender<S>,
365 receiver: WebSocketReceiver<S>,
366 ) -> Result<Self, (WebSocketSender<S>, WebSocketReceiver<S>)> {
367 if sender.is_pair_of(&receiver) {
368 drop(receiver);
369 let stream = Arc::try_unwrap(sender.shared)
370 .ok()
371 .expect("reunite the stream")
372 .into_inner();
373
374 Ok(stream)
375 } else {
376 Err((sender, receiver))
377 }
378 }
379}
380
381impl<S> WebSocketStream<S>
382where
383 S: AsyncRead + AsyncWrite + Unpin,
384{
385 fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Message, WsError>>> {
386 #[cfg(feature = "verbose-logging")]
387 trace!("{}:{} WebSocketStream.poll_next", file!(), line!());
388
389 if self.ended {
393 return Poll::Ready(None);
394 }
395
396 match ready!(self.with_context(Some((ContextWaker::Read, cx)), |s| {
397 #[cfg(feature = "verbose-logging")]
398 trace!(
399 "{}:{} WebSocketStream.with_context poll_next -> read()",
400 file!(),
401 line!()
402 );
403 cvt(s.read())
404 })) {
405 Ok(v) => Poll::Ready(Some(Ok(v))),
406 Err(e) => {
407 self.ended = true;
408 if matches!(e, WsError::AlreadyClosed | WsError::ConnectionClosed) {
409 Poll::Ready(None)
410 } else {
411 Poll::Ready(Some(Err(e)))
412 }
413 }
414 }
415 }
416
417 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), WsError>> {
418 if self.ready {
419 return Poll::Ready(Ok(()));
420 }
421
422 self.with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.flush()))
424 .map(|r| {
425 self.ready = true;
426 r
427 })
428 }
429
430 fn start_send(&mut self, item: Message) -> Result<(), WsError> {
431 match self.with_context(None, |s| s.write(item)) {
432 Ok(()) => {
433 self.ready = true;
434 Ok(())
435 }
436 Err(WsError::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => {
437 self.ready = false;
440 Ok(())
441 }
442 Err(e) => {
443 self.ready = true;
444 debug!("websocket start_send error: {}", e);
445 Err(e)
446 }
447 }
448 }
449
450 fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), WsError>> {
451 self.with_context(Some((ContextWaker::Write, cx)), |s| cvt(s.flush()))
452 .map(|r| {
453 self.ready = true;
454 match r {
455 Err(WsError::ConnectionClosed) => Ok(()),
457 other => other,
458 }
459 })
460 }
461
462 #[cfg(feature = "futures-03-sink")]
463 fn poll_close(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), WsError>> {
464 self.ready = true;
465 let res = if self.closing {
466 self.with_context(Some((ContextWaker::Write, cx)), |s| s.flush())
468 } else {
469 self.with_context(Some((ContextWaker::Write, cx)), |s| s.close(None))
470 };
471
472 match res {
473 Ok(()) => Poll::Ready(Ok(())),
474 Err(WsError::ConnectionClosed) => Poll::Ready(Ok(())),
475 Err(WsError::Io(err)) if err.kind() == std::io::ErrorKind::WouldBlock => {
476 trace!("WouldBlock");
477 self.closing = true;
478 Poll::Pending
479 }
480 Err(err) => {
481 debug!("websocket close error: {}", err);
482 Poll::Ready(Err(err))
483 }
484 }
485 }
486}
487
488impl<S> Stream for WebSocketStream<S>
489where
490 S: AsyncRead + AsyncWrite + Unpin,
491{
492 type Item = Result<Message, WsError>;
493
494 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
495 self.get_mut().poll_next(cx)
496 }
497}
498
499impl<S> FusedStream for WebSocketStream<S>
500where
501 S: AsyncRead + AsyncWrite + Unpin,
502{
503 fn is_terminated(&self) -> bool {
504 self.ended
505 }
506}
507
508#[cfg(feature = "futures-03-sink")]
509impl<S> futures_util::Sink<Message> for WebSocketStream<S>
510where
511 S: AsyncRead + AsyncWrite + Unpin,
512{
513 type Error = WsError;
514
515 fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
516 self.get_mut().poll_ready(cx)
517 }
518
519 fn start_send(self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
520 self.get_mut().start_send(item)
521 }
522
523 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
524 self.get_mut().poll_flush(cx)
525 }
526
527 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
528 self.get_mut().poll_close(cx)
529 }
530}
531
532#[cfg(not(feature = "futures-03-sink"))]
533impl<S> bytes::private::SealedSender for WebSocketStream<S>
534where
535 S: AsyncRead + AsyncWrite + Unpin,
536{
537 fn poll_write(
538 self: Pin<&mut Self>,
539 cx: &mut Context<'_>,
540 buf: &[u8],
541 ) -> Poll<Result<usize, WsError>> {
542 let me = self.get_mut();
543 ready!(me.poll_ready(cx))?;
544 let len = buf.len();
545 me.start_send(Message::binary(buf.to_owned()))?;
546 Poll::Ready(Ok(len))
547 }
548
549 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), WsError>> {
550 self.get_mut().poll_flush(cx)
551 }
552
553 fn poll_close(
554 self: Pin<&mut Self>,
555 cx: &mut Context<'_>,
556 msg: &mut Option<Message>,
557 ) -> Poll<Result<(), WsError>> {
558 let me = self.get_mut();
559 send_helper(me, msg, cx)
560 }
561}
562
563impl<S> WebSocketStream<S> {
564 pub async fn send(&mut self, msg: Message) -> Result<(), WsError>
566 where
567 S: AsyncRead + AsyncWrite + Unpin,
568 {
569 Send {
570 ws: self,
571 msg: Some(msg),
572 }
573 .await
574 }
575}
576
577struct Send<W> {
578 ws: W,
579 msg: Option<Message>,
580}
581
582fn send_helper<S>(
584 ws: &mut WebSocketStream<S>,
585 msg: &mut Option<Message>,
586 cx: &mut Context<'_>,
587) -> Poll<Result<(), WsError>>
588where
589 S: AsyncRead + AsyncWrite + Unpin,
590{
591 if msg.is_some() {
592 ready!(ws.poll_ready(cx))?;
593 let msg = msg.take().expect("unreachable");
594 ws.start_send(msg)?;
595 }
596
597 ws.poll_flush(cx)
598}
599
600impl<S> std::future::Future for Send<&mut WebSocketStream<S>>
601where
602 S: AsyncRead + AsyncWrite + Unpin,
603{
604 type Output = Result<(), WsError>;
605
606 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
607 let me = self.get_mut();
608 send_helper(me.ws, &mut me.msg, cx)
609 }
610}
611
612impl<S> std::future::Future for Send<&Shared<S>>
613where
614 S: AsyncRead + AsyncWrite + Unpin,
615{
616 type Output = Result<(), WsError>;
617
618 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
619 let me = self.get_mut();
620 let mut ws = me.ws.lock();
621 send_helper(&mut ws, &mut me.msg, cx)
622 }
623}
624
625#[derive(Debug)]
627pub struct WebSocketSender<S> {
628 shared: Arc<Shared<S>>,
629}
630
631impl<S> WebSocketSender<S> {
632 pub async fn send(&mut self, msg: Message) -> Result<(), WsError>
634 where
635 S: AsyncRead + AsyncWrite + Unpin,
636 {
637 Send {
638 ws: &*self.shared,
639 msg: Some(msg),
640 }
641 .await
642 }
643
644 pub async fn close(&mut self, msg: Option<CloseFrame>) -> Result<(), WsError>
646 where
647 S: AsyncRead + AsyncWrite + Unpin,
648 {
649 self.send(Message::Close(msg)).await
650 }
651
652 pub fn is_pair_of(&self, other: &WebSocketReceiver<S>) -> bool {
655 Arc::ptr_eq(&self.shared, &other.shared)
656 }
657}
658
659#[cfg(feature = "futures-03-sink")]
660impl<T> futures_util::Sink<Message> for WebSocketSender<T>
661where
662 T: AsyncRead + AsyncWrite + Unpin,
663{
664 type Error = WsError;
665
666 fn poll_ready(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
667 self.shared.lock().poll_ready(cx)
668 }
669
670 fn start_send(self: Pin<&mut Self>, item: Message) -> Result<(), Self::Error> {
671 self.shared.lock().start_send(item)
672 }
673
674 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
675 self.shared.lock().poll_flush(cx)
676 }
677
678 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
679 self.shared.lock().poll_close(cx)
680 }
681}
682
683#[cfg(not(feature = "futures-03-sink"))]
684impl<S> bytes::private::SealedSender for WebSocketSender<S>
685where
686 S: AsyncRead + AsyncWrite + Unpin,
687{
688 fn poll_write(
689 self: Pin<&mut Self>,
690 cx: &mut Context<'_>,
691 buf: &[u8],
692 ) -> Poll<Result<usize, WsError>> {
693 let me = self.get_mut();
694 let mut ws = me.shared.lock();
695 ready!(ws.poll_ready(cx))?;
696 let len = buf.len();
697 ws.start_send(Message::binary(buf.to_owned()))?;
698 Poll::Ready(Ok(len))
699 }
700
701 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), WsError>> {
702 self.shared.lock().poll_flush(cx)
703 }
704
705 fn poll_close(
706 self: Pin<&mut Self>,
707 cx: &mut Context<'_>,
708 msg: &mut Option<Message>,
709 ) -> Poll<Result<(), WsError>> {
710 let me = self.get_mut();
711 let mut ws = me.shared.lock();
712 send_helper(&mut ws, msg, cx)
713 }
714}
715
716#[derive(Debug)]
718pub struct WebSocketReceiver<S> {
719 shared: Arc<Shared<S>>,
720}
721
722impl<S> WebSocketReceiver<S> {
723 pub fn is_pair_of(&self, other: &WebSocketSender<S>) -> bool {
726 Arc::ptr_eq(&self.shared, &other.shared)
727 }
728}
729
730impl<S> Stream for WebSocketReceiver<S>
731where
732 S: AsyncRead + AsyncWrite + Unpin,
733{
734 type Item = Result<Message, WsError>;
735
736 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
737 self.shared.lock().poll_next(cx)
738 }
739}
740
741impl<S> FusedStream for WebSocketReceiver<S>
742where
743 S: AsyncRead + AsyncWrite + Unpin,
744{
745 fn is_terminated(&self) -> bool {
746 self.shared.lock().ended
747 }
748}
749
750#[derive(Debug)]
751struct Shared<S>(Mutex<WebSocketStream<S>>);
752
753impl<S> Shared<S> {
754 fn lock(&self) -> MutexGuard<'_, WebSocketStream<S>> {
755 self.0.lock().expect("lock shared stream")
756 }
757
758 fn into_inner(self) -> WebSocketStream<S> {
759 self.0.into_inner().expect("get shared stream")
760 }
761}
762
763#[cfg(any(
764 feature = "async-tls",
765 feature = "async-std-runtime",
766 feature = "smol-runtime",
767 feature = "tokio-runtime",
768 feature = "gio-runtime"
769))]
770#[inline]
772pub(crate) fn domain(
773 request: &tungstenite::handshake::client::Request,
774) -> Result<String, tungstenite::Error> {
775 request
776 .uri()
777 .host()
778 .map(|host| {
779 let host = if host.starts_with('[') {
785 &host[1..host.len() - 1]
786 } else {
787 host
788 };
789
790 host.to_owned()
791 })
792 .ok_or(tungstenite::Error::Url(
793 tungstenite::error::UrlError::NoHostName,
794 ))
795}
796
797#[cfg(any(
798 feature = "async-std-runtime",
799 feature = "smol-runtime",
800 feature = "tokio-runtime",
801 feature = "gio-runtime"
802))]
803#[inline]
805pub(crate) fn port(
806 request: &tungstenite::handshake::client::Request,
807) -> Result<u16, tungstenite::Error> {
808 request
809 .uri()
810 .port_u16()
811 .or_else(|| match request.uri().scheme_str() {
812 Some("wss") => Some(443),
813 Some("ws") => Some(80),
814 _ => None,
815 })
816 .ok_or(tungstenite::Error::Url(
817 tungstenite::error::UrlError::UnsupportedUrlScheme,
818 ))
819}
820
821#[cfg(test)]
822mod tests {
823 #[cfg(any(
824 feature = "async-tls",
825 feature = "async-std-runtime",
826 feature = "smol-runtime",
827 feature = "tokio-runtime",
828 feature = "gio-runtime"
829 ))]
830 #[test]
831 fn domain_strips_ipv6_brackets() {
832 use tungstenite::client::IntoClientRequest;
833
834 let request = "ws://[::1]:80".into_client_request().unwrap();
835 assert_eq!(crate::domain(&request).unwrap(), "::1");
836 }
837
838 #[cfg(feature = "handshake")]
839 #[test]
840 fn requests_cannot_contain_invalid_uris() {
841 use tungstenite::client::IntoClientRequest;
842
843 assert!("ws://[".into_client_request().is_err());
844 assert!("ws://[blabla/bla".into_client_request().is_err());
845 assert!("ws://[::1/bla".into_client_request().is_err());
846 }
847}