code wiki / _hdl_build / nx_proxy_route.nx

nx_proxy_route.nx

buildroot/runtime/_hdl_build/nx_proxy_route.nx

18069 B363 linesdepth 2pulls 2 transitivereach 7 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_proxy_route.nx -- SOVEREIGN data-driven PROXY route table (pure Nishi, no TLS, no crypto). The DYNAMIC-routing analog of nx_host_router's static docroot table: a config file maps (host, path-prefix) -> (backend_port, mode) so an app/site route is a CONFIG ROW, not a recompiled `sd2_contains(" /gallery")` branch in the TLS daemon. This closes the nx_host_router gap for DYNAMIC routes -> "migrate a bunch of sites" becomes add-a-row, zero recompile. SOTA basis: reverse-proxy / API-gateway route tables reloadable without rebuild (knowledge/fetched/plat_reverse_proxy.raw, plat_api_mgmt.raw); see knowledge/research/2026-06-29-platform-sclass-exceed-standard.md. license_tier: ORIGINAL Config line: "<host|*> <path-prefix> <backend_port> <mode>" (hash = comment, blank lines ok) host exact (case-insensitive) or '*' wildcard; exact host wins over '*' path-prefix request-line path prefix, boundary-safe (/gen matches /gen,/gen/,/gen?x NOT /generated) backend_port loopback 127.0.0.1:<port> to reverse-proxy to mode buffered | stream | gated -- THE WORDS ARE THE VOCABULARY. The integers below are the internal encoding handed to the daemon and are NOT accepted conf spellings. Match rule: among all rows whose host+prefix match, LONGEST prefix wins; tie -> exact host beats '*'. FAIL-CLOSED MODE PARSE -- 2026-08-21, /compare/trafficsafety ITEM 1. pr_mode used to `return PR_MODE_BUFFERED` for ANY token it did not recognise, so a mistyped `gated` silently became the PERMISSIVE mode with no diagnostic, in the table that fronts every request. `gated` is the FAIL-CLOSED variant (302 /login when the backend is down); `buffered` is the permissive one -- so the old default was wrong in the dangerous direction by construction. NOW: the three documented words resolve to themselves, an OMITTED token keeps the documented default (buffered), and ANY other token resolves to PR_MODE_GATED -- fail closed. WHY NOT A HARD REFUSAL AT REQUEST TIME, decided from the call sites and not from taste. pr_lookup has exactly one production caller (nx_sites_daemon_v2) and its 0 return does not mean "refuse", it means "no route" -- the daemon then falls through to the legacy static cascade, which is precisely the path that answered a machine client with the HOMEPAGE as a 200 and triggered a retry storm (seq1294, both edge outages). Refusing a row at request time would therefore make the failure LESS safe, not more, and would brick every route in a conf holding one typo. The refusal belongs at LOAD time: pr_conf_scan enumerates every offending row with its line number so the loader ANNOUNCES a worklist once per (re)load, instead of emitting one wrong answer per request forever.

dependencies 1 imports · 3 importers

nx_syscalls.nx nx_proxy_route.nx nx_docportal_admin_daemon.nx nx_proxy_route_gate.nx nx_sites_daemon_v2.nx

imports: nx_syscalls.nx

imported by: nx_docportal_admin_daemon.nxnx_proxy_route_gate.nxnx_sites_daemon_v2.nx

structs

none

consts

37const PR_MODE_BUFFERED: i64 = 0
38const PR_MODE_STREAM: i64 = 1
39const PR_MODE_GATED: i64 = 2
44const PR_ASCII_TAB: i64 = 9
45const PR_ASCII_LF: i64 = 10
46const PR_ASCII_CR: i64 = 13
47const PR_ASCII_SP: i64 = 32
48const PR_ASCII_HASH: i64 = 35
49const PR_ASCII_STAR: i64 = 42
51const PR_ASCII_ZERO: i64 = 48
52const PR_DEC_BASE: i64 = 10
55const PR_ROW_TOKS: i64 = 5 // host prefix port mode [timeout=<s>] -- the 5th is OPTIONAL (2026-09-02, search L2a)
56const PR_TOK_HOST: i64 = 0
57const PR_TOK_PREFIX: i64 = 1
58const PR_TOK_PORT: i64 = 2
59const PR_TOK_MODE: i64 = 3
60const PR_TOK_TMO: i64 = 4
62const PR_TOK_OFF_BASE: i64 = 0
63const PR_TOK_LEN_BASE: i64 = 5 // == PR_ROW_TOKS: the len array sits past the off array
64const PR_I64_BYTES: i64 = 8
65const PR_LINE_ORIGIN: i64 = 1
118const PR_TMO_KEY: *u8 = "timeout=" as *u8
119const PR_TMO_KEYLEN: i64 = 8
327const PR_ANN_LINES_CAP: i64 = 16
328const PR_ANN_LINES_BYTES: i64 = 128
329const PR_ANN_BOX_BYTES: i64 = 8
330const PR_ANN_NUM_BYTES: i64 = 24

functions

67func pr_lower(c: u8) -> u8
73func pr_ieq(a: *u8, b: *u8, n: i64) -> i64
called by 1: pr_lookup_tmo calls 1: pr_lower
79func pr_strlen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
called by 1: pr_word
82func pr_word(s: *u8, n: i64, lit: *u8) -> i64
called by 2: pr_mode_knownpr_mode calls 1: pr_strlen
90func pr_parse_u(s: *u8, n: i64) -> i64
106func pr_mode_known(s: *u8, n: i64) -> i64
called by 2: pr_conf_scanmain calls 1: pr_word
120func pr_tmo_prefixed(s: *u8, n: i64) -> i64
called by 1: pr_tmo_known calls 1: pr_lower
126func pr_tmo_known(s: *u8, n: i64) -> i64
133func pr_parse_tmo(s: *u8, n: i64) -> i64
138func pr_mode(s: *u8, n: i64) -> i64
called by 2: pr_lookup_tmomain calls 1: pr_word
148func pr_path_pref(path: *u8, pn: i64, pref: *u8, prefn: i64) -> i64
called by 1: pr_lookup_tmo
168func pr_row_toks(cfg: *u8, cfgn: i64, start: i64, tok: *i64) -> i64
217func pr_lookup(cfg: *u8, cfgn: i64, host: *u8, hn: i64, path: *u8, pn: i64, out_port: *i64, out_mode: *i64) -> i64
called by 2: mainmain calls 2: sys_mmappr_lookup_tmo
222func pr_lookup_tmo(cfg: *u8, cfgn: i64, host: *u8, hn: i64, path: *u8, pn: i64, out_port: *i64, out_mode: *i64, out_tmo: *i64) -> i64
283func pr_conf_scan(cfg: *u8, cfgn: i64, out_lines: *i64, cap: i64, out_listed: *i64, out_rows: *i64) -> i64
332func pr_ann_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
called by 1: pr_conf_announce calls 1: sys_write
333func pr_ann_num(v: i64) -> i64
called by 1: pr_conf_announce calls 2: sys_writesys_mmap
344func pr_conf_announce(cfg: *u8, cfgn: i64) -> i64