moqtap_client/draft17/session/setup.rs
1use crate::draft17::session::request_id::Role;
2use moqtap_codec::draft17::message::Setup;
3use moqtap_codec::varint::VarInt;
4
5/// The PATH setup parameter. It is the one setup parameter whose sender is
6/// restricted, and the restriction runs one way: PATH is the client's.
7const PATH: u64 = 0x01;
8
9/// Errors from setup message validation.
10#[derive(Debug, thiserror::Error, PartialEq, Eq)]
11pub enum SetupError {
12 /// A required setup parameter is missing.
13 #[error("missing required parameter: {0}")]
14 MissingParameter(
15 /// Name of the missing parameter.
16 &'static str,
17 ),
18 /// A setup parameter was sent by the endpoint that may not send it.
19 #[error("setup option {0:#x} may not be sent by a {1:?}")]
20 WrongOptionRole(
21 /// Key of the offending parameter.
22 u64,
23 /// The endpoint that sent it.
24 Role,
25 ),
26 /// A PATH parameter was offered on a session that is not native QUIC.
27 #[error("PATH may not be used when WebTransport is used")]
28 PathOverWebTransport,
29}
30
31/// Validate a unified SETUP message from the endpoint named by `sender`.
32///
33/// Draft-17 merges the two setup messages into one and uses ALPN for version
34/// negotiation, so there are no versions to check and nothing in the message
35/// itself says which end sent it. That makes the sender an argument: Section
36/// 9.4.1.2 says the PATH parameter "MUST NOT be used by the server", and with
37/// one message type for both directions the caller is the only thing that
38/// knows which direction this is.
39///
40/// # Errors
41///
42/// [`SetupError::WrongOptionRole`] if a server sent a PATH.
43pub fn validate_setup(msg: &Setup, sender: Role) -> Result<(), SetupError> {
44 if sender == Role::Server && has_path(&msg.options) {
45 return Err(SetupError::WrongOptionRole(PATH, sender));
46 }
47 Ok(())
48}
49
50/// Refuse a PATH parameter on a session that is not native QUIC.
51///
52/// The same sentence in Section 9.4.1.2 forbids PATH "when WebTransport is
53/// used". Which transport carries the session is known to the connection and
54/// not to the endpoint, so this is a separate call.
55///
56/// # Errors
57///
58/// [`SetupError::PathOverWebTransport`] if a PATH is offered over
59/// WebTransport.
60pub fn validate_client_path_transport(
61 options: &[moqtap_codec::kvp::KeyValuePair],
62 over_webtransport: bool,
63) -> Result<(), SetupError> {
64 if over_webtransport && has_path(options) {
65 return Err(SetupError::PathOverWebTransport);
66 }
67 Ok(())
68}
69
70fn has_path(options: &[moqtap_codec::kvp::KeyValuePair]) -> bool {
71 let path = VarInt::from_u64(PATH).unwrap();
72 options.iter().any(|o| o.key == path)
73}