1use std::cell::RefCell;
18use std::collections::VecDeque;
19use std::rc::Rc;
20use std::task::{Context, Poll, ready};
21
22use bytes::{Buf, Bytes, BytesMut};
23use web_transport_proto as proto;
24
25use super::{Connection, Error};
26
27const FRAME_WEBTRANSPORT: u64 = 0x41;
29const STREAM_WEBTRANSPORT: u64 = 0x54;
31const STREAM_CONTROL: u64 = 0x00;
34const STREAM_QPACK_ENCODER: u64 = 0x02;
35const STREAM_QPACK_DECODER: u64 = 0x03;
36const FRAME_DATA: u64 = 0x00;
38const CLOSE_GRACE: std::time::Duration = std::time::Duration::from_secs(1);
41const MESSAGE_LIMIT: usize = 64 * 1024;
49const HANDSHAKE_STREAMS: usize = 64;
57const HELD_STREAMS: usize = 8;
62const H3_GENERAL_PROTOCOL_ERROR: u64 = 0x0101;
65const H3_NO_ERROR: u64 = 0x0100;
68
69pub struct Request {
75 conn: Connection,
76 guard: Guard,
78 request: proto::ConnectRequest,
79 send: super::SendStream,
80 recv: super::RecvStream,
81 held: Vec<super::RecvStream>,
84 control: super::SendStream,
86 early: Vec<(u64, super::RecvStream)>,
89 pending: Vec<PendingUni>,
92}
93
94struct Guard {
104 conn: Option<Connection>,
105}
106
107impl Guard {
108 fn new(conn: Connection) -> Self {
109 Self { conn: Some(conn) }
110 }
111
112 fn disarm(&mut self) {
114 self.conn = None;
115 }
116
117 fn close(&mut self, reason: &str) {
118 if let Some(conn) = self.conn.take() {
119 conn.close_code(H3_GENERAL_PROTOCOL_ERROR, reason);
120 }
121 }
122}
123
124impl Drop for Guard {
125 fn drop(&mut self) {
126 self.close("webtransport handshake abandoned");
127 }
128}
129
130impl Request {
131 pub async fn accept(conn: Connection) -> Result<Self, Error> {
138 let mut guard = Guard::new(conn.clone());
142 match Self::handshake(conn).await {
143 Ok(request) => {
144 guard.disarm();
145 Ok(request)
146 }
147 Err(err) => {
148 guard.close(&err.to_string());
149 Err(err)
150 }
151 }
152 }
153
154 async fn handshake(mut conn: Connection) -> Result<Self, Error> {
155 let mut control = open_uni(&mut conn).await?;
157 let mut settings = proto::Settings::default();
158 settings.enable_webtransport(1);
159 let mut buf = Vec::new();
160 settings.encode(&mut buf);
161 write_all(&mut control, &buf).await?;
162
163 let mut pending: Vec<PendingUni> = Vec::new();
170 let mut held = Vec::new();
171 let mut early = Vec::new();
172 let mut arrivals = 0usize;
177 let mut peer_control = None;
178 std::future::poll_fn(|cx| {
179 loop {
180 let mut over = false;
187 while !over {
188 match web_transport_trait::poll::Session::poll_accept_uni(&mut conn, cx) {
189 Poll::Ready(Ok(recv)) => {
190 arrivals += 1;
191 pending.push(PendingUni::new(recv));
192 over = arrivals > HANDSHAKE_STREAMS;
193 }
194 Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
195 Poll::Pending => break,
196 }
197 }
198
199 let mut progressed = false;
202 let mut index = 0;
203 while index < pending.len() {
204 let Poll::Ready(class) = pending[index].poll_classify(cx) else {
205 index += 1;
206 continue;
207 };
208 let stream = pending.swap_remove(index);
211 progressed = true;
212 match class {
213 UniClass::Control => {
214 peer_control = Some(stream.recv);
215 return Poll::Ready(Ok(()));
216 }
217 UniClass::Qpack => held.push(stream.recv),
218 UniClass::Web(session) => early.push((session, stream.recv)),
219 UniClass::Unknown => {}
220 }
221 }
222
223 if over {
226 return Poll::Ready(Err(Error::Web("too many streams before the control stream".into())));
227 }
228 if !progressed {
229 return Poll::Pending;
230 }
231 }
232 })
233 .await?;
234
235 let mut peer_control = peer_control.expect("the loop only ends with a control stream");
236 let settings = read_settings(&mut peer_control).await?;
237 if settings.supports_webtransport() == 0 {
238 return Err(Error::Web("peer does not support WebTransport".into()));
239 }
240 held.push(peer_control);
241
242 let (send, mut recv) = accept_bi(&mut conn).await?;
246 let request = read_connect(&mut recv).await?;
247
248 Ok(Self {
249 guard: Guard::new(conn.clone()),
250 conn,
251 request,
252 send,
253 recv,
254 held,
255 control,
256 early,
257 pending,
258 })
259 }
260
261 pub fn url(&self) -> &url::Url {
266 &self.request.url
267 }
268
269 pub fn protocols(&self) -> &[String] {
272 &self.request.protocols
273 }
274
275 pub async fn respond(mut self, response: Response) -> Result<Session, Error> {
277 let Response { protocol } = response;
278
279 let mut encoded = proto::ConnectResponse::OK;
280 if let Some(protocol) = &protocol {
281 if !self.request.protocols.iter().any(|offered| offered == protocol) {
282 return Err(Error::Web(format!("subprotocol {protocol:?} was not offered")));
283 }
284 encoded = encoded.with_protocol(protocol);
285 }
286 let mut buf = Vec::new();
287 encoded.encode(&mut buf).map_err(|err| Error::Web(err.to_string()))?;
288 write_all(&mut self.send, &buf).await?;
289 self.guard.disarm();
290
291 Ok(Session::establish(self, protocol))
292 }
293
294 pub async fn ok(self) -> Result<Session, Error> {
296 self.respond(Response::default()).await
297 }
298
299 pub async fn reject(mut self, reason: Rejected) -> Result<(), Error> {
308 let response = proto::ConnectResponse::new(reason.status());
309 let mut buf = Vec::new();
310 response.encode(&mut buf).map_err(|err| Error::Web(err.to_string()))?;
311 write_all(&mut self.send, &buf).await?;
312 web_transport_trait::poll::SendStream::finish(&mut self.send)?;
313
314 let mut deadline = self.conn.owner().after(CLOSE_GRACE);
318 let send = &mut self.send;
319 kio::wait(|waiter| {
320 let mut cx = Context::from_waker(waiter.waker());
321 if web_transport_trait::poll::SendStream::poll_closed(send, &mut cx).is_ready() {
322 return Poll::Ready(());
323 }
324 deadline.poll(waiter)
325 })
326 .await;
327
328 self.guard.disarm();
331 self.conn.close_code(H3_NO_ERROR, "");
332 Ok(())
333 }
334}
335
336#[derive(Clone, Debug, Default)]
341pub struct Response {
342 protocol: Option<String>,
343}
344
345impl Response {
346 pub fn with_protocol(mut self, protocol: impl Into<String>) -> Self {
350 self.protocol = Some(protocol.into());
351 self
352 }
353}
354
355#[derive(Clone, Copy, Debug, PartialEq, Eq)]
361#[non_exhaustive]
362pub enum Rejected {
363 Unauthorized,
365 Forbidden,
367 NotFound,
369 BadRequest,
371 Unavailable,
373}
374
375impl Rejected {
376 fn status(self) -> http::StatusCode {
377 match self {
378 Self::Unauthorized => http::StatusCode::UNAUTHORIZED,
379 Self::Forbidden => http::StatusCode::FORBIDDEN,
380 Self::NotFound => http::StatusCode::NOT_FOUND,
381 Self::BadRequest => http::StatusCode::BAD_REQUEST,
382 Self::Unavailable => http::StatusCode::SERVICE_UNAVAILABLE,
383 }
384 }
385}
386
387impl std::fmt::Debug for Request {
388 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
389 f.debug_struct("Request").field("url", &self.request.url).finish()
390 }
391}
392
393struct Web {
395 session_id: u64,
397 header_uni: Bytes,
399 header_bi: Bytes,
400 header_datagram: Bytes,
401 state: RefCell<State>,
402 closed: RefCell<Option<Error>>,
406}
407
408struct State {
409 pending_uni: Vec<PendingUni>,
411 pending_bi: Vec<PendingBi>,
412 ready_uni: VecDeque<super::RecvStream>,
414 ready_bi: VecDeque<(super::SendStream, super::RecvStream)>,
415 held_recv: Vec<super::RecvStream>,
417 _control_send: Option<super::SendStream>,
418 connect_send: Option<super::SendStream>,
420}
421
422pub struct Session {
428 conn: Connection,
429 web: Option<Rc<Web>>,
430 protocol: Option<String>,
433}
434
435impl Session {
436 pub fn raw(conn: Connection) -> Self {
439 let protocol = web_transport_trait::poll::Session::protocol(&conn).map(str::to_owned);
440 Self {
441 conn,
442 web: None,
443 protocol,
444 }
445 }
446
447 fn establish(request: Request, protocol: Option<String>) -> Self {
449 let Request {
450 conn,
451 guard: _,
452 request: _,
453 send,
454 recv,
455 held,
456 control,
457 early,
458 pending,
459 } = request;
460
461 let session_id = send.id();
462 let mut header_uni = Vec::new();
463 encode_varint(STREAM_WEBTRANSPORT, &mut header_uni);
464 encode_varint(session_id, &mut header_uni);
465 let mut header_bi = Vec::new();
466 encode_varint(FRAME_WEBTRANSPORT, &mut header_bi);
467 encode_varint(session_id, &mut header_bi);
468 let mut header_datagram = Vec::new();
469 encode_varint(session_id, &mut header_datagram);
470
471 let ready_uni = early
474 .into_iter()
475 .filter_map(|(session, recv)| (session == session_id).then_some(recv))
476 .collect();
477
478 let web = Rc::new(Web {
479 session_id,
480 header_uni: header_uni.into(),
481 header_bi: header_bi.into(),
482 header_datagram: header_datagram.into(),
483 state: RefCell::new(State {
484 pending_uni: pending,
488 pending_bi: Vec::new(),
489 ready_uni,
490 ready_bi: VecDeque::new(),
491 held_recv: held,
492 _control_send: Some(control),
493 connect_send: Some(send),
494 }),
495 closed: RefCell::new(None),
496 });
497
498 let capsules = web.clone();
501 let capsule_conn = conn.clone();
502 conn.owner()
503 .spawn(async move { read_capsules(capsules, capsule_conn, recv).await });
504
505 Self {
506 conn,
507 web: Some(web),
508 protocol,
509 }
510 }
511
512 fn map_err(&self, err: Error) -> Error {
514 match self.web {
515 Some(_) => unmap_err(err),
516 None => err,
517 }
518 }
519}
520
521impl Clone for Session {
522 fn clone(&self) -> Self {
523 Self {
524 conn: self.conn.clone(),
525 web: self.web.clone(),
526 protocol: self.protocol.clone(),
527 }
528 }
529}
530
531impl std::fmt::Debug for Session {
532 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
533 f.debug_struct("Session")
534 .field("web", &self.web.is_some())
535 .field("protocol", &self.protocol)
536 .finish()
537 }
538}
539
540impl web_transport_trait::poll::Session for Session {
541 type SendStream = SendStream;
542 type RecvStream = RecvStream;
543 type Error = Error;
544
545 fn poll_accept_uni(&mut self, cx: &mut Context<'_>) -> Poll<Result<Self::RecvStream, Self::Error>> {
546 let Some(web) = self.web.clone() else {
547 let inner = ready!(web_transport_trait::poll::Session::poll_accept_uni(&mut self.conn, cx))?;
548 return Poll::Ready(Ok(RecvStream { inner, web: false }));
549 };
550
551 loop {
552 if let Some(inner) = web.state.borrow_mut().ready_uni.pop_front() {
553 return Poll::Ready(Ok(RecvStream { inner, web: true }));
554 }
555
556 loop {
560 match web_transport_trait::poll::Session::poll_accept_uni(&mut self.conn, cx) {
561 Poll::Ready(Ok(recv)) => web.state.borrow_mut().pending_uni.push(PendingUni::new(recv)),
562 Poll::Ready(Err(err)) => return Poll::Ready(Err(unmap_err(err))),
563 Poll::Pending => break,
564 }
565 }
566
567 if !classify_uni(&web, cx) {
568 return Poll::Pending;
569 }
570 }
571 }
572
573 fn poll_accept_bi(
574 &mut self,
575 cx: &mut Context<'_>,
576 ) -> Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
577 let Some(web) = self.web.clone() else {
578 let (send, recv) = ready!(web_transport_trait::poll::Session::poll_accept_bi(&mut self.conn, cx))?;
579 return Poll::Ready(Ok((
580 SendStream {
581 inner: send,
582 prefix: Bytes::new(),
583 finishing: false,
584 web: false,
585 },
586 RecvStream {
587 inner: recv,
588 web: false,
589 },
590 )));
591 };
592
593 loop {
594 if let Some((send, recv)) = web.state.borrow_mut().ready_bi.pop_front() {
595 return Poll::Ready(Ok((
596 SendStream {
597 inner: send,
598 prefix: Bytes::new(),
599 finishing: false,
600 web: true,
601 },
602 RecvStream { inner: recv, web: true },
603 )));
604 }
605
606 loop {
607 match web_transport_trait::poll::Session::poll_accept_bi(&mut self.conn, cx) {
608 Poll::Ready(Ok((send, recv))) => web.state.borrow_mut().pending_bi.push(PendingBi::new(send, recv)),
609 Poll::Ready(Err(err)) => return Poll::Ready(Err(unmap_err(err))),
610 Poll::Pending => break,
611 }
612 }
613
614 if !classify_bi(&web, cx) {
615 return Poll::Pending;
616 }
617 }
618 }
619
620 fn poll_open_uni(&mut self, cx: &mut Context<'_>) -> Poll<Result<Self::SendStream, Self::Error>> {
621 let inner = ready!(web_transport_trait::poll::Session::poll_open_uni(&mut self.conn, cx))
622 .map_err(|err| self.map_err(err))?;
623 let prefix = self.web.as_ref().map(|web| web.header_uni.clone()).unwrap_or_default();
624 Poll::Ready(Ok(SendStream {
625 inner,
626 prefix,
627 finishing: false,
628 web: self.web.is_some(),
629 }))
630 }
631
632 fn poll_open_bi(
633 &mut self,
634 cx: &mut Context<'_>,
635 ) -> Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
636 let (send, recv) = ready!(web_transport_trait::poll::Session::poll_open_bi(&mut self.conn, cx))
637 .map_err(|err| self.map_err(err))?;
638 let prefix = self.web.as_ref().map(|web| web.header_bi.clone()).unwrap_or_default();
639 Poll::Ready(Ok((
640 SendStream {
641 inner: send,
642 prefix,
643 finishing: false,
644 web: self.web.is_some(),
645 },
646 RecvStream {
647 inner: recv,
648 web: self.web.is_some(),
649 },
650 )))
651 }
652
653 fn poll_send_datagram(&mut self, cx: &mut Context<'_>, payload: &[u8]) -> Poll<Result<(), Self::Error>> {
654 let Some(web) = &self.web else {
655 return web_transport_trait::poll::Session::poll_send_datagram(&mut self.conn, cx, payload);
656 };
657 let mut framed = Vec::with_capacity(web.header_datagram.len() + payload.len());
658 framed.extend_from_slice(&web.header_datagram);
659 framed.extend_from_slice(payload);
660 web_transport_trait::poll::Session::poll_send_datagram(&mut self.conn, cx, &framed).map_err(unmap_err)
661 }
662
663 fn poll_recv_datagram(&mut self, cx: &mut Context<'_>) -> Poll<Result<Bytes, Self::Error>> {
664 let Some(web) = self.web.clone() else {
665 return web_transport_trait::poll::Session::poll_recv_datagram(&mut self.conn, cx);
666 };
667 loop {
668 let datagram = ready!(web_transport_trait::poll::Session::poll_recv_datagram(
669 &mut self.conn,
670 cx
671 ))
672 .map_err(unmap_err)?;
673 let mut peek: &[u8] = &datagram;
675 match decode_varint(&mut peek) {
676 Some(id) if id == web.session_id => {
677 let start = datagram.len() - peek.len();
678 return Poll::Ready(Ok(datagram.slice(start..)));
679 }
680 _ => tracing::debug!("dropping a datagram for an unknown session"),
681 }
682 }
683 }
684
685 fn max_datagram_size(&self) -> usize {
686 let inner = web_transport_trait::poll::Session::max_datagram_size(&self.conn);
687 match &self.web {
688 Some(web) => inner.saturating_sub(web.header_datagram.len()),
689 None => inner,
690 }
691 }
692
693 fn protocol(&self) -> Option<&str> {
694 self.protocol.as_deref()
695 }
696
697 fn close(&mut self, code: u32, reason: &str) {
698 let Some(web) = &self.web else {
699 return web_transport_trait::poll::Session::close(&mut self.conn, code, reason);
700 };
701
702 {
703 let mut closed = web.closed.borrow_mut();
704 if closed.is_some() {
705 return;
706 }
707 *closed = Some(Error::App {
708 code: u64::from(code),
709 reason: reason.to_string(),
710 });
711 }
712
713 let connect_send = web.state.borrow_mut().connect_send.take();
714 let http3 = proto::error_to_http3(code);
715 let Some(mut send) = connect_send else {
716 self.conn.close_code(http3, reason);
717 return;
718 };
719
720 let capsule = proto::Capsule::CloseWebTransportSession {
724 code,
725 reason: reason.to_string(),
726 };
727 let mut payload = Vec::new();
728 capsule.encode(&mut payload);
729 let mut frame = Vec::new();
730 encode_varint(FRAME_DATA, &mut frame);
731 encode_varint(payload.len() as u64, &mut frame);
732 frame.extend_from_slice(&payload);
733
734 let mut deadline = self.conn.owner().after(CLOSE_GRACE);
740 let reason = reason.to_string();
741 let mut conn = self.conn.clone();
742 self.conn.owner().spawn(async move {
743 let mut offset = 0;
744 kio::wait(|waiter| {
745 let mut cx = Context::from_waker(waiter.waker());
746
747 if web_transport_trait::poll::Session::poll_closed(&mut conn, &mut cx).is_ready() {
750 return Poll::Ready(());
751 }
752 while offset < frame.len() {
753 match web_transport_trait::poll::SendStream::poll_write(&mut send, &mut cx, &frame[offset..]) {
754 Poll::Ready(Ok(n)) => offset += n,
755 Poll::Ready(Err(_)) => return Poll::Ready(()),
758 Poll::Pending => break,
759 }
760 if offset == frame.len() {
761 let _ = web_transport_trait::poll::SendStream::finish(&mut send);
762 }
763 }
764
765 deadline.poll(waiter)
766 })
767 .await;
768 conn.close_code(http3, &reason);
769 });
770 }
771
772 fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<Self::Error> {
773 let err = ready!(web_transport_trait::poll::Session::poll_closed(&mut self.conn, cx));
774 let Some(web) = &self.web else {
775 return Poll::Ready(err);
776 };
777 if let Some(recorded) = web.closed.borrow().clone() {
780 return Poll::Ready(recorded);
781 }
782 Poll::Ready(unmap_err(err))
783 }
784
785 fn stats(&self) -> impl web_transport_trait::Stats {
786 web_transport_trait::poll::Session::stats(&self.conn)
787 }
788}
789
790pub struct SendStream {
800 inner: super::SendStream,
801 prefix: Bytes,
803 finishing: bool,
807 web: bool,
808}
809
810impl SendStream {
811 fn map(&self, err: Error) -> Error {
812 match self.web {
813 true => unmap_err(err),
814 false => err,
815 }
816 }
817}
818
819impl web_transport_trait::poll::SendStream for SendStream {
820 type Error = Error;
821
822 fn poll_write(&mut self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, Self::Error>> {
823 if self.finishing {
827 return Poll::Ready(Err(Error::Quic("stream already finished".to_string())));
828 }
829 while !self.prefix.is_empty() {
830 let n = ready!(web_transport_trait::poll::SendStream::poll_write(
831 &mut self.inner,
832 cx,
833 &self.prefix
834 ))
835 .map_err(|err| self.map(err))?;
836 self.prefix.advance(n);
837 }
838 match web_transport_trait::poll::SendStream::poll_write(&mut self.inner, cx, buf) {
839 Poll::Ready(Err(err)) => Poll::Ready(Err(self.map(err))),
840 other => other,
841 }
842 }
843
844 fn poll_write_buf<B: Buf>(&mut self, cx: &mut Context<'_>, buf: &mut B) -> Poll<Result<usize, Self::Error>> {
845 if self.finishing {
846 return Poll::Ready(Err(Error::Quic("stream already finished".to_string())));
847 }
848 while !self.prefix.is_empty() {
849 ready!(web_transport_trait::poll::SendStream::poll_write_buf(
850 &mut self.inner,
851 cx,
852 &mut self.prefix
853 ))
854 .map_err(|err| self.map(err))?;
855 }
856 match web_transport_trait::poll::SendStream::poll_write_buf(&mut self.inner, cx, buf) {
857 Poll::Ready(Err(err)) => Poll::Ready(Err(self.map(err))),
858 other => other,
859 }
860 }
861
862 fn set_priority(&mut self, order: u8) {
863 web_transport_trait::poll::SendStream::set_priority(&mut self.inner, order);
864 }
865
866 fn finish(&mut self) -> Result<(), Self::Error> {
867 if !self.prefix.is_empty() {
870 let n = self.inner.try_write(&self.prefix);
871 self.prefix.advance(n);
872 if !self.prefix.is_empty() {
873 self.finishing = true;
879 return Ok(());
880 }
881 }
882 web_transport_trait::poll::SendStream::finish(&mut self.inner).map_err(|err| self.map(err))
883 }
884
885 fn reset(&mut self, code: u32) {
886 match self.web {
887 true => self.inner.reset_code(proto::error_to_http3(code)),
888 false => web_transport_trait::poll::SendStream::reset(&mut self.inner, code),
889 }
890 }
891
892 fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
893 while self.finishing {
895 match ready!(web_transport_trait::poll::SendStream::poll_write(
896 &mut self.inner,
897 cx,
898 &self.prefix
899 )) {
900 Ok(n) => self.prefix.advance(n),
901 Err(err) => return Poll::Ready(Err(self.map(err))),
902 }
903 if self.prefix.is_empty() {
904 self.finishing = false;
905 if let Err(err) = web_transport_trait::poll::SendStream::finish(&mut self.inner) {
906 return Poll::Ready(Err(self.map(err)));
907 }
908 }
909 }
910 match web_transport_trait::poll::SendStream::poll_closed(&mut self.inner, cx) {
911 Poll::Ready(Err(err)) => Poll::Ready(Err(self.map(err))),
912 other => other,
913 }
914 }
915}
916
917impl Drop for SendStream {
918 fn drop(&mut self) {
919 if self.finishing {
924 let n = self.inner.try_write(&self.prefix);
925 self.prefix.advance(n);
926 if self.prefix.is_empty() {
927 let _ = web_transport_trait::poll::SendStream::finish(&mut self.inner);
928 }
929 }
930 if self.web && !self.inner.ended() {
935 self.inner.reset_code(proto::error_to_http3(0));
936 }
937 }
938}
939
940impl std::fmt::Debug for SendStream {
941 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
942 self.inner.fmt(f)
943 }
944}
945
946pub struct RecvStream {
948 inner: super::RecvStream,
949 web: bool,
950}
951
952impl RecvStream {
953 fn map(&self, err: Error) -> Error {
954 match self.web {
955 true => unmap_err(err),
956 false => err,
957 }
958 }
959}
960
961impl web_transport_trait::poll::RecvStream for RecvStream {
962 type Error = Error;
963
964 fn poll_read(&mut self, cx: &mut Context<'_>, dst: &mut [u8]) -> Poll<Result<Option<usize>, Self::Error>> {
965 match web_transport_trait::poll::RecvStream::poll_read(&mut self.inner, cx, dst) {
966 Poll::Ready(Err(err)) => Poll::Ready(Err(self.map(err))),
967 other => other,
968 }
969 }
970
971 fn stop(&mut self, code: u32) {
972 match self.web {
973 true => self.inner.stop_code(proto::error_to_http3(code)),
974 false => web_transport_trait::poll::RecvStream::stop(&mut self.inner, code),
975 }
976 }
977
978 fn poll_closed(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
979 match web_transport_trait::poll::RecvStream::poll_closed(&mut self.inner, cx) {
980 Poll::Ready(Err(err)) => Poll::Ready(Err(self.map(err))),
981 other => other,
982 }
983 }
984}
985
986impl Drop for RecvStream {
987 fn drop(&mut self) {
988 if self.web && !self.inner.ended() {
990 self.inner.stop_code(proto::error_to_http3(0));
991 }
992 }
993}
994
995impl std::fmt::Debug for RecvStream {
996 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
997 self.inner.fmt(f)
998 }
999}
1000
1001fn unmap_err(err: Error) -> Error {
1009 fn unmap(code: u64) -> Option<u64> {
1010 proto::error_from_http3(code).map(u64::from)
1011 }
1012 match err {
1013 Error::Reset(code) => match unmap(code) {
1014 Some(code) => Error::Reset(code),
1015 None => Error::Http3 {
1016 code,
1017 reason: String::new(),
1018 },
1019 },
1020 Error::Stop(code) => match unmap(code) {
1021 Some(code) => Error::Stop(code),
1022 None => Error::Http3 {
1023 code,
1024 reason: String::new(),
1025 },
1026 },
1027 Error::App { code, reason } => match unmap(code) {
1028 Some(code) => Error::App { code, reason },
1029 None => Error::Http3 { code, reason },
1030 },
1031 other => other,
1032 }
1033}
1034
1035#[derive(Default)]
1039struct VarRead {
1040 buf: [u8; 8],
1041 have: usize,
1042}
1043
1044enum VarPoll {
1045 Value(u64),
1046 End,
1048}
1049
1050impl VarRead {
1051 fn poll(&mut self, cx: &mut Context<'_>, recv: &mut super::RecvStream) -> Poll<VarPoll> {
1052 loop {
1053 let need = match self.have {
1054 0 => 1,
1055 _ => 1usize << (self.buf[0] >> 6),
1056 };
1057 if self.have >= need {
1058 let mut value = u64::from(self.buf[0] & 0x3f);
1059 for byte in &self.buf[1..need] {
1060 value = (value << 8) | u64::from(*byte);
1061 }
1062 return Poll::Ready(VarPoll::Value(value));
1063 }
1064 match ready!(web_transport_trait::poll::RecvStream::poll_read(
1065 recv,
1066 cx,
1067 &mut self.buf[self.have..need]
1068 )) {
1069 Ok(Some(n)) => self.have += n,
1070 Ok(None) | Err(_) => return Poll::Ready(VarPoll::End),
1071 }
1072 }
1073 }
1074}
1075
1076fn encode_varint(value: u64, buf: &mut Vec<u8>) {
1078 if value < 1 << 6 {
1079 buf.push(value as u8);
1080 } else if value < 1 << 14 {
1081 buf.extend_from_slice(&((value as u16) | 0x4000).to_be_bytes());
1082 } else if value < 1 << 30 {
1083 buf.extend_from_slice(&((value as u32) | 0x8000_0000).to_be_bytes());
1084 } else {
1085 buf.extend_from_slice(&(value | 0xc000_0000_0000_0000).to_be_bytes());
1086 }
1087}
1088
1089fn decode_varint(buf: &mut &[u8]) -> Option<u64> {
1091 let first = *buf.first()?;
1092 let len = 1usize << (first >> 6);
1093 if buf.len() < len {
1094 return None;
1095 }
1096 let mut value = u64::from(first & 0x3f);
1097 for byte in &buf[1..len] {
1098 value = (value << 8) | u64::from(*byte);
1099 }
1100 *buf = &buf[len..];
1101 Some(value)
1102}
1103
1104enum UniClass {
1106 Control,
1108 Qpack,
1110 Web(u64),
1112 Unknown,
1114}
1115
1116struct PendingUni {
1118 recv: super::RecvStream,
1119 typ: VarRead,
1120 session: VarRead,
1121 typ_value: Option<u64>,
1122}
1123
1124impl PendingUni {
1125 fn new(recv: super::RecvStream) -> Self {
1126 Self {
1127 recv,
1128 typ: VarRead::default(),
1129 session: VarRead::default(),
1130 typ_value: None,
1131 }
1132 }
1133
1134 fn poll_classify(&mut self, cx: &mut Context<'_>) -> Poll<UniClass> {
1135 let typ = match self.typ_value {
1136 Some(typ) => typ,
1137 None => match ready!(self.typ.poll(cx, &mut self.recv)) {
1138 VarPoll::Value(typ) => {
1139 self.typ_value = Some(typ);
1140 typ
1141 }
1142 VarPoll::End => return Poll::Ready(UniClass::Unknown),
1143 },
1144 };
1145 match typ {
1146 STREAM_WEBTRANSPORT => match ready!(self.session.poll(cx, &mut self.recv)) {
1147 VarPoll::Value(session) => Poll::Ready(UniClass::Web(session)),
1148 VarPoll::End => Poll::Ready(UniClass::Unknown),
1149 },
1150 STREAM_CONTROL => Poll::Ready(UniClass::Control),
1151 STREAM_QPACK_ENCODER | STREAM_QPACK_DECODER => Poll::Ready(UniClass::Qpack),
1152 _ => {
1153 tracing::debug!(typ, "ignoring an unknown unidirectional stream");
1154 Poll::Ready(UniClass::Unknown)
1155 }
1156 }
1157 }
1158}
1159
1160fn classify_uni(web: &Rc<Web>, cx: &mut Context<'_>) -> bool {
1162 let pending = std::mem::take(&mut web.state.borrow_mut().pending_uni);
1165 let mut keep = Vec::new();
1166 let mut progressed = false;
1167
1168 for mut stream in pending {
1169 match stream.poll_classify(cx) {
1170 Poll::Pending => keep.push(stream),
1171 Poll::Ready(UniClass::Web(session)) if session == web.session_id => {
1172 web.state.borrow_mut().ready_uni.push_back(stream.recv);
1173 progressed = true;
1174 }
1175 Poll::Ready(UniClass::Control | UniClass::Qpack) => {
1181 let mut state = web.state.borrow_mut();
1182 if state.held_recv.len() < HELD_STREAMS {
1183 state.held_recv.push(stream.recv);
1184 }
1185 }
1186 Poll::Ready(_) => {}
1187 }
1188 }
1189
1190 let mut state = web.state.borrow_mut();
1191 state.pending_uni.extend(keep);
1192 progressed
1193}
1194
1195struct PendingBi {
1197 send: super::SendStream,
1198 recv: super::RecvStream,
1199 typ: VarRead,
1200 session: VarRead,
1201 typ_value: Option<u64>,
1202}
1203
1204impl PendingBi {
1205 fn new(send: super::SendStream, recv: super::RecvStream) -> Self {
1206 Self {
1207 send,
1208 recv,
1209 typ: VarRead::default(),
1210 session: VarRead::default(),
1211 typ_value: None,
1212 }
1213 }
1214
1215 fn poll_classify(&mut self, cx: &mut Context<'_>) -> Poll<Option<u64>> {
1217 let typ = match self.typ_value {
1218 Some(typ) => typ,
1219 None => match ready!(self.typ.poll(cx, &mut self.recv)) {
1220 VarPoll::Value(typ) => {
1221 self.typ_value = Some(typ);
1222 typ
1223 }
1224 VarPoll::End => return Poll::Ready(None),
1225 },
1226 };
1227 if typ != FRAME_WEBTRANSPORT {
1228 tracing::debug!(typ, "ignoring an unknown bidirectional stream");
1229 return Poll::Ready(None);
1230 }
1231 match ready!(self.session.poll(cx, &mut self.recv)) {
1232 VarPoll::Value(session) => Poll::Ready(Some(session)),
1233 VarPoll::End => Poll::Ready(None),
1234 }
1235 }
1236}
1237
1238fn classify_bi(web: &Rc<Web>, cx: &mut Context<'_>) -> bool {
1240 let pending = std::mem::take(&mut web.state.borrow_mut().pending_bi);
1241 let mut keep = Vec::new();
1242 let mut progressed = false;
1243
1244 for mut stream in pending {
1245 match stream.poll_classify(cx) {
1246 Poll::Pending => keep.push(stream),
1247 Poll::Ready(Some(session)) if session == web.session_id => {
1248 web.state.borrow_mut().ready_bi.push_back((stream.send, stream.recv));
1249 progressed = true;
1250 }
1251 Poll::Ready(_) => {}
1252 }
1253 }
1254
1255 let mut state = web.state.borrow_mut();
1256 state.pending_bi.extend(keep);
1257 progressed
1258}
1259
1260async fn open_uni(conn: &mut Connection) -> Result<super::SendStream, Error> {
1263 std::future::poll_fn(|cx| web_transport_trait::poll::Session::poll_open_uni(conn, cx)).await
1264}
1265
1266async fn accept_bi(conn: &mut Connection) -> Result<(super::SendStream, super::RecvStream), Error> {
1267 std::future::poll_fn(|cx| web_transport_trait::poll::Session::poll_accept_bi(conn, cx)).await
1268}
1269
1270async fn write_all(send: &mut super::SendStream, mut buf: &[u8]) -> Result<(), Error> {
1271 while !buf.is_empty() {
1272 let n = std::future::poll_fn(|cx| web_transport_trait::poll::SendStream::poll_write(send, cx, buf)).await?;
1273 buf = &buf[n..];
1274 }
1275 Ok(())
1276}
1277
1278async fn read_some(recv: &mut super::RecvStream, buf: &mut BytesMut) -> Result<bool, Error> {
1283 let mut chunk = [0u8; 4096];
1284 let n = std::future::poll_fn(|cx| web_transport_trait::poll::RecvStream::poll_read(recv, cx, &mut chunk)).await?;
1285 match n {
1286 Some(n) => {
1287 if buf.len() + n > MESSAGE_LIMIT {
1288 return Err(Error::Web("an HTTP/3 message exceeded the buffer limit".into()));
1289 }
1290 buf.extend_from_slice(&chunk[..n]);
1291 Ok(true)
1292 }
1293 None => Ok(false),
1294 }
1295}
1296
1297async fn read_settings(recv: &mut super::RecvStream) -> Result<proto::Settings, Error> {
1300 let mut buf = BytesMut::new();
1301 buf.extend_from_slice(&[STREAM_CONTROL as u8]);
1304 loop {
1305 let mut peek: &[u8] = &buf;
1306 match proto::Settings::decode(&mut peek) {
1307 Ok(settings) => return Ok(settings),
1308 Err(proto::SettingsError::UnexpectedEnd) => {}
1309 Err(err) => return Err(Error::Web(err.to_string())),
1310 }
1311 if !read_some(recv, &mut buf).await? {
1312 return Err(Error::Web("control stream ended before SETTINGS".into()));
1313 }
1314 }
1315}
1316
1317async fn read_connect(recv: &mut super::RecvStream) -> Result<proto::ConnectRequest, Error> {
1319 let mut buf = BytesMut::new();
1320 loop {
1321 let mut peek: &[u8] = &buf;
1322 match proto::ConnectRequest::decode(&mut peek) {
1323 Ok(request) => return Ok(request),
1324 Err(proto::ConnectError::UnexpectedEnd) => {}
1325 Err(err) => return Err(Error::Web(err.to_string())),
1326 }
1327 if !read_some(recv, &mut buf).await? {
1328 return Err(Error::Web("stream ended before the CONNECT request".into()));
1329 }
1330 }
1331}
1332
1333async fn read_capsules(web: Rc<Web>, conn: Connection, mut recv: super::RecvStream) {
1339 let mut capsules = Capsules::default();
1340 let capsule = loop {
1341 match capsules.take() {
1342 Ok(Some(proto::Capsule::CloseWebTransportSession { code, reason })) => {
1343 break Some((code, reason));
1344 }
1345 Ok(Some(_)) => continue,
1348 Ok(None) => {}
1349 Err(err) => {
1350 tracing::debug!(%err, "failed to parse a capsule on the CONNECT stream");
1351 break None;
1352 }
1353 }
1354 match read_some(&mut recv, &mut capsules.frames).await {
1355 Ok(true) => {}
1356 Ok(false) | Err(_) => break None,
1359 }
1360 };
1361
1362 match capsule {
1363 Some((code, reason)) => {
1364 web.closed.borrow_mut().get_or_insert(Error::App {
1365 code: u64::from(code),
1366 reason: reason.clone(),
1367 });
1368 conn.close_code(proto::error_to_http3(code), &reason);
1369 }
1370 None => conn.close_code(proto::error_to_http3(0), ""),
1372 }
1373}
1374
1375#[derive(Default)]
1382struct Capsules {
1383 frames: BytesMut,
1385 body: BytesMut,
1387}
1388
1389impl Capsules {
1390 fn take(&mut self) -> Result<Option<proto::Capsule>, Error> {
1392 self.demux()?;
1393
1394 let mut peek: &[u8] = &self.body;
1395 match proto::Capsule::decode(&mut peek) {
1396 Ok(capsule) => {
1397 let consumed = self.body.len() - peek.len();
1398 self.body.advance(consumed);
1399 Ok(Some(capsule))
1400 }
1401 Err(proto::CapsuleError::UnexpectedEnd | proto::CapsuleError::VarInt(_)) => Ok(None),
1403 Err(err) => Err(Error::Web(err.to_string())),
1404 }
1405 }
1406
1407 fn demux(&mut self) -> Result<(), Error> {
1410 loop {
1411 let mut peek: &[u8] = &self.frames;
1412 let Some(typ) = decode_varint(&mut peek) else {
1413 return Ok(());
1414 };
1415 let Some(len) = decode_varint(&mut peek) else {
1416 return Ok(());
1417 };
1418 let len = usize::try_from(len).map_err(|_| Error::Web("oversized HTTP/3 frame".into()))?;
1419 if peek.len() < len {
1420 return Ok(());
1421 }
1422 let header = self.frames.len() - peek.len();
1423
1424 if typ == FRAME_DATA {
1425 if self.body.len() + len > MESSAGE_LIMIT {
1428 return Err(Error::Web("a capsule exceeded the buffer limit".into()));
1429 }
1430 self.body.extend_from_slice(&peek[..len]);
1431 }
1432 self.frames.advance(header + len);
1433 }
1434 }
1435}
1436
1437#[cfg(test)]
1438mod tests {
1439 use super::*;
1440
1441 #[test]
1445 fn an_unmappable_code_is_not_an_application_error() {
1446 use web_transport_trait::Error as _;
1447
1448 let app = unmap_err(Error::App {
1449 code: proto::error_to_http3(7),
1450 reason: "seven".into(),
1451 });
1452 assert!(
1453 matches!(&app, Error::App { code: 7, reason } if reason == "seven"),
1454 "got {app:?}"
1455 );
1456 assert_eq!(app.session_error(), Some((7, "seven".to_string())));
1457
1458 let h3 = unmap_err(Error::App {
1460 code: 0x100,
1461 reason: "done".into(),
1462 });
1463 assert!(
1464 matches!(&h3, Error::Http3 { code: 0x100, reason } if reason == "done"),
1465 "got {h3:?}"
1466 );
1467 assert_eq!(h3.session_error(), None, "not a code the peer's application chose");
1468
1469 let reset = unmap_err(Error::Reset(0x100));
1470 assert!(matches!(reset, Error::Http3 { code: 0x100, .. }), "got {reset:?}");
1471 assert_eq!(reset.stream_error(), None, "not a MoQ stream code");
1472 assert!(matches!(
1473 unmap_err(Error::Stop(proto::error_to_http3(3))),
1474 Error::Stop(3)
1475 ));
1476 }
1477
1478 fn frame(typ: u64, payload: &[u8]) -> Vec<u8> {
1480 let mut buf = Vec::new();
1481 encode_varint(typ, &mut buf);
1482 encode_varint(payload.len() as u64, &mut buf);
1483 buf.extend_from_slice(payload);
1484 buf
1485 }
1486
1487 fn close_capsule(code: u32, reason: &str) -> Vec<u8> {
1488 let mut buf = Vec::new();
1489 proto::Capsule::CloseWebTransportSession {
1490 code,
1491 reason: reason.to_string(),
1492 }
1493 .encode(&mut buf);
1494 buf
1495 }
1496
1497 #[test]
1500 fn a_capsule_spans_data_frames() {
1501 let capsule = close_capsule(42, "split");
1502 let (head, tail) = capsule.split_at(capsule.len() / 2);
1503
1504 let mut capsules = Capsules::default();
1505 capsules.frames.extend_from_slice(&frame(FRAME_DATA, head));
1506 assert!(capsules.take().expect("parse").is_none(), "half a capsule is not one");
1507
1508 capsules.frames.extend_from_slice(&frame(FRAME_DATA, tail));
1509 let capsule = capsules.take().expect("parse").expect("the second half completes it");
1510 assert_eq!(
1511 capsule,
1512 proto::Capsule::CloseWebTransportSession {
1513 code: 42,
1514 reason: "split".to_string()
1515 }
1516 );
1517 }
1518
1519 #[test]
1522 fn one_frame_carries_several_capsules() {
1523 let mut payload = close_capsule(1, "first");
1524 payload.extend_from_slice(&close_capsule(2, "second"));
1525
1526 let mut capsules = Capsules::default();
1527 capsules.frames.extend_from_slice(&frame(FRAME_DATA, &payload));
1528
1529 for (code, reason) in [(1, "first"), (2, "second")] {
1530 let capsule = capsules.take().expect("parse").expect("a whole capsule");
1531 assert_eq!(
1532 capsule,
1533 proto::Capsule::CloseWebTransportSession {
1534 code,
1535 reason: reason.to_string()
1536 }
1537 );
1538 }
1539 assert!(capsules.take().expect("parse").is_none(), "only two were written");
1540 }
1541
1542 #[test]
1545 fn a_non_data_frame_is_skipped() {
1546 let capsule = close_capsule(7, "after");
1547 let (head, tail) = capsule.split_at(1);
1548
1549 let mut capsules = Capsules::default();
1550 capsules.frames.extend_from_slice(&frame(FRAME_DATA, head));
1551 capsules.frames.extend_from_slice(&frame(0x07, b"\x00"));
1553 capsules.frames.extend_from_slice(&frame(FRAME_DATA, tail));
1554
1555 let capsule = capsules.take().expect("parse").expect("a whole capsule");
1556 assert_eq!(
1557 capsule,
1558 proto::Capsule::CloseWebTransportSession {
1559 code: 7,
1560 reason: "after".to_string()
1561 }
1562 );
1563 }
1564
1565 #[test]
1568 fn a_capsule_stream_is_bounded() {
1569 let mut header = Vec::new();
1573 encode_varint(0x2843, &mut header);
1574 encode_varint(65536, &mut header);
1575
1576 let mut capsules = Capsules::default();
1577 capsules.frames.extend_from_slice(&frame(FRAME_DATA, &header));
1578
1579 let chunk = vec![0u8; 8 * 1024];
1580 let err = loop {
1581 match capsules.take() {
1582 Ok(None) => {}
1583 Ok(Some(capsule)) => panic!("the payload never arrived, got {capsule:?}"),
1584 Err(err) => break err,
1585 }
1586 capsules.frames.extend_from_slice(&frame(FRAME_DATA, &chunk));
1587 };
1588 assert!(matches!(err, Error::Web(_)), "refused with {err}");
1589 assert!(capsules.body.len() <= MESSAGE_LIMIT, "the buffer stayed bounded");
1590 }
1591}