1use crate::{
2 ALPN_14, ALPN_15, ALPN_16, ALPN_17, ALPN_18, ALPN_19, ALPN_LITE, ALPN_LITE_03, ALPN_LITE_04, ALPN_LITE_05_WIP,
3 Error, NEGOTIATED, OriginConsumer, OriginProducer, Session, StatsHandle, Version, Versions,
4 coding::{Decode, Encode, Stream},
5 ietf, lite, setup,
6};
7
8#[derive(Default, Clone)]
10pub struct Server {
11 publish: Option<OriginConsumer>,
12 consume: Option<OriginProducer>,
13 stats: StatsHandle,
14 versions: Versions,
15}
16
17impl Server {
18 pub fn new() -> Self {
19 Default::default()
20 }
21
22 pub fn with_publish(mut self, publish: impl Into<Option<OriginConsumer>>) -> Self {
23 self.publish = publish.into();
24 self
25 }
26
27 pub fn with_consume(mut self, consume: impl Into<Option<OriginProducer>>) -> Self {
28 self.consume = consume.into();
29 self
30 }
31
32 pub fn with_stats(mut self, stats: StatsHandle) -> Self {
36 self.stats = stats;
37 self
38 }
39
40 pub fn with_origin(self, origin: OriginProducer) -> Self {
44 let consumer = origin.consume();
45 self.with_publish(consumer).with_consume(origin)
46 }
47
48 pub fn with_versions(mut self, versions: Versions) -> Self {
49 self.versions = versions;
50 self
51 }
52
53 pub async fn accept<S: web_transport_trait::Session>(&self, session: S) -> Result<Session, Error> {
59 self.accept_request(session).await?.ok().await
60 }
61
62 pub async fn accept_request<S: web_transport_trait::Session>(&self, session: S) -> Result<Request<S>, Error> {
73 let deferred = |handshake| Request {
75 server: self.clone(),
76 path: None,
77 handshake,
78 };
79
80 let (encoding, supported) = match session.protocol() {
81 Some(ALPN_19) => {
82 self.versions
83 .select(Version::Ietf(ietf::Version::Draft19))
84 .ok_or(Error::Version)?;
85 return Ok(deferred(Handshake::IetfModern {
86 session,
87 version: ietf::Version::Draft19,
88 }));
89 }
90 Some(ALPN_18) => {
91 self.versions
92 .select(Version::Ietf(ietf::Version::Draft18))
93 .ok_or(Error::Version)?;
94 return Ok(deferred(Handshake::IetfModern {
95 session,
96 version: ietf::Version::Draft18,
97 }));
98 }
99 Some(ALPN_17) => {
100 self.versions
101 .select(Version::Ietf(ietf::Version::Draft17))
102 .ok_or(Error::Version)?;
103 return Ok(deferred(Handshake::IetfModern {
104 session,
105 version: ietf::Version::Draft17,
106 }));
107 }
108 Some(ALPN_16) => {
109 let v = self
110 .versions
111 .select(Version::Ietf(ietf::Version::Draft16))
112 .ok_or(Error::Version)?;
113 (v, v.into())
114 }
115 Some(ALPN_15) => {
116 let v = self
117 .versions
118 .select(Version::Ietf(ietf::Version::Draft15))
119 .ok_or(Error::Version)?;
120 (v, v.into())
121 }
122 Some(ALPN_14) => {
123 let v = self
124 .versions
125 .select(Version::Ietf(ietf::Version::Draft14))
126 .ok_or(Error::Version)?;
127 (v, v.into())
128 }
129 Some(ALPN_LITE_05_WIP) => {
130 self.versions
131 .select(Version::Lite(lite::Version::Lite05Wip))
132 .ok_or(Error::Version)?;
133
134 let client_setup = lite::accept_setup(&session, lite::Version::Lite05Wip).await?;
137 return Ok(Request {
138 server: self.clone(),
139 path: client_setup.path,
140 handshake: Handshake::Lite05 { session },
141 });
142 }
143 Some(ALPN_LITE_04) => {
144 self.versions
145 .select(Version::Lite(lite::Version::Lite04))
146 .ok_or(Error::Version)?;
147 return Ok(deferred(Handshake::LiteBare {
148 session,
149 version: lite::Version::Lite04,
150 }));
151 }
152 Some(ALPN_LITE_03) => {
153 self.versions
154 .select(Version::Lite(lite::Version::Lite03))
155 .ok_or(Error::Version)?;
156 return Ok(deferred(Handshake::LiteBare {
157 session,
158 version: lite::Version::Lite03,
159 }));
160 }
161 Some(ALPN_LITE) | None => {
162 let supported = self.versions.filter(&NEGOTIATED.into()).ok_or(Error::Version)?;
163 (Version::Ietf(ietf::Version::Draft14), supported)
164 }
165 Some(p) => return Err(Error::UnknownAlpn(p.to_string())),
166 };
167
168 let mut stream = Stream::accept(&session, encoding).await?;
171 let mut client: setup::Client = stream.reader.decode().await?;
172
173 let version = client
174 .versions
175 .iter()
176 .flat_map(|v| Version::try_from(*v).ok())
177 .find(|v| supported.contains(v))
178 .ok_or(Error::Version)?;
179
180 let request_id_max = match version {
183 Version::Ietf(v) => {
184 let params = ietf::Parameters::decode(&mut client.parameters, v)?;
185 params
186 .get_varint(ietf::ParameterVarInt::MaxRequestId)
187 .map(ietf::RequestId)
188 }
189 Version::Lite(_) => None,
190 };
191
192 Ok(deferred(Handshake::Legacy {
193 session,
194 stream,
195 version,
196 request_id_max,
197 }))
198 }
199}
200
201pub struct Request<S: web_transport_trait::Session> {
208 server: Server,
209 path: Option<String>,
210 handshake: Handshake<S>,
211}
212
213enum Handshake<S: web_transport_trait::Session> {
216 IetfModern { session: S, version: ietf::Version },
218 LiteBare { session: S, version: lite::Version },
220 Lite05 { session: S },
222 Legacy {
225 session: S,
226 stream: Stream<S, Version>,
227 version: Version,
228 request_id_max: Option<ietf::RequestId>,
229 },
230}
231
232impl<S: web_transport_trait::Session> Request<S> {
233 pub fn path(&self) -> Option<&str> {
238 self.path.as_deref()
239 }
240
241 pub fn with_publish(mut self, publish: impl Into<Option<OriginConsumer>>) -> Self {
244 self.server.publish = publish.into();
245 self
246 }
247
248 pub fn with_consume(mut self, consume: impl Into<Option<OriginProducer>>) -> Self {
250 self.server.consume = consume.into();
251 self
252 }
253
254 pub fn with_stats(mut self, stats: StatsHandle) -> Self {
256 self.server.stats = stats;
257 self
258 }
259
260 pub async fn ok(self) -> Result<Session, Error> {
262 let server = self.server;
263
264 if server.publish.is_none() && server.consume.is_none() {
267 tracing::warn!("not publishing or consuming anything");
268 }
269
270 let (session, mut stream, version, request_id_max) = match self.handshake {
271 Handshake::IetfModern { session, version } => {
272 ietf::start(
273 session.clone(),
274 None,
275 None,
276 false,
277 server.publish,
278 server.consume,
279 server.stats,
280 version,
281 )?;
282 tracing::debug!(?version, "connected");
283 return Ok(Session::new(session, version.into(), None));
284 }
285 Handshake::LiteBare { session, version } => {
286 let recv_bw = lite::start(
287 session.clone(),
288 None,
289 server.publish,
290 server.consume,
291 server.stats,
292 version,
293 lite::Setup::default(),
294 )?;
295 return Ok(Session::new(session, version.into(), recv_bw));
296 }
297 Handshake::Lite05 { session } => {
298 let recv_bw = lite::start(
300 session.clone(),
301 None,
302 server.publish,
303 server.consume,
304 server.stats,
305 lite::Version::Lite05Wip,
306 lite::Setup::default(),
307 )?;
308 return Ok(Session::new(session, lite::Version::Lite05Wip.into(), recv_bw));
309 }
310 Handshake::Legacy {
311 session,
312 stream,
313 version,
314 request_id_max,
315 } => (session, stream, version, request_id_max),
316 };
317
318 let parameters = match version {
320 Version::Ietf(v) => {
321 let mut parameters = ietf::Parameters::default();
322 parameters.set_varint(ietf::ParameterVarInt::MaxRequestId, u32::MAX as u64);
323 parameters.set_bytes(ietf::ParameterBytes::Implementation, b"moq-lite-rs".to_vec());
324 parameters.encode_bytes(v)?
325 }
326 Version::Lite(v) => lite::Parameters::default().encode_bytes(v)?,
327 };
328
329 let server_setup = setup::Server {
330 version: version.into(),
331 parameters,
332 };
333 stream.writer.encode(&server_setup).await?;
334
335 let recv_bw = match version {
336 Version::Lite(v) => {
337 let stream = stream.with_version(v);
338 lite::start(
340 session.clone(),
341 Some(stream),
342 server.publish,
343 server.consume,
344 server.stats,
345 v,
346 lite::Setup::default(),
347 )?
348 }
349 Version::Ietf(v) => {
350 let stream = stream.with_version(v);
351 ietf::start(
352 session.clone(),
353 Some(stream),
354 request_id_max,
355 false,
356 server.publish,
357 server.consume,
358 server.stats,
359 v,
360 )?;
361 None
362 }
363 };
364
365 Ok(Session::new(session, version, recv_bw))
366 }
367
368 pub fn close(self, err: Error) {
370 let session = match self.handshake {
371 Handshake::IetfModern { session, .. } => session,
372 Handshake::LiteBare { session, .. } => session,
373 Handshake::Lite05 { session } => session,
374 Handshake::Legacy { session, .. } => session,
375 };
376 session.close(err.to_code(), &err.to_string());
377 }
378}
379
380#[cfg(test)]
381mod tests {
382 use super::*;
383 use std::{
384 collections::VecDeque,
385 sync::{Arc, Mutex},
386 };
387
388 use bytes::Bytes;
389
390 #[derive(Debug, Clone, Default)]
391 struct FakeError;
392 impl std::fmt::Display for FakeError {
393 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
394 write!(f, "fake transport error")
395 }
396 }
397 impl std::error::Error for FakeError {}
398 impl web_transport_trait::Error for FakeError {
399 fn session_error(&self) -> Option<(u32, String)> {
400 Some((0, "closed".to_string()))
401 }
402 }
403
404 #[derive(Clone)]
407 struct FakeSession {
408 protocol: Option<&'static str>,
409 uni: Arc<Mutex<VecDeque<Vec<u8>>>>,
410 }
411
412 impl FakeSession {
413 fn new(protocol: &'static str, uni: impl IntoIterator<Item = Vec<u8>>) -> Self {
414 Self {
415 protocol: Some(protocol),
416 uni: Arc::new(Mutex::new(uni.into_iter().collect())),
417 }
418 }
419 }
420
421 impl web_transport_trait::Session for FakeSession {
422 type SendStream = FakeSend;
423 type RecvStream = FakeRecv;
424 type Error = FakeError;
425
426 async fn accept_uni(&self) -> Result<Self::RecvStream, Self::Error> {
427 let data = self.uni.lock().unwrap().pop_front();
429 match data {
430 Some(data) => Ok(FakeRecv { data: data.into() }),
431 None => std::future::pending().await,
432 }
433 }
434 async fn accept_bi(&self) -> Result<(Self::SendStream, Self::RecvStream), Self::Error> {
435 std::future::pending().await
436 }
437 async fn open_bi(&self) -> Result<(Self::SendStream, Self::RecvStream), Self::Error> {
438 std::future::pending().await
439 }
440 async fn open_uni(&self) -> Result<Self::SendStream, Self::Error> {
441 std::future::pending().await
442 }
443 fn send_datagram(&self, _payload: Bytes) -> Result<(), Self::Error> {
444 Ok(())
445 }
446 async fn recv_datagram(&self) -> Result<Bytes, Self::Error> {
447 std::future::pending().await
448 }
449 fn max_datagram_size(&self) -> usize {
450 1200
451 }
452 fn protocol(&self) -> Option<&str> {
453 self.protocol
454 }
455 fn close(&self, _code: u32, _reason: &str) {}
456 async fn closed(&self) -> Self::Error {
457 std::future::pending().await
458 }
459 }
460
461 #[derive(Clone, Default)]
462 struct FakeSend;
463 impl web_transport_trait::SendStream for FakeSend {
464 type Error = FakeError;
465 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
466 Ok(buf.len())
467 }
468 fn set_priority(&mut self, _order: u8) {}
469 fn finish(&mut self) -> Result<(), Self::Error> {
470 Ok(())
471 }
472 fn reset(&mut self, _code: u32) {}
473 async fn closed(&mut self) -> Result<(), Self::Error> {
474 Ok(())
475 }
476 }
477
478 struct FakeRecv {
479 data: VecDeque<u8>,
480 }
481 impl web_transport_trait::RecvStream for FakeRecv {
482 type Error = FakeError;
483 async fn read(&mut self, dst: &mut [u8]) -> Result<Option<usize>, Self::Error> {
484 if self.data.is_empty() {
485 return Ok(None);
486 }
487 let size = dst.len().min(self.data.len());
488 for slot in dst.iter_mut().take(size) {
489 *slot = self.data.pop_front().unwrap();
490 }
491 Ok(Some(size))
492 }
493 fn stop(&mut self, _code: u32) {}
494 async fn closed(&mut self) -> Result<(), Self::Error> {
495 Ok(())
496 }
497 }
498
499 fn lite05_setup(path: Option<&str>) -> Vec<u8> {
501 let v = lite::Version::Lite05Wip;
502 let mut buf = Vec::new();
503 lite::DataType::Setup.encode(&mut buf, v).unwrap();
504 lite::Setup {
505 path: path.map(str::to_string),
506 }
507 .encode(&mut buf, v)
508 .unwrap();
509 buf
510 }
511
512 fn lite05_group() -> Vec<u8> {
514 let mut buf = Vec::new();
515 lite::DataType::Group
516 .encode(&mut buf, lite::Version::Lite05Wip)
517 .unwrap();
518 buf
519 }
520
521 #[tokio::test(start_paused = true)]
522 async fn accept_request_reads_lite05_path() {
523 let session = FakeSession::new(ALPN_LITE_05_WIP, [lite05_setup(Some("/team/room"))]);
524 let request = Server::new()
525 .with_versions(Version::Lite(lite::Version::Lite05Wip).into())
526 .accept_request(session)
527 .await
528 .unwrap();
529 assert_eq!(request.path(), Some("/team/room"));
530 }
531
532 #[tokio::test(start_paused = true)]
533 async fn accept_request_lite05_without_path_is_none() {
534 let session = FakeSession::new(ALPN_LITE_05_WIP, [lite05_setup(None)]);
535 let request = Server::new()
536 .with_versions(Version::Lite(lite::Version::Lite05Wip).into())
537 .accept_request(session)
538 .await
539 .unwrap();
540 assert_eq!(request.path(), None);
541 }
542
543 #[tokio::test(start_paused = true)]
544 async fn accept_request_skips_uni_stream_before_setup() {
545 let session = FakeSession::new(ALPN_LITE_05_WIP, [lite05_group(), lite05_setup(Some("/team/room"))]);
548 let request = Server::new()
549 .with_versions(Version::Lite(lite::Version::Lite05Wip).into())
550 .accept_request(session)
551 .await
552 .unwrap();
553 assert_eq!(request.path(), Some("/team/room"));
554 }
555}