code wiki / _hdl_build / nx_site_handler.nx
nx_site_handler.nx source
↩ module page · 80 lines · 4701 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 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}
20 var q: i64=k-1; while q>=0{d[o]=t[q];o=o+1;q=q-1} return o
21}
22
23// request-line path (between the 1st and 2nd ASCII space). -> len into out (NUL-term).
24func sh_path(req: *u8, n: i64, out: *u8, cap: i64) -> i64 {
25 var s1: i64 = 0-1; var i: i64 = 0
26 while i < n { if (req[i] as i64)==32 { s1=i; i=n } else { i=i+1 } }
27 if s1 < 0 { out[0]=0 as u8; return 0 }
28 var p: i64 = s1+1; var o: i64 = 0
29 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 } }
30 out[o]=0 as u8; return o
31}
32// Host header value -> len into out (NUL-term). finds "\nHost:" (so it can't match the request line), skips
33// spaces, copies to CR/LF. case-insensitive on the header name.
34func sh_host(req: *u8, n: i64, out: *u8, cap: i64) -> i64 {
35 var i: i64 = 0; var hs: i64 = 0-1
36 while i + 6 <= n {
37 if (req[i] as i64)==10 {
38 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
39 var hm: i64 = 0
40 if a==72 { if b==111 { if c==115 { if d==116 { if (req[i+5] as i64)==58 { hm=1 } } } } } // "Host:"
41 if a==104 { if b==111 { if c==115 { if d==116 { if (req[i+5] as i64)==58 { hm=1 } } } } } // "host:"
42 if hm==1 { hs=i+6; i=n }
43 }
44 if hs<0 { i=i+1 }
45 }
46 if hs < 0 { out[0]=0 as u8; return 0 }
47 var p: i64 = hs
48 var sk: i64 = 1
49 while sk==1 { if p>=n { sk=0 } else { if (req[p] as i64)==32 { p=p+1 } else { sk=0 } } }
50 var o: i64 = 0
51 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 } } }
52 out[o]=0 as u8; return o
53}
54
55func sh_handle(req: *u8, n: i64, rt: *u8, rtn: i64, vt: *u8, vtn: i64, out: *u8, dec: *i64) -> i64 {
56 let hostbuf: *u8 = sys_mmap(256); let pathbuf: *u8 = sys_mmap(SH_MAGIC_4096)
57 let hl: i64 = sh_host(req, n, hostbuf, 256)
58 let pl: i64 = sh_path(req, n, pathbuf, SH_MAGIC_4096)
59 let pb: *i64 = sys_mmap(8) as *i64; let mb: *i64 = sys_mmap(8) as *i64
60 if rt_match(rt, rtn, hostbuf, hl, pathbuf, pl, pb, mb) == 1 {
61 dec[0]=SH_PROXY; dec[1]=pb[0]; dec[2]=mb[0]; return 0
62 }
63 let drbuf: *u8 = sys_mmap(SH_MAGIC_2048)
64 if sd_vhost(vt, vtn, hostbuf, hl, drbuf) == 1 {
65 let szb: *i64 = sys_mmap(16) as *i64; szb[0]=0
66 let body: *u8 = sys_read_file(drbuf, szb)
67 if (body as i64)!=0 { if szb[0]>0 {
68 dec[0]=SH_STATIC
69 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)
70 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])
71 return o
72 } }
73 }
74 dec[0]=SH_NOTFOUND
75 let b: *u8 = "<!doctype html><meta charset=utf-8><title>404</title><h1>404 — not found</h1>" as *u8
76 var bn: i64=0; while b[bn]!=(0 as u8){bn=bn+1}
77 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)
78 o = sh_catn(out, o, bn); o = sh_cat(out, o, "\r\n\r\n" as *u8); o = sh_catb(out, o, b, bn)
79 return o
80}