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