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}