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}