code wiki / _hdl_build / nx_host_router2_test.nx
nx_host_router2_test.nx source
↩ module page · 95 lines · 5492 B
1// nx_host_router2_test.nx -- ENGINEER gate for the v2 serving path
2// (hr_serve2 / hr_emit_b / hr_emit_404). Real files, real request bytes.
3// Proves: (1) 200 + keep-alive (NOT close) on hit, (2) MISS verdict on
4// absent file (daemon falls through to legacy routing -- the rung that
5// lets nishifamily.com live in sites.conf without killing /wiki),
6// (3) MISS on unknown host, (4) 400 on traversal, (5) TOOBIG -> 500 when
7// the file exceeds outcap (the old hr_emit memory-corruption defect),
8// (6) new MIME entries (.webmanifest), (7) hr_emit_404 well-formed,
9// (8) old hr_serve byte-behaviour untouched (API contract stability).
10// license_tier: ORIGINAL
11
12import "nx_host_router.nx"
13
14func t_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
15func t_pn(v: i64) -> i64 { let b: *u8=sys_mmap(28); let nn: i64=hr_putdec(b,v); sys_write(1,b,nn); return 0 }
16func t_wr(path: *u8, data: *u8, n: i64) -> i64 { let fd: i64=sys_openat_wr(path,0x1a4); if fd<0{return 0-1} sys_write(fd,data,n); sys_close(fd); return 0 }
17func t_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
18func t_has(hay: *u8, hn: i64, needle: *u8) -> i64 {
19 let nn: i64=t_slen(needle)
20 if nn==0 { return 1 }
21 var i: i64=0
22 while i+nn<=hn { var k: i64=0; var ok: i64=1; while k<nn { if hay[i+k]!=needle[k]{ok=0; k=nn} k=k+1 } if ok==1 { return 1 } i=i+1 }
23 return 0
24}
25func t_check(name: *u8, cond: i64) -> i64 {
26 if cond==1 { t_puts(" PASS " as *u8) } else { t_puts(" FAIL " as *u8) }
27 t_puts(name); t_puts("\n" as *u8); return cond
28}
29
30func main() -> i64 {
31 t_puts("nx_host_router2 gate\n" as *u8)
32 // test doc roots live directly under /tmp (no mkdir dependency)
33 t_wr("/tmp/hr2_index.html" as *u8, "<h1>FAM2-HOME</h1>" as *u8, 18)
34 t_wr("/tmp/hr2_app.webmanifest" as *u8, "{}" as *u8, 2)
35 // 3000-byte file for the TOOBIG case (outcap 1024 below)
36 let big: *u8 = sys_mmap(3000)
37 var bi: i64 = 0
38 while bi < 3000 { big[bi] = (65 + (bi % 26)) as u8; bi = bi + 1 }
39 t_wr("/tmp/hr2_big.txt" as *u8, big, 3000)
40
41 let cfg: *u8 = "nishifamily.com /tmp\n" as *u8
42 let cfgn: i64 = t_slen(cfg)
43 let out: *u8 = sys_mmap(65536)
44 let nbox: *i64 = (sys_mmap(8)) as *i64
45 var pass: i64 = 0
46 var total: i64 = 0
47
48 // (1) hit -> OK verdict, 200, keep-alive
49 let r1: *u8 = "GET /hr2_index.html HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8
50 var v: i64 = hr_serve2(cfg, cfgn, r1, t_slen(r1), out, 65536, nbox)
51 pass = pass + t_check("hit -> HR_S2_OK" as *u8, v == HR_S2_OK); total = total + 1
52 pass = pass + t_check("hit -> 200 OK" as *u8, t_has(out, nbox[0], "200 OK" as *u8)); total = total + 1
53 pass = pass + t_check("hit -> body served" as *u8, t_has(out, nbox[0], "FAM2-HOME" as *u8)); total = total + 1
54 pass = pass + t_check("hit -> keep-alive (one handshake per page)" as *u8, t_has(out, nbox[0], "keep-alive" as *u8)); total = total + 1
55
56 // (2) absent file -> MISS (fallthrough), nothing written
57 let r2: *u8 = "GET /wiki/status HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8
58 v = hr_serve2(cfg, cfgn, r2, t_slen(r2), out, 65536, nbox)
59 pass = pass + t_check("absent file -> HR_S2_MISS (legacy fallthrough)" as *u8, v == HR_S2_MISS); total = total + 1
60 pass = pass + t_check("absent file -> out_n stays 0" as *u8, nbox[0] == 0); total = total + 1
61
62 // (3) unknown host -> MISS
63 let r3: *u8 = "GET / HTTP/1.1\r\nHost: nobody.example\r\n\r\n" as *u8
64 v = hr_serve2(cfg, cfgn, r3, t_slen(r3), out, 65536, nbox)
65 pass = pass + t_check("unknown host -> HR_S2_MISS" as *u8, v == HR_S2_MISS); total = total + 1
66
67 // (4) traversal -> BAD + 400
68 let r4: *u8 = "GET /../etc/passwd HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8
69 v = hr_serve2(cfg, cfgn, r4, t_slen(r4), out, 65536, nbox)
70 pass = pass + t_check("traversal -> HR_S2_BAD" as *u8, v == HR_S2_BAD); total = total + 1
71 pass = pass + t_check("traversal -> 400 response" as *u8, t_has(out, nbox[0], "400" as *u8)); total = total + 1
72
73 // (5) file bigger than outcap -> TOOBIG + 500 (NOT a buffer overflow)
74 let r5: *u8 = "GET /hr2_big.txt HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8
75 v = hr_serve2(cfg, cfgn, r5, t_slen(r5), out, 1024, nbox)
76 pass = pass + t_check("oversize file -> HR_S2_TOOBIG" as *u8, v == HR_S2_TOOBIG); total = total + 1
77 pass = pass + t_check("oversize file -> 500 response" as *u8, t_has(out, nbox[0], "500" as *u8)); total = total + 1
78
79 // (6) MIME: .webmanifest
80 let r6: *u8 = "GET /hr2_app.webmanifest HTTP/1.1\r\nHost: nishifamily.com\r\n\r\n" as *u8
81 v = hr_serve2(cfg, cfgn, r6, t_slen(r6), out, 65536, nbox)
82 pass = pass + t_check(".webmanifest -> manifest+json MIME" as *u8, t_has(out, nbox[0], "application/manifest+json" as *u8)); total = total + 1
83
84 // (7) hr_emit_404 well-formed
85 let n404: i64 = hr_emit_404(out, 65536)
86 pass = pass + t_check("hr_emit_404 -> 404 + keep-alive" as *u8, t_has(out, n404, "404 Not Found" as *u8)); total = total + 1
87
88 // (8) old hr_serve path unchanged: hit still 200 + Connection: close
89 let n8: i64 = hr_serve(cfg, cfgn, r1, t_slen(r1), out, 65536)
90 pass = pass + t_check("v1 hr_serve untouched (200 + close)" as *u8, t_has(out, n8, "Connection: close" as *u8)); total = total + 1
91
92 t_puts("---- router2 gate: passed " as *u8); t_pn(pass); t_puts(" / " as *u8); t_pn(total); t_puts(" ----\n" as *u8)
93 if pass == total { return 0 }
94 return 1
95}