code wiki / _hdl_build / nx_site_handler.nx

nx_site_handler.nx source

↩ module page · 81 lines · 4767 B

1// nx_site_handler.nx -- the RECONCILED daemon's REQUEST HANDLER (bytes-in -> bytes-out, the part the TLS shell 2// wraps). Parses the decrypted HTTP request (Host + path), runs the data-driven decision (rt_match route / sd_vhost 3// docroot), and EITHER serves the vhost's docroot file (STATIC 200, or 404 if missing) OR signals the transport to 4// PROXY (port+mode -- the streaming relay is the io layer's job). NO hardcoded routes/hosts. The cert was already 5// chosen by the transport at handshake time (SNI -> cr_match), so the handler is route/static only. The gate drives 6// this IN-PROCESS (craft request bytes -> assert response/decision), no TLS/socket. Composes nx_site_dispatch 7// (rt_match + sd_vhost). license_tier: ORIGINAL 8import "nx_site_dispatch.nx" 9const SH_MAGIC_4096: i64 = 4096 10const SH_MAGIC_2048: i64 = 2048 11 12const SH_PROXY: i64 = 0 // dec[1]=port dec[2]=mode -> transport relays (out_n returned 0) 13const SH_STATIC: i64 = 1 // out holds a full 200 response (docroot file) 14const SH_NOTFOUND: i64 = 2 // out holds a full 404 response 15 16func sh_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64=0; while s[i]!=(0 as u8){d[o]=s[i];o=o+1;i=i+1} return o } 17func sh_catb(d: *u8, o: i64, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n {d[o]=b[i];o=o+1;i=i+1} return o } 18func sh_catn(d: *u8, o: i64, v: i64) -> i64 { 19 if v < 0 { d[o] = 45 as u8; return sh_catn(d, o + 1, 0 - v) } 20 let t: *u8=sys_mmap(28); var m: i64=v; var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} 21 var q: i64=k-1; while q>=0{d[o]=t[q];o=o+1;q=q-1} return o 22} 23 24// request-line path (between the 1st and 2nd ASCII space). -> len into out (NUL-term). 25func sh_path(req: *u8, n: i64, out: *u8, cap: i64) -> i64 { 26 var s1: i64 = 0-1; var i: i64 = 0 27 while i < n { if (req[i] as i64)==32 { s1=i; i=n } else { i=i+1 } } 28 if s1 < 0 { out[0]=0 as u8; return 0 } 29 var p: i64 = s1+1; var o: i64 = 0 30 while p < n { let c: i64 = req[p] as i64; if c==32 { p=n } else { if o<cap-1 { out[o]=req[p]; o=o+1 } p=p+1 } } 31 out[o]=0 as u8; return o 32} 33// Host header value -> len into out (NUL-term). finds "\nHost:" (so it can't match the request line), skips 34// spaces, copies to CR/LF. case-insensitive on the header name. 35func sh_host(req: *u8, n: i64, out: *u8, cap: i64) -> i64 { 36 var i: i64 = 0; var hs: i64 = 0-1 37 while i + 6 <= n { 38 if (req[i] as i64)==10 { 39 let a: i64 = req[i+1] as i64; let b: i64 = req[i+2] as i64; let c: i64 = req[i+3] as i64; let d: i64 = req[i+4] as i64 40 var hm: i64 = 0 41 if a==72 { if b==111 { if c==115 { if d==116 { if (req[i+5] as i64)==58 { hm=1 } } } } } // "Host:" 42 if a==104 { if b==111 { if c==115 { if d==116 { if (req[i+5] as i64)==58 { hm=1 } } } } } // "host:" 43 if hm==1 { hs=i+6; i=n } 44 } 45 if hs<0 { i=i+1 } 46 } 47 if hs < 0 { out[0]=0 as u8; return 0 } 48 var p: i64 = hs 49 var sk: i64 = 1 50 while sk==1 { if p>=n { sk=0 } else { if (req[p] as i64)==32 { p=p+1 } else { sk=0 } } } 51 var o: i64 = 0 52 while p < n { let c: i64 = req[p] as i64; if c==13 { p=n } else { if c==10 { p=n } else { if o<cap-1 { out[o]=req[p]; o=o+1 } p=p+1 } } } 53 out[o]=0 as u8; return o 54} 55 56func sh_handle(req: *u8, n: i64, rt: *u8, rtn: i64, vt: *u8, vtn: i64, out: *u8, dec: *i64) -> i64 { 57 let hostbuf: *u8 = sys_mmap(256); let pathbuf: *u8 = sys_mmap(SH_MAGIC_4096) 58 let hl: i64 = sh_host(req, n, hostbuf, 256) 59 let pl: i64 = sh_path(req, n, pathbuf, SH_MAGIC_4096) 60 let pb: *i64 = sys_mmap(8) as *i64; let mb: *i64 = sys_mmap(8) as *i64 61 if rt_match(rt, rtn, hostbuf, hl, pathbuf, pl, pb, mb) == 1 { 62 dec[0]=SH_PROXY; dec[1]=pb[0]; dec[2]=mb[0]; return 0 63 } 64 let drbuf: *u8 = sys_mmap(SH_MAGIC_2048) 65 if sd_vhost(vt, vtn, hostbuf, hl, drbuf) == 1 { 66 let szb: *i64 = sys_mmap(16) as *i64; szb[0]=0 67 let body: *u8 = sys_read_file(drbuf, szb) 68 if (body as i64)!=0 { if szb[0]>0 { 69 dec[0]=SH_STATIC 70 var o: i64 = sh_cat(out, 0, "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: " as *u8) 71 o = sh_catn(out, o, szb[0]); o = sh_cat(out, o, "\r\n\r\n" as *u8); o = sh_catb(out, o, body, szb[0]) 72 return o 73 } } 74 } 75 dec[0]=SH_NOTFOUND 76 let b: *u8 = "<!doctype html><meta charset=utf-8><title>404</title><h1>404 &mdash; not found</h1>" as *u8 77 var bn: i64=0; while b[bn]!=(0 as u8){bn=bn+1} 78 var o: i64 = sh_cat(out, 0, "HTTP/1.1 404 Not Found\r\nContent-Type: text/html; charset=utf-8\r\nConnection: close\r\nContent-Length: " as *u8) 79 o = sh_catn(out, o, bn); o = sh_cat(out, o, "\r\n\r\n" as *u8); o = sh_catb(out, o, b, bn) 80 return o 81}