1use web_transport_trait::{MaybeSend, MaybeSync};
5
6use crate::origin;
7use crate::time::{Clock, Instant};
8use crate::{
9 ALPN_14, ALPN_15, ALPN_16, ALPN_17, ALPN_18, ALPN_19, ALPN_20, ALPN_21, ALPN_22, ALPN_LITE, ALPN_LITE_03,
10 ALPN_LITE_04, ALPN_LITE_05, ALPN_LITE_06, ALPN_LITE_07_WIP, Consume, Error, NEGOTIATED, Role, Session,
11 SessionError, Version, Versions,
12 coding::{Decode, Encode, Stream},
13 ietf, lite, setup, stats,
14};
15
16#[derive(Default, Clone)]
18pub struct Server {
19 publish: Option<origin::Consumer>,
20 subscribe: Option<origin::Producer>,
21 stats: stats::Session,
22 versions: Versions,
23}
24
25impl Server {
26 pub fn new() -> Self {
28 Default::default()
29 }
30
31 pub fn with_publisher(mut self, publish: impl Consume<origin::Consumer>) -> Self {
36 self.publish = Some(publish.consume());
37 self
38 }
39
40 pub fn with_subscriber(mut self, subscribe: origin::Producer) -> Self {
43 self.subscribe = Some(subscribe);
44 self
45 }
46
47 pub fn with_stats(mut self, stats: stats::Session) -> Self {
52 self.stats = stats;
53 self
54 }
55
56 pub fn with_origin(self, origin: origin::Producer) -> Self {
58 self.with_publisher(&origin).with_subscriber(origin)
59 }
60
61 pub fn with_versions(mut self, versions: Versions) -> Self {
64 self.versions = versions;
65 self
66 }
67
68 fn stat_tagged_origins(&self) -> (Option<origin::Consumer>, Option<origin::Producer>) {
73 let publish = self.publish.clone().map(|origin| origin.with_stats(self.stats.clone()));
74 let subscribe = self
75 .subscribe
76 .clone()
77 .map(|origin| origin.with_stats(self.stats.clone()));
78 (publish, subscribe)
79 }
80
81 fn start_lite<S>(
84 &self,
85 runtime: Clock,
86 session: S,
87 version: lite::Version,
88 client_setup: Option<lite::Setup>,
89 peer_hop: Option<crate::Hop>,
90 ) -> Result<(Session, crate::Driver<S>), Error>
91 where
92 S: crate::transport::poll::Session,
93 {
94 let (publish, subscribe) = self.stat_tagged_origins();
95
96 let our_setup = if version.has_setup_stream() {
100 lite::Setup {
101 probe: lite::ProbeLevel::detect(&session),
102 path: None,
103 role: None,
104 cost: None,
105 hop: None,
107 }
108 } else {
109 lite::Setup::default()
110 };
111
112 let start = lite::start(lite::Config {
113 runtime: runtime.clone(),
114 session: session.clone(),
115 setup_stream: None,
116 publish,
117 subscribe,
118 peer_hop,
119 version,
120 our_setup,
121 peer_setup: client_setup,
122 })?;
123
124 Ok(Session::new(
125 runtime,
126 session,
127 version.into(),
128 start.recv_bandwidth,
129 crate::driver::Protocol::Lite(Box::new(start.driver)),
130 start.goaway,
131 Some(start.estimate),
132 ))
133 }
134
135 pub async fn accept_lite<S>(&self, now: Instant, session: S) -> Result<(Session, crate::Driver<S>), Error>
144 where
145 S: crate::transport::poll::Session,
146 {
147 self.accept_request_lite(now, session).await?.ok().await
148 }
149
150 pub async fn accept_request_lite<S>(&self, now: Instant, session: S) -> Result<Handshake<S>, Error>
156 where
157 S: crate::transport::poll::Session,
158 {
159 let mut refused = session.clone();
160 self.handshake_lite(now, session)
161 .await
162 .inspect_err(|err| close(&mut refused, err))
163 }
164
165 async fn handshake_lite<S>(&self, now: Instant, mut session: S) -> Result<Handshake<S>, Error>
166 where
167 S: crate::transport::poll::Session,
168 {
169 let runtime = Clock::new(now);
170 let (path, role, origin, handshake) = match session.protocol() {
171 Some(alpn @ (ALPN_LITE_05 | ALPN_LITE_06 | ALPN_LITE_07_WIP)) => {
172 let version = match alpn {
173 ALPN_LITE_07_WIP => lite::Version::Lite07,
174 ALPN_LITE_06 => lite::Version::Lite06,
175 _ => lite::Version::Lite05,
176 };
177 self.versions.select(Version::Lite(version)).ok_or(Error::Version)?;
178 let client_setup = lite::accept_setup(&mut session, version).await?;
183 (
184 client_setup.path.clone(),
185 client_setup.role,
186 client_setup.hop,
187 PausedHandshake::LiteSetup {
188 session,
189 version,
190 client_setup,
191 },
192 )
193 }
194 Some(ALPN_LITE_04) => {
195 self.versions
196 .select(Version::Lite(lite::Version::Lite04))
197 .ok_or(Error::Version)?;
198 (
199 None,
200 None,
201 None,
202 PausedHandshake::LiteBare {
203 session,
204 version: lite::Version::Lite04,
205 },
206 )
207 }
208 Some(ALPN_LITE_03) => {
209 self.versions
210 .select(Version::Lite(lite::Version::Lite03))
211 .ok_or(Error::Version)?;
212 (
213 None,
214 None,
215 None,
216 PausedHandshake::LiteBare {
217 session,
218 version: lite::Version::Lite03,
219 },
220 )
221 }
222 _ => return Err(Error::Version),
223 };
224
225 Ok(Handshake {
226 path,
227 role,
228 origin,
229 token: None,
231 assigned_hop: crate::Hop::random(),
232 inner: Some(RequestInner {
233 server: self.clone(),
234 runtime,
235 handshake,
236 }),
237 })
238 }
239
240 pub async fn accept<S>(&self, now: Instant, session: S) -> Result<(Session, crate::Driver<S>), Error>
248 where
249 S: crate::transport::poll::Boxable,
250 S::SendStream: MaybeSync,
251 S::RecvStream: MaybeSync,
252 {
253 self.accept_request(now, session).await?.ok().await
254 }
255
256 pub async fn accept_request<S>(&self, now: Instant, session: S) -> Result<Handshake<S>, Error>
270 where
271 S: crate::transport::poll::Boxable,
272 S::SendStream: MaybeSync,
273 S::RecvStream: MaybeSync,
274 {
275 let mut refused = session.clone();
276 self.handshake(now, session)
277 .await
278 .inspect_err(|err| close(&mut refused, err))
279 }
280
281 async fn handshake<S>(&self, now: Instant, mut session: S) -> Result<Handshake<S>, Error>
282 where
283 S: crate::transport::poll::Boxable,
284 S::SendStream: MaybeSync,
285 S::RecvStream: MaybeSync,
286 {
287 let runtime = Clock::new(now);
288 let (encoding, supported) = match session.protocol() {
289 Some(alpn @ (ALPN_22 | ALPN_21 | ALPN_20 | ALPN_19 | ALPN_18 | ALPN_17)) => {
290 let draft = match alpn {
291 ALPN_22 => ietf::Version::Draft22,
292 ALPN_21 => ietf::Version::Draft21,
293 ALPN_20 => ietf::Version::Draft20,
294 ALPN_19 => ietf::Version::Draft19,
295 ALPN_18 => ietf::Version::Draft18,
296 _ => ietf::Version::Draft17,
297 };
298
299 self.versions.select(Version::Ietf(draft)).ok_or(Error::Version)?;
300 return self.accept_ietf_modern(runtime, session, draft).await;
301 }
302 Some(ALPN_16) => {
303 let v = self
304 .versions
305 .select(Version::Ietf(ietf::Version::Draft16))
306 .ok_or(Error::Version)?;
307 (v, v.into())
308 }
309 Some(ALPN_15) => {
310 let v = self
311 .versions
312 .select(Version::Ietf(ietf::Version::Draft15))
313 .ok_or(Error::Version)?;
314 (v, v.into())
315 }
316 Some(ALPN_14) => {
317 let v = self
318 .versions
319 .select(Version::Ietf(ietf::Version::Draft14))
320 .ok_or(Error::Version)?;
321 (v, v.into())
322 }
323 Some(ALPN_LITE_07_WIP | ALPN_LITE_06 | ALPN_LITE_05 | ALPN_LITE_04 | ALPN_LITE_03) => {
326 return self.handshake_lite(now, session).await;
327 }
328 Some(ALPN_LITE) | None => {
329 let supported = self.versions.filter(&NEGOTIATED.into()).ok_or(Error::Version)?;
330 (Version::Ietf(ietf::Version::Draft14), supported)
331 }
332 Some(p) => return Err(Error::UnknownAlpn(p.to_string())),
333 };
334
335 let mut stream = Stream::accept(&mut session, encoding).await?;
338 let mut client: setup::Client = stream.reader.decode().await?;
339
340 let version = client
341 .versions
342 .iter()
343 .flat_map(|v| Version::try_from(*v).ok())
344 .find(|v| supported.contains(v))
345 .ok_or(Error::Version)?;
346
347 let (path, token, request_id_max, peer_declared) = match version {
351 Version::Ietf(v) => {
352 let params = ietf::Parameters::decode(&mut client.parameters, v)?;
353 let path = match params.get_bytes(ietf::ParameterBytes::Path) {
354 Some(bytes) => Some(
355 std::str::from_utf8(bytes)
356 .map_err(|_| Error::Decode(crate::DecodeError::InvalidValue))?
357 .to_owned(),
358 ),
359 None => None,
360 };
361 let token = ietf::token::from_setup(¶ms, v)?;
362 let request_id_max = params
363 .get_varint(ietf::ParameterVarInt::MaxRequestId)
364 .map(ietf::RequestId);
365 let peer_declared = ietf::peer::Peer {
366 solicit: ietf::solicit::from_setup(¶ms, v)?,
367 hidden: ietf::hidden::from_setup(¶ms, v),
368 ..Default::default()
369 };
370 (path, token, request_id_max, peer_declared)
371 }
372 Version::Lite(_) => (None, None, None, ietf::peer::Peer::default()),
373 };
374
375 Ok(Handshake {
376 path,
377 role: None,
378 origin: None,
379 token,
380 assigned_hop: crate::Hop::random(),
381 inner: Some(RequestInner {
382 server: self.clone(),
383 runtime,
384 handshake: PausedHandshake::Boxed(Box::new(PausedLegacy {
385 session,
386 stream,
387 version,
388 request_id_max,
389 peer_declared,
390 })),
391 }),
392 })
393 }
394
395 async fn accept_ietf_modern<S>(
398 &self,
399 runtime: Clock,
400 mut session: S,
401 version: ietf::Version,
402 ) -> Result<Handshake<S>, Error>
403 where
404 S: crate::transport::poll::Boxable,
405 S::SendStream: MaybeSync,
406 S::RecvStream: MaybeSync,
407 {
408 let peer_setup = ietf::accept_setup(&mut session, version).await?;
409 Ok(Handshake {
410 path: peer_setup.path.clone(),
411 role: None,
412 origin: peer_setup.declared.cluster.hop.filter(|h| *h != crate::Hop::UNKNOWN),
415 token: peer_setup.token.clone(),
416 assigned_hop: crate::Hop::random(),
417 inner: Some(RequestInner {
418 server: self.clone(),
419 runtime,
420 handshake: PausedHandshake::Boxed(Box::new(PausedIetfModern {
421 session,
422 version,
423 peer_setup,
424 })),
425 }),
426 })
427 }
428}
429
430pub struct Handshake<S: crate::transport::poll::Session> {
438 path: Option<String>,
439 role: Option<Role>,
440 origin: Option<crate::Hop>,
441 token: Option<setup::Token>,
442 assigned_hop: crate::Hop,
446 inner: Option<RequestInner<S>>,
448}
449
450struct RequestInner<S: crate::transport::poll::Session> {
452 server: Server,
453 runtime: Clock,
455 handshake: PausedHandshake<S>,
456}
457
458enum PausedHandshake<S: crate::transport::poll::Session> {
461 LiteBare { session: S, version: lite::Version },
463 LiteSetup {
466 session: S,
467 version: lite::Version,
468 client_setup: lite::Setup,
469 },
470 Boxed(Box<dyn Paused<S>>),
477}
478
479type Accept<S> = crate::util::MaybeSendBox<'static, Result<(Session, crate::Driver<S>), Error>>;
480
481trait Paused<S: crate::transport::poll::Session>: MaybeSend + MaybeSync {
488 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S>;
490
491 fn close(self: Box<Self>, err: Error);
493}
494
495struct PausedIetfModern<S: crate::transport::poll::Session> {
499 session: S,
500 version: ietf::Version,
501 peer_setup: ietf::PeerSetup<S>,
502}
503
504impl<S> Paused<S> for PausedIetfModern<S>
505where
506 S: crate::transport::poll::Boxable,
507 S::SendStream: MaybeSync,
508 S::RecvStream: MaybeSync,
509{
510 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S> {
511 use crate::util::MaybeBoxedExt as _;
512 async move {
513 let Self {
514 session,
515 version,
516 peer_setup,
517 } = *self;
518 let (publish, subscribe) = server.stat_tagged_origins();
519
520 let (protocol, goaway) = ietf::start(ietf::Config {
523 runtime: runtime.clone(),
524 session: session.clone(),
525 setup: None,
526 request_id_max: None,
527 client: false,
528 publish,
529 subscribe,
530 peer_hop,
531 cost: None,
533 version,
534 path: None,
535 authority: None,
536 peer_setup_stream: Some(peer_setup.stream),
537 peer_declared: Some(peer_setup.declared),
538 early_unis: peer_setup.early,
539 })?;
540 tracing::debug!(?version, "connected");
541 Ok(Session::new(
542 runtime,
543 session,
544 version.into(),
545 None,
546 crate::driver::Protocol::Ietf(protocol),
547 goaway,
548 None,
549 ))
550 }
551 .maybe_boxed()
552 }
553
554 fn close(mut self: Box<Self>, err: Error) {
555 close(&mut self.session, &err);
556 }
557}
558
559struct PausedLegacy<S: crate::transport::poll::Session> {
563 session: S,
564 stream: Stream<S, Version>,
565 version: Version,
566 request_id_max: Option<ietf::RequestId>,
567 peer_declared: ietf::peer::Peer,
569}
570
571impl<S> Paused<S> for PausedLegacy<S>
572where
573 S: crate::transport::poll::Boxable,
574 S::SendStream: MaybeSync,
575 S::RecvStream: MaybeSync,
576{
577 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S> {
578 use crate::util::MaybeBoxedExt as _;
579 async move {
580 let Self {
581 session,
582 mut stream,
583 version,
584 request_id_max,
585 peer_declared,
586 } = *self;
587 let (publish, subscribe) = server.stat_tagged_origins();
588
589 let parameters = match version {
591 Version::Ietf(v) => {
592 let mut parameters = ietf::Parameters::default();
593 parameters.set_varint(ietf::ParameterVarInt::MaxRequestId, u32::MAX as u64);
594 parameters.set_bytes(ietf::ParameterBytes::Implementation, b"moq-lite-rs".to_vec());
595 ietf::solicit::into_setup(&mut parameters, v);
596 ietf::hidden::into_setup(&mut parameters, v);
597 parameters.encode_bytes(v)?
598 }
599 Version::Lite(v) => lite::Parameters::default().encode_bytes(v)?,
600 };
601
602 let server_setup = setup::Server {
603 version: version.into(),
604 parameters,
605 };
606 stream.writer.encode(&server_setup).await?;
607
608 let (recv_bw, protocol, goaway, estimate) = match version {
609 Version::Lite(v) => {
610 let stream = stream.with_version(v);
611 let start = lite::start(lite::Config {
613 runtime: runtime.clone(),
614 session: session.clone(),
615 setup_stream: Some(stream),
616 publish,
617 subscribe,
618 peer_hop,
619 version: v,
620 our_setup: lite::Setup::default(),
621 peer_setup: None,
622 })?;
623 (
624 start.recv_bandwidth,
625 crate::driver::Protocol::Lite(Box::new(start.driver)),
626 start.goaway,
627 Some(start.estimate),
628 )
629 }
630 Version::Ietf(v) => {
631 let stream = stream.with_version(v);
632 let (protocol, goaway) = ietf::start(ietf::Config {
634 runtime: runtime.clone(),
635 session: session.clone(),
636 setup: Some(stream),
637 request_id_max,
638 client: false,
639 publish,
640 subscribe,
641 peer_hop,
642 cost: None,
643 version: v,
644 path: None,
645 authority: None,
646 peer_setup_stream: None,
647 peer_declared: Some(peer_declared),
648 early_unis: Vec::new(),
649 })?;
650 (None, crate::driver::Protocol::Ietf(protocol), goaway, None)
651 }
652 };
653
654 Ok(Session::new(
655 runtime, session, version, recv_bw, protocol, goaway, estimate,
656 ))
657 }
658 .maybe_boxed()
659 }
660
661 fn close(mut self: Box<Self>, err: Error) {
662 close(&mut self.session, &err);
663 }
664}
665
666impl<S> Handshake<S>
667where
668 S: crate::transport::poll::Session,
669{
670 pub fn path(&self) -> &str {
677 self.path.as_deref().unwrap_or("")
678 }
679
680 pub fn role(&self) -> Option<Role> {
689 self.role
690 }
691
692 pub fn peer_hop(&self) -> Option<crate::Hop> {
701 self.origin
702 }
703
704 pub fn token(&self) -> Option<&setup::Token> {
709 self.token.as_ref()
710 }
711
712 pub fn with_publisher(mut self, publish: impl Consume<origin::Consumer>) -> Self {
715 self.inner_mut().server.publish = Some(publish.consume());
716 self
717 }
718
719 pub fn with_subscriber(mut self, subscribe: origin::Producer) -> Self {
721 self.inner_mut().server.subscribe = Some(subscribe);
722 self
723 }
724
725 pub fn with_peer_hop(mut self, hop: crate::Hop) -> Self {
738 self.assigned_hop = hop;
739 self
740 }
741
742 pub fn with_stats(mut self, stats: stats::Session) -> Self {
745 self.inner_mut().server.stats = stats;
746 self
747 }
748
749 fn inner_mut(&mut self) -> &mut RequestInner<S> {
750 self.inner.as_mut().expect("request already responded")
751 }
752
753 pub async fn ok(mut self) -> Result<(Session, crate::Driver<S>), Error> {
757 let peer_hop = Some(self.assigned_hop);
758 let RequestInner {
759 server,
760 runtime,
761 handshake,
762 } = self.inner.take().expect("request already responded");
763
764 match handshake {
765 PausedHandshake::LiteBare { session, version } => {
766 server.start_lite(runtime, session, version, None, peer_hop)
767 }
768 PausedHandshake::LiteSetup {
769 session,
770 version,
771 client_setup,
772 } => server.start_lite(runtime, session, version, Some(client_setup), peer_hop),
773 PausedHandshake::Boxed(paused) => paused.ok(server, runtime, peer_hop).await,
774 }
775 }
776
777 pub fn close(mut self, err: Error) {
779 let inner = self.inner.take().expect("request already responded");
780 inner.close(err);
781 }
782}
783
784impl<S: crate::transport::poll::Session> RequestInner<S> {
785 fn close(self, err: Error) {
786 let mut session = match self.handshake {
787 PausedHandshake::LiteBare { session, .. } => session,
788 PausedHandshake::LiteSetup { session, .. } => session,
789 PausedHandshake::Boxed(paused) => return paused.close(err),
790 };
791 close(&mut session, &err);
792 }
793}
794
795fn close<S: crate::transport::poll::Session>(session: &mut S, err: &Error) {
797 session.close(SessionError::from(err).to_code(), &err.to_string());
798}
799
800impl<S: crate::transport::poll::Session> Drop for Handshake<S> {
801 fn drop(&mut self) {
804 if let Some(inner) = self.inner.take() {
805 tracing::warn!("Handshake dropped without ok() or close(); rejecting the session");
806 inner.close(Error::Cancel);
807 }
808 }
809}
810
811#[cfg(test)]
812mod tests {
813 use super::*;
814 use crate::Hop;
815 use crate::model::ProduceTest;
816 use std::{
817 collections::VecDeque,
818 sync::{Arc, Mutex},
819 };
820
821 use crate::ALPN_LITE_05;
822 use bytes::Bytes;
823
824 fn occurrences(log: &crate::lite::test_transport::Log, needle: &[u8]) -> usize {
825 let writes = log.writes.lock().unwrap();
826 writes.windows(needle.len()).filter(|window| *window == needle).count()
827 }
828
829 #[derive(Debug, Clone, Default)]
830 struct FakeError;
831 impl std::fmt::Display for FakeError {
832 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
833 write!(f, "fake transport error")
834 }
835 }
836 impl std::error::Error for FakeError {}
837 impl web_transport_trait::Error for FakeError {
838 fn session_error(&self) -> Option<(u32, String)> {
839 Some((0, "closed".to_string()))
840 }
841 }
842
843 #[derive(Clone)]
847 struct FakeSession {
848 protocol: Option<&'static str>,
849 uni: Arc<Mutex<VecDeque<Vec<u8>>>>,
850 bi: Arc<Mutex<VecDeque<Vec<u8>>>>,
851 closed: Arc<Mutex<Option<u32>>>,
852 }
853
854 impl FakeSession {
855 fn new(protocol: &'static str, uni: impl IntoIterator<Item = Vec<u8>>) -> Self {
856 Self {
857 protocol: Some(protocol),
858 uni: Arc::new(Mutex::new(uni.into_iter().collect())),
859 bi: Default::default(),
860 closed: Default::default(),
861 }
862 }
863
864 fn with_bi(self, bi: Vec<u8>) -> Self {
865 self.bi.lock().unwrap().push_back(bi);
866 self
867 }
868
869 fn closed(&self) -> Option<u32> {
870 *self.closed.lock().unwrap()
871 }
872 }
873
874 impl web_transport_trait::poll::Session for FakeSession {
875 type SendStream = FakeSend;
876 type RecvStream = FakeRecv;
877 type Error = FakeError;
878
879 fn poll_accept_uni(
880 &mut self,
881 _cx: &mut std::task::Context<'_>,
882 ) -> std::task::Poll<Result<Self::RecvStream, Self::Error>> {
883 match self.uni.lock().unwrap().pop_front() {
884 Some(data) => std::task::Poll::Ready(Ok(FakeRecv { data: data.into() })),
885 None => std::task::Poll::Pending,
886 }
887 }
888 fn poll_accept_bi(
889 &mut self,
890 _cx: &mut std::task::Context<'_>,
891 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
892 match self.bi.lock().unwrap().pop_front() {
893 Some(data) => std::task::Poll::Ready(Ok((FakeSend, FakeRecv { data: data.into() }))),
894 None => std::task::Poll::Pending,
895 }
896 }
897 fn poll_open_bi(
898 &mut self,
899 _cx: &mut std::task::Context<'_>,
900 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
901 std::task::Poll::Pending
902 }
903 fn poll_open_uni(
904 &mut self,
905 _cx: &mut std::task::Context<'_>,
906 ) -> std::task::Poll<Result<Self::SendStream, Self::Error>> {
907 std::task::Poll::Pending
908 }
909 fn poll_send_datagram(
910 &mut self,
911 _cx: &mut std::task::Context<'_>,
912 _payload: &[u8],
913 ) -> std::task::Poll<Result<(), Self::Error>> {
914 std::task::Poll::Ready(Ok(()))
915 }
916 fn poll_recv_datagram(
917 &mut self,
918 _cx: &mut std::task::Context<'_>,
919 ) -> std::task::Poll<Result<Bytes, Self::Error>> {
920 std::task::Poll::Pending
921 }
922 fn max_datagram_size(&self) -> usize {
923 1200
924 }
925 fn protocol(&self) -> Option<&str> {
926 self.protocol
927 }
928 fn close(&mut self, code: u32, _reason: &str) {
929 self.closed.lock().unwrap().get_or_insert(code);
930 }
931 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Error> {
932 std::task::Poll::Pending
933 }
934 fn stats(&self) -> impl web_transport_trait::Stats {
935 web_transport_trait::StatsUnavailable
936 }
937 }
938
939 #[derive(Clone, Default)]
940 struct FakeSend;
941 impl web_transport_trait::poll::SendStream for FakeSend {
942 type Error = FakeError;
943 fn poll_write(
944 &mut self,
945 _cx: &mut std::task::Context<'_>,
946 buf: &[u8],
947 ) -> std::task::Poll<Result<usize, Self::Error>> {
948 std::task::Poll::Ready(Ok(buf.len()))
949 }
950 fn set_priority(&mut self, _order: u8) {}
951 fn finish(&mut self) -> Result<(), Self::Error> {
952 Ok(())
953 }
954 fn reset(&mut self, _code: u32) {}
955 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
956 std::task::Poll::Ready(Ok(()))
957 }
958 }
959
960 struct FakeRecv {
961 data: VecDeque<u8>,
962 }
963 impl web_transport_trait::poll::RecvStream for FakeRecv {
964 type Error = FakeError;
965 fn poll_read(
966 &mut self,
967 _cx: &mut std::task::Context<'_>,
968 dst: &mut [u8],
969 ) -> std::task::Poll<Result<Option<usize>, Self::Error>> {
970 if self.data.is_empty() {
971 return std::task::Poll::Ready(Ok(None));
972 }
973 let size = dst.len().min(self.data.len());
974 for slot in dst.iter_mut().take(size) {
975 *slot = self.data.pop_front().unwrap();
976 }
977 std::task::Poll::Ready(Ok(Some(size)))
978 }
979 fn stop(&mut self, _code: u32) {}
980 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
981 std::task::Poll::Ready(Ok(()))
982 }
983 }
984
985 fn lite05_setup(path: Option<&str>, role: Option<Role>, hop: Option<Hop>) -> Vec<u8> {
987 let v = lite::Version::Lite05;
988 let mut buf = Vec::new();
989 lite::DataType::Setup.encode(&mut buf, v).unwrap();
990 lite::Setup {
991 probe: lite::ProbeLevel::None,
992 path: path.map(str::to_string),
993 role,
994 cost: None,
995 hop,
996 }
997 .encode(&mut buf, v)
998 .unwrap();
999 buf
1000 }
1001
1002 fn ietf_setup(version: ietf::Version, path: Option<&str>) -> Vec<u8> {
1005 let mut params = ietf::Parameters::default();
1006 if let Some(path) = path {
1007 params.set_bytes(ietf::ParameterBytes::Path, path.as_bytes().to_vec());
1008 }
1009 ietf_setup_with(version, params)
1010 }
1011
1012 fn ietf_setup_with(version: ietf::Version, params: ietf::Parameters) -> Vec<u8> {
1013 let parameters = params.encode_bytes(version).unwrap();
1014
1015 let mut buf = Vec::new();
1016 setup::Setup { parameters }
1017 .encode(&mut buf, crate::Version::Ietf(version))
1018 .unwrap();
1019 buf
1020 }
1021
1022 fn legacy_setup(version: ietf::Version, params: ietf::Parameters) -> Vec<u8> {
1024 let mut buf = Vec::new();
1025 setup::Client {
1026 versions: crate::coding::Versions::from([crate::Version::Ietf(version).into()]),
1027 parameters: params.encode_bytes(version).unwrap(),
1028 }
1029 .encode(&mut buf, crate::Version::Ietf(version))
1030 .unwrap();
1031 buf
1032 }
1033
1034 fn setup_token() -> setup::Token {
1035 setup::Token {
1036 kind: setup::Token::OUT_OF_BAND,
1037 value: vec![0x00, 0xff, b'j', b'w', b't'],
1038 }
1039 }
1040
1041 fn token_params(version: ietf::Version) -> ietf::Parameters {
1042 let mut params = ietf::Parameters::default();
1043 ietf::token::into_setup(&mut params, &setup_token(), version).unwrap();
1044 params
1045 }
1046
1047 #[tokio::test(start_paused = true)]
1048 async fn accept_request_exposes_the_setup_token() {
1049 let modern = FakeSession::new(
1050 ALPN_19,
1051 [ietf_setup_with(
1052 ietf::Version::Draft19,
1053 token_params(ietf::Version::Draft19),
1054 )],
1055 );
1056 let legacy = FakeSession::new(ALPN_16, []).with_bi(legacy_setup(
1057 ietf::Version::Draft16,
1058 token_params(ietf::Version::Draft16),
1059 ));
1060 for (name, session) in [("draft-19", modern), ("draft-16", legacy)] {
1061 let request = Server::new()
1062 .accept_request(tokio::time::Instant::now().into_std(), session)
1063 .await
1064 .unwrap();
1065 assert_eq!(request.token(), Some(&setup_token()), "{name}");
1066 }
1067 }
1068
1069 #[tokio::test(start_paused = true)]
1070 async fn accept_request_without_a_token_reports_none() {
1071 let ietf = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, None)]);
1072 let lite = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1073 for (name, session) in [("draft-19", ietf), ("lite-05", lite)] {
1074 let request = Server::new()
1075 .accept_request(tokio::time::Instant::now().into_std(), session)
1076 .await
1077 .unwrap();
1078 assert_eq!(request.token(), None, "{name}");
1079 }
1080 }
1081
1082 #[tokio::test(start_paused = true)]
1085 async fn a_refused_setup_token_closes_with_its_code() {
1086 let delete = [0x0, 0x7]; let truncated = [0x3]; for (raw, code) in [
1089 (&delete[..], SessionError::ProtocolViolation),
1090 (&truncated[..], SessionError::KeyValueFormatting),
1091 ] {
1092 let mut params = ietf::Parameters::default();
1093 params.set_bytes(ietf::ParameterBytes::AuthorizationToken, raw.to_vec());
1094
1095 let modern = FakeSession::new(ALPN_19, [ietf_setup_with(ietf::Version::Draft19, params.clone())]);
1096 let legacy = FakeSession::new(ALPN_16, []).with_bi(legacy_setup(ietf::Version::Draft16, params));
1097 for (name, session) in [("draft-19", modern), ("draft-16", legacy)] {
1098 let result = Server::new()
1099 .accept_request(tokio::time::Instant::now().into_std(), session.clone())
1100 .await;
1101 assert!(result.is_err(), "{name}");
1102 assert_eq!(session.closed(), Some(code.to_code()), "{name} {code}");
1103 }
1104 }
1105 }
1106
1107 #[tokio::test(start_paused = true)]
1108 async fn accept_request_reads_ietf_path() {
1109 for (alpn, version) in [
1112 (ALPN_17, ietf::Version::Draft17),
1113 (ALPN_18, ietf::Version::Draft18),
1114 (ALPN_19, ietf::Version::Draft19),
1115 ] {
1116 let session = FakeSession::new(alpn, [ietf_setup(version, Some("/team/room"))]);
1117 let request = Server::new()
1118 .accept_request(tokio::time::Instant::now().into_std(), session)
1119 .await
1120 .unwrap();
1121 assert_eq!(request.path(), "/team/room", "{alpn}");
1122 }
1123 }
1124
1125 #[tokio::test(start_paused = true)]
1126 async fn accept_request_ietf_without_path_is_empty() {
1127 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, None)]);
1128 let request = Server::new()
1129 .accept_request(tokio::time::Instant::now().into_std(), session)
1130 .await
1131 .unwrap();
1132 assert_eq!(request.path(), "");
1133 }
1134
1135 #[tokio::test(start_paused = true)]
1136 async fn accept_request_ietf_empty_path_is_accepted() {
1137 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, Some(""))]);
1138 let request = Server::new()
1139 .accept_request(tokio::time::Instant::now().into_std(), session)
1140 .await
1141 .unwrap();
1142 assert_eq!(request.path(), "");
1143 }
1144
1145 fn lite05_group() -> Vec<u8> {
1147 let mut buf = Vec::new();
1148 lite::DataType::Group.encode(&mut buf, lite::Version::Lite05).unwrap();
1149 buf
1150 }
1151
1152 #[tokio::test(start_paused = true)]
1153 async fn accept_request_reads_lite05_path() {
1154 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some("/team/room"), None, None)]);
1155 let request = Server::new()
1156 .accept_request(tokio::time::Instant::now().into_std(), session)
1157 .await
1158 .unwrap();
1159 assert_eq!(request.path(), "/team/room");
1160 assert_eq!(request.role(), None, "a client that omits the role is bidirectional");
1161 }
1162
1163 #[tokio::test(start_paused = true)]
1164 async fn accept_request_lite05_without_path_is_empty() {
1165 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1166 let request = Server::new()
1167 .accept_request(tokio::time::Instant::now().into_std(), session)
1168 .await
1169 .unwrap();
1170 assert_eq!(request.path(), "");
1171 }
1172
1173 #[tokio::test(start_paused = true)]
1174 async fn accept_request_lite05_empty_path_is_accepted() {
1175 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some(""), None, None)]);
1178 let request = Server::new()
1179 .accept_request(tokio::time::Instant::now().into_std(), session)
1180 .await
1181 .unwrap();
1182 assert_eq!(request.path(), "");
1183 }
1184
1185 #[tokio::test(start_paused = true)]
1186 async fn accept_request_reads_lite05_role() {
1187 let session = FakeSession::new(
1188 ALPN_LITE_05,
1189 [lite05_setup(Some("/team/room"), Some(Role::Publisher), None)],
1190 );
1191 let request = Server::new()
1192 .accept_request(tokio::time::Instant::now().into_std(), session)
1193 .await
1194 .unwrap();
1195 assert_eq!(request.role(), Some(Role::Publisher));
1196 }
1197
1198 #[tokio::test(start_paused = true)]
1199 async fn accept_request_skips_uni_stream_before_setup() {
1200 let session = FakeSession::new(
1203 ALPN_LITE_05,
1204 [lite05_group(), lite05_setup(Some("/team/room"), None, None)],
1205 );
1206 let request = Server::new()
1207 .accept_request(tokio::time::Instant::now().into_std(), session)
1208 .await
1209 .unwrap();
1210 assert_eq!(request.path(), "/team/room");
1211 }
1212
1213 #[tokio::test(start_paused = true)]
1214 async fn accept_request_reads_lite05_peer_hop() {
1215 let hop = Hop::new(42).unwrap();
1216 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, Some(hop))]);
1217 let request = Server::new()
1218 .accept_request(tokio::time::Instant::now().into_std(), session)
1219 .await
1220 .unwrap();
1221 assert_eq!(request.peer_hop(), Some(hop));
1222 }
1223
1224 #[tokio::test(start_paused = true)]
1225 async fn anonymous_peer_hop_filters_routes_from_server_session() {
1226 let other = Hop::new(778).unwrap();
1227 let origin = crate::origin::Config::new(Hop::new(1).unwrap()).produce();
1228
1229 let gate = kio::Producer::new(true);
1230 let transport = crate::lite::test_transport::SinkSession::gated_bi(gate.consume());
1231 let log = transport.log.clone();
1232 let version = ietf::Version::Draft18;
1233 let request = Handshake {
1234 path: None,
1235 role: None,
1236 origin: None,
1237 token: None,
1238 assigned_hop: Hop::random(),
1239 inner: Some(RequestInner {
1240 server: Server::new().with_publisher(&origin),
1241 runtime: Clock::new(tokio::time::Instant::now().into_std()),
1242 handshake: PausedHandshake::Boxed(Box::new(PausedIetfModern {
1243 session: transport,
1244 version,
1245 peer_setup: ietf::PeerSetup {
1246 stream: crate::coding::Reader::new(
1247 crate::lite::test_transport::PendingRecv,
1248 Version::Ietf(version),
1249 ),
1250 path: None,
1251 token: None,
1252 declared: ietf::peer::Peer::default(),
1253 early: Vec::new(),
1254 },
1255 })),
1256 }),
1257 };
1258 let assigned = request.assigned_hop;
1259
1260 let mut echoed_hops = crate::Hops::new();
1261 echoed_hops.push(crate::Hop::UNKNOWN).unwrap();
1262 let _echoed = origin
1263 .announce(
1264 "echoed-route",
1265 crate::origin::Route::default()
1266 .with_hops(echoed_hops)
1267 .with_via(assigned),
1268 )
1269 .unwrap();
1270
1271 let mut local_hops = crate::Hops::new();
1272 local_hops.push(other).unwrap();
1273 let _local = origin
1274 .announce("local-route", crate::origin::Route::default().with_hops(local_hops))
1275 .unwrap();
1276
1277 let (session, driver) = request.ok().await.unwrap();
1278 tokio::spawn(crate::time::run(driver));
1279
1280 for _ in 0..100 {
1281 if occurrences(&log, b"local-route") > 0 {
1282 break;
1283 }
1284 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
1285 }
1286
1287 assert_eq!(occurrences(&log, b"echoed-route"), 0);
1288 assert_eq!(occurrences(&log, b"local-route"), 1);
1289 drop(session);
1290 }
1291}