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}