Skip to content

blackbull.protocol.framing

blackbull.protocol.framing

RFC 9112 §6 — how a message declares its body length.

Whatever side reads or writes it answers Content-Length identically, so the answer is here once: one value, written once, in 1*DIGIT, agreed on by every occurrence. A message that carries two boundaries does not have one.

is_informational(status)

Whether status is an informational (1xx) response — RFC 9110 §15.

An informational response is provisional: it shares its sender with the final response that must still follow, so it commits no status, completes no exchange, and carries no content framing.

method_is(method, expected)

Whether method is exactly expected.

RFC 9110 §9.1 makes a method name case-sensitive, so head is not HEAD and folding the two together changes whether a response may carry content.

parse_content_length(fields)

The length every Content-Length occurrence agrees on, or None.

Occurrences are #field-value lists too, so each member counts. Raises ValueError when a member is not 1*DIGIT or the members disagree; the message names the values it could not reconcile.

parse_status(value)

A status code as RFC 9110 §15 writes one, or None if it is not.

Three ASCII digits and nothing else. There is deliberately no 100-599 bound: a range one transport enforces and the other does not is an accept set the two disagree on, and neither protocol draws one here.

response_has_content(method, status)

How the body length of a response to method with status is found.

RFC 9112 §6.3 rule 1: a response to HEAD (RFC 9110 §9.3.2) and any 1xx (§15.2), 204 (§15.3.5) or 304 (§15.4.5) has none whatever the field sections say, and an informational response is not the response yet.

This is the framing question and it stops there. RFC 9110 §15.3.6 also forbids a server to generate content in a 205, but RFC 9112 §6.3 still frames one normally, so a peer that sends one has to be read to the length it declared — leaving those octets behind would desynchronise the reader from the very peer that was already misbehaving. The generation rule lives on the sender beside it, not in here.

split_transfer_codings(fields)

Every Transfer-Encoding member as RFC 9110 §10.1.4 writes one, or ValueError.

Commas split, OWS off, the coding token lowered, the parameters kept rather than dropped — a policy that refuses chunked carrying a parameter sees one, a policy that reads only the names drops them as its own decision. An empty member stays (b'', ()) (chunked, is not chunked to a sender rewriting the field; a reader ignores empties per RFC 9110 §5.6.1). A member outside the grammar raises — a parameter this reading cannot see through must not hide a different final coding — as does a list over the empty-member bound.