moqtap_codec/error.rs
1/// Maximum control message payload length: 2^16 - 1 bytes.
2pub const MAX_MESSAGE_LENGTH: usize = 65535;
3/// Maximum reason phrase length: 1024 bytes.
4pub const MAX_REASON_PHRASE_LENGTH: usize = 1024;
5/// Maximum GOAWAY new session URI length: 8192 bytes.
6pub const MAX_GOAWAY_URI_LENGTH: usize = 8192;
7/// Maximum full track name length: 4096 bytes.
8pub const MAX_FULL_TRACK_NAME_LENGTH: usize = 4096;
9/// Maximum track namespace tuple size: 32 elements.
10pub const MAX_NAMESPACE_TUPLE_SIZE: usize = 32;
11
12/// Errors produced during MoQT message encoding and decoding.
13///
14/// # Adding a variant
15///
16/// This enum is deliberately **not** `#[non_exhaustive]`, so that a session-close
17/// table matching it exhaustively fails to compile until a new variant has been
18/// placed on each of the drafts — either among the rules that draft
19/// answers with a close or among the ones it names and does not. A wildcard arm
20/// would make each draft's decision silently, all in the direction of "no
21/// rule", and a missing arm and a deliberate exclusion look identical from
22/// inside such a table.
23#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
24pub enum CodecError {
25 /// Unknown or unsupported message type identifier.
26 #[error("unknown message type: 0x{0:x}")]
27 UnknownMessageType(u64),
28 /// Not enough bytes in the buffer to complete decoding.
29 #[error("insufficient bytes")]
30 UnexpectedEnd,
31 /// Control message payload exceeds [`MAX_MESSAGE_LENGTH`].
32 #[error("message too long: {0} bytes (max {MAX_MESSAGE_LENGTH})")]
33 MessageTooLong(usize),
34 /// Variable-length integer encoding/decoding error.
35 #[error("varint error: {0}")]
36 VarInt(#[from] crate::varint::VarIntError),
37 /// Key-value pair encoding/decoding error.
38 #[error("kvp error: {0}")]
39 Kvp(#[from] crate::kvp::KvpError),
40 /// A decoded field value is not valid for its type.
41 #[error("invalid field value")]
42 InvalidField,
43 /// Namespace tuple element count is outside the range the caller allows.
44 ///
45 /// The upper bound is [`MAX_NAMESPACE_TUPLE_SIZE`] everywhere. The lower
46 /// bound is per-draft, and three wordings carry two rules. Drafts 07
47 /// through 14 define a Track Namespace as "an ordered N-tuple of bytes
48 /// where N can be between 1 and 32"; drafts 15 and 16 rename the elements
49 /// to Track Namespace Fields and keep the 1; drafts 17 and later lower it
50 /// to 0. So an empty tuple is refused only through draft-16.
51 #[error("namespace tuple size {0} is not allowed here (max {MAX_NAMESPACE_TUPLE_SIZE})")]
52 InvalidNamespaceTupleSize(usize),
53 /// A Track Namespace Field was declared with a length of zero.
54 ///
55 /// Drafts 16 through 19 all carry the same sentence in Section 2.4.1: "Each
56 /// Track Namespace Field Value MUST contain at least one byte. If an
57 /// endpoint receives a Track Namespace Field with a Track Namespace Field
58 /// Length of 0, it MUST close the session with a PROTOCOL_VIOLATION."
59 #[error("track namespace field is empty; each field must contain at least one byte")]
60 EmptyNamespaceField,
61 /// Full track name exceeds [`MAX_FULL_TRACK_NAME_LENGTH`].
62 #[error("track namespace or full track name exceeds {MAX_FULL_TRACK_NAME_LENGTH} bytes")]
63 TrackNameTooLong,
64 /// A requested range ends before it starts.
65 ///
66 /// Every draft states it, in the wording its fields have at the time.
67 /// Draft-07 Section 6.4 and Section 6.7: "EndGroup and EndObject MUST
68 /// specify the same or a later object than StartGroup and StartObject".
69 /// Draft-08 Section 7.4 through draft-14 Section 9.7, for the AbsoluteRange
70 /// filter: "End Group MUST specify the same or a larger Group than
71 /// specified in Start". Draft-12 Section 8.16 onwards, for FETCH: "End
72 /// Location MUST specify the same or a larger Location than Start
73 /// Location", which drafts 14 and later qualify with "for Standalone and
74 /// Absolute Joining Fetches".
75 ///
76 /// The two ends are reported as they appear on the wire, before the
77 /// draft's plus-one adjustments are undone, so the numbers here are the
78 /// ones a peer would read out of the frame.
79 #[error("range from group {0} object {1} ends at group {2} object {3}, which is earlier")]
80 InvalidRange(u64, u64, u64, u64),
81 /// A parameter's value is not the shape the parameter's own type implies.
82 ///
83 /// Drafts 07 through 10 state it once each, in the section that gives the
84 /// Parameter format: "If a receiver understands a parameter type, and the
85 /// parameter length implied by that type does not match the Parameter Length
86 /// field, the receiver MUST terminate the session with error code 'Parameter
87 /// Length Mismatch'." Each of those drafts assigns that code its own number
88 /// in the session termination registry. Drafts 11 and later drop the
89 /// sentence along with the Parameter framing it describes.
90 ///
91 /// The parameter reported is the one whose value disagreed with its type.
92 /// Which namespace the type is read in matters: a setup 0x02 is a
93 /// MAX_SUBSCRIBE_ID integer and a version-specific 0x02 is an
94 /// AUTHORIZATION INFO string.
95 #[error("parameter type {0} carries a value of the wrong length for its type")]
96 ParameterLengthMismatch(u64),
97 /// A key-value pair's value is not the serialization its own Type defines.
98 ///
99 /// Drafts 11 through 19 state it once each, in the section that gives the
100 /// Key-Value-Pair format. Drafts 14 and 15 word it: "If a receiver
101 /// understands a Type, and the following Value or Length/Value does not
102 /// match the serialization defined by that Type, the receiver MUST
103 /// terminate the session with error code KEY_VALUE_FORMATTING_ERROR".
104 /// Drafts 16 through 19 say close where those two say terminate, and
105 /// drafts 11 through 13 spell the code 'Key-Value Formatting Error'. Every
106 /// one of the nine assigns it a number in the session termination
107 /// registry.
108 ///
109 /// This is the successor to [`CodecError::ParameterLengthMismatch`], which
110 /// drafts 07 through 10 state about the Parameter framing they had instead.
111 /// The two never overlap: no draft states both, and the earlier rule is
112 /// about a declared length disagreeing with a type while this one is about
113 /// the bytes themselves.
114 ///
115 /// The rule is conditional on understanding the Type, so it reaches only the
116 /// types a draft defines a serialization for. A parameter this codec cannot
117 /// name carries bytes no rule here describes, and refusing it would close
118 /// sessions over extensions the drafts leave room for.
119 ///
120 /// `key` is the parameter type as the frame spelled it, in the namespace it
121 /// was read in — AUTHORIZATION TOKEN is 0x01 on draft-11 and 0x03 on drafts
122 /// 12 through 19, and a setup 0x01 is a PATH on draft-11 rather than a token
123 /// at all. `detail` says which way the value failed to match, because the
124 /// serialization is a structure rather than a length and "malformed" alone
125 /// leaves the reader to re-derive it.
126 #[error(
127 "key-value pair of type {key} does not match the serialization that type defines: {detail}"
128 )]
129 KeyValueFormatting {
130 /// The parameter type whose value did not match, as the frame spelled
131 /// it.
132 key: u64,
133 /// How the value failed to match the serialization.
134 detail: &'static str,
135 },
136 /// A control message carried a Message Parameter whose type its draft does
137 /// not define.
138 ///
139 /// Drafts 16, 17, 18 and 19 state it in the paragraph that introduces
140 /// parameters: "All Message Parameters MUST be defined in the negotiated
141 /// version of MOQT or negotiated via Setup Options. An endpoint that
142 /// receives an unknown Message Parameter MUST close the session with
143 /// PROTOCOL_VIOLATION." Drafts 17 and later add the reasoning — "Because the
144 /// receiver has to understand every Message Parameter, there is no need for
145 /// a mechanism to skip unknown parameters" — and draft-19 draws the
146 /// consequence for the framing: "Because unknown parameters cannot be
147 /// skipped, the block is bounded by a parameter count rather than a length."
148 /// Drafts 07 through 15 are the other way round and this must not reach
149 /// them. They say "Receivers MUST allow duplicates of unknown parameters",
150 /// which presumes unknown parameters arrive and are carried; refusing one
151 /// there would close a session over an extension those drafts leave room
152 /// for. Draft-16 is where the sentence narrows to *unknown **Setup**
153 /// Parameters*, in the same paragraph that adds the close — one edit, both
154 /// halves.
155 ///
156 /// Setup Parameters keep the older behaviour on every draft, which is why
157 /// this is about one namespace and not both. Drafts 16 through 19 all say a
158 /// receiver ignores an unrecognised Setup Option or Setup Parameter, so a
159 /// type unknown in that namespace is carried and only a type unknown in the
160 /// message namespace ends the session.
161 #[error("message parameter type {0} is not one this draft defines")]
162 UnknownMessageParameter(u64),
163 /// A Message Parameter appeared in a message type its own definition does
164 /// not name.
165 ///
166 /// Drafts 17, 18 and 19 only, and the split is the whole reason this is a
167 /// variant rather than a shared rule. All the drafts state the first
168 /// half the same way and ten of them state the opposite consequence.
169 /// Draft-19 Section 10.2.1, draft-18 Section 10.2.1 and draft-17 Section
170 /// 9.3.1: "Each Message Parameter definition indicates the message types in
171 /// which it can appear. If it appears in some other type of message, the
172 /// receiving endpoint MUST close the connection with a PROTOCOL_VIOLATION."
173 /// Draft-16 Section 9.2.2 and, under the older name Version Specific
174 /// Parameters, drafts 07 through 15, end the same sentence "it MUST be
175 /// ignored". Raising this on any of those ten would close a session over
176 /// traffic they oblige an endpoint to tolerate, so the decoder never does.
177 ///
178 /// What each draft's own text settles, and what it leaves open:
179 ///
180 /// * A parameter's scope is the set of message types named as the
181 /// destination of its "MAY appear in" sentence, with trailing and
182 /// parenthesised qualifiers read as describing one of those destinations
183 /// rather than adding another. Draft-17's LARGEST_OBJECT "MAY appear in
184 /// SUBSCRIBE_OK, PUBLISH or in REQUEST_OK (in response to REQUEST_UPDATE
185 /// or TRACK_STATUS)" scopes three message types, not five, which is how
186 /// drafts 18 and 19 write the same rule once the responses have names of
187 /// their own.
188 /// * Half the response names are one wire type. Draft-19 Section 10.5:
189 /// "This document uses the shorthand PUBLISH_OK, REQUEST_UPDATE_OK,
190 /// TRACK_STATUS_OK, SUBSCRIBE_NAMESPACE_OK, and PUBLISH_NAMESPACE_OK to
191 /// refer to a REQUEST_OK sent in response to the corresponding request
192 /// type." Which one a given REQUEST_OK is depends on the request its
193 /// Request ID answers, which is session state and not in the frame, so
194 /// every name that resolves to REQUEST_OK widens the same set and a
195 /// REQUEST_OK is held only to their union.
196 ///
197 /// Both readings err toward carrying the parameter, which is the direction
198 /// a rule that ends sessions should be wrong in.
199 ///
200 /// `key` is the absolute parameter type after any delta encoding is
201 /// resolved, and `message_type` is the type id off the wire, so a log names
202 /// the pair the sender actually wrote.
203 #[error("message parameter type {key} may not appear in message type {message_type}")]
204 ParameterOutOfScope {
205 /// The parameter type that was out of scope, absolute.
206 key: u64,
207 /// The message type it arrived in, as its id on the wire.
208 message_type: u64,
209 },
210 /// A Message Parameter carried a value outside the range its type allows.
211 ///
212 /// Drafts 15 through 19 give several parameters a range and answer anything
213 /// outside it with a close. GROUP_ORDER: "The allowed values are Ascending
214 /// (0x1) or Descending (0x2). If an endpoint receives a value outside this
215 /// range, it MUST close the session with PROTOCOL_VIOLATION." FORWARD says
216 /// the same of 0 and 1. Drafts 15 and 16 add SUBSCRIBER_PRIORITY — "The
217 /// range is restricted to 0-255" — which drafts 17 and later do not need,
218 /// having made the parameter a uint8 so that nothing outside the range can
219 /// be spelled. Draft-15 alone carries DYNAMIC_GROUPS as a Message Parameter,
220 /// where "Values larger than 1 are a Protocol Violation"; draft-16 moved it
221 /// into the extension header namespace, which this codec carries as opaque
222 /// bytes.
223 ///
224 /// Not draft-15's PUBLISHER_PRIORITY. It says "Priorities above 255 are
225 /// invalid" and stops there, naming no consequence, where every parameter
226 /// above states one in the next clause. The contrast is within one section,
227 /// so the omission is the draft's and not an oversight to be read past.
228 ///
229 /// Nor the Group Order and Forward *fields* of drafts 07 through 14, which
230 /// are a different serialization and are answered separately — Forward by
231 /// [`CodecError::InvalidForward`], Group Order by nothing, for the reason
232 /// given there.
233 ///
234 /// `key` is the absolute parameter type, after any delta encoding is
235 /// resolved, so a log names the type the sender meant rather than the
236 /// increment it wrote.
237 #[error(
238 "message parameter type {key} carries value {value}, which is outside the range it allows"
239 )]
240 ParameterValueOutOfRange {
241 /// The parameter type whose value was out of range, absolute.
242 key: u64,
243 /// The value as it arrived.
244 value: u64,
245 },
246 /// A Track Extension or Track Property carried a value outside the range its
247 /// type allows.
248 ///
249 /// A separate namespace from [`CodecError::ParameterValueOutOfRange`], and
250 /// separate for a reason rather than for tidiness: the two registries assign
251 /// the same numbers to different things. Type 0x22 is the GROUP_ORDER
252 /// Message Parameter and it is also DEFAULT_PUBLISHER_GROUP_ORDER, which is
253 /// a property of the track rather than a preference expressed by one
254 /// subscriber. Type 0x30 is DYNAMIC_GROUPS in the second namespace and is
255 /// unassigned in the first from draft-16 on. A single variant covering both
256 /// would name a type without saying which table to read it in.
257 ///
258 /// Draft-16 states the rules of the extension header namespace and drafts
259 /// 17, 18 and 19 restate them of the Track Property namespace that replaced
260 /// it. Two types restrict their range and answer anything outside it with a
261 /// close. DEFAULT_PUBLISHER_GROUP_ORDER: "The allowed values are Ascending
262 /// (0x1) or Descending (0x2). If an endpoint receives a value outside this
263 /// range, it MUST close the session with PROTOCOL_VIOLATION." DYNAMIC_GROUPS:
264 /// "The allowed values are 0 or 1... If an endpoint receives a value larger
265 /// than 1, it MUST close the session with PROTOCOL_VIOLATION."
266 ///
267 /// Draft-16 adds a third, and only draft-16: "DELIVERY_TIMEOUT, if present,
268 /// MUST contain a value greater than 0. If an endpoint receives a
269 /// DELIVERY_TIMEOUT equal to 0 it MUST close the session with
270 /// PROTOCOL_VIOLATION." Draft-17 renamed the type to
271 /// OBJECT_DELIVERY_TIMEOUT and states no range for it, so the rule ends
272 /// where the name does.
273 ///
274 /// Not DEFAULT_PUBLISHER_PRIORITY, on any of the four. "Priorities above 255
275 /// are invalid" names no consequence, in a section where its neighbours
276 /// name one in the next clause. The same contrast excludes draft-15's
277 /// PUBLISHER_PRIORITY from [`CodecError::ParameterValueOutOfRange`], and it
278 /// is the draft's distinction both times.
279 ///
280 /// `key` is the absolute type, after any delta encoding is resolved.
281 #[error(
282 "track property type {key} carries value {value}, which is outside the range it allows"
283 )]
284 TrackPropertyValueOutOfRange {
285 /// The extension or property type whose value was out of range,
286 /// absolute.
287 key: u64,
288 /// The value as it arrived.
289 value: u64,
290 },
291 /// A Forward field carried a value other than zero or one.
292 ///
293 /// Drafts 11 through 14 carry the field, and state the rule in two wordings.
294 /// SUBSCRIBE and SUBSCRIBE_UPDATE, on all four: "Forward: If 1, Objects
295 /// matching the subscription are forwarded to the subscriber. If 0, Objects
296 /// are not forwarded to the subscriber. Any other value is a protocol error
297 /// and MUST terminate the session with a Protocol Violation". PUBLISH, added
298 /// in draft-12: "Any value other than 0 or 1 is a Protocol Violation."
299 /// Draft-14 spells both codes PROTOCOL_VIOLATION and is otherwise unchanged.
300 ///
301 /// PUBLISH_OK, also from draft-12, is the one site that names no
302 /// consequence: "Forward: The Forward State for this subscription, either 0
303 /// (don't forward) or 1 (forward)." It is reported here all the same. The
304 /// field carries the same two values in every message that has one, three of
305 /// the four sites state the close outright, and the sentence enumerates 0
306 /// and 1 without giving a third value any meaning — so this is the same rule
307 /// stated shorter, not a permission. Reading an omission the other way is
308 /// how a wrong claim gets in: on Group Order, drafts 12 through 14 do state
309 /// the 0x0 rule for SUBSCRIBE_OK, PUBLISH and FETCH_OK, so a reading that has
310 /// them silent about it is wrong about all three.
311 ///
312 /// Drafts 07 through 10 have no such field. Drafts 15 and later carry
313 /// forwarding as the FORWARD parameter instead, under the same rule but a
314 /// different serialization; that form is
315 /// [`CodecError::ParameterValueOutOfRange`].
316 #[error("forward field carries {0}, which is neither zero nor one")]
317 InvalidForward(u8),
318 /// A subscription filter names a Filter Type no draft in its range assigns.
319 ///
320 /// Every draft with a Filter Type states the rule, and they do not state
321 /// the same consequence. Drafts 20 and 21 have no Filter Type: their
322 /// filter's shape comes from its length. Drafts 07 through 13: "A filter
323 /// type other than the above MUST be treated as error", which names no code
324 /// and no close. Draft-14:
325 /// "An endpoint that receives a filter type other than the above MUST be
326 /// close the session with PROTOCOL_VIOLATION", the typo being the draft's.
327 /// Drafts 15 through 19 say the same without the typo, and draft-22, whose
328 /// `Location Filter Type` numbers its forms afresh, writes it as "Any other
329 /// Location Filter Type is a PROTOCOL_VIOLATION." So the same value in the
330 /// same place is a refused message on the first seven drafts and a session
331 /// close on the later ones, and only the per-draft session table can tell
332 /// them apart.
333 ///
334 /// The assigned set is not constant either. Drafts 07 and 08 assign 0x1 as
335 /// Latest Group, drafts 09 and 10 withdraw it and list three types, and
336 /// drafts 11 and later reinstate 0x1 as Next Group Start — a different
337 /// meaning at the same number. A decoder that accepts the union would read a
338 /// draft-09 SUBSCRIBE the draft requires it to reject.
339 ///
340 /// The serialization moves as well. Drafts 07 through 14 carry the Filter
341 /// Type as a field of SUBSCRIBE and its relatives; drafts 15 through 19
342 /// carry it as the first field inside the length-prefixed filter parameter,
343 /// which is a place a reader of the field has to know to look. Draft-22
344 /// carries it first in a LOCATION_FILTER parameter that has no length at
345 /// all, so there an unknown type leaves the reader unable to find the end
346 /// of the parameter, let alone the next one.
347 #[error("filter type {0} is not one this draft assigns")]
348 InvalidFilterType(u64),
349 /// A FETCH names a Fetch Type no draft in its range assigns.
350 ///
351 /// The sentence next to the Filter Type one, and it moves the same way.
352 /// Drafts 08 through 13: "A Fetch Type other than 0x1, 0x2 or 0x3 MUST be
353 /// treated as an error", naming no code and no close — 0x3 being absent from
354 /// the sentence on drafts 08, 09 and 10, which assign only two types.
355 /// Draft-14: "An endpoint that receives a Fetch Type other than 0x1, 0x2 or
356 /// 0x3 MUST be close the session with a PROTOCOL_VIOLATION", carrying the
357 /// same missing word as its Filter Type sentence. Drafts 15 through 19 say it
358 /// without the typo. Draft-07 has no FETCH at all.
359 ///
360 /// Like the Filter Type, the value decides which fields follow it: a
361 /// Standalone fetch carries a Track Namespace, a Track Name and a range, and
362 /// a joining fetch carries a Request ID and an offset. A reader that cannot
363 /// name the type cannot find the end of the message, which is why the later
364 /// drafts answer it with a close rather than by ignoring the field.
365 #[error("fetch type {0} is not one this draft assigns")]
366 InvalidFetchType(u64),
367 /// A subscription filter parameter's value is not a filter.
368 ///
369 /// Drafts 15 and 16 state it of this parameter directly: "If the length of
370 /// the Subscription Filter does not match the parameter length, the publisher
371 /// MUST close the session with PROTOCOL_VIOLATION." Drafts 17 through 19
372 /// drop that sentence and leave the general one, which every draft from 15
373 /// on also carries: "If a receiver understands a Type, and the following
374 /// Value or Length/Value does not match the serialization defined by that
375 /// Type, the receiver MUST close the session with error code
376 /// KEY_VALUE_FORMATTING_ERROR."
377 ///
378 /// Two sentences, two codes, one malformation — which is why this is a
379 /// variant of its own rather than reported as
380 /// [`CodecError::KeyValueFormatting`]. A filter three bytes long inside a
381 /// four-byte parameter ends a draft-16 session with PROTOCOL_VIOLATION and a
382 /// draft-17 session with KEY_VALUE_FORMATTING_ERROR, and the session tables
383 /// are where that difference belongs.
384 ///
385 /// A Filter Type outside the assigned set is not this: the filter's own
386 /// section names PROTOCOL_VIOLATION for that on all five drafts, and it is
387 /// [`CodecError::InvalidFilterType`].
388 ///
389 /// `detail` says which way the value failed, because "malformed" alone
390 /// leaves the reader to work out whether the filter ran short or the
391 /// parameter ran long.
392 #[error("subscription filter parameter is not a filter: {detail}")]
393 SubscriptionFilterMalformed {
394 /// How the value failed to be a filter.
395 detail: &'static str,
396 },
397 /// An AbsoluteRange filter's End Group Delta carries the range past the end
398 /// of the number space.
399 ///
400 /// Drafts 17 and later replaced the absolute End Group with a delta measured
401 /// from the Start Location's Group, which makes the last group in range a
402 /// sum rather than a field. Drafts 18 and 19 answer the sum leaving the
403 /// range: "Otherwise, the last Group ID to be delivered will be the Group ID
404 /// in Start Location plus the End Group Delta. If the resulting Group ID
405 /// would be greater than 2^64 - 1, the endpoint MUST close the session with
406 /// a PROTOCOL_VIOLATION."
407 ///
408 /// Draft-17 introduced the delta and states no such sentence, so it is
409 /// absent from that draft's session table. Drafts 15 and 16 write the End
410 /// Group out in full and can express nothing to overflow.
411 #[error(
412 "filter start group {start_group} plus end group delta {delta} leaves the 64-bit range"
413 )]
414 FilterEndGroupOverflow {
415 /// The Group ID of the filter's Start Location.
416 start_group: u64,
417 /// The End Group Delta as the filter carried it.
418 delta: u64,
419 },
420 /// An end-of-track object states an Object ID other than zero.
421 ///
422 /// Drafts 08, 09 and 10 describe Object Status 0x5 as "end of Track. GroupID
423 /// is one greater than the largest group produced in this track and the
424 /// ObjectId is zero", and continue: "An object with this status that has a
425 /// Group ID less than or equal to any other Group ID, or an Object ID other
426 /// than zero, is a protocol error, and the receiver MUST terminate the
427 /// session." The Group ID half needs the largest group seen on the track and
428 /// is not settleable from one header; the Object ID half is, and is what this
429 /// reports. Draft-07 assigns no 0x5 and drafts 11 and later drop the
430 /// sentence.
431 #[error("end-of-track object states object id {0}; an end of track ends at object zero")]
432 EndOfTrackObjectId(u64),
433 /// A delta-encoded key would exceed 2^64 - 1 once the delta is added to the
434 /// previous key.
435 ///
436 /// Drafts 16, 17, 18 and 19 all say, in Section 1.4.3: "The previous Type
437 /// value plus the Delta Type MUST NOT be greater than 2^64 - 1. If a Delta
438 /// Type is received that would be too large, the Session MUST be closed
439 /// with a PROTOCOL_VIOLATION." Delta encoding arrives with draft-16;
440 /// drafts 15 and earlier write absolute types and cannot reach this.
441 #[error("delta-encoded key {0} + {1} exceeds 2^64 - 1")]
442 KeyDeltaOverflow(u64, u64),
443 /// A caller asked to encode a parameter list that is not in ascending order
444 /// by type.
445 ///
446 /// Drafts 17, 18 and 19 require it in as many words: "Parameters MUST be
447 /// serialized in ascending order by Type." Draft-16 delta-encodes types
448 /// without stating that sentence, but the constraint is the same there and
449 /// is structural rather than stated: the delta is an unsigned difference
450 /// from the previous type, so a descending pair has no representation at
451 /// all. Encoding one anyway wraps the subtraction and emits a nine-byte
452 /// delta the peer resolves to an unrelated key, which is why draft-16
453 /// reports this too.
454 #[error("parameter type {1} follows {0}; parameters must be in ascending order by type")]
455 ParametersOutOfOrder(u64, u64),
456 /// The same parameter type appears twice in one message, and its definition
457 /// does not allow that.
458 ///
459 /// Every draft from 07 to 20 states the sender's half: "Senders MUST NOT
460 /// repeat the same Parameter Type in a message" — drafts 11 and later
461 /// adding "unless the parameter definition explicitly allows multiple
462 /// instances of that type to be sent in a single message." The receiver's
463 /// half is a SHOULD, and from draft-11 it carries a limit that makes the
464 /// rule asymmetric: "Receivers MUST allow duplicates of unknown
465 /// parameters." A receiver may therefore refuse a repeat only of a type its
466 /// own draft names, while a sender may repeat nothing it is not granted.
467 ///
468 /// One type is granted repeats, from draft-11 onward: AUTHORIZATION TOKEN,
469 /// numbered 0x01 on draft-11 and 0x03 on drafts 12 through 19. It is not
470 /// reported here. Drafts 07 through 10 state neither the exemption clause
471 /// nor the unknown-duplicates sentence, so on those four the rule is
472 /// symmetric and every repeat is refused in both directions.
473 ///
474 /// Setup Parameters and Version Specific Parameters are separate
475 /// namespaces that assign different meanings to the same number, so the
476 /// exemption is per namespace: on draft-11, 0x01 is the repeatable
477 /// AUTHORIZATION TOKEN in a SUBSCRIBE and the non-repeatable PATH in a
478 /// CLIENT_SETUP.
479 #[error("parameter type {0} appears more than once")]
480 DuplicateParameter(u64),
481 /// A delta-encoded Object ID would exceed 2^64 - 1 once the delta is added
482 /// to the previous Object ID on the same stream.
483 ///
484 /// Drafts 18 through 20 Section 11.4.2, and drafts 21 through 23 Section 11.3.1: "The
485 /// Object ID Delta + 1 is added to the previous Object ID in the Subgroup
486 /// stream if there was one... If the resulting Object ID would be greater
487 /// than 2^64 - 1, the endpoint MUST close the session with a
488 /// PROTOCOL_VIOLATION."
489 ///
490 /// Drafts 14 through 17 Section 10.4.2 describe the same arithmetic and
491 /// state no consequence, so on those four this is a decode failure and
492 /// nothing more. The delta encoding does not exist before draft-14, which
493 /// is why the range starts there rather than at the first draft with a
494 /// subgroup stream.
495 ///
496 /// Distinct from [`CodecError::InvalidField`], which is too coarse for this
497 /// rule: a caller could not tell the wrap from a dozen unrelated
498 /// malformations, and so could not act on the rule.
499 #[error("object id {0} + {1} + 1 exceeds 2^64 - 1")]
500 ObjectIdOverflow(u64, u64),
501 /// An Object with Object Status 'Object Does Not Exist' carries extension
502 /// headers.
503 ///
504 /// Drafts 11 through 14 state it once each — draft-11 Section 9.1.1.2,
505 /// drafts 12 and 13 Section 9.2.1.2, draft-14 Section 10.2.1.2 — and the
506 /// first three word it: "Any Object may have extension headers except those
507 /// with Object Status 'Object Does Not Exist'. If an endpoint receives a
508 /// non-existent Object containing extension headers it MUST close the
509 /// session with a Protocol Violation." Draft-14 states the same sentence
510 /// with the code spelled PROTOCOL_VIOLATION.
511 ///
512 /// The rule names one status and no others, so extensions beside End of
513 /// Group or End of Track are legal on those four drafts and are not
514 /// reported here. Drafts 15 and later replaced this narrow form with the
515 /// general one — extensions, later properties, are permitted only beside
516 /// Normal — which is a different rule with a different subject and is
517 /// reported by the carriers' own `extensions_permitted` predicates.
518 ///
519 /// Drafts 07 through 10 state neither form.
520 ///
521 /// All three carriers that announce a status reach this, in both
522 /// directions: an object on a subgroup stream, an object on a fetch stream,
523 /// and a status datagram. A plain datagram has no status field and is the
524 /// one carrier that cannot break the rule.
525 ///
526 /// Distinct from [`CodecError::InvalidField`], which is too coarse for this
527 /// rule: a caller could not tell it from a dozen unrelated malformations, so
528 /// a session could not be closed over it without closing sessions the drafts
529 /// do not ask to be closed.
530 #[error("object with status 'object does not exist' carries {0} bytes of extension headers")]
531 ExtensionsOnNonExistentObject(usize),
532 /// An object's property block (Extension Headers before draft-17) cannot be
533 /// read as Key-Value-Pairs: a property runs past the end of the block, or
534 /// Immutable Properties hold another Immutable Properties.
535 ///
536 /// Either one makes the Track malformed: draft-14 and draft-16 Section
537 /// 11.2, draft-15 Section 11.1, draft-17 Section 11.6, drafts 18-20 Section
538 /// 12.7, drafts 21-23 Section 10.7. No draft closes the session over it.
539 ///
540 /// Raised by the readers that hand back a whole object. The framing readers
541 /// a relay uses delimit the block by its length and never read inside it.
542 #[error("malformed property block at byte {offset}: {detail}")]
543 MalformedObjectProperties {
544 /// Where in the block the property that cannot be read begins.
545 offset: usize,
546 /// What is wrong with it.
547 detail: String,
548 },
549 /// An object arrived carrying a payload the draft gives it no room for.
550 ///
551 /// All the drafts state the rule, in two phrasings. Drafts 07 through
552 /// 18 say it of the status code — draft-07 Section 7.1.1.1, drafts 08 and
553 /// 09 Section 8.1.1.1, drafts 10 and 11 Section 9.1.1.1, drafts 12 and 13
554 /// Section 9.2.1.1, drafts 14 through 17 Section 10.2.1.1, draft-18 Section
555 /// 11.2.1.1: "Any object with a status code other than zero MUST have an
556 /// empty payload." Drafts 19 and 20 state it of a registry instead, both in
557 /// their Section 11.2.1.1: "An Object MUST have an empty payload unless its
558 /// Object Status value is registered as permitting a payload in the Object
559 /// Status registry (Section 15.9). Of the values defined in this document,
560 /// only Normal (0x0) permits a payload." The two agree on every status those
561 /// documents define and differ in what a later one may add.
562 ///
563 /// `detail` separates the two ways an object can break it, because they are
564 /// different mistakes and the second is the one a decoder can be fooled by:
565 ///
566 /// * The framing already said there would be no payload. A datagram whose
567 /// Type sets the STATUS bit carries a status in the payload's place, so
568 /// bytes after it are not a short payload or an odd one — they are bytes
569 /// the frame does not define. This bites hardest at status Normal, whose
570 /// status alone would report a payload as permitted, and a caller that
571 /// treats what is left as the payload hands the application content the
572 /// publisher never framed as content.
573 /// * The status forbids one. The registry rule above, reached where a
574 /// caller holds a status and a payload together and the framing has not
575 /// already ruled one of them out.
576 ///
577 /// **No draft turns this into a close.** The sentence is a MUST on the
578 /// sender with no receiver action named, and the "SHOULD be treated as a
579 /// protocol error" beside it belongs to the neighbouring rule about
580 /// unassigned status values. So every draft's session-close table places it
581 /// among the rules they state and do not end a session over — which is a
582 /// decision this variant makes visible, and one
583 /// [`CodecError::InvalidField`] was making by accident.
584 ///
585 /// Distinct from that variant for the reason
586 /// [`CodecError::ExtensionsOnNonExistentObject`] is: an error a caller
587 /// cannot name is one no test can assert and no log can explain.
588 #[error("object with status {status} carries {len} bytes of payload; {detail}")]
589 PayloadNotPermitted {
590 /// The object's status as it arrived on the wire.
591 status: u64,
592 /// How many bytes followed it.
593 len: usize,
594 /// Which of the two rules the bytes broke.
595 detail: &'static str,
596 },
597 /// A request message's Required Request ID Delta names a dependency below
598 /// zero.
599 ///
600 /// Draft-17 Section 9.2: "An endpoint MUST close the session with
601 /// INVALID_REQUIRED_REQUEST_ID if it receives a delta where 2 × Required
602 /// Request ID Delta exceeds the Request ID." Draft-18 removed the field.
603 #[error("required request id delta {1} is too large for request id {0}")]
604 InvalidRequiredRequestIdDelta(u64, u64),
605 /// A unidirectional stream announced a type its draft's stream table does
606 /// not assign.
607 ///
608 /// Every draft from 07 to 20 requires the session to end for this, in one
609 /// of two phrasings. Draft-07 and drafts 17 through 19 say "An endpoint
610 /// that receives an unknown stream type MUST close the session"; drafts 08
611 /// through 16 fold the streams and the datagrams into one sentence, "an
612 /// unknown stream or datagram type", whose second half is
613 /// [`CodecError::UnknownDatagramType`]. No draft in the range is silent,
614 /// and neither phrasing is a hint that the other draft's rule is weaker.
615 ///
616 /// What the tables assign moves across the range, so the set this reports
617 /// on is per-draft rather than shared. Draft-07 has a single table covering
618 /// streams and datagrams together, which is why an OBJECT_DATAGRAM type at
619 /// the head of a draft-07 stream is *not* unknown; drafts 08 onward split
620 /// them into two tables with independent numbering; drafts 17 through 19
621 /// add SETUP, and drafts 18 and 19 add PADDING, both of which are assigned
622 /// stream types that a subgroup reader must refuse without reporting this.
623 ///
624 /// A stream announcing an assigned type this reader cannot read is not this
625 /// error: the value is one the draft defines, and the disagreement is with
626 /// the caller rather than with the draft. Those stay
627 /// [`CodecError::InvalidField`]. The distinction is the whole point of the
628 /// variant — reporting an assigned type as unknown closes sessions over
629 /// streams the draft permits, which is the more costly way to be wrong.
630 #[error("stream type {0} is not one this draft assigns")]
631 UnknownStreamType(u64),
632 /// A datagram announced a type its draft's datagram table does not assign.
633 ///
634 /// The datagram half of the rule above, and stated by all the drafts
635 /// for the same reason: drafts 08 through 16 name streams and datagrams in
636 /// one sentence, and drafts 17, 18 and 19 give the datagrams their own —
637 /// "An endpoint that receives an unknown datagram type MUST close the
638 /// session." Draft-07 alone numbers its datagrams in the stream table, so
639 /// its datagram types are reported by [`CodecError::UnknownStreamType`] and
640 /// this variant is never produced there.
641 ///
642 /// Separate from the stream variant because the two number spaces are
643 /// separate from draft-08 on: 0x05 is FETCH_HEADER on a stream and an
644 /// assigned OBJECT_DATAGRAM form in several drafts' datagram tables, so a
645 /// single variant could not say which table had been consulted.
646 #[error("datagram type {0} is not one this draft assigns")]
647 UnknownDatagramType(u64),
648 /// A subgroup stream header's Type was inside the form its draft defines,
649 /// but held a combination the draft separately names as invalid.
650 ///
651 /// Distinct from [`CodecError::UnknownStreamType`], which reports a value
652 /// no table assigns. Drafts 16 through 23 describe the subgroup Type as a
653 /// bit field rather than as a list of code points, and then rule
654 /// combinations out *within* the form: on each of them a SUBGROUP_ID_MODE of
655 /// 0b11, and from draft-20 also a Type that leaves the subgroup form's own
656 /// bit clear or that runs past the one-byte flags space. The enclosing
657 /// form is assigned, so calling these unknown would misname them; the
658 /// drafts call them invalid and require a close, with PROTOCOL_VIOLATION
659 /// through draft-22 and INVALID_STREAM_HEADER in draft-23.
660 ///
661 /// Separate from [`CodecError::InvalidDatagramTypeValue`] because the
662 /// drafts state the two as separate sentences in separate sections — "If
663 /// an endpoint receives a stream header with any of these" against "If an
664 /// endpoint receives a datagram with any of these". A single variant
665 /// spanning both could not say which of the two sentences a frame broke,
666 /// and `raw` cannot be made to say it either: the two Type spaces overlap,
667 /// so deriving the namespace from the number would be this crate guessing
668 /// which table had been consulted. A consumer that publishes the rule
669 /// beside the refusal would then be right on half the frames and wrong on
670 /// the other half, with nothing in the row to say which.
671 ///
672 /// `detail` names which combination was seen, because the rule is a list
673 /// rather than a single condition and a log that says only "invalid" leaves
674 /// the reader to re-derive the bits.
675 #[error("stream header type {raw:#x} is one this draft names as invalid: {detail}")]
676 InvalidStreamTypeValue {
677 /// The Type value as it arrived, before any narrowing to a byte.
678 raw: u64,
679 /// Which of the draft's lists it fell into.
680 detail: &'static str,
681 },
682 /// A datagram's Type was inside the form its draft defines, but held a
683 /// combination the draft separately names as invalid.
684 ///
685 /// The datagram half of [`CodecError::InvalidStreamTypeValue`], which
686 /// carries the reason the two are separate variants rather than one.
687 /// Drafts 16 through 23 rule out a Type asking to be both an object status
688 /// and an end-of-group marker; drafts 20 through 23 add the bit reserved for a
689 /// datagram, and any other bit their form leaves unspecified.
690 ///
691 /// `detail` names which combination was seen, for the reason the stream
692 /// variant gives.
693 #[error("datagram type {raw:#x} is one this draft names as invalid: {detail}")]
694 InvalidDatagramTypeValue {
695 /// The Type value as it arrived, before any narrowing to a byte.
696 raw: u64,
697 /// Which of the draft's lists it fell into.
698 detail: &'static str,
699 },
700 /// A ContentExists field carried a value other than zero or one.
701 ///
702 /// Drafts 07 through 13 all state it in the same words: "Content Exists: 1
703 /// if an object has been published on this track, 0 if not. If 0, then the
704 /// Largest Group ID and Largest Object ID fields will not be present. Any
705 /// other value is a protocol error and MUST terminate the session with a
706 /// Protocol Violation". Draft-14 states the same sentence with the code
707 /// spelled PROTOCOL_VIOLATION. Draft-07 states it for SUBSCRIBE_OK
708 /// in Section 6.15 and SUBSCRIBE_DONE in Section 6.19; drafts 08 through 11
709 /// keep the SUBSCRIBE_OK site alone; drafts 12, 13 and 14 add PUBLISH.
710 /// Draft-15 removed the field, replacing it with the presence or absence of
711 /// a LARGEST_OBJECT parameter, so no draft from 15 on has one.
712 ///
713 /// The field is a single byte and it decides whether two more follow, so a
714 /// value that is neither leaves a reader with no way to know where the
715 /// message ends.
716 #[error("content exists field carries {0}, which is neither zero nor one")]
717 InvalidContentExists(u8),
718 /// A control message's declared Length disagrees with the fields it
719 /// carries.
720 ///
721 /// All the drafts state it in the same paragraph that gives the
722 /// message type registry, and only the code changes: drafts 07 through 10
723 /// say "If the length does not match the length of the message content, the
724 /// receiver MUST close the session", naming no code; drafts 11 through 18
725 /// name the Message Payload and answer with PROTOCOL_VIOLATION; draft-19
726 /// renames the field to Message Body and keeps the code.
727 ///
728 /// Both directions are the same rule and both are reported here. Fields that
729 /// stop short leave bytes unread — a trailing field the sender wrote and
730 /// this reader does not know about, or one it read at the wrong width.
731 /// Fields that run past the end wanted more bytes than the Length allowed,
732 /// which is the same disagreement seen from the other side.
733 /// The second case is why this cannot be left as
734 /// [`CodecError::UnexpectedEnd`]. That variant means *the message is still
735 /// arriving* everywhere else, and a reader loops on it rather than closing;
736 /// inside a buffer already bounded by the declared Length there is nothing
737 /// left to arrive, so running out there means something else entirely.
738 ///
739 /// Distinct from [`CodecError::InvalidField`], which is too coarse for the
740 /// leftover-bytes case: a caller could not tell it from a dozen unrelated
741 /// malformations, so a session could not be closed over it.
742 #[error("control message declares {declared} bytes of payload; {detail}")]
743 ControlMessageLengthMismatch {
744 /// The Length field the sender wrote.
745 declared: usize,
746 /// Which way the two disagreed, in words, because the useful number is
747 /// different in each direction and neither is knowable in the other.
748 detail: &'static str,
749 },
750 /// A control message's Length is larger than the receiver's
751 /// MAX_CONTROL_MESSAGE_SIZE, or one about to be sent is larger than the
752 /// peer's.
753 ///
754 /// Draft-23 Section 9: "If an endpoint receives a control message with a
755 /// length larger than its MAX_CONTROL_MESSAGE_SIZE, it MUST close the
756 /// session with FIELD_LENGTH_EXCEEDED." Drafts 11 through 22 cap the
757 /// Length at 2^16-1 by its width and report an oversized body on encode as
758 /// [`CodecError::MessageTooLong`].
759 #[error("control message body of {length} bytes exceeds the limit of {limit}")]
760 ControlMessageExceedsLimit {
761 /// The body length, as declared or as about to be written.
762 length: u64,
763 /// The MAX_CONTROL_MESSAGE_SIZE in force.
764 limit: u64,
765 },
766 /// A REQUEST_ERROR whose Error Code requires an Error Detail carries none.
767 ///
768 /// Draft-23 Section 9.4.2.1: "An endpoint that receives a REQUEST_ERROR
769 /// with Error Code REDIRECT and no REDIRECT Error Detail MUST close the
770 /// session with MALFORMED_MESSAGE."
771 #[error("REQUEST_ERROR code {error_code:#x} carries no Error Detail of type {detail_type:#x}")]
772 MissingErrorDetail {
773 /// The Error Code that requires the detail.
774 error_code: u64,
775 /// The Error Detail type it requires.
776 detail_type: u64,
777 },
778 /// A known Error Detail whose value is not the structure its Type defines.
779 ///
780 /// Draft-23 Section 9.4.2.1 gives the REDIRECT Error Detail a structure,
781 /// and draft-23 Section 8.3: "If a receiver understands a Type, and the
782 /// following Value or Length/Value does not match the serialization defined
783 /// by that Type, the receiver MUST close the session with
784 /// MALFORMED_KEY_VALUE."
785 #[error(
786 "error detail of type {detail_type:#x} is not the structure that type defines: {detail}"
787 )]
788 MalformedErrorDetail {
789 /// The Error Detail type.
790 detail_type: u64,
791 /// How the value failed to match.
792 detail: &'static str,
793 },
794 /// A SETUP whose AUTHORIZATION TOKEN option names an Alias with DELETE or
795 /// USE_ALIAS.
796 ///
797 /// SETUP is the first message on the control stream, so no Alias is
798 /// registered when it arrives. Draft-23 Section 9.1.4: "If a server
799 /// receives Alias Type DELETE (0x0) or USE_ALIAS (0x2) in a SETUP message,
800 /// it MUST close the session with ROLE_VIOLATION." At a client, Section
801 /// 8.9: "The receiver of a message referencing an Alias that is not
802 /// currently registered MUST reject the message with
803 /// UNKNOWN_AUTH_TOKEN_ALIAS." Which applies is the receiver's role.
804 #[error("SETUP carries an authorization token with Alias Type {alias_type:#x}")]
805 TokenAliasInSetup {
806 /// The Alias Type, DELETE (0x0) or USE_ALIAS (0x2).
807 alias_type: u64,
808 },
809 /// A Track Name with a length of zero.
810 ///
811 /// Draft-23 Section 2.4.1: "If an endpoint receives a Track Name with a
812 /// length of 0, it MUST close the session with a PROTOCOL_VIOLATION."
813 /// Drafts 07 through 22 allow an empty Track Name.
814 #[error("track name is empty; a track name must contain at least one byte")]
815 EmptyTrackName,
816 /// An AUTHORIZATION TOKEN whose Token structure cannot be decoded.
817 ///
818 /// Draft-23 Section 8.9: "If the Token structure cannot be decoded,
819 /// including an unknown Alias Type, the receiver MUST close the Session
820 /// with MALFORMED_AUTH_TOKEN." Drafts 11 through 22 report the same
821 /// failure as [`CodecError::KeyValueFormatting`].
822 #[error("authorization token in parameter type {key} cannot be decoded: {detail}")]
823 MalformedAuthToken {
824 /// The parameter or Setup Option type that carried the token.
825 key: u64,
826 /// How the token failed to decode.
827 detail: &'static str,
828 },
829 /// Track Properties in a REQUEST_OK that answers a request whose OK must
830 /// carry none.
831 ///
832 /// Draft-23 Section 9.3: Track Properties "are empty in PUBLISH_OK,
833 /// REQUEST_UPDATE_OK, SUBSCRIBE_NAMESPACE_OK and PUBLISH_NAMESPACE_OK. If
834 /// an endpoint receives Track Properties in one of these messages it MUST
835 /// close the session with INVALID_FIELD."
836 #[error("REQUEST_OK carries Track Properties where its request permits none")]
837 TrackPropertiesNotPermitted,
838 /// A Group ID or Object ID decoded from a delta on a fetch stream is
839 /// below 0 or above 2^64-1.
840 ///
841 /// Draft-23 Section 12.2: "DELTA_ENCODING_OVERFLOW (0x400): A value
842 /// decoded from a delta encoding is less than 0 or greater than 2^64 - 1."
843 #[error("fetch stream {detail} is outside 0 to 2^64 - 1")]
844 DeltaDecodingOverflow {
845 /// Which value overflowed.
846 detail: &'static str,
847 },
848 /// An Object on a fetch stream whose serialization cannot be decoded.
849 ///
850 /// Draft-23 Section 12.2: "MALFORMED_OBJECT (0x201): The serialization of
851 /// an Object on a data stream or in a datagram cannot be decoded, for
852 /// example a flag references a prior Object that does not exist."
853 #[error("fetch object cannot be decoded: {detail}")]
854 MalformedObject {
855 /// What could not be decoded.
856 detail: &'static str,
857 },
858 /// An Object whose Prior Group ID Gap or Prior Object ID Gap makes its
859 /// Track malformed.
860 ///
861 /// Draft-23 Section 10.8: "A Track is considered malformed (see Section
862 /// 12.1) if any of the following conditions are detected", and Section
863 /// 10.9 the same for Prior Object ID Gap. Only the conditions one Object,
864 /// or one subgroup stream, shows are detected here.
865 ///
866 /// Drafts 14-22 state the same conditions, in draft-14 Section 11.1,
867 /// draft-14 Section 11.3, draft-15 Section 11.1, draft-15 Section 11.2,
868 /// draft-16 Section 11.3, draft-16 Section 11.4, draft-17 Section 11.7,
869 /// draft-17 Section 11.8, draft-18 Section 12.8, draft-18 Section 12.9,
870 /// draft-19 Section 12.8, draft-19 Section 12.9, draft-20 Section 12.8,
871 /// draft-20 Section 12.9, draft-21 Section 10.8, draft-21 Section 10.9,
872 /// draft-22 Section 10.8 and draft-22 Section 10.9. Drafts 11-13 state
873 /// only the Prior Group ID Gap ones: draft-11 Section 10.1,
874 /// draft-12 Section 10.1 and draft-13 Section 10.1.
875 #[error("malformed track: {detail}")]
876 MalformedTrack {
877 /// Which condition was detected.
878 detail: String,
879 },
880 /// An Object Status the draft does not assign, on a subgroup stream or in
881 /// a datagram.
882 ///
883 /// Draft-23 Section 11.1.1: "If an endpoint receives any other value, it
884 /// SHOULD close the session with INVALID_OBJECT_STATUS (Section 12.2)."
885 #[error("Object Status {0:#x} is not an assigned status")]
886 UnknownObjectStatus(u64),
887 /// Reason phrase exceeds [`MAX_REASON_PHRASE_LENGTH`].
888 #[error("reason phrase exceeds {MAX_REASON_PHRASE_LENGTH} bytes")]
889 ReasonPhraseTooLong,
890 /// GOAWAY URI exceeds [`MAX_GOAWAY_URI_LENGTH`].
891 #[error("GOAWAY URI exceeds {MAX_GOAWAY_URI_LENGTH} bytes")]
892 GoAwayUriTooLong,
893 /// Draft not implemented or not enabled via feature flag.
894 #[error("unsupported draft: {0}")]
895 UnsupportedDraft(String),
896}
897
898impl CodecError {
899 /// Whether more bytes might complete this decode.
900 ///
901 /// A reader that owns a growing buffer asks this to tell *the input has
902 /// not all arrived* from *the input is wrong*: `true` means fill the
903 /// buffer and decode again, `false` means the bytes are what they are and
904 /// no amount of waiting improves them.
905 ///
906 /// # Why this is a predicate and not a variant test
907 ///
908 /// Running out of bytes has four spellings here, because a decode can run
909 /// out inside a nested decoder that reports in its own error type and each
910 /// one names the condition after itself:
911 ///
912 /// * [`CodecError::UnexpectedEnd`], from a field this module read;
913 /// * [`CodecError::VarInt`] carrying [`VarIntError::UnexpectedEnd`], from a
914 /// varint whose length prefix promised bytes the buffer did not hold;
915 /// * [`CodecError::Kvp`] carrying [`KvpError::UnexpectedEnd`], and
916 /// * the same wrapped one level deeper as
917 /// [`KvpError::VarInt`]`(`[`VarIntError::UnexpectedEnd`]`)`, from a
918 /// key-value pair that ran out in its length or in its value.
919 ///
920 /// All four mean the same thing to a caller and only the first announces
921 /// it in the variant name. That is not a hypothetical: a reader matching
922 /// the first alone treated a subgroup object whose leading varint had not
923 /// arrived yet as a malformed stream, and reported `insufficient bytes for
924 /// varint decoding` for an object that was merely still in flight. The
925 /// condition is one fact about a buffer, so it is answered in one place
926 /// rather than re-derived by every reader that has to know it.
927 ///
928 /// # What is deliberately not here
929 ///
930 /// [`CodecError::ControlMessageLengthMismatch`] is the case that looks
931 /// like this one and is its opposite, and its own documentation says why:
932 /// inside a buffer already bounded by a declared Length there is nothing
933 /// left to arrive, so running out there is a malformation and waiting for
934 /// more would be waiting forever.
935 ///
936 /// [`VarIntError::UnexpectedEnd`]: crate::varint::VarIntError::UnexpectedEnd
937 /// [`KvpError::UnexpectedEnd`]: crate::kvp::KvpError::UnexpectedEnd
938 /// [`KvpError::VarInt`]: crate::kvp::KvpError::VarInt
939 pub fn is_incomplete(&self) -> bool {
940 use crate::kvp::KvpError;
941 use crate::varint::VarIntError;
942 matches!(
943 self,
944 CodecError::UnexpectedEnd
945 | CodecError::VarInt(VarIntError::UnexpectedEnd)
946 | CodecError::Kvp(KvpError::UnexpectedEnd)
947 | CodecError::Kvp(KvpError::VarInt(VarIntError::UnexpectedEnd))
948 )
949 }
950}