1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use std::time::Duration;
use crate::proto::{TransportParams, DEFAULT_MAX_RECORD_SIZE};
use crate::Version;
/// How the application-level protocol is determined for a session.
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub enum Protocol {
/// No application protocol.
#[default]
None,
/// Advertise these protocols and negotiate one in-band, via the QMux
/// `application_protocols` transport parameter (preference order).
///
/// For transports without ALPN (TCP, Unix sockets). Both peers must opt in:
/// receiving the parameter while *not* in this mode is a protocol error.
/// The agreed protocol is surfaced by
/// [`Session::protocol`](web_transport_trait::Session::protocol), resolved
/// by the time [`Session::connect`](crate::Session::connect) /
/// [`accept`](crate::Session::accept) returns.
Negotiate(Vec<String>),
/// Already negotiated out of band (TLS / WebSocket ALPN). Reported as-is;
/// the `application_protocols` parameter is never sent, and receiving it is
/// a protocol error.
Negotiated(String),
}
/// Configuration for a QMux session.
///
/// Construct with [`Config::new`] (or [`Config::negotiated`]) and set the public
/// fields you need; the struct is `#[non_exhaustive]` so new fields can be added
/// without breaking callers. For the common transports, prefer the higher-level
/// [`tcp`](crate::tcp) / [`uds`](crate::uds) builders, which wrap this.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct Config {
/// Wire format version.
pub version: Version,
/// How the application protocol is determined. See [`Protocol`].
pub protocol: Protocol,
/// Max concurrent bidirectional streams the peer can open.
pub max_streams_bidi: u64,
/// Max concurrent unidirectional streams the peer can open.
pub max_streams_uni: u64,
/// Connection-level receive window in bytes.
pub max_data: u64,
/// Per-stream receive window for bidi streams we initiate.
pub max_stream_data_bidi_local: u64,
/// Per-stream receive window for bidi streams the peer initiates.
pub max_stream_data_bidi_remote: u64,
/// Per-stream receive window for uni streams.
pub max_stream_data_uni: u64,
/// Idle timeout in milliseconds (0 = disabled). Only used in QMux01.
pub max_idle_timeout: u64,
/// Maximum QMux Record size in bytes (draft-01). Default: 16382.
pub max_record_size: u64,
/// How long [`Session::connect`](crate::Session::connect) /
/// [`accept`](crate::Session::accept) waits for the peer's transport
/// parameters before giving up. Bounds the handshake so a peer that completes
/// the transport connection but never sends its parameters can't hang
/// establishment forever. Default: 10s; a zero duration disables the timeout
/// (wait indefinitely).
pub handshake_timeout: Duration,
}
impl Default for Config {
fn default() -> Self {
Self {
version: Version::QMux01,
protocol: Protocol::None,
max_streams_bidi: 100,
max_streams_uni: 100,
max_data: 1_048_576, // 1 MB
max_stream_data_bidi_local: 262_144, // 256 KB
max_stream_data_bidi_remote: 262_144, // 256 KB
max_stream_data_uni: 262_144, // 256 KB
max_idle_timeout: 30_000, // 30 seconds
max_record_size: DEFAULT_MAX_RECORD_SIZE,
handshake_timeout: Duration::from_secs(10),
}
}
}
impl Config {
/// Create a config with default flow control values and no application
/// protocol. Set [`Config::protocol`] to negotiate one.
pub fn new(version: Version) -> Self {
Self {
version,
..Default::default()
}
}
/// Create a config whose protocol was already negotiated out of band
/// (TLS / WebSocket ALPN). `protocol` is the chosen name, or `None`.
pub fn negotiated(version: Version, protocol: Option<String>) -> Self {
Self {
protocol: match protocol {
Some(name) => Protocol::Negotiated(name),
None => Protocol::None,
},
..Self::new(version)
}
}
/// Convert to wire-format transport parameters.
pub(crate) fn to_transport_params(&self) -> TransportParams {
TransportParams {
max_idle_timeout: self.max_idle_timeout,
initial_max_data: self.max_data,
initial_max_stream_data_bidi_local: self.max_stream_data_bidi_local,
initial_max_stream_data_bidi_remote: self.max_stream_data_bidi_remote,
initial_max_stream_data_uni: self.max_stream_data_uni,
initial_max_streams_bidi: self.max_streams_bidi,
initial_max_streams_uni: self.max_streams_uni,
max_record_size: self.max_record_size,
// Only advertise protocols when negotiating in-band; TLS/WS already
// chose one via ALPN and must not send this parameter.
protocols: match &self.protocol {
Protocol::Negotiate(list) => list.clone(),
Protocol::None | Protocol::Negotiated(_) => Vec::new(),
},
}
}
}