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 stats: self.stats.clone(),
115 session: session.clone(),
116 setup_stream: None,
117 publish,
118 subscribe,
119 peer_hop,
120 version,
121 our_setup,
122 peer_setup: client_setup,
123 })?;
124
125 Ok(Session::new(
126 runtime,
127 session,
128 version.into(),
129 start.recv_bandwidth,
130 crate::driver::Protocol::Lite(Box::new(start.driver)),
131 start.goaway,
132 Some(start.estimate),
133 ))
134 }
135
136 pub async fn accept_lite<S>(&self, now: Instant, session: S) -> Result<(Session, crate::Driver<S>), Error>
145 where
146 S: crate::transport::poll::Session,
147 {
148 self.accept_request_lite(now, session).await?.ok().await
149 }
150
151 pub async fn accept_request_lite<S>(&self, now: Instant, session: S) -> Result<Handshake<S>, Error>
157 where
158 S: crate::transport::poll::Session,
159 {
160 let mut refused = session.clone();
161 self.handshake_lite(now, session)
162 .await
163 .inspect_err(|err| close(&mut refused, err))
164 }
165
166 async fn handshake_lite<S>(&self, now: Instant, mut session: S) -> Result<Handshake<S>, Error>
167 where
168 S: crate::transport::poll::Session,
169 {
170 let runtime = Clock::new(now);
171 let (path, role, origin, handshake) = match session.protocol() {
172 Some(alpn @ (ALPN_LITE_05 | ALPN_LITE_06 | ALPN_LITE_07_WIP)) => {
173 let version = match alpn {
174 ALPN_LITE_07_WIP => lite::Version::Lite07,
175 ALPN_LITE_06 => lite::Version::Lite06,
176 _ => lite::Version::Lite05,
177 };
178 self.versions.select(Version::Lite(version)).ok_or(Error::Version)?;
179 let (client_setup, client_setup_size) = lite::accept_setup(&mut session, version).await?;
184 (
185 client_setup.path.clone(),
186 client_setup.role,
187 client_setup.hop,
188 PausedHandshake::LiteSetup {
189 session,
190 version,
191 client_setup,
192 client_setup_size,
193 },
194 )
195 }
196 Some(ALPN_LITE_04) => {
197 self.versions
198 .select(Version::Lite(lite::Version::Lite04))
199 .ok_or(Error::Version)?;
200 (
201 None,
202 None,
203 None,
204 PausedHandshake::LiteBare {
205 session,
206 version: lite::Version::Lite04,
207 },
208 )
209 }
210 Some(ALPN_LITE_03) => {
211 self.versions
212 .select(Version::Lite(lite::Version::Lite03))
213 .ok_or(Error::Version)?;
214 (
215 None,
216 None,
217 None,
218 PausedHandshake::LiteBare {
219 session,
220 version: lite::Version::Lite03,
221 },
222 )
223 }
224 _ => return Err(Error::Version),
225 };
226
227 Ok(Handshake {
228 path,
229 role,
230 origin,
231 token: None,
233 assigned_hop: crate::Hop::random(),
234 inner: Some(RequestInner {
235 server: self.clone(),
236 runtime,
237 handshake,
238 }),
239 })
240 }
241
242 pub async fn accept<S>(&self, now: Instant, session: S) -> Result<(Session, crate::Driver<S>), Error>
250 where
251 S: crate::transport::poll::Boxable,
252 S::SendStream: MaybeSync,
253 S::RecvStream: MaybeSync,
254 {
255 self.accept_request(now, session).await?.ok().await
256 }
257
258 pub async fn accept_request<S>(&self, now: Instant, session: S) -> Result<Handshake<S>, Error>
272 where
273 S: crate::transport::poll::Boxable,
274 S::SendStream: MaybeSync,
275 S::RecvStream: MaybeSync,
276 {
277 let mut refused = session.clone();
278 self.handshake(now, session)
279 .await
280 .inspect_err(|err| close(&mut refused, err))
281 }
282
283 async fn handshake<S>(&self, now: Instant, mut session: S) -> Result<Handshake<S>, Error>
284 where
285 S: crate::transport::poll::Boxable,
286 S::SendStream: MaybeSync,
287 S::RecvStream: MaybeSync,
288 {
289 let runtime = Clock::new(now);
290 let (encoding, supported) = match session.protocol() {
291 Some(alpn @ (ALPN_22 | ALPN_21 | ALPN_20 | ALPN_19 | ALPN_18 | ALPN_17)) => {
292 let draft = match alpn {
293 ALPN_22 => ietf::Version::Draft22,
294 ALPN_21 => ietf::Version::Draft21,
295 ALPN_20 => ietf::Version::Draft20,
296 ALPN_19 => ietf::Version::Draft19,
297 ALPN_18 => ietf::Version::Draft18,
298 _ => ietf::Version::Draft17,
299 };
300
301 self.versions.select(Version::Ietf(draft)).ok_or(Error::Version)?;
302 return self.accept_ietf_modern(runtime, session, draft).await;
303 }
304 Some(ALPN_16) => {
305 let v = self
306 .versions
307 .select(Version::Ietf(ietf::Version::Draft16))
308 .ok_or(Error::Version)?;
309 (v, v.into())
310 }
311 Some(ALPN_15) => {
312 let v = self
313 .versions
314 .select(Version::Ietf(ietf::Version::Draft15))
315 .ok_or(Error::Version)?;
316 (v, v.into())
317 }
318 Some(ALPN_14) => {
319 let v = self
320 .versions
321 .select(Version::Ietf(ietf::Version::Draft14))
322 .ok_or(Error::Version)?;
323 (v, v.into())
324 }
325 Some(ALPN_LITE_07_WIP | ALPN_LITE_06 | ALPN_LITE_05 | ALPN_LITE_04 | ALPN_LITE_03) => {
328 return self.handshake_lite(now, session).await;
329 }
330 Some(ALPN_LITE) | None => {
331 let supported = self.versions.filter(&NEGOTIATED.into()).ok_or(Error::Version)?;
332 (Version::Ietf(ietf::Version::Draft14), supported)
333 }
334 Some(p) => return Err(Error::UnknownAlpn(p.to_string())),
335 };
336
337 let mut stream = Stream::accept(&mut session, encoding).await?;
341 let (mut client, client_setup_size) = stream.reader.decode_sized::<setup::Client>().await?;
342
343 let version = client
344 .versions
345 .iter()
346 .flat_map(|v| Version::try_from(*v).ok())
347 .find(|v| supported.contains(v))
348 .ok_or(Error::Version)?;
349
350 let (path, token, request_id_max, peer_declared) = match version {
354 Version::Ietf(v) => {
355 let params = ietf::Parameters::decode(&mut client.parameters, v)?;
356 let path = match params.get_bytes(ietf::ParameterBytes::Path) {
357 Some(bytes) => Some(
358 std::str::from_utf8(bytes)
359 .map_err(|_| Error::Decode(crate::DecodeError::InvalidValue))?
360 .to_owned(),
361 ),
362 None => None,
363 };
364 let token = ietf::token::from_setup(¶ms, v)?;
365 let request_id_max = params
366 .get_varint(ietf::ParameterVarInt::MaxRequestId)
367 .map(ietf::RequestId);
368 let peer_declared = ietf::peer::Peer {
369 solicit: ietf::solicit::from_setup(¶ms, v)?,
370 hidden: ietf::hidden::from_setup(¶ms, v),
371 ..Default::default()
372 };
373 (path, token, request_id_max, peer_declared)
374 }
375 Version::Lite(_) => (None, None, None, ietf::peer::Peer::default()),
376 };
377
378 Ok(Handshake {
379 path,
380 role: None,
381 origin: None,
382 token,
383 assigned_hop: crate::Hop::random(),
384 inner: Some(RequestInner {
385 server: self.clone(),
386 runtime,
387 handshake: PausedHandshake::Boxed(Box::new(PausedLegacy {
388 session,
389 stream,
390 version,
391 request_id_max,
392 peer_declared,
393 client_setup_size,
394 })),
395 }),
396 })
397 }
398
399 async fn accept_ietf_modern<S>(
402 &self,
403 runtime: Clock,
404 mut session: S,
405 version: ietf::Version,
406 ) -> Result<Handshake<S>, Error>
407 where
408 S: crate::transport::poll::Boxable,
409 S::SendStream: MaybeSync,
410 S::RecvStream: MaybeSync,
411 {
412 let peer_setup = ietf::accept_setup(&mut session, version).await?;
413 Ok(Handshake {
414 path: peer_setup.path.clone(),
415 role: None,
416 origin: peer_setup.declared.cluster.hop.filter(|h| *h != crate::Hop::UNKNOWN),
419 token: peer_setup.token.clone(),
420 assigned_hop: crate::Hop::random(),
421 inner: Some(RequestInner {
422 server: self.clone(),
423 runtime,
424 handshake: PausedHandshake::Boxed(Box::new(PausedIetfModern {
425 session,
426 version,
427 peer_setup,
428 })),
429 }),
430 })
431 }
432}
433
434pub struct Handshake<S: crate::transport::poll::Session> {
442 path: Option<String>,
443 role: Option<Role>,
444 origin: Option<crate::Hop>,
445 token: Option<setup::Token>,
446 assigned_hop: crate::Hop,
450 inner: Option<RequestInner<S>>,
452}
453
454struct RequestInner<S: crate::transport::poll::Session> {
456 server: Server,
457 runtime: Clock,
459 handshake: PausedHandshake<S>,
460}
461
462enum PausedHandshake<S: crate::transport::poll::Session> {
465 LiteBare { session: S, version: lite::Version },
467 LiteSetup {
470 session: S,
471 version: lite::Version,
472 client_setup: lite::Setup,
473 client_setup_size: usize,
475 },
476 Boxed(Box<dyn Paused<S>>),
483}
484
485type Accept<S> = crate::util::MaybeSendBox<'static, Result<(Session, crate::Driver<S>), Error>>;
486
487trait Paused<S: crate::transport::poll::Session>: MaybeSend + MaybeSync {
494 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S>;
496
497 fn close(self: Box<Self>, err: Error);
499}
500
501struct PausedIetfModern<S: crate::transport::poll::Session> {
505 session: S,
506 version: ietf::Version,
507 peer_setup: ietf::PeerSetup<S>,
508}
509
510impl<S> Paused<S> for PausedIetfModern<S>
511where
512 S: crate::transport::poll::Boxable,
513 S::SendStream: MaybeSync,
514 S::RecvStream: MaybeSync,
515{
516 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S> {
517 use crate::util::MaybeBoxedExt as _;
518 async move {
519 let Self {
520 session,
521 version,
522 peer_setup,
523 } = *self;
524 server.stats.control(stats::Control::Session, peer_setup.size, true);
525 let (publish, subscribe) = server.stat_tagged_origins();
526
527 let (protocol, goaway) = ietf::start(ietf::Config {
530 runtime: runtime.clone(),
531 stats: server.stats.clone(),
532 session: session.clone(),
533 setup: None,
534 request_id_max: None,
535 client: false,
536 publish,
537 subscribe,
538 peer_hop,
539 cost: None,
541 version,
542 path: None,
543 authority: None,
544 peer_setup_stream: Some(peer_setup.stream),
545 peer_declared: Some(peer_setup.declared),
546 early_unis: peer_setup.early,
547 })?;
548 tracing::debug!(?version, "connected");
549 Ok(Session::new(
550 runtime,
551 session,
552 version.into(),
553 None,
554 crate::driver::Protocol::Ietf(protocol),
555 goaway,
556 None,
557 ))
558 }
559 .maybe_boxed()
560 }
561
562 fn close(mut self: Box<Self>, err: Error) {
563 close(&mut self.session, &err);
564 }
565}
566
567struct PausedLegacy<S: crate::transport::poll::Session> {
571 session: S,
572 stream: Stream<S, Version>,
573 version: Version,
574 request_id_max: Option<ietf::RequestId>,
575 peer_declared: ietf::peer::Peer,
577 client_setup_size: usize,
579}
580
581impl<S> Paused<S> for PausedLegacy<S>
582where
583 S: crate::transport::poll::Boxable,
584 S::SendStream: MaybeSync,
585 S::RecvStream: MaybeSync,
586{
587 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S> {
588 use crate::util::MaybeBoxedExt as _;
589 async move {
590 let Self {
591 session,
592 stream,
593 version,
594 request_id_max,
595 peer_declared,
596 client_setup_size,
597 } = *self;
598 let mut stream = stream.with_stats(&server.stats);
599 server.stats.control(stats::Control::Session, client_setup_size, true);
600 let (publish, subscribe) = server.stat_tagged_origins();
601
602 let parameters = match version {
604 Version::Ietf(v) => {
605 let mut parameters = ietf::Parameters::default();
606 parameters.set_varint(ietf::ParameterVarInt::MaxRequestId, u32::MAX as u64);
607 parameters.set_bytes(ietf::ParameterBytes::Implementation, b"moq-lite-rs".to_vec());
608 ietf::solicit::into_setup(&mut parameters, v);
609 ietf::hidden::into_setup(&mut parameters, v);
610 parameters.encode_bytes(v)?
611 }
612 Version::Lite(v) => lite::Parameters::default().encode_bytes(v)?,
613 };
614
615 let server_setup = setup::Server {
616 version: version.into(),
617 parameters,
618 };
619 stream.writer.encode(&server_setup).await?;
620
621 let (recv_bw, protocol, goaway, estimate) = match version {
622 Version::Lite(v) => {
623 let stream = stream.with_version(v);
624 let start = lite::start(lite::Config {
626 runtime: runtime.clone(),
627 stats: server.stats.clone(),
628 session: session.clone(),
629 setup_stream: Some(stream),
630 publish,
631 subscribe,
632 peer_hop,
633 version: v,
634 our_setup: lite::Setup::default(),
635 peer_setup: None,
636 })?;
637 (
638 start.recv_bandwidth,
639 crate::driver::Protocol::Lite(Box::new(start.driver)),
640 start.goaway,
641 Some(start.estimate),
642 )
643 }
644 Version::Ietf(v) => {
645 let stream = stream.with_version(v);
646 let (protocol, goaway) = ietf::start(ietf::Config {
648 runtime: runtime.clone(),
649 stats: server.stats.clone(),
650 session: session.clone(),
651 setup: Some(stream),
652 request_id_max,
653 client: false,
654 publish,
655 subscribe,
656 peer_hop,
657 cost: None,
658 version: v,
659 path: None,
660 authority: None,
661 peer_setup_stream: None,
662 peer_declared: Some(peer_declared),
663 early_unis: Vec::new(),
664 })?;
665 (None, crate::driver::Protocol::Ietf(protocol), goaway, None)
666 }
667 };
668
669 Ok(Session::new(
670 runtime, session, version, recv_bw, protocol, goaway, estimate,
671 ))
672 }
673 .maybe_boxed()
674 }
675
676 fn close(mut self: Box<Self>, err: Error) {
677 close(&mut self.session, &err);
678 }
679}
680
681impl<S> Handshake<S>
682where
683 S: crate::transport::poll::Session,
684{
685 pub fn path(&self) -> &str {
692 self.path.as_deref().unwrap_or("")
693 }
694
695 pub fn role(&self) -> Option<Role> {
704 self.role
705 }
706
707 pub fn peer_hop(&self) -> Option<crate::Hop> {
716 self.origin
717 }
718
719 pub fn token(&self) -> Option<&setup::Token> {
724 self.token.as_ref()
725 }
726
727 pub fn with_publisher(mut self, publish: impl Consume<origin::Consumer>) -> Self {
730 self.inner_mut().server.publish = Some(publish.consume());
731 self
732 }
733
734 pub fn with_subscriber(mut self, subscribe: origin::Producer) -> Self {
736 self.inner_mut().server.subscribe = Some(subscribe);
737 self
738 }
739
740 pub fn with_peer_hop(mut self, hop: crate::Hop) -> Self {
753 self.assigned_hop = hop;
754 self
755 }
756
757 pub fn with_stats(mut self, stats: stats::Session) -> Self {
760 self.inner_mut().server.stats = stats;
761 self
762 }
763
764 fn inner_mut(&mut self) -> &mut RequestInner<S> {
765 self.inner.as_mut().expect("request already responded")
766 }
767
768 pub async fn ok(mut self) -> Result<(Session, crate::Driver<S>), Error> {
772 let peer_hop = Some(self.assigned_hop);
773 let RequestInner {
774 server,
775 runtime,
776 handshake,
777 } = self.inner.take().expect("request already responded");
778
779 match handshake {
780 PausedHandshake::LiteBare { session, version } => {
781 server.start_lite(runtime, session, version, None, peer_hop)
782 }
783 PausedHandshake::LiteSetup {
784 session,
785 version,
786 client_setup,
787 client_setup_size,
788 } => {
789 server.stats.control(stats::Control::Session, client_setup_size, true);
790 server.start_lite(runtime, session, version, Some(client_setup), peer_hop)
791 }
792 PausedHandshake::Boxed(paused) => paused.ok(server, runtime, peer_hop).await,
793 }
794 }
795
796 pub fn close(mut self, err: Error) {
798 let inner = self.inner.take().expect("request already responded");
799 inner.close(err);
800 }
801}
802
803impl<S: crate::transport::poll::Session> RequestInner<S> {
804 fn close(self, err: Error) {
805 let mut session = match self.handshake {
806 PausedHandshake::LiteBare { session, .. } => session,
807 PausedHandshake::LiteSetup { session, .. } => session,
808 PausedHandshake::Boxed(paused) => return paused.close(err),
809 };
810 close(&mut session, &err);
811 }
812}
813
814fn close<S: crate::transport::poll::Session>(session: &mut S, err: &Error) {
816 session.close(SessionError::from(err).to_code(), &err.to_string());
817}
818
819impl<S: crate::transport::poll::Session> Drop for Handshake<S> {
820 fn drop(&mut self) {
823 if let Some(inner) = self.inner.take() {
824 tracing::warn!("Handshake dropped without ok() or close(); rejecting the session");
825 inner.close(Error::Cancel);
826 }
827 }
828}
829
830#[cfg(test)]
831mod tests {
832 use super::*;
833 use crate::Hop;
834 use crate::model::ProduceTest;
835 use std::{
836 collections::VecDeque,
837 sync::{Arc, Mutex},
838 };
839
840 use crate::ALPN_LITE_05;
841 use bytes::Bytes;
842
843 fn occurrences(log: &crate::lite::test_transport::Log, needle: &[u8]) -> usize {
844 let writes = log.writes.lock().unwrap();
845 writes.windows(needle.len()).filter(|window| *window == needle).count()
846 }
847
848 #[derive(Debug, Clone, Default)]
849 struct FakeError;
850 impl std::fmt::Display for FakeError {
851 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
852 write!(f, "fake transport error")
853 }
854 }
855 impl std::error::Error for FakeError {}
856 impl web_transport_trait::Error for FakeError {
857 fn session_error(&self) -> Option<(u32, String)> {
858 Some((0, "closed".to_string()))
859 }
860 }
861
862 #[derive(Clone)]
866 struct FakeSession {
867 protocol: Option<&'static str>,
868 uni: Arc<Mutex<VecDeque<Vec<u8>>>>,
869 bi: Arc<Mutex<VecDeque<Vec<u8>>>>,
870 closed: Arc<Mutex<Option<u32>>>,
871 }
872
873 impl FakeSession {
874 fn new(protocol: &'static str, uni: impl IntoIterator<Item = Vec<u8>>) -> Self {
875 Self {
876 protocol: Some(protocol),
877 uni: Arc::new(Mutex::new(uni.into_iter().collect())),
878 bi: Default::default(),
879 closed: Default::default(),
880 }
881 }
882
883 fn with_bi(self, bi: Vec<u8>) -> Self {
884 self.bi.lock().unwrap().push_back(bi);
885 self
886 }
887
888 fn closed(&self) -> Option<u32> {
889 *self.closed.lock().unwrap()
890 }
891 }
892
893 impl web_transport_trait::poll::Session for FakeSession {
894 type SendStream = FakeSend;
895 type RecvStream = FakeRecv;
896 type Error = FakeError;
897
898 fn poll_accept_uni(
899 &mut self,
900 _cx: &mut std::task::Context<'_>,
901 ) -> std::task::Poll<Result<Self::RecvStream, Self::Error>> {
902 match self.uni.lock().unwrap().pop_front() {
903 Some(data) => std::task::Poll::Ready(Ok(FakeRecv { data: data.into() })),
904 None => std::task::Poll::Pending,
905 }
906 }
907 fn poll_accept_bi(
908 &mut self,
909 _cx: &mut std::task::Context<'_>,
910 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
911 match self.bi.lock().unwrap().pop_front() {
912 Some(data) => std::task::Poll::Ready(Ok((FakeSend, FakeRecv { data: data.into() }))),
913 None => std::task::Poll::Pending,
914 }
915 }
916 fn poll_open_bi(
917 &mut self,
918 _cx: &mut std::task::Context<'_>,
919 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
920 std::task::Poll::Pending
921 }
922 fn poll_open_uni(
923 &mut self,
924 _cx: &mut std::task::Context<'_>,
925 ) -> std::task::Poll<Result<Self::SendStream, Self::Error>> {
926 std::task::Poll::Pending
927 }
928 fn poll_send_datagram(
929 &mut self,
930 _cx: &mut std::task::Context<'_>,
931 _payload: &[u8],
932 ) -> std::task::Poll<Result<(), Self::Error>> {
933 std::task::Poll::Ready(Ok(()))
934 }
935 fn poll_recv_datagram(
936 &mut self,
937 _cx: &mut std::task::Context<'_>,
938 ) -> std::task::Poll<Result<Bytes, Self::Error>> {
939 std::task::Poll::Pending
940 }
941 fn max_datagram_size(&self) -> usize {
942 1200
943 }
944 fn protocol(&self) -> Option<&str> {
945 self.protocol
946 }
947 fn close(&mut self, code: u32, _reason: &str) {
948 self.closed.lock().unwrap().get_or_insert(code);
949 }
950 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Error> {
951 std::task::Poll::Pending
952 }
953 fn stats(&self) -> impl web_transport_trait::Stats {
954 web_transport_trait::StatsUnavailable
955 }
956 }
957
958 #[derive(Clone, Default)]
959 struct FakeSend;
960 impl web_transport_trait::poll::SendStream for FakeSend {
961 type Error = FakeError;
962 fn poll_write(
963 &mut self,
964 _cx: &mut std::task::Context<'_>,
965 buf: &[u8],
966 ) -> std::task::Poll<Result<usize, Self::Error>> {
967 std::task::Poll::Ready(Ok(buf.len()))
968 }
969 fn set_priority(&mut self, _order: u8) {}
970 fn finish(&mut self) -> Result<(), Self::Error> {
971 Ok(())
972 }
973 fn reset(&mut self, _code: u32) {}
974 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
975 std::task::Poll::Ready(Ok(()))
976 }
977 }
978
979 struct FakeRecv {
980 data: VecDeque<u8>,
981 }
982 impl web_transport_trait::poll::RecvStream for FakeRecv {
983 type Error = FakeError;
984 fn poll_read(
985 &mut self,
986 _cx: &mut std::task::Context<'_>,
987 dst: &mut [u8],
988 ) -> std::task::Poll<Result<Option<usize>, Self::Error>> {
989 if self.data.is_empty() {
990 return std::task::Poll::Ready(Ok(None));
991 }
992 let size = dst.len().min(self.data.len());
993 for slot in dst.iter_mut().take(size) {
994 *slot = self.data.pop_front().unwrap();
995 }
996 std::task::Poll::Ready(Ok(Some(size)))
997 }
998 fn stop(&mut self, _code: u32) {}
999 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
1000 std::task::Poll::Ready(Ok(()))
1001 }
1002 }
1003
1004 fn lite05_setup(path: Option<&str>, role: Option<Role>, hop: Option<Hop>) -> Vec<u8> {
1006 let v = lite::Version::Lite05;
1007 let mut buf = Vec::new();
1008 lite::DataType::Setup.encode(&mut buf, v).unwrap();
1009 lite::Setup {
1010 probe: lite::ProbeLevel::None,
1011 path: path.map(str::to_string),
1012 role,
1013 cost: None,
1014 hop,
1015 }
1016 .encode(&mut buf, v)
1017 .unwrap();
1018 buf
1019 }
1020
1021 fn ietf_setup(version: ietf::Version, path: Option<&str>) -> Vec<u8> {
1024 let mut params = ietf::Parameters::default();
1025 if let Some(path) = path {
1026 params.set_bytes(ietf::ParameterBytes::Path, path.as_bytes().to_vec());
1027 }
1028 ietf_setup_with(version, params)
1029 }
1030
1031 fn ietf_setup_with(version: ietf::Version, params: ietf::Parameters) -> Vec<u8> {
1032 let parameters = params.encode_bytes(version).unwrap();
1033
1034 let mut buf = Vec::new();
1035 setup::Setup { parameters }
1036 .encode(&mut buf, crate::Version::Ietf(version))
1037 .unwrap();
1038 buf
1039 }
1040
1041 fn legacy_setup(version: ietf::Version, params: ietf::Parameters) -> Vec<u8> {
1043 let mut buf = Vec::new();
1044 setup::Client {
1045 versions: crate::coding::Versions::from([crate::Version::Ietf(version).into()]),
1046 parameters: params.encode_bytes(version).unwrap(),
1047 }
1048 .encode(&mut buf, crate::Version::Ietf(version))
1049 .unwrap();
1050 buf
1051 }
1052
1053 fn setup_token() -> setup::Token {
1054 setup::Token {
1055 kind: setup::Token::OUT_OF_BAND,
1056 value: vec![0x00, 0xff, b'j', b'w', b't'],
1057 }
1058 }
1059
1060 fn token_params(version: ietf::Version) -> ietf::Parameters {
1061 let mut params = ietf::Parameters::default();
1062 ietf::token::into_setup(&mut params, &setup_token(), version).unwrap();
1063 params
1064 }
1065
1066 #[tokio::test(start_paused = true)]
1067 async fn accept_request_exposes_the_setup_token() {
1068 let modern = FakeSession::new(
1069 ALPN_19,
1070 [ietf_setup_with(
1071 ietf::Version::Draft19,
1072 token_params(ietf::Version::Draft19),
1073 )],
1074 );
1075 let legacy = FakeSession::new(ALPN_16, []).with_bi(legacy_setup(
1076 ietf::Version::Draft16,
1077 token_params(ietf::Version::Draft16),
1078 ));
1079 for (name, session) in [("draft-19", modern), ("draft-16", legacy)] {
1080 let request = Server::new()
1081 .accept_request(tokio::time::Instant::now().into_std(), session)
1082 .await
1083 .unwrap();
1084 assert_eq!(request.token(), Some(&setup_token()), "{name}");
1085 }
1086 }
1087
1088 #[tokio::test(start_paused = true)]
1089 async fn accept_request_without_a_token_reports_none() {
1090 let ietf = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, None)]);
1091 let lite = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1092 for (name, session) in [("draft-19", ietf), ("lite-05", lite)] {
1093 let request = Server::new()
1094 .accept_request(tokio::time::Instant::now().into_std(), session)
1095 .await
1096 .unwrap();
1097 assert_eq!(request.token(), None, "{name}");
1098 }
1099 }
1100
1101 #[tokio::test(start_paused = true)]
1104 async fn a_refused_setup_token_closes_with_its_code() {
1105 let delete = [0x0, 0x7]; let truncated = [0x3]; for (raw, code) in [
1108 (&delete[..], SessionError::ProtocolViolation),
1109 (&truncated[..], SessionError::KeyValueFormatting),
1110 ] {
1111 let mut params = ietf::Parameters::default();
1112 params.set_bytes(ietf::ParameterBytes::AuthorizationToken, raw.to_vec());
1113
1114 let modern = FakeSession::new(ALPN_19, [ietf_setup_with(ietf::Version::Draft19, params.clone())]);
1115 let legacy = FakeSession::new(ALPN_16, []).with_bi(legacy_setup(ietf::Version::Draft16, params));
1116 for (name, session) in [("draft-19", modern), ("draft-16", legacy)] {
1117 let result = Server::new()
1118 .accept_request(tokio::time::Instant::now().into_std(), session.clone())
1119 .await;
1120 assert!(result.is_err(), "{name}");
1121 assert_eq!(session.closed(), Some(code.to_code()), "{name} {code}");
1122 }
1123 }
1124 }
1125
1126 #[tokio::test(start_paused = true)]
1127 async fn accept_request_reads_ietf_path() {
1128 for (alpn, version) in [
1131 (ALPN_17, ietf::Version::Draft17),
1132 (ALPN_18, ietf::Version::Draft18),
1133 (ALPN_19, ietf::Version::Draft19),
1134 ] {
1135 let session = FakeSession::new(alpn, [ietf_setup(version, Some("/team/room"))]);
1136 let request = Server::new()
1137 .accept_request(tokio::time::Instant::now().into_std(), session)
1138 .await
1139 .unwrap();
1140 assert_eq!(request.path(), "/team/room", "{alpn}");
1141 }
1142 }
1143
1144 #[tokio::test(start_paused = true)]
1145 async fn accept_request_ietf_without_path_is_empty() {
1146 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, None)]);
1147 let request = Server::new()
1148 .accept_request(tokio::time::Instant::now().into_std(), session)
1149 .await
1150 .unwrap();
1151 assert_eq!(request.path(), "");
1152 }
1153
1154 #[tokio::test(start_paused = true)]
1155 async fn accept_request_ietf_empty_path_is_accepted() {
1156 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, Some(""))]);
1157 let request = Server::new()
1158 .accept_request(tokio::time::Instant::now().into_std(), session)
1159 .await
1160 .unwrap();
1161 assert_eq!(request.path(), "");
1162 }
1163
1164 fn lite05_group() -> Vec<u8> {
1166 let mut buf = Vec::new();
1167 lite::DataType::Group.encode(&mut buf, lite::Version::Lite05).unwrap();
1168 buf
1169 }
1170
1171 #[tokio::test(start_paused = true)]
1172 async fn accept_request_reads_lite05_path() {
1173 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some("/team/room"), None, None)]);
1174 let request = Server::new()
1175 .accept_request(tokio::time::Instant::now().into_std(), session)
1176 .await
1177 .unwrap();
1178 assert_eq!(request.path(), "/team/room");
1179 assert_eq!(request.role(), None, "a client that omits the role is bidirectional");
1180 }
1181
1182 #[tokio::test(start_paused = true)]
1183 async fn accept_request_lite05_without_path_is_empty() {
1184 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1185 let request = Server::new()
1186 .accept_request(tokio::time::Instant::now().into_std(), session)
1187 .await
1188 .unwrap();
1189 assert_eq!(request.path(), "");
1190 }
1191
1192 #[tokio::test(start_paused = true)]
1193 async fn accept_request_lite05_empty_path_is_accepted() {
1194 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some(""), None, None)]);
1197 let request = Server::new()
1198 .accept_request(tokio::time::Instant::now().into_std(), session)
1199 .await
1200 .unwrap();
1201 assert_eq!(request.path(), "");
1202 }
1203
1204 #[tokio::test(start_paused = true)]
1205 async fn repeated_lite_setup_parameter_closes_the_session() {
1206 let session = FakeSession::new(ALPN_LITE_05, [vec![1, 5, 2, 0, 0, 0, 0]]);
1208 let result = Server::new()
1209 .accept_request(tokio::time::Instant::now().into_std(), session.clone())
1210 .await;
1211 assert!(result.is_err());
1212 assert_eq!(session.closed(), Some(SessionError::ProtocolViolation.to_code()));
1213 }
1214
1215 #[tokio::test(start_paused = true)]
1216 async fn accepted_lite_setup_refuses_a_second_setup_stream() {
1217 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1218 let transport = session.clone();
1219 let request = Server::new()
1220 .accept_request(tokio::time::Instant::now().into_std(), session)
1221 .await
1222 .unwrap();
1223 let (_session, mut driver) = request.ok().await.unwrap();
1224 transport.uni.lock().unwrap().push_back(vec![1]);
1225 let _ = driver.poll(tokio::time::Instant::now().into_std(), &kio::Waiter::noop());
1226 assert_eq!(transport.closed(), Some(SessionError::ProtocolViolation.to_code()));
1227 }
1228
1229 #[tokio::test(start_paused = true)]
1230 async fn accept_request_reads_lite05_role() {
1231 let session = FakeSession::new(
1232 ALPN_LITE_05,
1233 [lite05_setup(Some("/team/room"), Some(Role::Publisher), None)],
1234 );
1235 let request = Server::new()
1236 .accept_request(tokio::time::Instant::now().into_std(), session)
1237 .await
1238 .unwrap();
1239 assert_eq!(request.role(), Some(Role::Publisher));
1240 }
1241
1242 #[tokio::test(start_paused = true)]
1243 async fn accept_request_skips_uni_stream_before_setup() {
1244 let session = FakeSession::new(
1247 ALPN_LITE_05,
1248 [lite05_group(), lite05_setup(Some("/team/room"), None, None)],
1249 );
1250 let request = Server::new()
1251 .accept_request(tokio::time::Instant::now().into_std(), session)
1252 .await
1253 .unwrap();
1254 assert_eq!(request.path(), "/team/room");
1255 }
1256
1257 #[tokio::test(start_paused = true)]
1258 async fn accept_request_reads_lite05_peer_hop() {
1259 let hop = Hop::new(42).unwrap();
1260 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, Some(hop))]);
1261 let request = Server::new()
1262 .accept_request(tokio::time::Instant::now().into_std(), session)
1263 .await
1264 .unwrap();
1265 assert_eq!(request.peer_hop(), Some(hop));
1266 }
1267
1268 #[tokio::test(start_paused = true)]
1269 async fn anonymous_peer_hop_filters_routes_from_server_session() {
1270 let other = Hop::new(778).unwrap();
1271 let origin = crate::origin::Config::new(Hop::new(1).unwrap()).produce();
1272
1273 let gate = kio::Producer::new(true);
1274 let transport = crate::lite::test_transport::SinkSession::gated_bi(gate.consume());
1275 let log = transport.log.clone();
1276 let version = ietf::Version::Draft18;
1277 let request = Handshake {
1278 path: None,
1279 role: None,
1280 origin: None,
1281 token: None,
1282 assigned_hop: Hop::random(),
1283 inner: Some(RequestInner {
1284 server: Server::new().with_publisher(&origin),
1285 runtime: Clock::new(tokio::time::Instant::now().into_std()),
1286 handshake: PausedHandshake::Boxed(Box::new(PausedIetfModern {
1287 session: transport,
1288 version,
1289 peer_setup: ietf::PeerSetup {
1290 stream: crate::coding::Reader::new(
1291 crate::lite::test_transport::PendingRecv,
1292 Version::Ietf(version),
1293 ),
1294 size: 0,
1295 path: None,
1296 token: None,
1297 declared: ietf::peer::Peer::default(),
1298 early: Vec::new(),
1299 },
1300 })),
1301 }),
1302 };
1303 let assigned = request.assigned_hop;
1304
1305 let mut echoed_hops = crate::Hops::new();
1306 echoed_hops.push(crate::Hop::UNKNOWN).unwrap();
1307 let _echoed = origin
1308 .announce(
1309 "echoed-route",
1310 crate::origin::Route::default()
1311 .with_hops(echoed_hops)
1312 .with_via(assigned),
1313 )
1314 .unwrap();
1315
1316 let mut local_hops = crate::Hops::new();
1317 local_hops.push(other).unwrap();
1318 let _local = origin
1319 .announce("local-route", crate::origin::Route::default().with_hops(local_hops))
1320 .unwrap();
1321
1322 let (session, driver) = request.ok().await.unwrap();
1323 tokio::spawn(crate::time::run(driver));
1324
1325 for _ in 0..100 {
1326 if occurrences(&log, b"local-route") > 0 {
1327 break;
1328 }
1329 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
1330 }
1331
1332 assert_eq!(occurrences(&log, b"echoed-route"), 0);
1333 assert_eq!(occurrences(&log, b"local-route"), 1);
1334 drop(session);
1335 }
1336}