Skip to content

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.