code wiki / _hdl_build / nx_vizsla_serve.nx

nx_vizsla_serve.nx source

↩ module page · 336 lines · 13390 B

1// nx_vizsla_serve.nx -- NISHI VIZSLA: the sovereign HTTP transport that makes the first-party UI LIVE in the 2// Nishi browser. Operator 2026-06-22: manage relationships IN the first party nishi browser, privacy-first. 3// Binds 127.0.0.1 ONLY (never exposed), no third-party, your data never leaves the box. 4// GET /<tid> -> fork nx_vizsla_render -> serve that tenant's sovereign 0-JS page (GET / -> elderwesto) 5// POST /v/submit -> read the form body -> fork nx_vizsla_action submit -> 303 redirect back to GET /<tid> 6// Socket accept loop is the proven gallery_serve idiom (fork-per-conn, reap). A `handle <base> <reqfile>` CLI 7// mode runs the router over a request read from a file (gateable without socket timing). tid validated 8// [A-Za-z0-9_-] = no path traversal. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10const K_MAGIC_719468: i64 = 719468 11const K_MAGIC_146097: i64 = 146097 12const K_MAGIC_146096: i64 = 146096 13const K_MAGIC_1460: i64 = 1460 14const K_MAGIC_36524: i64 = 36524 15const K_MAGIC_86400: i64 = 86400 16const K_MAGIC_65536: i64 = 65536 17const K_MAGIC_1048576: i64 = 1048576 18const K_MAGIC_18097: i64 = 18097 19 20func vs_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 21 22func vs_cat(dst: *u8, off: i64, s: *u8) -> i64 { 23 var i: i64 = 0 24 while s[i] != (0 as u8) { dst[off + i] = s[i]; i = i + 1 } 25 return off + i 26} 27 28func vs_catn(dst: *u8, off: i64, v: i64) -> i64 { 29 var o: i64 = off 30 var m: i64 = v 31 if m < 0 { dst[o] = 45 as u8; o = o + 1; m = 0 - m } 32 let t: *u8 = sys_mmap(28) 33 var k: i64 = 0 34 if m == 0 { t[0] = 48 as u8; k = 1 } 35 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 36 var i: i64 = 0 37 while i < k { dst[o + i] = t[k - 1 - i]; i = i + 1 } 38 return o + k 39} 40 41// req[0,rn) begins with pat ? 42func vs_match(req: *u8, rn: i64, pat: *u8) -> i64 { 43 let pl: i64 = vs_slen(pat) 44 if pl > rn { return 0 } 45 var j: i64 = 0 46 while j < pl { if req[j] != pat[j] { return 0 } j = j + 1 } 47 return 1 48} 49 50func vs_valid_tid(s: *u8) -> i64 { 51 if s[0] == (0 as u8) { return 0 } 52 var i: i64 = 0 53 while s[i] != (0 as u8) { 54 let c: i64 = s[i] as i64 55 var ok: i64 = 0 56 if c >= 48 { if c <= 57 { ok = 1 } } 57 if c >= 65 { if c <= 90 { ok = 1 } } 58 if c >= 97 { if c <= 122 { ok = 1 } } 59 if c == 45 { ok = 1 } 60 if c == 95 { ok = 1 } 61 if ok == 0 { return 0 } 62 i = i + 1 63 } 64 return 1 65} 66 67// from "GET /<tid> HTTP.." -> tid (until ' ' or '?'); empty if "GET / " 68func vs_pathtid(req: *u8, rn: i64, out: *u8) -> i64 { 69 var p: i64 = 0 70 while p < rn { if req[p] == (32 as u8) { break } p = p + 1 } // skip method 71 p = p + 1 72 if p < rn { if req[p] == (47 as u8) { p = p + 1 } } // skip leading '/' 73 var o: i64 = 0 74 while p < rn { 75 let c: i64 = req[p] as i64 76 if c == 32 { break } 77 if c == 63 { break } 78 if c == 47 { break } 79 if o < 127 { out[o] = c as u8; o = o + 1 } 80 p = p + 1 81 } 82 out[o] = 0 as u8 83 return o 84} 85 86func vs_keyeq(req: *u8, rn: i64, p: i64, key: *u8, kl: i64) -> i64 { 87 if p + kl + 1 > rn { return 0 } 88 var j: i64 = 0 89 while j < kl { if req[p + j] != key[j] { return 0 } j = j + 1 } 90 if req[p + kl] != (61 as u8) { return 0 } 91 return 1 92} 93 94// body starts after "\r\n\r\n"; find key= in body -> raw value (until '&'); 1 if found 95func vs_bodyfield(req: *u8, rn: i64, key: *u8, out: *u8) -> i64 { 96 var b: i64 = 0 - 1 97 var i: i64 = 0 98 while i + 3 < rn { 99 if req[i] == (13 as u8) { if req[i+1] == (10 as u8) { if req[i+2] == (13 as u8) { if req[i+3] == (10 as u8) { b = i + 4; i = rn } } } } 100 i = i + 1 101 } 102 if b < 0 { out[0] = 0 as u8; return 0 } 103 let kl: i64 = vs_slen(key) 104 var p: i64 = b 105 while p < rn { 106 var atb: i64 = 0 107 if p == b { atb = 1 } 108 if p > b { if req[p - 1] == (38 as u8) { atb = 1 } } 109 var hit: i64 = 0 110 if atb == 1 { hit = vs_keyeq(req, rn, p, key, kl) } 111 if hit == 1 { 112 var q: i64 = p + kl + 1 113 var o: i64 = 0 114 while q < rn { if req[q] == (38 as u8) { break } if o < 255 { out[o] = req[q]; o = o + 1 } q = q + 1 } 115 out[o] = 0 as u8 116 return 1 117 } 118 p = p + 1 119 } 120 out[0] = 0 as u8 121 return 0 122} 123 124// days since epoch -> civil (out[0]=y out[1]=m out[2]=d) 125func vs_civil(z0: i64, out: *i64) -> i64 { 126 var z: i64 = z0 + K_MAGIC_719468 127 var era: i64 = z / K_MAGIC_146097 128 if z < 0 { era = (z - K_MAGIC_146096) / K_MAGIC_146097 } 129 let doe: i64 = z - era * K_MAGIC_146097 130 let yoe: i64 = (doe - doe / K_MAGIC_1460 + doe / K_MAGIC_36524 - doe / K_MAGIC_146096) / 365 131 let y0: i64 = yoe + era * 400 132 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100) 133 let mp: i64 = (5 * doy + 2) / 153 134 let d: i64 = doy - (153 * mp + 2) / 5 + 1 135 var m: i64 = mp + 3 136 if mp >= 10 { m = mp - 9 } 137 var y: i64 = y0 138 if m <= 2 { y = y0 + 1 } 139 out[0] = y; out[1] = m; out[2] = d 140 return 0 141} 142 143func vs_today(out: *u8) -> i64 { 144 let sec: i64 = sys_now_realtime_sec() 145 let days: i64 = sec / K_MAGIC_86400 146 let ymd: *i64 = sys_mmap(8 * 4) as *i64 147 vs_civil(days, ymd) 148 var o: i64 = 0 149 o = vs_catn(out, o, ymd[0]); out[o] = 45 as u8; o = o + 1 150 if ymd[1] < 10 { out[o] = 48 as u8; o = o + 1 } 151 o = vs_catn(out, o, ymd[1]); out[o] = 45 as u8; o = o + 1 152 if ymd[2] < 10 { out[o] = 48 as u8; o = o + 1 } 153 o = vs_catn(out, o, ymd[2]); out[o] = 0 as u8 154 return o 155} 156 157func vs_readall(path: *u8, szp: *i64) -> *u8 { 158 let fd: i64 = sys_openat_rd(path) 159 if fd < 0 { szp[0] = 0; return 0 as *u8 } 160 let sz: i64 = sys_lseek(fd, 0, 2) 161 sys_lseek(fd, 0, 0) 162 let buf: *u8 = sys_mmap(sz + 64) 163 var got: i64 = 0 164 var n: i64 = 1 165 while n > 0 { n = sys_read(fd, (buf as i64 + got) as *u8, K_MAGIC_65536); if n > 0 { got = got + n } } 166 sys_close(fd) 167 szp[0] = got 168 return buf 169} 170 171// fork render -> /tmp page -> wrap as HTTP 200 in rbuf; returns total length 172func vs_render(base: *u8, tid: *u8, rbuf: *u8) -> i64 { 173 let today: *u8 = sys_mmap(32); vs_today(today) 174 let tmp: *u8 = sys_mmap(256) 175 var to: i64 = 0 176 to = vs_cat(tmp, to, "/tmp/vs_pg_" as *u8); to = vs_catn(tmp, to, sys_now_us()); to = vs_cat(tmp, to, ".html" as *u8); tmp[to] = 0 as u8 177 let pid: i64 = sys_fork() 178 if pid == 0 { 179 let nul: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4) 180 if nul >= 0 { sys_dup3(nul, 1, 0); sys_dup3(nul, 2, 0) } 181 let argv: *i64 = sys_mmap(64) as *i64 182 argv[0] = "_offc/nx_vizsla_render.elf" as *u8 as i64 183 argv[1] = "page" as *u8 as i64 184 argv[2] = base as i64 185 argv[3] = tid as i64 186 argv[4] = today as i64 187 argv[5] = tmp as i64 188 argv[6] = 0 189 let envp: *i64 = sys_mmap(16) as *i64 190 envp[0] = 0 191 sys_execve_clean("_offc/nx_vizsla_render.elf" as *u8, argv, envp) 192 sys_exit(127) 193 } 194 let st: *i64 = sys_mmap(16) as *i64 195 sys_wait4(pid, st, 0) 196 let szp: *i64 = sys_mmap(16) as *i64 197 let hb: *u8 = vs_readall(tmp, szp) 198 let hn: i64 = szp[0] 199 if hn <= 0 { 200 return vs_cat(rbuf, 0, "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 14\r\nConnection: close\r\n\r\nno such tenant" as *u8) 201 } 202 var o: i64 = 0 203 o = vs_cat(rbuf, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nCache-Control: no-store\r\nReferrer-Policy: no-referrer\r\nConnection: close\r\nContent-Length: " as *u8) 204 o = vs_catn(rbuf, o, hn) 205 o = vs_cat(rbuf, o, "\r\n\r\n" as *u8) 206 var k: i64 = 0 207 while k < hn { rbuf[o] = hb[k]; o = o + 1; k = k + 1 } 208 return o 209} 210 211func vs_redirect(tid: *u8, rbuf: *u8) -> i64 { 212 var o: i64 = 0 213 o = vs_cat(rbuf, o, "HTTP/1.1 303 See Other\r\nLocation: /" as *u8) 214 o = vs_cat(rbuf, o, tid) 215 o = vs_cat(rbuf, o, "\r\nContent-Length: 0\r\nConnection: close\r\n\r\n" as *u8) 216 return o 217} 218 219// fork the blessed action controller: submit <base> <tid> <action> <body> 220func vs_run_action(base: *u8, tid: *u8, action: *u8, body: *u8) -> i64 { 221 let pid: i64 = sys_fork() 222 if pid == 0 { 223 let nul: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4) 224 if nul >= 0 { sys_dup3(nul, 1, 0); sys_dup3(nul, 2, 0) } 225 let argv: *i64 = sys_mmap(64) as *i64 226 argv[0] = "_offc/nx_vizsla_action.elf" as *u8 as i64 227 argv[1] = "submit" as *u8 as i64 228 argv[2] = base as i64 229 argv[3] = tid as i64 230 argv[4] = action as i64 231 argv[5] = body as i64 232 argv[6] = 0 233 let envp: *i64 = sys_mmap(16) as *i64 234 envp[0] = 0 235 sys_execve_clean("_offc/nx_vizsla_action.elf" as *u8, argv, envp) 236 sys_exit(127) 237 } 238 let st: *i64 = sys_mmap(16) as *i64 239 sys_wait4(pid, st, 0) 240 return (st[0] >> 8) & 0xff 241} 242 243// the router: GET -> render, POST /v/submit -> action + 303 244func vs_handle(req: *u8, rn: i64, base: *u8, rbuf: *u8) -> i64 { 245 if vs_match(req, rn, "POST /v/submit" as *u8) == 1 { 246 let tid: *u8 = sys_mmap(256) 247 let action: *u8 = sys_mmap(256) 248 vs_bodyfield(req, rn, "tid" as *u8, tid) 249 vs_bodyfield(req, rn, "action" as *u8, action) 250 var rtid: *u8 = "elderwesto" as *u8 251 if vs_valid_tid(tid) == 1 { rtid = tid } 252 // the body (after headers) is what the action organ parses for id/name/... 253 var b: i64 = 0 - 1 254 var i: i64 = 0 255 while i + 3 < rn { 256 if req[i] == (13 as u8) { if req[i+1] == (10 as u8) { if req[i+2] == (13 as u8) { if req[i+3] == (10 as u8) { b = i + 4; i = rn } } } } 257 i = i + 1 258 } 259 if b >= 0 { 260 let bl: i64 = rn - b 261 let body: *u8 = sys_mmap(bl + 8) 262 var c: i64 = 0 263 while c < bl { body[c] = req[b + c]; c = c + 1 } 264 body[bl] = 0 as u8 265 if vs_valid_tid(tid) == 1 { if action[0] != (0 as u8) { vs_run_action(base, tid, action, body) } } 266 } 267 return vs_redirect(rtid, rbuf) 268 } 269 let tid: *u8 = sys_mmap(256) 270 vs_pathtid(req, rn, tid) 271 var rtid: *u8 = "elderwesto" as *u8 272 if vs_valid_tid(tid) == 1 { rtid = tid } 273 return vs_render(base, rtid, rbuf) 274} 275 276func main(argc: i64, argv: *i64) -> i64 { 277 // explicit subcommand so a bare run (how the build runner invokes it) does NOT block in accept() 278 if argc < 2 { let u: *u8 = "VIZSLA-SERVE usage: serve [port] [base] | handle <base> <reqfile>\n" as *u8; sys_write(2, u, vs_slen(u)); return 1 } 279 let cmd: *u8 = argv[1] as *u8 280 281 // handle mode (gate hook): run the router over a request read from a file 282 if vs_match(cmd, vs_slen(cmd), "handle" as *u8) == 1 { 283 if argc < 4 { let u: *u8 = "VIZSLA-SERVE handle needs <base> <reqfile>\n" as *u8; sys_write(2, u, vs_slen(u)); return 1 } 284 let base: *u8 = argv[2] as *u8 285 let szp: *i64 = sys_mmap(16) as *i64 286 let req: *u8 = vs_readall(argv[3] as *u8, szp) 287 let rn: i64 = szp[0] 288 let rbuf: *u8 = sys_mmap(K_MAGIC_1048576) 289 let rlen: i64 = vs_handle(req, rn, base, rbuf) 290 sys_write(1, rbuf, rlen) 291 return 0 292 } 293 294 if vs_match(cmd, vs_slen(cmd), "serve" as *u8) == 0 { let u: *u8 = "VIZSLA-SERVE unknown command (serve|handle)\n" as *u8; sys_write(2, u, vs_slen(u)); return 1 } 295 296 // serve mode: serve [port] [base] 297 var port: i64 = K_MAGIC_18097 298 var base: *u8 = "knowledge/vizsla/" as *u8 299 if argc >= 3 { var pv: i64 = 0; var pi: i64 = 0; let pa: *u8 = argv[2] as *u8; while pa[pi] != (0 as u8) { if pa[pi] >= (48 as u8) { if pa[pi] <= (57 as u8) { pv = pv * 10 + ((pa[pi] as i64) - 48) } } pi = pi + 1 } if pv > 0 { port = pv } } 300 if argc >= 4 { base = argv[3] as *u8 } 301 302 let addr: *u8 = sys_mmap(16) 303 addr[0] = 2 as u8; addr[1] = 0 as u8; addr[2] = ((port >> 8) & 0xff) as u8; addr[3] = (port & 0xff) as u8 304 addr[4] = 127 as u8; addr[5] = 0 as u8; addr[6] = 0 as u8; addr[7] = 1 as u8 305 addr[8] = 0 as u8; addr[9] = 0 as u8; addr[10] = 0 as u8; addr[11] = 0 as u8; addr[12] = 0 as u8; addr[13] = 0 as u8; addr[14] = 0 as u8; addr[15] = 0 as u8 306 let lfd: i64 = sys_socket(2, 1, 0) 307 if lfd < 0 { return 10 } 308 let optval: *u8 = sys_mmap(4); optval[0] = 1 as u8; optval[1] = 0 as u8; optval[2] = 0 as u8; optval[3] = 0 as u8 309 sys_setsockopt(lfd, 1, 2, optval, 4) 310 if sys_bind(lfd, addr, 16) < 0 { return 20 } 311 if sys_listen(lfd, 64) < 0 { return 30 } 312 let banner: *u8 = "VIZSLA-SERVE listening on http://127.0.0.1:" as *u8; sys_write(2, banner, vs_slen(banner)) 313 let pbuf: *u8 = sys_mmap(16); var pbo: i64 = vs_catn(pbuf, 0, port); pbuf[pbo] = 10 as u8; sys_write(2, pbuf, pbo + 1) 314 315 let req: *u8 = sys_mmap(K_MAGIC_65536) 316 let reapst: *i64 = sys_mmap(16) as *i64 317 while 1 == 1 { 318 let cfd: i64 = sys_accept(lfd) 319 if cfd < 0 { continue } 320 let pid: i64 = sys_fork() 321 if pid == 0 { 322 sys_close(lfd) 323 let rn: i64 = sys_read(cfd, req, K_MAGIC_65536) 324 let rbuf: *u8 = sys_mmap(K_MAGIC_1048576) 325 let rlen: i64 = vs_handle(req, rn, base, rbuf) 326 sys_write(cfd, rbuf, rlen) 327 sys_close(cfd) 328 sys_exit(0) 329 } 330 sys_close(cfd) 331 var reaped: i64 = 1 332 while reaped > 0 { reaped = sys_wait4(0 - 1, reapst, 1) } 333 } 334 sys_close(lfd) 335 return 0 336}