Skip to main content

check_extensions_against_status_on_encode

Function check_extensions_against_status_on_encode 

Source
fn check_extensions_against_status_on_encode(
    status: Option<u64>,
    extension_headers_len: u64,
) -> Result<(), CodecError>
Expand description

Refuse an object that would be written with extension headers beside a status other than Normal.

Draft-15 Section 10.2.1.2: “Any Object with status Normal can have extension headers. If an endpoint receives extension headers on Objects with status that is not Normal, it MUST close the session with a PROTOCOL_VIOLATION.”

Wider than the rule drafts 11 through 14 carry. There, at draft-14 Section 10.2.1.2, the sentence read “Any Object may have extension headers except those with Object Status ‘Object Does Not Exist’”, which left extensions beside End of Group and End of Track legal; draft-15 is where the single exception became the general case. Using the earlier wording here would let an End of Group object carry metadata draft-15 says to close the session over.

Called from DatagramHeader::encode_checked and nowhere else, and deliberately so. A frame carrying extensions beside a non-Normal status is well formed — every length is honest and every field parses — so a decoder can hand it back intact, and a tool that reproduces a capture has to. Refusing it on decode would make a captured violation unreadable, which loses the one artifact anybody debugging it needs.

The same argument bars it from a carrier’s only writer. SubgroupObjectReader::write_object and FetchObjectReader::write_object_header are the sole way to write their objects, so a refusal there would leave a captured violation impossible to re-emit; the corpus ships exactly such a subgroup frame. A datagram is the one carrier with two encoders, so encode_checked can refuse while DatagramHeader::encode still reproduces bytes verbatim. That is the whole of the rule: opt-in strictness where an unchecked path exists, and a predicate — SubgroupObject::extensions_permitted, SubgroupObjectMeta::extensions_permitted, DatagramHeader::extensions_permitted, FetchObjectHeader::extensions_permitted — everywhere else.

That is why drafts 11 through 14 look different and should stay different: they state only the narrow Object Does Not Exist form, they apply it on both sides, and no vector exercises it. Drafts 15 through 19 state the broad form and enforce it on encode alone. The split is intentional, not an inconsistency to harmonise away.

status is the code the object resolves to, not the field as it appears on the wire. An object whose framing omits the status field has status Normal — on a subgroup or fetch stream because its payload length is non-zero, on a datagram because its type byte leaves the status bit clear — and such an object may carry extensions. Passing None says exactly that.