Skip to main content

moqtap_client/draft20/session/
setup.rs

1use crate::draft20::session::request_id::Role;
2use moqtap_codec::draft20::message::Setup;
3use moqtap_codec::varint::VarInt;
4
5/// The PATH setup option. It is the one setup option 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 option is missing.
13    #[error("missing required parameter: {0}")]
14    MissingParameter(
15        /// Name of the missing option.
16        &'static str,
17    ),
18    /// A setup option 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 option.
22        u64,
23        /// The endpoint that sent it.
24        Role,
25    ),
26    /// A PATH option 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-20 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/// 10.3.1.2 says the PATH option "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 option on a session that is not native QUIC.
51///
52/// The same sentence in Section 10.3.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}