pub enum AboveCodecRule {
Show 28 variants
PropertiesOnNonNormalStatus,
PayloadOnStatusDatagram,
BidiStreamOpener,
MessageOnTheWrongStream,
ResponseNamesAnotherRequest,
ResponseBeforeItsFirstResponse,
GoAwayAtServer,
RepeatedGoAway,
RedirectUriAtServer,
RedirectTrackNameOnNamespaceRequest,
RequestIdParity,
RequestIdOutOfSequence,
RequestIdCeiling,
MaxRequestIdDecreased,
SetupParameterValue,
DuplicateTrackAlias,
MixedForwardingPreference,
EndOfTrackOutOfPlace,
ObjectPastFinalObject,
RequestUpdateForTheWrongRequest,
TooManyRequestUpdates,
TrackPropertiesOnNonTrackStatus,
StateNotifyOnTheWrongRequest,
UnrequestedFillStream,
SubscribeAfterAnnounceCancel,
TrackStatusIsNotASubscription,
MessageNamesAnUnknownRequest,
NamespacePrefixOverlap,
}Expand description
A rule a peer broke that no decoder could have caught.
Deliberately not #[non_exhaustive]. A consumer matching on this — a
conformance report deciding what it will name a relay for — should find out
about a new rule by failing to build, not by silently filing it under a
wildcard arm.
The close that travels beside it in
crate::dispatch::ErrorCause::PeerViolation is the negotiated draft’s
own, and several of these are stated with a close on some drafts and without
one on others. The rule is the same rule either way; what the draft does
about it is the other field.
Variants§
PropertiesOnNonNormalStatus
An Object arrived carrying properties on a status that is not Normal.
Drafts 15 and 16 state it of extension headers and drafts 17 through
20 of properties; the block was renamed and the rule was not. Every
draft that states it answers it with a close, so a caller reading
crate::dispatch::ErrorCause::PeerViolation finds close: Some on
all six.
PayloadOnStatusDatagram
A datagram whose header declared a status permitting no payload arrived with bytes after the header.
The one rule here the drafts state as a property of a conforming Object
rather than as a “MUST close the session” case, so close is None on
every draft that states it, and the datagram is refused with the session
left running. A caller that gates on close: Some will therefore never
see this one, which is the correct behaviour and not an oversight: a
relay cannot be published for breaking a rule its draft attaches no
consequence to.
BidiStreamOpener
A bidirectional stream the peer opened began with a message type the draft does not permit one to begin with.
The permitted set differs — draft-16 allows the control stream and SUBSCRIBE_NAMESPACE, drafts 17 through 20 allow any message that begins a request stream — and the sentence that forbids the rest is the same on all four. The offending stream is reset and the session closed before the error is returned.
Reached from both halves of this module: a draft’s own ConnectionError
raises it where the connection owns the stream, and EndpointError
where the endpoint does. One rule, so one name.
MessageOnTheWrongStream
A message arrived on a stream the draft does not place it on.
The control stream carrying one the draft puts on a request stream, a request stream carrying one that may not follow a request there, a response arriving where no request is outstanding. Draft-16 states it of NAMESPACE and NAMESPACE_DONE; drafts 18 through 20 state it of every message their Table 5 gives a Stream value to.
Distinct from Self::BidiStreamOpener, which is about the first
message on a stream and is what decides what that stream is. This is
about a later one arriving somewhere it does not belong.
§No draft states a close for it
The rule is real — a NAMESPACE on the control stream names no request
and there is nothing for a receiver to do with it — and the
consequence would be ours to invent. The tempting one is
Some(PROTOCOL_VIOLATION), on the reading that Section 3.3’s opener
sentence covers a message on the wrong stream. It does not: that
sentence is about what a bidirectional stream may begin with, and a
message arriving on the control stream begins nothing.
Read across all texts for a sentence that closes a session over
a message being in the wrong place, there is none. The drafts state
placement per message, mostly descriptively; drafts 18 through 20 add a
Stream column to their message table, whose only MUST is that a message
marked First is the first message on a new request stream — which is
Self::BidiStreamOpener’s subject and names no code; and the only
sentence in the range that closes a session over misplacement is drafts
19 and 20’s REQUEST_UPDATE sentence, which is
Self::RequestUpdateForTheWrongRequest’s.
So a close here would be this build’s model of the protocol rather than
a draft’s. session_error_code answers None for every variant that
reaches this rule on every draft that raises it, and the receive paths
that raise them do not fail the session: the message is refused, the
caller is told, and the session runs on — which it can, because a
control message carries its own length and the next boundary on the
stream is known however this one was refused.
One variant is covered by a draft sentence and is filed under the rule
that carries it rather than here. A REQUEST_UPDATE on the control stream
is, on drafts 19 and 20, squarely inside the sentence that closes over a
REQUEST_UPDATE outside the two cases those drafts permit — the first of
which is the request’s own bidi stream — so it is
Self::RequestUpdateForTheWrongRequest there, with the citation that
rule already carries. On drafts 17 and 18 the same message answers
None, because those drafts describe the placement and attach no
consequence to it.
The rule stays named. It is enforced, it is the peer’s doing, and a draft that attaches a consequence to it should arrive here as a citation rather than as a rediscovery.
ResponseNamesAnotherRequest
A response arrived on one request’s stream naming a different request.
Draft-16 only, and only because that draft has both halves at once: a stream per namespace subscription and a Request ID on the messages that travel it, so the two can disagree. Drafts 17 and later deleted the id from responses, which deletes the disagreement.
ResponseBeforeItsFirstResponse
A request stream’s response half opened with something other than the response the draft requires first.
Drafts 18 through 20, of SUBSCRIBE_NAMESPACE and SUBSCRIBE_TRACKS: “If the subscriber receives any message other than a REQUEST_OK or a REQUEST_ERROR as the first message on the response half of the stream, then it MUST close the session with a PROTOCOL_VIOLATION.”
GoAwayAtServer
A GOAWAY arrived at a server that had no standing to be sent one.
Draft-07 states the rule about the message — a server may not be sent a
GOAWAY at all — and drafts 08 through 20 about the migration URI it
carries, since only a server may tell a client where to reconnect. The
rename is the same shape as Self::PropertiesOnNonNormalStatus’s: the
text moved the prohibition onto the field, and what a conforming client
may send did not change.
RepeatedGoAway
A second GOAWAY arrived where the draft allows one.
Per session on every draft, and from draft-18 also per request stream — that draft lets a GOAWAY migrate a single request, so one on each of two request streams is two first GOAWAYs and not a repeat. Both are the same sentence read at two scopes.
RedirectUriAtServer
A server received a Redirect carrying a Connect URI.
Drafts 18 through 20. The same standing Self::GoAwayAtServer is
about, stated of the message that replaced GOAWAY’s migration half.
RedirectTrackNameOnNamespaceRequest
A Redirect answering a namespace-scoped request carried a Track Name.
Drafts 18 through 20: “an endpoint that receives a non-empty Track Name in a Redirect for a namespace-scoped request MUST close the session with a PROTOCOL_VIOLATION.”
Which requests are namespace-scoped is named in the first half of that same sentence, and is described here rather than quoted because the list is the half of it that moves: draft-18 names SUBSCRIBE_NAMESPACE and PUBLISH_NAMESPACE, and drafts 19 and 20 add SUBSCRIBE_TRACKS. An ellipsis across that list would join the clause before it to the clause after it and make a sentence none of the three drafts has — which a checker reports as in no draft at all, and which a reader cannot tell from a transcription.
RequestIdParity
A Request ID arrived whose least significant bit belongs to this endpoint’s half of the number space.
Drafts 11 and later, which split the space by parity. Drafts 07 through 10 have one shared sequence and state no parity rule, so they cannot break this one.
RequestIdOutOfSequence
A new request carried a Request ID that is not the next one the peer’s own sequence calls for.
A repeat and a skip alike. Drafts 11 through 16 state it as “a new request with a Request ID that is not expected” and drafts 17 through 20 as “a duplicate Request ID”; drafts 07 through 10 require the shared Subscribe ID to be “unique and monotonically increasing”. Three phrasings of one requirement — that an id identifies exactly one request for the life of a session.
RequestIdCeiling
A request carried a Request ID at or above the ceiling this endpoint advertised.
Drafts 07 through 16. The number measured against is the one this endpoint sent, not the one the peer sent it, and the two are different values. Draft-17 removed MAX_REQUEST_ID and the drafts after it have not brought it back, so there is no ceiling left to exceed.
MaxRequestIdDecreased
A ceiling the peer raised did not increase.
Every draft from 07 to 16 states it, and no one sentence covers them. Drafts 11 through 13: “The Maximum Request ID MUST only increase within a session, and receipt of a MAX_REQUEST_ID message with an equal or smaller Request ID value is a ‘Protocol Violation’.”
The other three eras say the same thing in different words. Drafts 07
through 10 state it of the Maximum Subscribe Id and MAX_SUBSCRIBE_ID;
drafts 14 and 15 carry draft-14’s rename of the code, so the sentence
ends is a PROTOCOL_VIOLATION with no quotation marks on it; and
draft-16 splits it in two, keeping the first clause as a sentence of its
own and answering the second with a close. Draft-17 removed
MAX_REQUEST_ID and nothing after it restored one, so there is no ceiling
left for a peer to lower. A setup parameter carrying the same field is
held to the same sentence.
The mirror — this endpoint asked to send a ceiling of its own that does
not increase — is a separate EndpointError variant on every draft that
has this one, so that the two never arrive as the same value. See
EndpointFault for why one variant covering both would have been a
silent wrong answer rather than an imprecise one.
SetupParameterValue
A setup parameter arrived with a value of a kind the draft does not give that parameter.
Drafts 07 through 10, where MAX_SUBSCRIBE_ID is read out of the setup block by hand. The frame decodes — a key-value pair holding bytes where a varint was meant is a well-formed key-value pair — so the decoder cannot see it and the endpoint reading the parameter is what does.
DuplicateTrackAlias
The peer used one Track Alias for two different tracks at once.
Every draft states it, and every draft names a code of its own for it rather than the general one — which is why the code travels beside the rule instead of being assumed from it.
MixedForwardingPreference
Objects of one track arrived under more than one forwarding preference.
Drafts 07 through 11: “it SHOULD close the session with an error of ‘Protocol Violation’”. SHOULD, so the close is the caller’s to make and this build’s is opt-in. The condition the drafts state it of narrows at draft-11, from any two differing preferences to Objects arriving on both Subgroup streams and datagrams for one SUBSCRIBE; the consequence is the same clause either way, which is why the clause and not the whole sentence is what is quoted.
Drafts 12 through 15 raise it as well and answer it with nothing. That
is where a differing Forwarding Preference became one entry in the
Malformed Track list, and what those drafts require of a subscriber that
detects one is an UNSUBSCRIBE and an error to the application — see
Self::ObjectPastFinalObject, which is another entry in the same
list. The quotation is held to drafts 07 through 11 for that reason:
ranging it across all nine would file four drafts’ silence under a
sentence they dropped.
EndOfTrackOutOfPlace
An Object with status END_OF_TRACK arrived somewhere the draft does not allow one.
Drafts 08 through 13: “the receiver MUST terminate the session”.
ObjectPastFinalObject
An Object arrived past the Object the track had already ended at.
Drafts 12 and later. A Malformed Track rather than a session error, and what the drafts require of a subscriber that detects one moves twice across that range. The words here are drafts 17 through 20’s: “it MUST cancel any corresponding subscription or fetches for that Track from that publisher”.
Drafts 12 and 13 say UNSUBSCRIBE from the Track; drafts 14 through 16
say UNSUBSCRIBE any subscription and FETCH_CANCEL any fetch for that
Track from that publisher, which is the same operation named by the two
messages that perform it. All three are transport operations on the
requests and none of them is a close, so close is None wherever this
appears — the reading the range shares, and the reason one quotation
stands for the whole of it here.
Past is the drafts’ own Location comparison and not a reading of the word: an Object in a later group is past the end whatever its own Object ID is.
RequestUpdateForTheWrongRequest
An update arrived naming a request that cannot take one.
A request the session has never carried, one that has already ended, one of a kind the draft does not let a subscriber update. Drafts 12 through 20 state some of these; drafts 19 and 20 gather them into one sentence — “An endpoint that receives a REQUEST_UPDATE other than in the two cases above MUST close the session with a PROTOCOL_VIOLATION.”
TooManyRequestUpdates
More outstanding REQUEST_UPDATEs on one stream than this endpoint advertised room for.
Drafts 19 and 20: “If an endpoint receives a REQUEST_UPDATE on a stream that already has MAX_REQUEST_UPDATES outstanding REQUEST_UPDATEs, it MUST close the session with TOO_MANY_REQUEST_UPDATES.”
The ceiling beside it in the same section, MAX_FILTER_RANGES, is
answered with a REQUEST_ERROR instead, and nothing about either sentence
signals which — see EndpointFault::ThisEndpoint, which is where that
one lands.
TrackPropertiesOnNonTrackStatus
Track Properties arrived on a REQUEST_OK answering something that is not a TRACK_STATUS.
Drafts 18 through 20: they “are empty in PUBLISH_OK, REQUEST_UPDATE_OK, SUBSCRIBE_NAMESPACE_OK and PUBLISH_NAMESPACE_OK. If an endpoint receives Track Properties in one of these messages it MUST close the session with a PROTOCOL_VIOLATION.”
StateNotifyOnTheWrongRequest
A PUBLISH_STATE_NOTIFY arrived for something that is not a subscription, or from the end of one that may not send it.
Draft-20, one sentence covering both: “PUBLISH_STATE_NOTIFY applies only to subscriptions, and is sent only by the publisher. An endpoint that receives a PUBLISH_STATE_NOTIFY for any other request type, or from the subscriber, MUST close the session with a PROTOCOL_VIOLATION.”
UnrequestedFillStream
A fill fetch stream opened against a request that asked for no fill.
Draft-20, where FILL_PARAMETERS is the whole of the request: “Its
presence is what requests a fill fetch stream; a subscription with no
FILL_PARAMETERS opens none.” Not a close — the draft states no
consequence, and the honest handling is STOP_SENDING on that stream
alone.
SubscribeAfterAnnounceCancel
A SUBSCRIBE arrived for a namespace the peer had cancelled.
Draft-07 alone: “it SHOULD close the session as a ‘Protocol Violation’”. The mechanism it is stated about, ANNOUNCE_CANCEL against a namespace the subscriber then subscribes under, survives the later drafts; the sentence does not.
TrackStatusIsNotASubscription
An UNSUBSCRIBE or REQUEST_UPDATE arrived naming a TRACK_STATUS.
Drafts 13 through 18: a track status request is answered once and is
never a subscription, so there is nothing for either message to act on.
The drafts state it without a code, so close is None.
MessageNamesAnUnknownRequest
A message arrived naming a request this session has no record of.
Stated by every draft of the messages that carry an id, and answered by
none of them with a code, so close is None throughout.
This is narrower than it looks. Most of the variants that could carry it
are raised on both a receive path and a send path and answer
EndpointFault::EitherEnd instead; only the ones a draft raises on a
receive path alone reach this rule.
NamespacePrefixOverlap
The peer subscribed to a namespace prefix overlapping one it already has.
Drafts 07 through 10, which catch it as the message arrives. From
draft-11 the same condition is caught where the answer is built, which
makes it a refusal this endpoint owes rather than a fault it observed —
see EndpointFault::ThisEndpoint.
Never a close on any draft: “it MUST respond with REQUEST_ERROR with error code PREFIX_OVERLAP” is a reply, and a reply needs the request it answers to have been taken.
Implementations§
Source§impl AboveCodecRule
impl AboveCodecRule
Sourcepub fn citations(self) -> &'static [RuleCitation]
pub fn citations(self) -> &'static [RuleCitation]
Every draft run this rule has a checked citation for, oldest first.
Exhaustive with no wildcard arm, for the reason the enum is not
#[non_exhaustive]: a rule added to this file arrives here as an
E0004 and a decision about which drafts state it, rather than as an
empty slice nobody chose.
An empty slice is one of those decisions and not an oversight. Nine rules answer with one, in two groups.
Eight are rules no draft in range answers with a session close. The
datagram payload rule, a response naming another request, a setup
parameter whose value is not of its type’s kind, an Object past the one
the track ended at, a fill stream nobody asked for, an UNSUBSCRIBE or
REQUEST_UPDATE naming a TRACK_STATUS, a message naming a request the
session has no record of, and a namespace prefix overlapping one the
peer already has. Every one is a real rule this endpoint enforces, and
session_error_code already answers None for all of them, so nothing
downstream could publish one whatever this table said. They are written
out so that a draft attaching a consequence to one arrives here as a
build failure.
The ninth is Self::MessageOnTheWrongStream. It is enforced on
drafts 16 through 20 and no draft in that range states it, so it is
named, enforced and attributed to the peer while publishing nothing:
there is no sentence to publish and close is None on every draft.
The variant’s own doc carries the reading across all texts that
establishes it, and the one variant that really is covered by a draft
sentence is filed under the rule whose sentence covers it. A draft that
attaches a consequence to this one arrives as a citation rather than as
a rediscovery.
Sourcepub fn citation(self, draft: u8) -> Option<&'static RuleCitation>
pub fn citation(self, draft: u8) -> Option<&'static RuleCitation>
This rule as draft states it, or None where that draft does not.
None has two readings and the caller does not need to tell them apart:
the draft may not state the rule at all, or it may state it in words
nobody has yet checked. Both mean the same thing downstream — there is
no sentence to publish, so there is no accusation to make — and that is
the whole of why this returns an Option rather than falling back on a
neighbouring draft’s wording. A fallback publishes a sentence the
negotiated draft does not contain, which is the defect this table exists
to prevent.