Scalar transaction variables
On this page 4
Issue WAF-07 establishes the
bounded scalar registry and the transaction producers needed by later rule,
body, and collection work. variables.Name is the executable source of truth:
all 78 canonical names round-trip case-insensitively and have a minimum phase
and default origin. MULTIPART_SEMICOLON_MISSING is accepted as the historical
alias for MULTIPART_MISSING_SEMICOLON.
Ownership and bounds
Every published value is copied into transaction-owned storage. Values of 64
bytes or less stay inline; larger values use the WAF allocator. Both individual
values and aggregate live scalar bytes are bounded by Limits. Failed updates
leave their prior value owned and valid. Callers may retain a View only until
the next update of that variable or transaction destruction.
Origins distinguish connection data, request targets and headers, body and response processing, timing, parsers, compatibility state, rule matches, engine-generated values, and connector identity. A stored value is invisible before its minimum availability point even when a connector supplies it early.
Producer behavior
- Connection setup publishes remote/server addresses and ports.
REMOTE_HOSTfollows ModSecurity compatibility behavior and initially mirrors the remote address; no blocking reverse DNS lookup occurs on the request path. - URI setup publishes raw/canonical URI foundations, path, basename, query, method, protocol, and request line. Strict decoding and complete origin offsets are owned by WAF-23.
- Request headers derive
SERVER_NAME,AUTH_TYPE, and the standard request body processor names without retaining header buffers. - Request and response body writes publish inspected byte counts. Parser
integrations report request and response body errors through explicit hooks;
successful phase completion fills absent error flags with
0. - Response processing publishes content type, protocol, status, legacy status
forms, actual inspected
RESPONSE_CONTENT_LENGTH, outbound-limit state, and response-parser diagnostics. The nonstandardRESPONSE_BODY_LENGTHspelling is rejected. - Identity hooks publish
REMOTE_USER,USERID,SESSIONID, andWEBAPPID. The engine generates a bounded per-generationUNIQUE_IDfrom transaction time and an atomic sequence. - Rule matches replace
MATCHED_VARandMATCHED_VAR_NAMEwith the latest match.HIGHEST_SEVERITYbegins at255and retains the lowest numeric severity seen. - Regex integrations can distinguish a general compatibility error from an execution-limit error without pretending PCRE2 is the production engine.
Time semantics
Creation captures Unix wall time and an awake/monotonic timestamp. Calendar
variables are rendered in UTC for reproducibility; TIME_WDAY uses the
POSIX/Go convention (Sunday=0). DURATION is elapsed monotonic milliseconds,
so wall-clock corrections cannot make it go backward.
Builder.setIo accepts the application-owned Zig 0.17 std.Io backend. Tests
and specialized embedders may instead use setClockSource; that callback must
be nonblocking and thread-safe and its context must outlive the WAF. A timestamp
before the Unix epoch fails explicitly during connection initialization.
Deliberate downstream ownership
The registry includes scalar names whose bytes can only be produced by later subsystems. WAF-08 owns collection-derived aggregates such as argument and file sizes. WAF-24 and WAF-28 own opt-in bounded materialization of full request and response bodies. Those variables are absent until their producer publishes a real value; the engine never substitutes an empty value or silently buffers an unbounded body.
Run zig build bench-scalars -Doptimize=ReleaseFast to measure transaction size
and a complete populated scalar lifecycle. This benchmark performs no logging,
database, telemetry, or UI work.