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, mut session: S) -> Result<Handshake<S>, Error>
155 where
156 S: crate::transport::poll::Session,
157 {
158 let runtime = Clock::new(now);
159 let (path, role, origin, handshake) = match session.protocol() {
160 Some(alpn @ (ALPN_LITE_05 | ALPN_LITE_06 | ALPN_LITE_07_WIP)) => {
161 let version = match alpn {
162 ALPN_LITE_07_WIP => lite::Version::Lite07,
163 ALPN_LITE_06 => lite::Version::Lite06,
164 _ => lite::Version::Lite05,
165 };
166 self.versions.select(Version::Lite(version)).ok_or(Error::Version)?;
167 let client_setup = lite::accept_setup(&mut session, version).await?;
172 (
173 client_setup.path.clone(),
174 client_setup.role,
175 client_setup.hop,
176 PausedHandshake::LiteSetup {
177 session,
178 version,
179 client_setup,
180 },
181 )
182 }
183 Some(ALPN_LITE_04) => {
184 self.versions
185 .select(Version::Lite(lite::Version::Lite04))
186 .ok_or(Error::Version)?;
187 (
188 None,
189 None,
190 None,
191 PausedHandshake::LiteBare {
192 session,
193 version: lite::Version::Lite04,
194 },
195 )
196 }
197 Some(ALPN_LITE_03) => {
198 self.versions
199 .select(Version::Lite(lite::Version::Lite03))
200 .ok_or(Error::Version)?;
201 (
202 None,
203 None,
204 None,
205 PausedHandshake::LiteBare {
206 session,
207 version: lite::Version::Lite03,
208 },
209 )
210 }
211 _ => return Err(Error::Version),
212 };
213
214 Ok(Handshake {
215 path,
216 role,
217 origin,
218 assigned_hop: crate::Hop::random(),
219 inner: Some(RequestInner {
220 server: self.clone(),
221 runtime,
222 handshake,
223 }),
224 })
225 }
226
227 pub async fn accept<S>(&self, now: Instant, session: S) -> Result<(Session, crate::Driver<S>), Error>
235 where
236 S: crate::transport::poll::Boxable,
237 S::SendStream: MaybeSync,
238 S::RecvStream: MaybeSync,
239 {
240 self.accept_request(now, session).await?.ok().await
241 }
242
243 pub async fn accept_request<S>(&self, now: Instant, mut session: S) -> Result<Handshake<S>, Error>
254 where
255 S: crate::transport::poll::Boxable,
256 S::SendStream: MaybeSync,
257 S::RecvStream: MaybeSync,
258 {
259 let runtime = Clock::new(now);
260 let (encoding, supported) = match session.protocol() {
261 Some(alpn @ (ALPN_22 | ALPN_21 | ALPN_20 | ALPN_19 | ALPN_18 | ALPN_17)) => {
262 let draft = match alpn {
263 ALPN_22 => ietf::Version::Draft22,
264 ALPN_21 => ietf::Version::Draft21,
265 ALPN_20 => ietf::Version::Draft20,
266 ALPN_19 => ietf::Version::Draft19,
267 ALPN_18 => ietf::Version::Draft18,
268 _ => ietf::Version::Draft17,
269 };
270
271 self.versions.select(Version::Ietf(draft)).ok_or(Error::Version)?;
272 return self.accept_ietf_modern(runtime, session, draft).await;
273 }
274 Some(ALPN_16) => {
275 let v = self
276 .versions
277 .select(Version::Ietf(ietf::Version::Draft16))
278 .ok_or(Error::Version)?;
279 (v, v.into())
280 }
281 Some(ALPN_15) => {
282 let v = self
283 .versions
284 .select(Version::Ietf(ietf::Version::Draft15))
285 .ok_or(Error::Version)?;
286 (v, v.into())
287 }
288 Some(ALPN_14) => {
289 let v = self
290 .versions
291 .select(Version::Ietf(ietf::Version::Draft14))
292 .ok_or(Error::Version)?;
293 (v, v.into())
294 }
295 Some(ALPN_LITE_07_WIP | ALPN_LITE_06 | ALPN_LITE_05 | ALPN_LITE_04 | ALPN_LITE_03) => {
298 return self.accept_request_lite(now, session).await;
299 }
300 Some(ALPN_LITE) | None => {
301 let supported = self.versions.filter(&NEGOTIATED.into()).ok_or(Error::Version)?;
302 (Version::Ietf(ietf::Version::Draft14), supported)
303 }
304 Some(p) => return Err(Error::UnknownAlpn(p.to_string())),
305 };
306
307 let mut stream = Stream::accept(&mut session, encoding).await?;
310 let mut client: setup::Client = stream.reader.decode().await?;
311
312 let version = client
313 .versions
314 .iter()
315 .flat_map(|v| Version::try_from(*v).ok())
316 .find(|v| supported.contains(v))
317 .ok_or(Error::Version)?;
318
319 let (path, request_id_max, peer_declared) = match version {
323 Version::Ietf(v) => {
324 let params = ietf::Parameters::decode(&mut client.parameters, v)?;
325 let path = match params.get_bytes(ietf::ParameterBytes::Path) {
326 Some(bytes) => Some(
327 std::str::from_utf8(bytes)
328 .map_err(|_| Error::Decode(crate::DecodeError::InvalidValue))?
329 .to_owned(),
330 ),
331 None => None,
332 };
333 let request_id_max = params
334 .get_varint(ietf::ParameterVarInt::MaxRequestId)
335 .map(ietf::RequestId);
336 let peer_declared = ietf::peer::Peer {
337 solicit: ietf::solicit::from_setup(¶ms, v)?,
338 hidden: ietf::hidden::from_setup(¶ms, v),
339 ..Default::default()
340 };
341 (path, request_id_max, peer_declared)
342 }
343 Version::Lite(_) => (None, None, ietf::peer::Peer::default()),
344 };
345
346 Ok(Handshake {
347 path,
348 role: None,
349 origin: None,
350 assigned_hop: crate::Hop::random(),
351 inner: Some(RequestInner {
352 server: self.clone(),
353 runtime,
354 handshake: PausedHandshake::Boxed(Box::new(PausedLegacy {
355 session,
356 stream,
357 version,
358 request_id_max,
359 peer_declared,
360 })),
361 }),
362 })
363 }
364
365 async fn accept_ietf_modern<S>(
368 &self,
369 runtime: Clock,
370 mut session: S,
371 version: ietf::Version,
372 ) -> Result<Handshake<S>, Error>
373 where
374 S: crate::transport::poll::Boxable,
375 S::SendStream: MaybeSync,
376 S::RecvStream: MaybeSync,
377 {
378 let peer_setup = ietf::accept_setup(&mut session, version).await?;
379 Ok(Handshake {
380 path: peer_setup.path.clone(),
381 role: None,
382 origin: peer_setup.declared.cluster.hop.filter(|h| *h != crate::Hop::UNKNOWN),
385 assigned_hop: crate::Hop::random(),
386 inner: Some(RequestInner {
387 server: self.clone(),
388 runtime,
389 handshake: PausedHandshake::Boxed(Box::new(PausedIetfModern {
390 session,
391 version,
392 peer_setup,
393 })),
394 }),
395 })
396 }
397}
398
399pub struct Handshake<S: crate::transport::poll::Session> {
407 path: Option<String>,
408 role: Option<Role>,
409 origin: Option<crate::Hop>,
410 assigned_hop: crate::Hop,
414 inner: Option<RequestInner<S>>,
416}
417
418struct RequestInner<S: crate::transport::poll::Session> {
420 server: Server,
421 runtime: Clock,
423 handshake: PausedHandshake<S>,
424}
425
426enum PausedHandshake<S: crate::transport::poll::Session> {
429 LiteBare { session: S, version: lite::Version },
431 LiteSetup {
434 session: S,
435 version: lite::Version,
436 client_setup: lite::Setup,
437 },
438 Boxed(Box<dyn Paused<S>>),
445}
446
447type Accept<S> = crate::util::MaybeSendBox<'static, Result<(Session, crate::Driver<S>), Error>>;
448
449trait Paused<S: crate::transport::poll::Session>: MaybeSend + MaybeSync {
456 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S>;
458
459 fn close(self: Box<Self>, err: Error);
461}
462
463struct PausedIetfModern<S: crate::transport::poll::Session> {
467 session: S,
468 version: ietf::Version,
469 peer_setup: ietf::PeerSetup<S>,
470}
471
472impl<S> Paused<S> for PausedIetfModern<S>
473where
474 S: crate::transport::poll::Boxable,
475 S::SendStream: MaybeSync,
476 S::RecvStream: MaybeSync,
477{
478 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S> {
479 use crate::util::MaybeBoxedExt as _;
480 async move {
481 let Self {
482 session,
483 version,
484 peer_setup,
485 } = *self;
486 let (publish, subscribe) = server.stat_tagged_origins();
487
488 let (protocol, goaway) = ietf::start(ietf::Config {
491 runtime: runtime.clone(),
492 session: session.clone(),
493 setup: None,
494 request_id_max: None,
495 client: false,
496 publish,
497 subscribe,
498 peer_hop,
499 cost: None,
501 version,
502 path: None,
503 peer_setup_stream: Some(peer_setup.stream),
504 peer_declared: Some(peer_setup.declared),
505 })?;
506 tracing::debug!(?version, "connected");
507 Ok(Session::new(
508 runtime,
509 session,
510 version.into(),
511 None,
512 crate::driver::Protocol::Ietf(protocol),
513 goaway,
514 ))
515 }
516 .maybe_boxed()
517 }
518
519 fn close(self: Box<Self>, err: Error) {
520 let mut session = self.session;
521 session.close(SessionError::from(&err).to_code(), &err.to_string());
522 }
523}
524
525struct PausedLegacy<S: crate::transport::poll::Session> {
529 session: S,
530 stream: Stream<S, Version>,
531 version: Version,
532 request_id_max: Option<ietf::RequestId>,
533 peer_declared: ietf::peer::Peer,
535}
536
537impl<S> Paused<S> for PausedLegacy<S>
538where
539 S: crate::transport::poll::Boxable,
540 S::SendStream: MaybeSync,
541 S::RecvStream: MaybeSync,
542{
543 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S> {
544 use crate::util::MaybeBoxedExt as _;
545 async move {
546 let Self {
547 session,
548 mut stream,
549 version,
550 request_id_max,
551 peer_declared,
552 } = *self;
553 let (publish, subscribe) = server.stat_tagged_origins();
554
555 let parameters = match version {
557 Version::Ietf(v) => {
558 let mut parameters = ietf::Parameters::default();
559 parameters.set_varint(ietf::ParameterVarInt::MaxRequestId, u32::MAX as u64);
560 parameters.set_bytes(ietf::ParameterBytes::Implementation, b"moq-lite-rs".to_vec());
561 ietf::solicit::into_setup(&mut parameters, v);
562 ietf::hidden::into_setup(&mut parameters, v);
563 parameters.encode_bytes(v)?
564 }
565 Version::Lite(v) => lite::Parameters::default().encode_bytes(v)?,
566 };
567
568 let server_setup = setup::Server {
569 version: version.into(),
570 parameters,
571 };
572 stream.writer.encode(&server_setup).await?;
573
574 let (recv_bw, protocol, goaway) = match version {
575 Version::Lite(v) => {
576 let stream = stream.with_version(v);
577 let start = lite::start(lite::Config {
579 runtime: runtime.clone(),
580 session: session.clone(),
581 setup_stream: Some(stream),
582 publish,
583 subscribe,
584 peer_hop,
585 version: v,
586 our_setup: lite::Setup::default(),
587 peer_setup: None,
588 })?;
589 (
590 start.recv_bandwidth,
591 crate::driver::Protocol::Lite(Box::new(start.driver)),
592 start.goaway,
593 )
594 }
595 Version::Ietf(v) => {
596 let stream = stream.with_version(v);
597 let (protocol, goaway) = ietf::start(ietf::Config {
599 runtime: runtime.clone(),
600 session: session.clone(),
601 setup: Some(stream),
602 request_id_max,
603 client: false,
604 publish,
605 subscribe,
606 peer_hop,
607 cost: None,
608 version: v,
609 path: None,
610 peer_setup_stream: None,
611 peer_declared: Some(peer_declared),
612 })?;
613 (None, crate::driver::Protocol::Ietf(protocol), goaway)
614 }
615 };
616
617 Ok(Session::new(runtime, session, version, recv_bw, protocol, goaway))
618 }
619 .maybe_boxed()
620 }
621
622 fn close(self: Box<Self>, err: Error) {
623 let mut session = self.session;
624 session.close(SessionError::from(&err).to_code(), &err.to_string());
625 }
626}
627
628impl<S> Handshake<S>
629where
630 S: crate::transport::poll::Session,
631{
632 pub fn path(&self) -> &str {
639 self.path.as_deref().unwrap_or("")
640 }
641
642 pub fn role(&self) -> Option<Role> {
651 self.role
652 }
653
654 pub fn peer_hop(&self) -> Option<crate::Hop> {
663 self.origin
664 }
665
666 pub fn with_publisher(mut self, publish: impl Consume<origin::Consumer>) -> Self {
669 self.inner_mut().server.publish = Some(publish.consume());
670 self
671 }
672
673 pub fn with_subscriber(mut self, subscribe: origin::Producer) -> Self {
675 self.inner_mut().server.subscribe = Some(subscribe);
676 self
677 }
678
679 pub fn with_peer_hop(mut self, hop: crate::Hop) -> Self {
692 self.assigned_hop = hop;
693 self
694 }
695
696 pub fn with_stats(mut self, stats: stats::Session) -> Self {
699 self.inner_mut().server.stats = stats;
700 self
701 }
702
703 fn inner_mut(&mut self) -> &mut RequestInner<S> {
704 self.inner.as_mut().expect("request already responded")
705 }
706
707 pub async fn ok(mut self) -> Result<(Session, crate::Driver<S>), Error> {
711 let peer_hop = Some(self.assigned_hop);
712 let RequestInner {
713 server,
714 runtime,
715 handshake,
716 } = self.inner.take().expect("request already responded");
717
718 match handshake {
719 PausedHandshake::LiteBare { session, version } => {
720 server.start_lite(runtime, session, version, None, peer_hop)
721 }
722 PausedHandshake::LiteSetup {
723 session,
724 version,
725 client_setup,
726 } => server.start_lite(runtime, session, version, Some(client_setup), peer_hop),
727 PausedHandshake::Boxed(paused) => paused.ok(server, runtime, peer_hop).await,
728 }
729 }
730
731 pub fn close(mut self, err: Error) {
733 let inner = self.inner.take().expect("request already responded");
734 inner.close(err);
735 }
736}
737
738impl<S: crate::transport::poll::Session> RequestInner<S> {
739 fn close(self, err: Error) {
740 let mut session = match self.handshake {
741 PausedHandshake::LiteBare { session, .. } => session,
742 PausedHandshake::LiteSetup { session, .. } => session,
743 PausedHandshake::Boxed(paused) => return paused.close(err),
744 };
745 session.close(SessionError::from(&err).to_code(), &err.to_string());
746 }
747}
748
749impl<S: crate::transport::poll::Session> Drop for Handshake<S> {
750 fn drop(&mut self) {
753 if let Some(inner) = self.inner.take() {
754 tracing::warn!("Handshake dropped without ok() or close(); rejecting the session");
755 inner.close(Error::Cancel);
756 }
757 }
758}
759
760#[cfg(test)]
761mod tests {
762 use super::*;
763 use crate::Hop;
764 use crate::model::ProduceTest;
765 use std::{
766 collections::VecDeque,
767 sync::{Arc, Mutex},
768 };
769
770 use crate::ALPN_LITE_05;
771 use bytes::Bytes;
772
773 fn occurrences(log: &crate::lite::test_transport::Log, needle: &[u8]) -> usize {
774 let writes = log.writes.lock().unwrap();
775 writes.windows(needle.len()).filter(|window| *window == needle).count()
776 }
777
778 #[derive(Debug, Clone, Default)]
779 struct FakeError;
780 impl std::fmt::Display for FakeError {
781 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
782 write!(f, "fake transport error")
783 }
784 }
785 impl std::error::Error for FakeError {}
786 impl web_transport_trait::Error for FakeError {
787 fn session_error(&self) -> Option<(u32, String)> {
788 Some((0, "closed".to_string()))
789 }
790 }
791
792 #[derive(Clone)]
795 struct FakeSession {
796 protocol: Option<&'static str>,
797 uni: Arc<Mutex<VecDeque<Vec<u8>>>>,
798 }
799
800 impl FakeSession {
801 fn new(protocol: &'static str, uni: impl IntoIterator<Item = Vec<u8>>) -> Self {
802 Self {
803 protocol: Some(protocol),
804 uni: Arc::new(Mutex::new(uni.into_iter().collect())),
805 }
806 }
807 }
808
809 impl web_transport_trait::poll::Session for FakeSession {
810 type SendStream = FakeSend;
811 type RecvStream = FakeRecv;
812 type Error = FakeError;
813
814 fn poll_accept_uni(
815 &mut self,
816 _cx: &mut std::task::Context<'_>,
817 ) -> std::task::Poll<Result<Self::RecvStream, Self::Error>> {
818 match self.uni.lock().unwrap().pop_front() {
819 Some(data) => std::task::Poll::Ready(Ok(FakeRecv { data: data.into() })),
820 None => std::task::Poll::Pending,
821 }
822 }
823 fn poll_accept_bi(
824 &mut self,
825 _cx: &mut std::task::Context<'_>,
826 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
827 std::task::Poll::Pending
828 }
829 fn poll_open_bi(
830 &mut self,
831 _cx: &mut std::task::Context<'_>,
832 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
833 std::task::Poll::Pending
834 }
835 fn poll_open_uni(
836 &mut self,
837 _cx: &mut std::task::Context<'_>,
838 ) -> std::task::Poll<Result<Self::SendStream, Self::Error>> {
839 std::task::Poll::Pending
840 }
841 fn poll_send_datagram(
842 &mut self,
843 _cx: &mut std::task::Context<'_>,
844 _payload: &[u8],
845 ) -> std::task::Poll<Result<(), Self::Error>> {
846 std::task::Poll::Ready(Ok(()))
847 }
848 fn poll_recv_datagram(
849 &mut self,
850 _cx: &mut std::task::Context<'_>,
851 ) -> std::task::Poll<Result<Bytes, Self::Error>> {
852 std::task::Poll::Pending
853 }
854 fn max_datagram_size(&self) -> usize {
855 1200
856 }
857 fn protocol(&self) -> Option<&str> {
858 self.protocol
859 }
860 fn close(&mut self, _code: u32, _reason: &str) {}
861 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Error> {
862 std::task::Poll::Pending
863 }
864 fn stats(&self) -> impl web_transport_trait::Stats {
865 web_transport_trait::StatsUnavailable
866 }
867 }
868
869 #[derive(Clone, Default)]
870 struct FakeSend;
871 impl web_transport_trait::poll::SendStream for FakeSend {
872 type Error = FakeError;
873 fn poll_write(
874 &mut self,
875 _cx: &mut std::task::Context<'_>,
876 buf: &[u8],
877 ) -> std::task::Poll<Result<usize, Self::Error>> {
878 std::task::Poll::Ready(Ok(buf.len()))
879 }
880 fn set_priority(&mut self, _order: u8) {}
881 fn finish(&mut self) -> Result<(), Self::Error> {
882 Ok(())
883 }
884 fn reset(&mut self, _code: u32) {}
885 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
886 std::task::Poll::Ready(Ok(()))
887 }
888 }
889
890 struct FakeRecv {
891 data: VecDeque<u8>,
892 }
893 impl web_transport_trait::poll::RecvStream for FakeRecv {
894 type Error = FakeError;
895 fn poll_read(
896 &mut self,
897 _cx: &mut std::task::Context<'_>,
898 dst: &mut [u8],
899 ) -> std::task::Poll<Result<Option<usize>, Self::Error>> {
900 if self.data.is_empty() {
901 return std::task::Poll::Ready(Ok(None));
902 }
903 let size = dst.len().min(self.data.len());
904 for slot in dst.iter_mut().take(size) {
905 *slot = self.data.pop_front().unwrap();
906 }
907 std::task::Poll::Ready(Ok(Some(size)))
908 }
909 fn stop(&mut self, _code: u32) {}
910 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
911 std::task::Poll::Ready(Ok(()))
912 }
913 }
914
915 fn lite05_setup(path: Option<&str>, role: Option<Role>, hop: Option<Hop>) -> Vec<u8> {
917 let v = lite::Version::Lite05;
918 let mut buf = Vec::new();
919 lite::DataType::Setup.encode(&mut buf, v).unwrap();
920 lite::Setup {
921 probe: lite::ProbeLevel::None,
922 path: path.map(str::to_string),
923 role,
924 cost: None,
925 hop,
926 }
927 .encode(&mut buf, v)
928 .unwrap();
929 buf
930 }
931
932 fn ietf_setup(version: ietf::Version, path: Option<&str>) -> Vec<u8> {
935 let mut params = ietf::Parameters::default();
936 if let Some(path) = path {
937 params.set_bytes(ietf::ParameterBytes::Path, path.as_bytes().to_vec());
938 }
939 let parameters = params.encode_bytes(version).unwrap();
940
941 let mut buf = Vec::new();
942 setup::Setup { parameters }
943 .encode(&mut buf, crate::Version::Ietf(version))
944 .unwrap();
945 buf
946 }
947
948 #[tokio::test(start_paused = true)]
949 async fn accept_request_reads_ietf_path() {
950 for (alpn, version) in [
953 (ALPN_17, ietf::Version::Draft17),
954 (ALPN_18, ietf::Version::Draft18),
955 (ALPN_19, ietf::Version::Draft19),
956 ] {
957 let session = FakeSession::new(alpn, [ietf_setup(version, Some("/team/room"))]);
958 let request = Server::new()
959 .accept_request(tokio::time::Instant::now().into_std(), session)
960 .await
961 .unwrap();
962 assert_eq!(request.path(), "/team/room", "{alpn}");
963 }
964 }
965
966 #[tokio::test(start_paused = true)]
967 async fn accept_request_ietf_without_path_is_empty() {
968 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, None)]);
969 let request = Server::new()
970 .accept_request(tokio::time::Instant::now().into_std(), session)
971 .await
972 .unwrap();
973 assert_eq!(request.path(), "");
974 }
975
976 #[tokio::test(start_paused = true)]
977 async fn accept_request_ietf_empty_path_is_accepted() {
978 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, Some(""))]);
979 let request = Server::new()
980 .accept_request(tokio::time::Instant::now().into_std(), session)
981 .await
982 .unwrap();
983 assert_eq!(request.path(), "");
984 }
985
986 fn lite05_group() -> Vec<u8> {
988 let mut buf = Vec::new();
989 lite::DataType::Group.encode(&mut buf, lite::Version::Lite05).unwrap();
990 buf
991 }
992
993 #[tokio::test(start_paused = true)]
994 async fn accept_request_reads_lite05_path() {
995 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some("/team/room"), None, None)]);
996 let request = Server::new()
997 .accept_request(tokio::time::Instant::now().into_std(), session)
998 .await
999 .unwrap();
1000 assert_eq!(request.path(), "/team/room");
1001 assert_eq!(request.role(), None, "a client that omits the role is bidirectional");
1002 }
1003
1004 #[tokio::test(start_paused = true)]
1005 async fn accept_request_lite05_without_path_is_empty() {
1006 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1007 let request = Server::new()
1008 .accept_request(tokio::time::Instant::now().into_std(), session)
1009 .await
1010 .unwrap();
1011 assert_eq!(request.path(), "");
1012 }
1013
1014 #[tokio::test(start_paused = true)]
1015 async fn accept_request_lite05_empty_path_is_accepted() {
1016 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some(""), None, None)]);
1019 let request = Server::new()
1020 .accept_request(tokio::time::Instant::now().into_std(), session)
1021 .await
1022 .unwrap();
1023 assert_eq!(request.path(), "");
1024 }
1025
1026 #[tokio::test(start_paused = true)]
1027 async fn accept_request_reads_lite05_role() {
1028 let session = FakeSession::new(
1029 ALPN_LITE_05,
1030 [lite05_setup(Some("/team/room"), Some(Role::Publisher), None)],
1031 );
1032 let request = Server::new()
1033 .accept_request(tokio::time::Instant::now().into_std(), session)
1034 .await
1035 .unwrap();
1036 assert_eq!(request.role(), Some(Role::Publisher));
1037 }
1038
1039 #[tokio::test(start_paused = true)]
1040 async fn accept_request_skips_uni_stream_before_setup() {
1041 let session = FakeSession::new(
1044 ALPN_LITE_05,
1045 [lite05_group(), lite05_setup(Some("/team/room"), None, None)],
1046 );
1047 let request = Server::new()
1048 .accept_request(tokio::time::Instant::now().into_std(), session)
1049 .await
1050 .unwrap();
1051 assert_eq!(request.path(), "/team/room");
1052 }
1053
1054 #[tokio::test(start_paused = true)]
1055 async fn accept_request_reads_lite05_peer_hop() {
1056 let hop = Hop::new(42).unwrap();
1057 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, Some(hop))]);
1058 let request = Server::new()
1059 .accept_request(tokio::time::Instant::now().into_std(), session)
1060 .await
1061 .unwrap();
1062 assert_eq!(request.peer_hop(), Some(hop));
1063 }
1064
1065 #[tokio::test(start_paused = true)]
1066 async fn anonymous_peer_hop_filters_routes_from_server_session() {
1067 let other = Hop::new(778).unwrap();
1068 let origin = crate::origin::Config::new(Hop::new(1).unwrap()).produce();
1069
1070 let gate = kio::Producer::new(true);
1071 let transport = crate::lite::test_transport::SinkSession::gated_bi(gate.consume());
1072 let log = transport.log.clone();
1073 let version = ietf::Version::Draft18;
1074 let request = Handshake {
1075 path: None,
1076 role: None,
1077 origin: None,
1078 assigned_hop: Hop::random(),
1079 inner: Some(RequestInner {
1080 server: Server::new().with_publisher(&origin),
1081 runtime: Clock::new(tokio::time::Instant::now().into_std()),
1082 handshake: PausedHandshake::Boxed(Box::new(PausedIetfModern {
1083 session: transport,
1084 version,
1085 peer_setup: ietf::PeerSetup {
1086 stream: crate::coding::Reader::new(
1087 crate::lite::test_transport::PendingRecv,
1088 Version::Ietf(version),
1089 ),
1090 path: None,
1091 declared: ietf::peer::Peer::default(),
1092 },
1093 })),
1094 }),
1095 };
1096 let assigned = request.assigned_hop;
1097
1098 let mut echoed_hops = crate::Hops::new();
1099 echoed_hops.push(crate::Hop::UNKNOWN).unwrap();
1100 let _echoed = origin
1101 .announce(
1102 "echoed-route",
1103 crate::origin::Route::default()
1104 .with_hops(echoed_hops)
1105 .with_via(assigned),
1106 )
1107 .unwrap();
1108
1109 let mut local_hops = crate::Hops::new();
1110 local_hops.push(other).unwrap();
1111 let _local = origin
1112 .announce("local-route", crate::origin::Route::default().with_hops(local_hops))
1113 .unwrap();
1114
1115 let (session, driver) = request.ok().await.unwrap();
1116 tokio::spawn(crate::time::run(driver));
1117
1118 for _ in 0..100 {
1119 if occurrences(&log, b"local-route") > 0 {
1120 break;
1121 }
1122 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
1123 }
1124
1125 assert_eq!(occurrences(&log, b"echoed-route"), 0);
1126 assert_eq!(occurrences(&log, b"local-route"), 1);
1127 drop(session);
1128 }
1129}