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
//! The inbound bound that holds before a connection is admitted.
//!
//! Until a `Connect` has been accepted, the only frame a connection can
//! legitimately need is that `Connect`. Every other frame either tears an
//! authenticated server's connection down or is a pre-handshake courtesy
//! (`Ping`, `Disconnect`) a few bytes long. Buffering an unadmitted peer's
//! message up to the generic `u32` frame ceiling would let any socket that
//! completed a TCP or WebSocket handshake make the server hold gigabytes
//! before a single credential is checked. Both transports therefore refuse,
//! by name and before buffering, any inbound frame or reassembled message
//! larger than [`PRE_ADMISSION_FRAME_BOUND`] until the `Connect` succeeds; the
//! negotiated bound applies from then on exactly as before.
use ;
use GENERIC_HEADER_LEN;
/// Bytes a complete `Connect` frame needs besides its opaque auth token: the
/// generic header, the minimum and maximum protocol versions, and the token's
/// `u32` length prefix. Derived from the codec's own field widths so it moves
/// with them.
pub const CONNECT_FIXED_BYTES: usize =
GENERIC_HEADER_LEN + 2 * WIRE_LEN + ;
/// Largest complete inbound frame (or reassembled WebSocket message) accepted
/// from a connection whose `Connect` has not yet succeeded.
///
/// A `Connect` is [`CONNECT_FIXED_BYTES`] plus its token. The token is either
/// the operator's bearer token, held to [`MAX_CONNECT_AUTH_TOKEN_BYTES`] at
/// configuration load, or a registry pass: 134 fixed bytes plus its
/// participant id, its live label, and eight bytes per scoped conversation. A
/// pass naming several thousand conversations fits, which is two orders of
/// magnitude beyond any pass minted today; the bound is still four orders of
/// magnitude below the generic frame ceiling it replaces before admission.
pub const PRE_ADMISSION_FRAME_BOUND: usize = 64 * 1024;
/// Largest auth token a `Connect` can carry and still fit
/// [`PRE_ADMISSION_FRAME_BOUND`]. A configured bearer token longer than this
/// could never be presented, so configuration validation refuses it.
pub const MAX_CONNECT_AUTH_TOKEN_BYTES: usize = PRE_ADMISSION_FRAME_BOUND - CONNECT_FIXED_BYTES;
/// The name every pre-admission oversize refusal carries, on every
/// transport: the TCP `ConnectError` message and the WebSocket close reason
/// both begin with it, so a client reads one name whichever door it used.
pub const REFUSAL_NAME: &str = "FrameTooLarge before admission";
/// An inbound frame or message refused because it exceeded
/// [`PRE_ADMISSION_FRAME_BOUND`] before the connection was admitted.
/// The byte-stream transport's answer to a refusal: a `ConnectError` whose
/// message is the refusal by name.
/// Checks the complete-frame size a buffered generic header declares against
/// the pre-admission bound.
///
/// Returns `Ok` once `admitted`, while fewer than a header's bytes are
/// buffered, or when the declared frame fits. The check reads only the
/// header's length field, so it refuses before the declared body is buffered.
///
/// # Errors
/// Returns [`PreAdmissionOversize`] when an unadmitted connection's buffered
/// header declares a complete frame larger than [`PRE_ADMISSION_FRAME_BOUND`].