code wiki / _hdl_build / _gallery_serve_ref.nx

_gallery_serve_ref.nx source

↩ module page · 327 lines · 13613 B

1// _gallery_serve_ref.nx -- HAND REFERENCE (written ONCE, scratch) for the spec2 gallery daemon target. 2// This is the byte-identical TARGET nx_eg (which==2) must reproduce from a STRUCTURAL spec table. Its 3// control flow extends the PROVEN spec1 frame (socket->setsockopt->bind->listen->`while accept`-> 4// `if cfd<0 continue`->fork->dispatch->send) with a 3-ROUTE flat-if chain: 5// GET / -> gs_grid (browse: lists the REAL ingested img: CIDs from the seg-store) 6// GET /img/<CID> -> gs_serve_png (serves the REAL on-disk PNG bytes via a CID->path sidecar) 7// POST /rate -> gs_rate (same-origin enforced; appends EXACTLY one EVAL O-line) 8// Dialect rails honored: flat-ifs only (LM-002), no &&/|| (LM-001 -> compound guards are SEQUENCES of 9// flat ifs), funcs <=6 params (LM-BIGARGS), mask-after-shift port bytes (LM-005). The route literals 10// "GET / " / "GET /img/" / "POST /rate" are the tamperable spec fields. license_tier: ORIGINAL 11import "nx_seg_store.nx" 12import "nx_canon_cid.nx" 13import "nx_syscalls.nx" 14 15// substring match: does buf[0..n) contain the plen bytes of pat contiguously? (route + header probe) 16func eh_find(buf: *u8, n: i64, pat: *u8, plen: i64) -> i64 { 17 var i: i64 = 0 18 while i + plen <= n { 19 var j: i64 = 0 20 var ok: i64 = 1 21 while j < plen { 22 if buf[i+j] != pat[j] { ok = 0 } 23 j = j + 1 24 } 25 if ok == 1 { return 1 } 26 i = i + 1 27 } 28 return 0 29} 30 31// copy null-terminated s into dst at off; return new offset. 32func gs_cat(dst: *u8, off: i64, s: *u8) -> i64 { 33 var i: i64 = 0 34 while s[i] != (0 as u8) { dst[off+i] = s[i]; i = i + 1 } 35 return off + i 36} 37 38// write decimal v into dst at off; return new offset (v >= 0). 39func gs_u(dst: *u8, off: i64, v: i64) -> i64 { 40 var m: i64 = v 41 let t: *u8 = sys_mmap(28) 42 var k: i64 = 0 43 if m == 0 { t[0] = 48 as u8; k = 1 } 44 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 45 var o: i64 = off 46 var i: i64 = 0 47 while i < k { dst[o] = t[k-1-i]; o = o + 1; i = i + 1 } 48 return o 49} 50 51// append the HTML grid of every img: CID in the live store to body at off; return new offset. 52// Walks the manifest, reads each seg .docs, finds records whose key starts "img:" (105,109,103,58) 53// and emits the 68-byte CID after the prefix as a clickable <a href="/img/<CID>"> cell. 54func gs_grid_body(body: *u8, off: i64, prefix: *u8) -> i64 { 55 var o: i64 = off 56 let segs: *i64 = sys_mmap(8 * 260) as *i64 57 let ns: i64 = ss_manifest(prefix, segs) 58 var s: i64 = 0 59 while s < ns { 60 let path: *u8 = sys_mmap(512) 61 var po: i64 = 0 62 po = gs_cat(path, po, prefix) 63 po = gs_cat(path, po, segs[s] as *u8) 64 po = gs_cat(path, po, ".docs" as *u8) 65 path[po] = 0 as u8 66 let szp: *i64 = sys_mmap(16) as *i64 67 let b: *u8 = sys_read_file(path, szp) 68 let sz: i64 = szp[0] 69 var i: i64 = 0 70 while i + 9 <= sz { 71 let kl: i64 = ss_r32(b, i + 1) 72 let koff: i64 = i + 5 73 let vl: i64 = ss_r32(b, koff + kl) 74 let voff: i64 = koff + kl + 4 75 var isimg: i64 = 0 76 if kl == 73 { 77 isimg = 1 78 if b[koff] != (105 as u8) { isimg = 0 } 79 if b[koff+1] != (109 as u8) { isimg = 0 } 80 if b[koff+2] != (103 as u8) { isimg = 0 } 81 if b[koff+3] != (58 as u8) { isimg = 0 } 82 } 83 if isimg == 1 { 84 o = gs_cat(body, o, "<a class=\"cell\" href=\"/img/" as *u8) 85 var c: i64 = 0 86 while c < 69 { body[o] = b[koff + 4 + c]; o = o + 1; c = c + 1 } 87 o = gs_cat(body, o, "\"><img src=\"/img/" as *u8) 88 c = 0 89 while c < 69 { body[o] = b[koff + 4 + c]; o = o + 1; c = c + 1 } 90 o = gs_cat(body, o, "\" width=\"160\"><div>" as *u8) 91 c = 0 92 while c < 69 { body[o] = b[koff + 4 + c]; o = o + 1; c = c + 1 } 93 o = gs_cat(body, o, "</div></a>\n" as *u8) 94 } 95 i = voff + vl 96 } 97 s = s + 1 98 } 99 return o 100} 101 102// browse grid: build the HTML body into a temp buffer, then write a 200 header + body into rbuf. 103func gs_grid(rbuf: *u8, prefix: *u8) -> i64 { 104 let body: *u8 = sys_mmap(262144) 105 var bo: i64 = 0 106 bo = gs_cat(body, bo, "<!doctype html><meta charset=utf-8><title>Nishi Gallery</title><body><h1>Nishi Gallery</h1><div class=grid>\n" as *u8) 107 bo = gs_grid_body(body, bo, prefix) 108 bo = gs_cat(body, bo, "</div></body>" as *u8) 109 var o: i64 = 0 110 o = gs_cat(rbuf, o, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: " as *u8) 111 o = gs_u(rbuf, o, bo) 112 o = gs_cat(rbuf, o, "\r\nConnection: close\r\n\r\n" as *u8) 113 var i: i64 = 0 114 while i < bo { rbuf[o] = body[i]; o = o + 1; i = i + 1 } 115 return o 116} 117 118// peel the 68-char CID from req after the literal "GET /img/" into cidout (null-terminated); return 1 ok, 0 none. 119func gs_peel_cid(req: *u8, rn: i64, cidout: *u8) -> i64 { 120 let pat: *u8 = "GET /img/" as *u8 121 var i: i64 = 0 122 var at: i64 = 0 - 1 123 while i + 9 <= rn { 124 var j: i64 = 0 125 var ok: i64 = 1 126 while j < 9 { if req[i+j] != pat[j] { ok = 0 } j = j + 1 } 127 if ok == 1 { if at < 0 { at = i + 9 } } 128 i = i + 1 129 } 130 if at < 0 { return 0 } 131 var c: i64 = 0 132 while c < 69 { cidout[c] = req[at + c]; c = c + 1 } 133 cidout[69] = 0 as u8 134 return 1 135} 136 137// scan the CID->path sidecar TSV for cid (69 bytes); copy the absolute path into pathout (null-term); return 1 hit, 0 miss. 138func gs_sidecar(cid: *u8, pathout: *u8) -> i64 { 139 let szp: *i64 = sys_mmap(16) as *i64 140 let b: *u8 = sys_read_file("knowledge/status/galx_cid_paths.tsv" as *u8, szp) 141 let sz: i64 = szp[0] 142 if (b as i64) == 0 { return 0 } 143 var i: i64 = 0 144 var ls: i64 = 0 145 while i < sz { 146 if b[i] == (10 as u8) { 147 var eq: i64 = 1 148 var k: i64 = 0 149 while k < 69 { if b[ls + k] != cid[k] { eq = 0 } k = k + 1 } 150 if b[ls + 69] != (9 as u8) { eq = 0 } 151 if eq == 1 { 152 var po: i64 = 0 153 var p: i64 = ls + 70 154 while p < i { pathout[po] = b[p]; po = po + 1; p = p + 1 } 155 pathout[po] = 0 as u8 156 return 1 157 } 158 ls = i + 1 159 } 160 i = i + 1 161 } 162 return 0 163} 164 165// serve the real PNG bytes for the requested CID; emit 200+bytes on hit, 404 on miss; return length. 166func gs_serve_png(rbuf: *u8, req: *u8, rn: i64, root: *u8) -> i64 { 167 let cid: *u8 = sys_mmap(96) 168 let havec: i64 = gs_peel_cid(req, rn, cid) 169 if havec == 0 { return gs_cat(rbuf, 0, "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nnot found" as *u8) } 170 let path: *u8 = sys_mmap(512) 171 let havep: i64 = gs_sidecar(cid, path) 172 if havep == 0 { return gs_cat(rbuf, 0, "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nnot found" as *u8) } 173 let szp: *i64 = sys_mmap(16) as *i64 174 let png: *u8 = sys_read_file(path, szp) 175 let plen: i64 = szp[0] 176 if (png as i64) == 0 { return gs_cat(rbuf, 0, "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nnot found" as *u8) } 177 var o: i64 = 0 178 o = gs_cat(rbuf, o, "HTTP/1.1 200 OK\r\nContent-Type: image/png\r\nContent-Length: " as *u8) 179 o = gs_u(rbuf, o, plen) 180 o = gs_cat(rbuf, o, "\r\nConnection: close\r\n\r\n" as *u8) 181 var i: i64 = 0 182 while i < plen { rbuf[o] = png[i]; o = o + 1; i = i + 1 } 183 return o 184} 185 186// POST /rate handler: enforce same-origin, parse img=<id>&score=<permil>, append EXACTLY one EVAL O-line. 187// Same-origin = the request carries Host: 127.0.0.1:18090 (loopback self). A foreign Origin header that is 188// NOT our own origin -> 403, NO write. Returns response length. 189func gs_rate(rbuf: *u8, req: *u8, rn: i64) -> i64 { 190 // same-origin: must carry our own Host. A cross-site form post carries a foreign Origin: header. 191 let okhost: i64 = eh_find(req, rn, "Host: 127.0.0.1:18090" as *u8, 21) 192 if okhost != 1 { return gs_cat(rbuf, 0, "HTTP/1.1 403 Forbidden\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nforbidden" as *u8) } 193 // reject any foreign Origin (cross-origin attacker sets Origin to their site). Only our own Origin or none is allowed. 194 let hasorigin: i64 = eh_find(req, rn, "Origin: " as *u8, 8) 195 let okorigin: i64 = eh_find(req, rn, "Origin: http://127.0.0.1:18090" as *u8, 30) 196 var crossorigin: i64 = 0 197 if hasorigin == 1 { crossorigin = 1 } 198 if okorigin == 1 { crossorigin = 0 } 199 if crossorigin == 1 { return gs_cat(rbuf, 0, "HTTP/1.1 403 Forbidden\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nforbidden" as *u8) } 200 // locate the body (after the blank line CRLFCRLF) 201 var i: i64 = 0 202 var bodyat: i64 = 0 - 1 203 while i + 4 <= rn { 204 var ok: i64 = 1 205 if req[i] != (13 as u8) { ok = 0 } 206 if req[i+1] != (10 as u8) { ok = 0 } 207 if req[i+2] != (13 as u8) { ok = 0 } 208 if req[i+3] != (10 as u8) { ok = 0 } 209 if ok == 1 { if bodyat < 0 { bodyat = i + 4 } } 210 i = i + 1 211 } 212 if bodyat < 0 { return gs_cat(rbuf, 0, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nContent-Length: 3\r\nConnection: close\r\n\r\nbad" as *u8) } 213 // locate "img=" in the body, then copy the value up to '&' or end. 214 let img: *u8 = sys_mmap(128) 215 var im: i64 = 0 216 var iat: i64 = 0 - 1 217 var pi: i64 = bodyat 218 while pi + 4 <= rn { 219 var oki: i64 = 1 220 if req[pi] != (105 as u8) { oki = 0 } 221 if req[pi+1] != (109 as u8) { oki = 0 } 222 if req[pi+2] != (103 as u8) { oki = 0 } 223 if req[pi+3] != (61 as u8) { oki = 0 } 224 if oki == 1 { if iat < 0 { iat = pi + 4 } } 225 pi = pi + 1 226 } 227 if iat >= 0 { 228 var p: i64 = iat 229 var go: i64 = 1 230 while p < rn { if go == 1 { if req[p] == (38 as u8) { go = 0 } else { img[im] = req[p]; im = im + 1 } } p = p + 1 } 231 } 232 img[im] = 0 as u8 233 // locate "score=" in the body, then copy the digits. 234 let score: *u8 = sys_mmap(32) 235 var sm: i64 = 0 236 var sat: i64 = 0 - 1 237 var ps: i64 = bodyat 238 while ps + 6 <= rn { 239 var oks: i64 = 1 240 let sp: *u8 = "score=" as *u8 241 var jj: i64 = 0 242 while jj < 6 { if req[ps+jj] != sp[jj] { oks = 0 } jj = jj + 1 } 243 if oks == 1 { if sat < 0 { sat = ps + 6 } } 244 ps = ps + 1 245 } 246 if sat >= 0 { 247 var q: i64 = sat 248 var god: i64 = 1 249 while q < rn { if god == 1 { if req[q] >= (48 as u8) { if req[q] <= (57 as u8) { score[sm] = req[q]; sm = sm + 1 } else { god = 0 } } else { god = 0 } } q = q + 1 } 250 } 251 score[sm] = 0 as u8 252 // append EXACTLY one EVAL O-line 253 let logfd: i64 = sys_openat_append("knowledge/status/eval_lanes.log" as *u8, 0x1a4) 254 if logfd >= 0 { 255 let line: *u8 = sys_mmap(256) 256 var lo: i64 = 0 257 lo = gs_cat(line, lo, "EVAL img=" as *u8) 258 lo = gs_cat(line, lo, img) 259 lo = gs_cat(line, lo, " lane=O score=" as *u8) 260 lo = gs_cat(line, lo, score) 261 lo = gs_cat(line, lo, "\n" as *u8) 262 sys_write(logfd, line, lo) 263 sys_close(logfd) 264 } 265 return gs_cat(rbuf, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 5\r\nConnection: close\r\n\r\nrated" as *u8) 266} 267 268func main() -> i64 { 269 let port: i64 = 18090 270 let addr: *u8 = sys_mmap(16) 271 addr[0] = 2 as u8 272 addr[1] = 0 as u8 273 addr[2] = ((port >> 8) & 0xff) as u8 274 addr[3] = (port & 0xff) as u8 275 addr[4] = 127 as u8 276 addr[5] = 0 as u8 277 addr[6] = 0 as u8 278 addr[7] = 1 as u8 279 addr[8] = 0 as u8 280 addr[9] = 0 as u8 281 addr[10] = 0 as u8 282 addr[11] = 0 as u8 283 addr[12] = 0 as u8 284 addr[13] = 0 as u8 285 addr[14] = 0 as u8 286 addr[15] = 0 as u8 287 let lfd: i64 = sys_socket(2, 1, 0) 288 if lfd < 0 { return 10 } 289 let optval: *u8 = sys_mmap(4) 290 optval[0] = 1 as u8 291 optval[1] = 0 as u8 292 optval[2] = 0 as u8 293 optval[3] = 0 as u8 294 sys_setsockopt(lfd, 1, 2, optval, 4) 295 let brc: i64 = sys_bind(lfd, addr, 16) 296 if brc < 0 { return 20 } 297 let lrc: i64 = sys_listen(lfd, 16) 298 if lrc < 0 { return 30 } 299 let req: *u8 = sys_mmap(8192) 300 let nf404: *u8 = "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 9\r\nConnection: close\r\n\r\nnot found" as *u8 301 var served: i64 = 0 302 while served < 64 { 303 let cfd: i64 = sys_accept(lfd) 304 if cfd < 0 { continue } 305 let pid: i64 = sys_fork() 306 if pid == 0 { 307 sys_close(lfd) 308 let rn: i64 = sys_read(cfd, req, 8192) 309 var rbuf: *u8 = sys_mmap(262144) 310 var rlen: i64 = 0 311 let is_root: i64 = eh_find(req, rn, "GET / " as *u8, 6) 312 if is_root == 1 { rlen = gs_grid(rbuf, "/tmp/galx-serve-" as *u8) } 313 let is_img: i64 = eh_find(req, rn, "GET /img/" as *u8, 9) 314 if is_img == 1 { rlen = gs_serve_png(rbuf, req, rn, "/tmp/galx-serve-" as *u8) } 315 let is_rate: i64 = eh_find(req, rn, "POST /rate" as *u8, 10) 316 if is_rate == 1 { rlen = gs_rate(rbuf, req, rn) } 317 if rlen == 0 { rlen = gs_cat(rbuf, 0, nf404) } 318 sys_write(cfd, rbuf, rlen) 319 sys_close(cfd) 320 sys_exit(0) 321 } 322 sys_close(cfd) 323 served = served + 1 324 } 325 sys_close(lfd) 326 return 0 327}