code wiki / _hdl_build / nx_hub_gw_decide.nx
nx_hub_gw_decide.nx source
↩ module page · 114 lines · 6036 B
1// nx_hub_gw_decide.nx -- the HUB gateway's PURE request->decision handler (bytes in, HTTP status out).
2// 2026-07-29 seq1232 (P2 safe-subset): per-call scratch -> lazy statics (no-munmap page leak class).
3static gd_scr_fs: *i64
4static gd_scr_fe: *i64
5static gd_scr_path: *u8
6static gd_scr_tok: *u8
7static gd_scr_handle: *u8
8// This is the glue that makes the maturity-flag router live: it parses a raw HTTP request, resolves the
9// OPAQUE no-cookie session token -> handle, calls mr_route, and maps the action to an HTTP status. Pure
10// (no socket) so it is gated in-process per the sovereignty exemplar (bytes-in/bytes-out handler + gate;
11// no curl/sed/port/timing). The daemon shell is a thin loop over this + hr_serve2 for the 200 body.
12//
13// SESSION RESOLUTION SEAM (drop-in for the live daemon): hgw_resolve_handle() looks up a sessions
14// registry (token<TAB>handle) -- a faithful, testable stand-in for the proven live chain in the OPAQUE
15// login daemon: olg_whoami(ctx, token, ...) -> uid -> olgd_idx_lookup(uid) -> handle (see
16// nx_opaque_login_daemon.nx:281-338). The live daemon replaces this one call; everything else is identical.
17//
18// STATUS MAP (fail-closed): SERVE->200 DENY(no session)->302 /login DENY(logged-in, under-level)->403
19// NOTFOUND->404 TIER_MISMATCH->404 (never leak that it exists in another zone)
20// Sovereign: nx_syscalls + nx_site_lock_lib + nx_maturity_registry. license_tier: ORIGINAL
21import "nx_syscalls.nx"
22import "nx_site_lock_lib.nx"
23import "nx_maturity_registry.nx"
24const K_MAGIC_1024: i64 = 1024
25
26// extract the request-target from the request line "METHOD <path> HTTP/x" -> out (nul-terminated). len or 0.
27func hgw_path(req: *u8, n: i64, out: *u8, cap: i64) -> i64 {
28 var sp1: i64 = 0 - 1; var i: i64 = 0
29 while i < n { if sp1 < 0 { if req[i] == (32 as u8) { sp1 = i } } i = i + 1 }
30 if sp1 < 0 { return 0 }
31 var sp2: i64 = 0 - 1; var j: i64 = sp1 + 1
32 while j < n { if sp2 < 0 { if req[j] == (32 as u8) { sp2 = j } } j = j + 1 }
33 if sp2 < 0 { return 0 }
34 var o: i64 = 0; var k: i64 = sp1 + 1
35 while k < sp2 { if o < cap - 1 { out[o] = req[k] } o = o + 1; k = k + 1 }
36 out[o] = 0 as u8
37 return o
38}
39
40// extract a header value by name (name includes the ':'); tolerant of '\n' or '\r\n' line endings. len or 0.
41func hgw_hdr_val(req: *u8, n: i64, name: *u8, namelen: i64, out: *u8, cap: i64) -> i64 {
42 var ls: i64 = 0
43 while ls < n {
44 var le: i64 = ls; var rg: i64 = 1
45 while rg == 1 { if le >= n { rg = 0 } else { if req[le] == (10 as u8) { rg = 0 } else { le = le + 1 } } }
46 if le - ls >= namelen {
47 var m: i64 = 1; var c: i64 = 0
48 while c < namelen { if req[ls + c] != name[c] { m = 0; c = namelen } else { c = c + 1 } }
49 if m == 1 {
50 var vs: i64 = ls + namelen; var sk: i64 = 1
51 while sk == 1 { if vs >= le { sk = 0 } else { if req[vs] == (32 as u8) { vs = vs + 1 } else { sk = 0 } } }
52 var ve: i64 = le
53 if ve > vs { if req[ve - 1] == (13 as u8) { ve = ve - 1 } }
54 var o: i64 = 0; var k: i64 = vs
55 while k < ve { if o < cap - 1 { out[o] = req[k] } o = o + 1; k = k + 1 }
56 out[o] = 0 as u8
57 return o
58 }
59 }
60 ls = le + 1
61 }
62 out[0] = 0 as u8
63 return 0
64}
65
66// token -> handle via the sessions registry (token<TAB>handle). SEAM: live daemon swaps this for
67// olg_whoami + olgd_idx_lookup. Returns handle length (0 = no/invalid session = anonymous).
68func hgw_resolve_handle(sessions: *u8, slen: i64, token: *u8, tlen: i64, out: *u8, cap: i64) -> i64 {
69 if (gd_scr_fs as i64) == 0 { gd_scr_fs = sys_mmap(8) as *i64 }
70 if (gd_scr_fe as i64) == 0 { gd_scr_fe = sys_mmap(8) as *i64 }
71 let fs: *i64 = gd_scr_fs; let fe: *i64 = gd_scr_fe
72 var ls: i64 = 0
73 while ls < slen {
74 let le: i64 = slk_line_end(sessions, slen, ls)
75 if le > ls { if sessions[ls] != (35 as u8) {
76 if slk_field(sessions, ls, le, 0, fs, fe) == 1 {
77 if slk_eq(slk_at(sessions, fs[0]), fe[0] - fs[0], token, tlen) == 1 {
78 if slk_field(sessions, ls, le, 1, fs, fe) == 1 {
79 var o: i64 = 0; let hl: i64 = fe[0] - fs[0]
80 while o < hl { if o < cap - 1 { out[o] = sessions[fs[0] + o] } o = o + 1 }
81 out[o] = 0 as u8
82 return o
83 }
84 }
85 }
86 } }
87 ls = le + 1
88 }
89 out[0] = 0 as u8
90 return 0
91}
92
93// THE HANDLER. Returns the mr_route action (1 SERVE / 0 DENY / -1 NOTFOUND / -2 MISMATCH) and writes the
94// HTTP status to out_status[0]; on SERVE, out_target = the doc-root-relative file to send.
95func hgw_decide(req: *u8, n: i64, registry: *u8, reglen: i64, roles: *u8, rolelen: i64,
96 sessions: *u8, seslen: i64,
97 out_status: *i64, out_target: *u8, tcap: i64, out_req: *i64, out_grant: *i64) -> i64 {
98 out_req[0] = 0; out_grant[0] = 0
99 if (gd_scr_path as i64) == 0 { gd_scr_path = sys_mmap(K_MAGIC_1024) }
100 if (gd_scr_tok as i64) == 0 { gd_scr_tok = sys_mmap(512) }
101 if (gd_scr_handle as i64) == 0 { gd_scr_handle = sys_mmap(128) }
102 let path: *u8 = gd_scr_path; let pl: i64 = hgw_path(req, n, path, K_MAGIC_1024)
103 let tok: *u8 = gd_scr_tok; let tl: i64 = hgw_hdr_val(req, n, "X-Nishi-Session:" as *u8, 16, tok, 512)
104 let handle: *u8 = gd_scr_handle; var hl: i64 = 0
105 if tl > 0 { hl = hgw_resolve_handle(sessions, seslen, tok, tl, handle, 128) }
106 let act: i64 = mr_route(registry, reglen, roles, rolelen, path, pl, handle, hl, out_target, tcap, out_req, out_grant)
107 if act == 1 { out_status[0] = 200; return act }
108 if act == 0 {
109 if out_grant[0] == 0 { out_status[0] = 302 } else { out_status[0] = 403 }
110 return act
111 }
112 out_status[0] = 404 // NOTFOUND(-1) and TIER_MISMATCH(-2) both -> 404 (no leak)
113 return act
114}