pub fn is_gateway_api_http_path(path: &str) -> Result<(), String>Expand description
Predicate: assert that path is a valid HTTP path under both the
K8s Gateway API v1 HTTPPathMatch.value admission grammar AND the
Cilium L7 path: rule grammar — the two landing sites every
validated pleme-io HTTP-shaped path lands in. The contract:
- 1..=
GATEWAY_API_HTTP_PATH_MAX_LEN(1024) bytes; - leading
/(thePathPrefixinvariant — pre-checked at the call site by each axis’s narrower*NotAbsolutevariant; re-checked here so the predicate is usable from any future call site without a shape-mismatch footgun); - no consecutive
/characters (HTTP path matchers reject//— collapse to a single/); - no
/./or/../segments (and no trailing/.or/..) — path-traversal and no-op segments are rejected outright; - no
?(query separator: queries are matched separately viaHTTPRoutequeryParams, never in the path); - no
#(fragment separator: fragments are client-side and never reach the gateway); - no whitespace (space, tab — must be percent-encoded as
%20); - no ASCII control characters (
0x00..0x1F,0x7F); - no non-ASCII bytes (
>= 0x80) — RFC 3986 requires%XXpercent-encoding for anything outside the ASCII unreserved + reserved set; - no printable-ASCII byte outside the K8s Gateway API
HTTPPathMatch.valueapiserver-sideOpenAPIregex^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$accepted set — namely"<>[\]^`{|}. These eleven bytes are printable ASCII but RFC 3986’spchar = unreserved / pct-encoded / sub-delims / ":" / "@"grammar excludes them, so the apiserver rejects them at admission time on everyHTTPRoute.spec.rules[].matches[]. path.valuelanding site and the Cilium L7 path matcher refuses them too. Percent-encode (%XX) if the literal byte is intended.
Returns the parser-shaped reason on rejection (without wrapping in
any error variant) so each per-axis caller — validate_entrada_path
for :entrada :paths entries, WitContract::target for the HTTP-
shaped :contratos :endpoint axis, every future per-path lift
(the M4 CR materializer’s per-path validator, the future
per-HTTPRouteRule per-path-match emission) — wraps the same
reason in its own typed *Invalid { <axis>, reason } variant. The
reason wording is axis-agnostic (“HTTP path matchers reject
//”) so every call site reading the same diagnostic points at
the same rule; drift between any two axes’ rule enforcement is a
build error visible at this predicate, not a per-renderer “this
passed validate but failed admission” surprise.
Empty input is rejected at the call site (each axis has its own
narrower *Empty variant — crate::AplicacaoError::EntradaPathEmpty,
crate::AplicacaoError::ContratoEndpointEmpty) before this
predicate is consulted, mirroring is_dns_1123_label’s empty-first
cascade. The predicate body re-checks empty + leading-/
defensively so it can be called from any future call site without
a shape-mismatch footgun.
Lifted from caixa-core::aplicacao::validate_entrada_path (where
it was first inlined for :entrada :paths in 55410e4) at the
second occurrence of the HTTP-path-grammar — the :contratos :endpoint axis (c4213a4 gated non-empty + leading-/ only,
silently passing the same authoring footguns the :entrada :paths
gate catches) — so the second axis lands as a thin three-line
wrapper at the per-axis call site rather than re-inlining 90 lines
of grammar enforcement. Same compounding shape as
is_dns_1123_label (lifted at its third occurrence in 31bfa43)
and the M2-overlay / label-selector helpers (9e3a057, 9d09cfb,
9dbeafd, 31455a7, 07a4544) on the render side — each lifted a
recurring shape into a typed primitive at the threshold where the
duplication budget would otherwise have been exceeded.
§Errors
Returns the parser-shaped reason naming the specific violation
(length / character-class / segment / consecutive-slash), without
wrapping in any error variant — every caller maps the same
String into its own typed *Invalid { <axis>, reason } enum
variant.