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