blackbull.fault_injection.scenario_h1¶
blackbull.fault_injection.scenario_h1
¶
HTTP/1.1 client-side fault scenarios for a target server.
JSON Lines preserves typed steps. from_bytes is a total decoder for fuzz inputs: malformed input must still map to a scenario rather than crash parsing.
Abort
dataclass
¶
Hard-close the connection (transport.abort → RST on Linux).
Distinct from the graceful writer.close() / wait_closed()
in HTTP1Client.__aexit__. Subsequent steps short-circuit; the
executor stops walking the scenario after an Abort.
ExpectResponse
dataclass
¶
Read one response and record whether it matched.
A guard, not a filter: nothing is skipped and the executor moves on either way. It answers is the peer behaving as this scenario assumes? — and a scenario whose premise silently failed would otherwise look like a pass.
Twin of
ExpectRequest.
HalfClose
dataclass
¶
Shut down the sending direction only (FIN), keep reading.
Not terminal — later steps still run, which is the whole point.
Abort is not a substitute: it sends RST, discarding what is buffered
and leaving nothing to read.
ReadResponse
dataclass
¶
Read one HTTP/1.1 response from the connection.
timeout bounds the entire status-line + headers + body read.
On timeout the executor records the outcome on the
ScenarioResult and does not raise — the caller decides
whether to treat that as a transport-fail or normal outcome.
Scenario
dataclass
¶
A sequence of steps the executor walks against one connection.
from_bytes(raw)
classmethod
¶
Decode every byte string into a runnable fuzz scenario, including empty input.
Truncated input returns the completed steps. Abort discards remaining bytes; SEND payload lengths are uint16. This decoder must not raise on arbitrary input.
from_json(src)
classmethod
¶
Parse JSON Lines back to a Scenario.
Skips blank lines so files that end with a trailing newline (the conventional git-friendly shape) parse cleanly.
A HEADER line carries the name and is optional on the way in:
a file without one parses to an unnamed scenario.
to_json()
¶
Serialize JSON Lines with base64 byte payloads and a first HEADER carrying name.
well_formed(raw_request, *, response_timeout=5.0)
classmethod
¶
Wrap a complete raw HTTP/1.1 request as a one-shot scenario.
Equivalent to "send these bytes, then read one response".
Used by the Hypothesis well_formed_scenario_strategy in the
HTTP/1.1 differential suite.
ScenarioResult
dataclass
¶
Collect scenario outcomes; fields are not mutually exclusive.
A timeout may precede a later response; response is newest, received holds all.
SendRawBytes
dataclass
¶
Push raw bytes onto the connection.
byte_interval > 0 transmits one byte at a time with that delay
between bytes — the primitive slowloris-style stall that lets
scenarios express trickled headers or trickled bodies without
dropping to a raw asyncio socket.
Sleep
dataclass
¶
Idle for duration seconds without sending or reading.
Useful for post-headers idle, mid-keep-alive idle, and pre-response stall scenarios where the server is expected to time out and close.
StepOp
¶
Bases: str, Enum
Tag for serialising / decoding a step. str mixin so values
drop straight into JSON without a custom encoder.
WaitForResponse
dataclass
¶
Read responses until one satisfies match, or the timeout wins.
A filter: non-matching responses are read, counted in
wait_skipped, and passed over. The role-axis twin of
WaitForRequest,
and it exists for the same reason — a scenario that has to know
exactly how many messages precede the interesting one is a scenario
written against a particular peer.
On HTTP/1.1 a non-zero wait_skipped is worth reading: responses
arrive in request order, so skipping one means the scenario is a
response further along than it thinks.
__getattr__(name)
¶
Deprecated SendBytes alias for SendRawBytes; removal no earlier than 2027-08-19.
response_matches(response, match)
¶
Return True iff response satisfies every key in match.
Recognised keys: status, reason, version, header,
header_absent, body_contains. Unknown keys fail closed —
an unrecognised key is almost certainly a typo in a scenario, and
silently matching on a key nobody reads would hide it.
request_matches and frame_matches made the same choice for the
same reason.
header takes (name, value); pass value=None to match on
presence alone. header_absent takes a name.
scenario_from_json(src)
¶
Parse what Scenario.to_json produced. Twin of the other three.