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 early_unis: peer_setup.early,
538 })?;
539 tracing::debug!(?version, "connected");
540 Ok(Session::new(
541 runtime,
542 session,
543 version.into(),
544 None,
545 crate::driver::Protocol::Ietf(protocol),
546 goaway,
547 ))
548 }
549 .maybe_boxed()
550 }
551
552 fn close(mut self: Box<Self>, err: Error) {
553 close(&mut self.session, &err);
554 }
555}
556
557struct PausedLegacy<S: crate::transport::poll::Session> {
561 session: S,
562 stream: Stream<S, Version>,
563 version: Version,
564 request_id_max: Option<ietf::RequestId>,
565 peer_declared: ietf::peer::Peer,
567}
568
569impl<S> Paused<S> for PausedLegacy<S>
570where
571 S: crate::transport::poll::Boxable,
572 S::SendStream: MaybeSync,
573 S::RecvStream: MaybeSync,
574{
575 fn ok(self: Box<Self>, server: Server, runtime: Clock, peer_hop: Option<crate::Hop>) -> Accept<S> {
576 use crate::util::MaybeBoxedExt as _;
577 async move {
578 let Self {
579 session,
580 mut stream,
581 version,
582 request_id_max,
583 peer_declared,
584 } = *self;
585 let (publish, subscribe) = server.stat_tagged_origins();
586
587 let parameters = match version {
589 Version::Ietf(v) => {
590 let mut parameters = ietf::Parameters::default();
591 parameters.set_varint(ietf::ParameterVarInt::MaxRequestId, u32::MAX as u64);
592 parameters.set_bytes(ietf::ParameterBytes::Implementation, b"moq-lite-rs".to_vec());
593 ietf::solicit::into_setup(&mut parameters, v);
594 ietf::hidden::into_setup(&mut parameters, v);
595 parameters.encode_bytes(v)?
596 }
597 Version::Lite(v) => lite::Parameters::default().encode_bytes(v)?,
598 };
599
600 let server_setup = setup::Server {
601 version: version.into(),
602 parameters,
603 };
604 stream.writer.encode(&server_setup).await?;
605
606 let (recv_bw, protocol, goaway) = match version {
607 Version::Lite(v) => {
608 let stream = stream.with_version(v);
609 let start = lite::start(lite::Config {
611 runtime: runtime.clone(),
612 session: session.clone(),
613 setup_stream: Some(stream),
614 publish,
615 subscribe,
616 peer_hop,
617 version: v,
618 our_setup: lite::Setup::default(),
619 peer_setup: None,
620 })?;
621 (
622 start.recv_bandwidth,
623 crate::driver::Protocol::Lite(Box::new(start.driver)),
624 start.goaway,
625 )
626 }
627 Version::Ietf(v) => {
628 let stream = stream.with_version(v);
629 let (protocol, goaway) = ietf::start(ietf::Config {
631 runtime: runtime.clone(),
632 session: session.clone(),
633 setup: Some(stream),
634 request_id_max,
635 client: false,
636 publish,
637 subscribe,
638 peer_hop,
639 cost: None,
640 version: v,
641 path: None,
642 authority: None,
643 peer_setup_stream: None,
644 peer_declared: Some(peer_declared),
645 early_unis: Vec::new(),
646 })?;
647 (None, crate::driver::Protocol::Ietf(protocol), goaway)
648 }
649 };
650
651 Ok(Session::new(runtime, session, version, recv_bw, protocol, goaway))
652 }
653 .maybe_boxed()
654 }
655
656 fn close(mut self: Box<Self>, err: Error) {
657 close(&mut self.session, &err);
658 }
659}
660
661impl<S> Handshake<S>
662where
663 S: crate::transport::poll::Session,
664{
665 pub fn path(&self) -> &str {
672 self.path.as_deref().unwrap_or("")
673 }
674
675 pub fn role(&self) -> Option<Role> {
684 self.role
685 }
686
687 pub fn peer_hop(&self) -> Option<crate::Hop> {
696 self.origin
697 }
698
699 pub fn token(&self) -> Option<&setup::Token> {
704 self.token.as_ref()
705 }
706
707 pub fn with_publisher(mut self, publish: impl Consume<origin::Consumer>) -> Self {
710 self.inner_mut().server.publish = Some(publish.consume());
711 self
712 }
713
714 pub fn with_subscriber(mut self, subscribe: origin::Producer) -> Self {
716 self.inner_mut().server.subscribe = Some(subscribe);
717 self
718 }
719
720 pub fn with_peer_hop(mut self, hop: crate::Hop) -> Self {
733 self.assigned_hop = hop;
734 self
735 }
736
737 pub fn with_stats(mut self, stats: stats::Session) -> Self {
740 self.inner_mut().server.stats = stats;
741 self
742 }
743
744 fn inner_mut(&mut self) -> &mut RequestInner<S> {
745 self.inner.as_mut().expect("request already responded")
746 }
747
748 pub async fn ok(mut self) -> Result<(Session, crate::Driver<S>), Error> {
752 let peer_hop = Some(self.assigned_hop);
753 let RequestInner {
754 server,
755 runtime,
756 handshake,
757 } = self.inner.take().expect("request already responded");
758
759 match handshake {
760 PausedHandshake::LiteBare { session, version } => {
761 server.start_lite(runtime, session, version, None, peer_hop)
762 }
763 PausedHandshake::LiteSetup {
764 session,
765 version,
766 client_setup,
767 } => server.start_lite(runtime, session, version, Some(client_setup), peer_hop),
768 PausedHandshake::Boxed(paused) => paused.ok(server, runtime, peer_hop).await,
769 }
770 }
771
772 pub fn close(mut self, err: Error) {
774 let inner = self.inner.take().expect("request already responded");
775 inner.close(err);
776 }
777}
778
779impl<S: crate::transport::poll::Session> RequestInner<S> {
780 fn close(self, err: Error) {
781 let mut session = match self.handshake {
782 PausedHandshake::LiteBare { session, .. } => session,
783 PausedHandshake::LiteSetup { session, .. } => session,
784 PausedHandshake::Boxed(paused) => return paused.close(err),
785 };
786 close(&mut session, &err);
787 }
788}
789
790fn close<S: crate::transport::poll::Session>(session: &mut S, err: &Error) {
792 session.close(SessionError::from(err).to_code(), &err.to_string());
793}
794
795impl<S: crate::transport::poll::Session> Drop for Handshake<S> {
796 fn drop(&mut self) {
799 if let Some(inner) = self.inner.take() {
800 tracing::warn!("Handshake dropped without ok() or close(); rejecting the session");
801 inner.close(Error::Cancel);
802 }
803 }
804}
805
806#[cfg(test)]
807mod tests {
808 use super::*;
809 use crate::Hop;
810 use crate::model::ProduceTest;
811 use std::{
812 collections::VecDeque,
813 sync::{Arc, Mutex},
814 };
815
816 use crate::ALPN_LITE_05;
817 use bytes::Bytes;
818
819 fn occurrences(log: &crate::lite::test_transport::Log, needle: &[u8]) -> usize {
820 let writes = log.writes.lock().unwrap();
821 writes.windows(needle.len()).filter(|window| *window == needle).count()
822 }
823
824 #[derive(Debug, Clone, Default)]
825 struct FakeError;
826 impl std::fmt::Display for FakeError {
827 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
828 write!(f, "fake transport error")
829 }
830 }
831 impl std::error::Error for FakeError {}
832 impl web_transport_trait::Error for FakeError {
833 fn session_error(&self) -> Option<(u32, String)> {
834 Some((0, "closed".to_string()))
835 }
836 }
837
838 #[derive(Clone)]
842 struct FakeSession {
843 protocol: Option<&'static str>,
844 uni: Arc<Mutex<VecDeque<Vec<u8>>>>,
845 bi: Arc<Mutex<VecDeque<Vec<u8>>>>,
846 closed: Arc<Mutex<Option<u32>>>,
847 }
848
849 impl FakeSession {
850 fn new(protocol: &'static str, uni: impl IntoIterator<Item = Vec<u8>>) -> Self {
851 Self {
852 protocol: Some(protocol),
853 uni: Arc::new(Mutex::new(uni.into_iter().collect())),
854 bi: Default::default(),
855 closed: Default::default(),
856 }
857 }
858
859 fn with_bi(self, bi: Vec<u8>) -> Self {
860 self.bi.lock().unwrap().push_back(bi);
861 self
862 }
863
864 fn closed(&self) -> Option<u32> {
865 *self.closed.lock().unwrap()
866 }
867 }
868
869 impl web_transport_trait::poll::Session for FakeSession {
870 type SendStream = FakeSend;
871 type RecvStream = FakeRecv;
872 type Error = FakeError;
873
874 fn poll_accept_uni(
875 &mut self,
876 _cx: &mut std::task::Context<'_>,
877 ) -> std::task::Poll<Result<Self::RecvStream, Self::Error>> {
878 match self.uni.lock().unwrap().pop_front() {
879 Some(data) => std::task::Poll::Ready(Ok(FakeRecv { data: data.into() })),
880 None => std::task::Poll::Pending,
881 }
882 }
883 fn poll_accept_bi(
884 &mut self,
885 _cx: &mut std::task::Context<'_>,
886 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
887 match self.bi.lock().unwrap().pop_front() {
888 Some(data) => std::task::Poll::Ready(Ok((FakeSend, FakeRecv { data: data.into() }))),
889 None => std::task::Poll::Pending,
890 }
891 }
892 fn poll_open_bi(
893 &mut self,
894 _cx: &mut std::task::Context<'_>,
895 ) -> std::task::Poll<Result<(Self::SendStream, Self::RecvStream), Self::Error>> {
896 std::task::Poll::Pending
897 }
898 fn poll_open_uni(
899 &mut self,
900 _cx: &mut std::task::Context<'_>,
901 ) -> std::task::Poll<Result<Self::SendStream, Self::Error>> {
902 std::task::Poll::Pending
903 }
904 fn poll_send_datagram(
905 &mut self,
906 _cx: &mut std::task::Context<'_>,
907 _payload: &[u8],
908 ) -> std::task::Poll<Result<(), Self::Error>> {
909 std::task::Poll::Ready(Ok(()))
910 }
911 fn poll_recv_datagram(
912 &mut self,
913 _cx: &mut std::task::Context<'_>,
914 ) -> std::task::Poll<Result<Bytes, Self::Error>> {
915 std::task::Poll::Pending
916 }
917 fn max_datagram_size(&self) -> usize {
918 1200
919 }
920 fn protocol(&self) -> Option<&str> {
921 self.protocol
922 }
923 fn close(&mut self, code: u32, _reason: &str) {
924 self.closed.lock().unwrap().get_or_insert(code);
925 }
926 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Error> {
927 std::task::Poll::Pending
928 }
929 fn stats(&self) -> impl web_transport_trait::Stats {
930 web_transport_trait::StatsUnavailable
931 }
932 }
933
934 #[derive(Clone, Default)]
935 struct FakeSend;
936 impl web_transport_trait::poll::SendStream for FakeSend {
937 type Error = FakeError;
938 fn poll_write(
939 &mut self,
940 _cx: &mut std::task::Context<'_>,
941 buf: &[u8],
942 ) -> std::task::Poll<Result<usize, Self::Error>> {
943 std::task::Poll::Ready(Ok(buf.len()))
944 }
945 fn set_priority(&mut self, _order: u8) {}
946 fn finish(&mut self) -> Result<(), Self::Error> {
947 Ok(())
948 }
949 fn reset(&mut self, _code: u32) {}
950 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
951 std::task::Poll::Ready(Ok(()))
952 }
953 }
954
955 struct FakeRecv {
956 data: VecDeque<u8>,
957 }
958 impl web_transport_trait::poll::RecvStream for FakeRecv {
959 type Error = FakeError;
960 fn poll_read(
961 &mut self,
962 _cx: &mut std::task::Context<'_>,
963 dst: &mut [u8],
964 ) -> std::task::Poll<Result<Option<usize>, Self::Error>> {
965 if self.data.is_empty() {
966 return std::task::Poll::Ready(Ok(None));
967 }
968 let size = dst.len().min(self.data.len());
969 for slot in dst.iter_mut().take(size) {
970 *slot = self.data.pop_front().unwrap();
971 }
972 std::task::Poll::Ready(Ok(Some(size)))
973 }
974 fn stop(&mut self, _code: u32) {}
975 fn poll_closed(&mut self, _cx: &mut std::task::Context<'_>) -> std::task::Poll<Result<(), Self::Error>> {
976 std::task::Poll::Ready(Ok(()))
977 }
978 }
979
980 fn lite05_setup(path: Option<&str>, role: Option<Role>, hop: Option<Hop>) -> Vec<u8> {
982 let v = lite::Version::Lite05;
983 let mut buf = Vec::new();
984 lite::DataType::Setup.encode(&mut buf, v).unwrap();
985 lite::Setup {
986 probe: lite::ProbeLevel::None,
987 path: path.map(str::to_string),
988 role,
989 cost: None,
990 hop,
991 }
992 .encode(&mut buf, v)
993 .unwrap();
994 buf
995 }
996
997 fn ietf_setup(version: ietf::Version, path: Option<&str>) -> Vec<u8> {
1000 let mut params = ietf::Parameters::default();
1001 if let Some(path) = path {
1002 params.set_bytes(ietf::ParameterBytes::Path, path.as_bytes().to_vec());
1003 }
1004 ietf_setup_with(version, params)
1005 }
1006
1007 fn ietf_setup_with(version: ietf::Version, params: ietf::Parameters) -> Vec<u8> {
1008 let parameters = params.encode_bytes(version).unwrap();
1009
1010 let mut buf = Vec::new();
1011 setup::Setup { parameters }
1012 .encode(&mut buf, crate::Version::Ietf(version))
1013 .unwrap();
1014 buf
1015 }
1016
1017 fn legacy_setup(version: ietf::Version, params: ietf::Parameters) -> Vec<u8> {
1019 let mut buf = Vec::new();
1020 setup::Client {
1021 versions: crate::coding::Versions::from([crate::Version::Ietf(version).into()]),
1022 parameters: params.encode_bytes(version).unwrap(),
1023 }
1024 .encode(&mut buf, crate::Version::Ietf(version))
1025 .unwrap();
1026 buf
1027 }
1028
1029 fn setup_token() -> setup::Token {
1030 setup::Token {
1031 kind: setup::Token::OUT_OF_BAND,
1032 value: vec![0x00, 0xff, b'j', b'w', b't'],
1033 }
1034 }
1035
1036 fn token_params(version: ietf::Version) -> ietf::Parameters {
1037 let mut params = ietf::Parameters::default();
1038 ietf::token::into_setup(&mut params, &setup_token(), version).unwrap();
1039 params
1040 }
1041
1042 #[tokio::test(start_paused = true)]
1043 async fn accept_request_exposes_the_setup_token() {
1044 let modern = FakeSession::new(
1045 ALPN_19,
1046 [ietf_setup_with(
1047 ietf::Version::Draft19,
1048 token_params(ietf::Version::Draft19),
1049 )],
1050 );
1051 let legacy = FakeSession::new(ALPN_16, []).with_bi(legacy_setup(
1052 ietf::Version::Draft16,
1053 token_params(ietf::Version::Draft16),
1054 ));
1055 for (name, session) in [("draft-19", modern), ("draft-16", legacy)] {
1056 let request = Server::new()
1057 .accept_request(tokio::time::Instant::now().into_std(), session)
1058 .await
1059 .unwrap();
1060 assert_eq!(request.token(), Some(&setup_token()), "{name}");
1061 }
1062 }
1063
1064 #[tokio::test(start_paused = true)]
1065 async fn accept_request_without_a_token_reports_none() {
1066 let ietf = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, None)]);
1067 let lite = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1068 for (name, session) in [("draft-19", ietf), ("lite-05", lite)] {
1069 let request = Server::new()
1070 .accept_request(tokio::time::Instant::now().into_std(), session)
1071 .await
1072 .unwrap();
1073 assert_eq!(request.token(), None, "{name}");
1074 }
1075 }
1076
1077 #[tokio::test(start_paused = true)]
1080 async fn a_refused_setup_token_closes_with_its_code() {
1081 let delete = [0x0, 0x7]; let truncated = [0x3]; for (raw, code) in [
1084 (&delete[..], SessionError::ProtocolViolation),
1085 (&truncated[..], SessionError::KeyValueFormatting),
1086 ] {
1087 let mut params = ietf::Parameters::default();
1088 params.set_bytes(ietf::ParameterBytes::AuthorizationToken, raw.to_vec());
1089
1090 let modern = FakeSession::new(ALPN_19, [ietf_setup_with(ietf::Version::Draft19, params.clone())]);
1091 let legacy = FakeSession::new(ALPN_16, []).with_bi(legacy_setup(ietf::Version::Draft16, params));
1092 for (name, session) in [("draft-19", modern), ("draft-16", legacy)] {
1093 let result = Server::new()
1094 .accept_request(tokio::time::Instant::now().into_std(), session.clone())
1095 .await;
1096 assert!(result.is_err(), "{name}");
1097 assert_eq!(session.closed(), Some(code.to_code()), "{name} {code}");
1098 }
1099 }
1100 }
1101
1102 #[tokio::test(start_paused = true)]
1103 async fn accept_request_reads_ietf_path() {
1104 for (alpn, version) in [
1107 (ALPN_17, ietf::Version::Draft17),
1108 (ALPN_18, ietf::Version::Draft18),
1109 (ALPN_19, ietf::Version::Draft19),
1110 ] {
1111 let session = FakeSession::new(alpn, [ietf_setup(version, Some("/team/room"))]);
1112 let request = Server::new()
1113 .accept_request(tokio::time::Instant::now().into_std(), session)
1114 .await
1115 .unwrap();
1116 assert_eq!(request.path(), "/team/room", "{alpn}");
1117 }
1118 }
1119
1120 #[tokio::test(start_paused = true)]
1121 async fn accept_request_ietf_without_path_is_empty() {
1122 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, None)]);
1123 let request = Server::new()
1124 .accept_request(tokio::time::Instant::now().into_std(), session)
1125 .await
1126 .unwrap();
1127 assert_eq!(request.path(), "");
1128 }
1129
1130 #[tokio::test(start_paused = true)]
1131 async fn accept_request_ietf_empty_path_is_accepted() {
1132 let session = FakeSession::new(ALPN_19, [ietf_setup(ietf::Version::Draft19, Some(""))]);
1133 let request = Server::new()
1134 .accept_request(tokio::time::Instant::now().into_std(), session)
1135 .await
1136 .unwrap();
1137 assert_eq!(request.path(), "");
1138 }
1139
1140 fn lite05_group() -> Vec<u8> {
1142 let mut buf = Vec::new();
1143 lite::DataType::Group.encode(&mut buf, lite::Version::Lite05).unwrap();
1144 buf
1145 }
1146
1147 #[tokio::test(start_paused = true)]
1148 async fn accept_request_reads_lite05_path() {
1149 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some("/team/room"), None, None)]);
1150 let request = Server::new()
1151 .accept_request(tokio::time::Instant::now().into_std(), session)
1152 .await
1153 .unwrap();
1154 assert_eq!(request.path(), "/team/room");
1155 assert_eq!(request.role(), None, "a client that omits the role is bidirectional");
1156 }
1157
1158 #[tokio::test(start_paused = true)]
1159 async fn accept_request_lite05_without_path_is_empty() {
1160 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, None)]);
1161 let request = Server::new()
1162 .accept_request(tokio::time::Instant::now().into_std(), session)
1163 .await
1164 .unwrap();
1165 assert_eq!(request.path(), "");
1166 }
1167
1168 #[tokio::test(start_paused = true)]
1169 async fn accept_request_lite05_empty_path_is_accepted() {
1170 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(Some(""), None, None)]);
1173 let request = Server::new()
1174 .accept_request(tokio::time::Instant::now().into_std(), session)
1175 .await
1176 .unwrap();
1177 assert_eq!(request.path(), "");
1178 }
1179
1180 #[tokio::test(start_paused = true)]
1181 async fn accept_request_reads_lite05_role() {
1182 let session = FakeSession::new(
1183 ALPN_LITE_05,
1184 [lite05_setup(Some("/team/room"), Some(Role::Publisher), None)],
1185 );
1186 let request = Server::new()
1187 .accept_request(tokio::time::Instant::now().into_std(), session)
1188 .await
1189 .unwrap();
1190 assert_eq!(request.role(), Some(Role::Publisher));
1191 }
1192
1193 #[tokio::test(start_paused = true)]
1194 async fn accept_request_skips_uni_stream_before_setup() {
1195 let session = FakeSession::new(
1198 ALPN_LITE_05,
1199 [lite05_group(), lite05_setup(Some("/team/room"), None, None)],
1200 );
1201 let request = Server::new()
1202 .accept_request(tokio::time::Instant::now().into_std(), session)
1203 .await
1204 .unwrap();
1205 assert_eq!(request.path(), "/team/room");
1206 }
1207
1208 #[tokio::test(start_paused = true)]
1209 async fn accept_request_reads_lite05_peer_hop() {
1210 let hop = Hop::new(42).unwrap();
1211 let session = FakeSession::new(ALPN_LITE_05, [lite05_setup(None, None, Some(hop))]);
1212 let request = Server::new()
1213 .accept_request(tokio::time::Instant::now().into_std(), session)
1214 .await
1215 .unwrap();
1216 assert_eq!(request.peer_hop(), Some(hop));
1217 }
1218
1219 #[tokio::test(start_paused = true)]
1220 async fn anonymous_peer_hop_filters_routes_from_server_session() {
1221 let other = Hop::new(778).unwrap();
1222 let origin = crate::origin::Config::new(Hop::new(1).unwrap()).produce();
1223
1224 let gate = kio::Producer::new(true);
1225 let transport = crate::lite::test_transport::SinkSession::gated_bi(gate.consume());
1226 let log = transport.log.clone();
1227 let version = ietf::Version::Draft18;
1228 let request = Handshake {
1229 path: None,
1230 role: None,
1231 origin: None,
1232 token: None,
1233 assigned_hop: Hop::random(),
1234 inner: Some(RequestInner {
1235 server: Server::new().with_publisher(&origin),
1236 runtime: Clock::new(tokio::time::Instant::now().into_std()),
1237 handshake: PausedHandshake::Boxed(Box::new(PausedIetfModern {
1238 session: transport,
1239 version,
1240 peer_setup: ietf::PeerSetup {
1241 stream: crate::coding::Reader::new(
1242 crate::lite::test_transport::PendingRecv,
1243 Version::Ietf(version),
1244 ),
1245 path: None,
1246 token: None,
1247 declared: ietf::peer::Peer::default(),
1248 early: Vec::new(),
1249 },
1250 })),
1251 }),
1252 };
1253 let assigned = request.assigned_hop;
1254
1255 let mut echoed_hops = crate::Hops::new();
1256 echoed_hops.push(crate::Hop::UNKNOWN).unwrap();
1257 let _echoed = origin
1258 .announce(
1259 "echoed-route",
1260 crate::origin::Route::default()
1261 .with_hops(echoed_hops)
1262 .with_via(assigned),
1263 )
1264 .unwrap();
1265
1266 let mut local_hops = crate::Hops::new();
1267 local_hops.push(other).unwrap();
1268 let _local = origin
1269 .announce("local-route", crate::origin::Route::default().with_hops(local_hops))
1270 .unwrap();
1271
1272 let (session, driver) = request.ok().await.unwrap();
1273 tokio::spawn(crate::time::run(driver));
1274
1275 for _ in 0..100 {
1276 if occurrences(&log, b"local-route") > 0 {
1277 break;
1278 }
1279 tokio::time::sleep(std::time::Duration::from_millis(1)).await;
1280 }
1281
1282 assert_eq!(occurrences(&log, b"echoed-route"), 0);
1283 assert_eq!(occurrences(&log, b"local-route"), 1);
1284 drop(session);
1285 }
1286}