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 — 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}