code wiki / _hdl_build / nx_host_router.nx

nx_host_router.nx source

↩ module page · 931 lines · 49520 B

1// nx_host_router.nx -- S-class sovereign multi-site host router (pure Nishi, no TLS, no crypto). 2// Config-driven vhost table + PER-REQUEST file serving = HOT CONTENT LOADING: push a file, it is 3// live on the next request, NO recompile. Path-traversal-safe. This is L5 (content) of the sovereign 4// hosting design (knowledge/research/2026-06-05-sovereign-web-hosting.md). Composed into the TLS 5// daemon, which supplies L3/L4. license_tier: ORIGINAL 6import "nx_syscalls.nx" 7import "nx_fio.nx" 8import "nx_range_header.nx" 9const HR_S2_FILE_STREAM: i64 = 6 10// SOVEREIGN DEFLATE (2026-08-08). The estate's own RFC-1951 compressor has existed and been 11// gunzip-byte-identity proven since 2026-07-20, while this router emitted no Content-Encoding at 12// all -- nx_gzip.nx's header literally calls compression "the #1 remaining HOSTING SOTA gap". 13// The ONLY thing keeping them apart was that nx_gzip.nx defines main(), and NishiLang cannot 14// import a module with main(). nx_gzip_lib.nx is that file with main() renamed, so the deflate 15// code here is byte-identical to the KAT-proven original and inherits its correctness oracle. 16import "nx_gzip_lib.nx" 17const HR_MAGIC_9216: i64 = 9216 18const HR_MAGIC_8192: i64 = 8192 19const HR_MAGIC_1024: i64 = 1024 20const HR_MAGIC_4096: i64 = 4096 21const HR_MAGIC_5120: i64 = 5120 22const HR_MAGIC_2048: i64 = 2048 23const HR_MAGIC_4095: i64 = 4095 24 25func hr_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 26 27func hr_copy(dst: *u8, src: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { dst[i] = src[i]; i = i + 1 } return n } 28 29func hr_eq(a: *u8, b: *u8, n: i64) -> i64 { 30 var i: i64 = 0 31 while i < n { if a[i] != b[i] { return 0 } i = i + 1 } 32 return 1 33} 34 35func hr_lower(c: u8) -> u8 { 36 if c >= (65 as u8) { if c <= (90 as u8) { return (c + (32 as u8)) } } 37 return c 38} 39 40func hr_ieq(a: *u8, b: *u8, n: i64) -> i64 { 41 var i: i64 = 0 42 while i < n { if hr_lower(a[i]) != hr_lower(b[i]) { return 0 } i = i + 1 } 43 return 1 44} 45 46// Decimal-render v into out; return digit count (no modulo operator dependency). 47func hr_putdec(out: *u8, v: i64) -> i64 { 48 if v == 0 { out[0] = (48 as u8); return 1 } 49 let tmp: *u8 = sys_mmap(32) 50 var n: i64 = 0 51 var x: i64 = v 52 while x > 0 { 53 let q: i64 = x / 10 54 let r: i64 = x - q * 10 55 tmp[n] = ((48 + r) as u8) 56 n = n + 1 57 x = q 58 } 59 var i: i64 = 0 60 while i < n { out[i] = tmp[n - 1 - i]; i = i + 1 } 61 return n 62} 63 64// Extract the request path ("GET <path> HTTP/1.1") into out (NUL-terminated); drop any ?query. 65func hr_req_path(req: *u8, reqn: i64, out: *u8, cap: i64) -> i64 { 66 var i: i64 = 0 67 while i < reqn { if req[i] == (32 as u8) { break } i = i + 1 } 68 i = i + 1 69 var j: i64 = 0 70 while i < reqn { 71 let c: u8 = req[i] 72 if c == (32 as u8) { break } 73 if c == (63 as u8) { break } 74 if j < cap - 1 { out[j] = c; j = j + 1 } 75 i = i + 1 76 } 77 out[j] = (0 as u8) 78 return j 79} 80 81// Extract the ?query of the request line INCLUDING the leading '?' (empty -> 0). seq365: the canonical 82// 301 used to rebuild Location from the PATH alone, silently dropping ?room=&k=... from parameterized 83// links (family invites, probe URLs). Redirects must CARRY the query; this is its one extractor. 84func hr_req_query(req: *u8, reqn: i64, out: *u8, cap: i64) -> i64 { 85 var i: i64 = 0 86 while i < reqn { if req[i] == (32 as u8) { break } i = i + 1 } 87 i = i + 1 88 var q: i64 = 0 - 1 89 while i < reqn { 90 let c: u8 = req[i] 91 if c == (32 as u8) { break } 92 if c == (63 as u8) { q = i; break } 93 i = i + 1 94 } 95 if q < 0 { out[0] = (0 as u8); return 0 } 96 var j: i64 = 0 97 while q < reqn { 98 let c2: u8 = req[q] 99 if c2 == (32 as u8) { break } 100 if c2 == (13 as u8) { break } 101 if c2 == (10 as u8) { break } 102 if j < cap - 1 { out[j] = c2; j = j + 1 } 103 q = q + 1 104 } 105 out[j] = (0 as u8) 106 return j 107} 108 109// Extract the Host header (lowercased, port stripped) into out (NUL-terminated). 110func hr_req_host(req: *u8, reqn: i64, out: *u8, cap: i64) -> i64 { 111 var i: i64 = 0 112 var found: i64 = 0 - 1 113 while i + 5 <= reqn { 114 if hr_ieq(((req as i64 + i) as *u8), "host:" as *u8, 5) == 1 { found = i + 5; break } 115 i = i + 1 116 } 117 if found < 0 { out[0] = (0 as u8); return 0 } 118 var k: i64 = found 119 while k < reqn { if req[k] == (32 as u8) { k = k + 1 } else { break } } 120 var j: i64 = 0 121 while k < reqn { 122 let c: u8 = req[k] 123 if c == (13 as u8) { break } 124 if c == (10 as u8) { break } 125 if c == (58 as u8) { break } 126 if c == (32 as u8) { break } 127 if j < cap - 1 { out[j] = hr_lower(c); j = j + 1 } 128 k = k + 1 129 } 130 out[j] = (0 as u8) 131 return j 132} 133 134// Find the doc root for host in the config (lines "<host> <root>"; '#' comment; '*' wildcard default). 135// Exact host wins over wildcard regardless of line order. Returns root length (0 = no match). 136func hr_lookup_root(cfg: *u8, cfgn: i64, host: *u8, hostn: i64, out: *u8, cap: i64) -> i64 { 137 var i: i64 = 0 138 var wild: i64 = 0 - 1 139 var wildlen: i64 = 0 140 while i < cfgn { 141 while i < cfgn { let c: u8 = cfg[i]; if c == (32 as u8) { i = i + 1 } else { if c == (9 as u8) { i = i + 1 } else { break } } } 142 if i < cfgn { 143 if cfg[i] == (35 as u8) { 144 while i < cfgn { if cfg[i] == (10 as u8) { break } i = i + 1 } 145 i = i + 1 146 continue 147 } 148 } 149 let htok: i64 = i 150 while i < cfgn { let c: u8 = cfg[i]; if c == (32 as u8) { break } if c == (9 as u8) { break } if c == (10 as u8) { break } if c == (13 as u8) { break } i = i + 1 } 151 let htoklen: i64 = i - htok 152 while i < cfgn { let c: u8 = cfg[i]; if c == (32 as u8) { i = i + 1 } else { if c == (9 as u8) { i = i + 1 } else { break } } } 153 let rtok: i64 = i 154 while i < cfgn { let c: u8 = cfg[i]; if c == (32 as u8) { break } if c == (9 as u8) { break } if c == (10 as u8) { break } if c == (13 as u8) { break } i = i + 1 } 155 let rtoklen: i64 = i - rtok 156 while i < cfgn { if cfg[i] == (10 as u8) { break } i = i + 1 } 157 i = i + 1 158 if htoklen == hostn { 159 if hr_eq(((cfg as i64 + htok) as *u8), host, hostn) == 1 { 160 if rtoklen > 0 { hr_copy(out, ((cfg as i64 + rtok) as *u8), rtoklen); out[rtoklen] = (0 as u8); return rtoklen } 161 } 162 } 163 if htoklen == 1 { if cfg[htok] == (42 as u8) { if rtoklen > 0 { wild = rtok; wildlen = rtoklen } } } 164 } 165 if wild >= 0 { if wildlen > 0 { hr_copy(out, ((cfg as i64 + wild) as *u8), wildlen); out[wildlen] = (0 as u8); return wildlen } } 166 return 0 167} 168 169// Reject path traversal / NUL / non-absolute. Conservative: any ".." anywhere fails. 170func hr_path_safe(path: *u8, pathn: i64) -> i64 { 171 if pathn == 0 { return 0 } 172 if path[0] != (47 as u8) { return 0 } 173 var i: i64 = 0 174 while i < pathn { 175 if path[i] == (0 as u8) { return 0 } 176 if path[i] == (46 as u8) { if i + 1 < pathn { if path[i + 1] == (46 as u8) { return 0 } } } 177 i = i + 1 178 } 179 return 1 180} 181 182// Join root + path into out; append index.html when the path ends in '/'. 183func hr_resolve(root: *u8, rootn: i64, path: *u8, pathn: i64, out: *u8, cap: i64) -> i64 { 184 var j: i64 = 0 185 var i: i64 = 0 186 while i < rootn { if j < cap - 1 { out[j] = root[i]; j = j + 1 } i = i + 1 } 187 if j > 0 { if out[j - 1] == (47 as u8) { j = j - 1 } } 188 i = 0 189 while i < pathn { if j < cap - 1 { out[j] = path[i]; j = j + 1 } i = i + 1 } 190 if pathn > 0 { 191 if path[pathn - 1] == (47 as u8) { 192 // path ends in '/': append index.html 193 let idx: *u8 = "index.html" as *u8 194 var k: i64 = 0 195 while idx[k] != (0 as u8) { if j < cap - 1 { out[j] = idx[k]; j = j + 1 } k = k + 1 } 196 } else { 197 // bare path: if the last segment has no '.', it is a directory -> 198 // append /index.html so a CLEAN URL (e.g. /econsim) serves the page 199 // instead of reading the dir as a 0-byte octet-stream download. 200 var seg_has_dot: i64 = 0 201 var s: i64 = pathn - 1 202 while s >= 0 { 203 if path[s] == (47 as u8) { break } 204 if path[s] == (46 as u8) { seg_has_dot = 1; break } 205 s = s - 1 206 } 207 if seg_has_dot == 0 { 208 let idx2: *u8 = "/index.html" as *u8 209 var k2: i64 = 0 210 while idx2[k2] != (0 as u8) { if j < cap - 1 { out[j] = idx2[k2]; j = j + 1 } k2 = k2 + 1 } 211 } 212 } 213 } 214 out[j] = (0 as u8) 215 return j 216} 217 218// MIME by extension. 219func hr_ctype(file: *u8, filen: i64) -> *u8 { 220 var dot: i64 = 0 - 1 221 var i: i64 = 0 222 while i < filen { if file[i] == (46 as u8) { dot = i } i = i + 1 } 223 if dot < 0 { return "application/octet-stream" as *u8 } 224 let ext: *u8 = (file as i64 + dot) as *u8 225 if hr_ieq(ext, ".html" as *u8, 5) == 1 { return "text/html; charset=utf-8" as *u8 } 226 if hr_ieq(ext, ".htm" as *u8, 4) == 1 { return "text/html; charset=utf-8" as *u8 } 227 if hr_ieq(ext, ".css" as *u8, 4) == 1 { return "text/css; charset=utf-8" as *u8 } 228 if hr_ieq(ext, ".json" as *u8, 5) == 1 { return "application/json" as *u8 } 229 // .xml (2026-07-30): sitemap.xml was being served as application/octet-stream because the map had no 230 // XML row -- the one file on the site whose entire purpose is to be parsed by a machine was the one 231 // told it was an opaque blob. RFC 7303 media type; sitemaps.org expects an XML content type. 232 if hr_ieq(ext, ".xml" as *u8, 4) == 1 { return "application/xml; charset=utf-8" as *u8 } 233 if hr_ieq(ext, ".js" as *u8, 3) == 1 { return "application/javascript" as *u8 } 234 if hr_ieq(ext, ".png" as *u8, 4) == 1 { return "image/png" as *u8 } 235 if hr_ieq(ext, ".jpg" as *u8, 4) == 1 { return "image/jpeg" as *u8 } 236 if hr_ieq(ext, ".jpeg" as *u8, 5) == 1 { return "image/jpeg" as *u8 } 237 if hr_ieq(ext, ".svg" as *u8, 4) == 1 { return "image/svg+xml" as *u8 } 238 if hr_ieq(ext, ".gif" as *u8, 4) == 1 { return "image/gif" as *u8 } 239 if hr_ieq(ext, ".txt" as *u8, 4) == 1 { return "text/plain; charset=utf-8" as *u8 } 240 if hr_ieq(ext, ".ico" as *u8, 4) == 1 { return "image/x-icon" as *u8 } 241 if hr_ieq(ext, ".pdf" as *u8, 4) == 1 { return "application/pdf" as *u8 } 242 if hr_ieq(ext, ".webmanifest" as *u8, 12) == 1 { return "application/manifest+json" as *u8 } 243 if hr_ieq(ext, ".wasm" as *u8, 5) == 1 { return "application/wasm" as *u8 } 244 if hr_ieq(ext, ".mp4" as *u8, 4) == 1 { return "video/mp4" as *u8 } 245 if hr_ieq(ext, ".webm" as *u8, 5) == 1 { return "video/webm" as *u8 } 246 if hr_ieq(ext, ".woff2" as *u8, 6) == 1 { return "font/woff2" as *u8 } 247 // interop artifacts (the office/coordination second-half): calendar subscribe + office docs 248 if hr_ieq(ext, ".ics" as *u8, 4) == 1 { return "text/calendar; charset=utf-8" as *u8 } 249 if hr_ieq(ext, ".docx" as *u8, 5) == 1 { return "application/vnd.openxmlformats-officedocument.wordprocessingml.document" as *u8 } 250 if hr_ieq(ext, ".xlsx" as *u8, 5) == 1 { return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" as *u8 } 251 if hr_ieq(ext, ".pptx" as *u8, 5) == 1 { return "application/vnd.openxmlformats-officedocument.presentationml.presentation" as *u8 } 252 if hr_ieq(ext, ".odt" as *u8, 4) == 1 { return "application/vnd.oasis.opendocument.text" as *u8 } 253 if hr_ieq(ext, ".eml" as *u8, 4) == 1 { return "message/rfc822" as *u8 } 254 return "application/octet-stream" as *u8 255} 256 257// Emit a full HTTP/1.1 response (status line + Content-Type + Content-Length + body) into out. 258func hr_emit(out: *u8, statusline: *u8, ctype: *u8, body: *u8, bodyn: i64) -> i64 { 259 var j: i64 = 0 260 var k: i64 = 0 261 while statusline[k] != (0 as u8) { out[j] = statusline[k]; j = j + 1; k = k + 1 } 262 let h1: *u8 = "\r\nContent-Type: " as *u8 263 k = 0; while h1[k] != (0 as u8) { out[j] = h1[k]; j = j + 1; k = k + 1 } 264 k = 0; while ctype[k] != (0 as u8) { out[j] = ctype[k]; j = j + 1; k = k + 1 } 265 let h2: *u8 = "\r\nContent-Length: " as *u8 266 k = 0; while h2[k] != (0 as u8) { out[j] = h2[k]; j = j + 1; k = k + 1 } 267 j = j + hr_putdec(((out as i64 + j) as *u8), bodyn) 268 let h3: *u8 = "\r\nConnection: close\r\nX-Served-By: nishi-host\r\n\r\n" as *u8 269 k = 0; while h3[k] != (0 as u8) { out[j] = h3[k]; j = j + 1; k = k + 1 } 270 var b: i64 = 0 271 while b < bodyn { out[j] = body[b]; j = j + 1; b = b + 1 } 272 return j 273} 274 275// Does the request's Host match a configured site? Lets the daemon route ONLY config hosts 276// through the file server and fall back to its legacy routing (e.g. the wiki) for the rest. 277func hr_known_host(cfg: *u8, cfgn: i64, req: *u8, reqn: i64) -> i64 { 278 if cfgn <= 0 { return 0 } 279 let host: *u8 = sys_mmap(256) 280 let root: *u8 = sys_mmap(HR_MAGIC_1024) 281 let hn: i64 = hr_req_host(req, reqn, host, 256) 282 if hr_lookup_root(cfg, cfgn, host, hn, root, HR_MAGIC_1024) > 0 { return 1 } 283 return 0 284} 285 286// Full pipeline: request bytes + config -> HTTP response bytes in out. Reads the file PER REQUEST 287// (hot content). outcap must hold headers + file. Returns response length. 288func hr_serve(cfg: *u8, cfgn: i64, req: *u8, reqn: i64, out: *u8, outcap: i64) -> i64 { 289 let host: *u8 = sys_mmap(256) 290 let path: *u8 = sys_mmap(HR_MAGIC_4096) 291 let root: *u8 = sys_mmap(HR_MAGIC_1024) 292 let file: *u8 = sys_mmap(HR_MAGIC_5120) 293 let hn: i64 = hr_req_host(req, reqn, host, 256) 294 let pn: i64 = hr_req_path(req, reqn, path, HR_MAGIC_4096) 295 let rn: i64 = hr_lookup_root(cfg, cfgn, host, hn, root, HR_MAGIC_1024) 296 if rn == 0 { 297 let b0: *u8 = "<!doctype html><meta charset=utf-8><title>404</title><h1>404 &mdash; unknown host</h1>" as *u8 298 return hr_emit(out, "HTTP/1.1 404 Not Found" as *u8, "text/html; charset=utf-8" as *u8, b0, hr_slen(b0)) 299 } 300 if hr_path_safe(path, pn) == 0 { 301 let b1: *u8 = "<!doctype html><meta charset=utf-8><title>400</title><h1>400 &mdash; bad path</h1>" as *u8 302 return hr_emit(out, "HTTP/1.1 400 Bad Request" as *u8, "text/html; charset=utf-8" as *u8, b1, hr_slen(b1)) 303 } 304 let fnlen: i64 = hr_resolve(root, rn, path, pn, file, HR_MAGIC_5120) 305 let lenbox: *i64 = (sys_mmap(8)) as *i64 306 lenbox[0] = 0 307 let data: *u8 = sys_read_file(file, lenbox) 308 if (data as i64) == 0 { 309 let b2: *u8 = "<!doctype html><meta charset=utf-8><title>404</title><h1>404 &mdash; not found</h1>" as *u8 310 return hr_emit(out, "HTTP/1.1 404 Not Found" as *u8, "text/html; charset=utf-8" as *u8, b2, hr_slen(b2)) 311 } 312 let dn: i64 = lenbox[0] 313 let ct: *u8 = hr_ctype(file, fnlen) 314 return hr_emit(out, "HTTP/1.1 200 OK" as *u8, ct, data, dn) 315} 316 317// ===== v2: bounds-checked, keep-alive, fallthrough-aware serving ===== 318// (ADDITIVE -- hr_serve/hr_emit above are unchanged; the deployed daemon's 319// behaviour is bit-identical until it opts into hr_serve2.) 320 321// Bounds-checked emit. Writes status + Content-Type + Content-Length + 322// keep-alive headers + body into out; returns total length, or -1 if it 323// would not fit in outcap (caller turns that into a 500). Keep-alive (not 324// close) so one TLS handshake serves the whole page's assets. 325// Asset cache window. HTML is NEVER cached (the slot rotates on a 60s window and the served-impression 326// counter rides the HTML, so a cached page would freeze both rotation and billing); an asset is a 327// different fact. Bounded rather than immutable because house creatives sit at STABLE urls -- anything 328// uploaded through nx_adnet_creative is content-addressed and could safely take far longer. 329// DECLARED ABOVE ITS READER ON PURPOSE: nx_parse refuses a forward const read rather than silently 330// letting it evaluate to 0, which would have emitted "max-age=0" and looked like it worked. 331const HR_ASSET_MAXAGE: i64 = 3600 332 333// gzip negotiation helper. MEASURED 2026-08-08: NishiLang has NO module-level mutable state -- a 334// `var` at module scope is a STATEMENT AT MODULE LEVEL and FAILS THE BUILD (nx_cc, line 27904). 335// So the flag-in-a-static design is impossible; the gzip bit must be threaded as a PARAMETER. 336func hr_ae_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c } 337func hr_accepts_gzip(req: *u8, reqn: i64) -> i64 { 338 let key: *u8 = "accept-encoding:" as *u8 339 var i: i64 = 0 340 while i + 16 <= reqn { 341 var j: i64 = 0 342 var ok: i64 = 1 343 while j < 16 { if hr_ae_lc(req[i+j] as i64) != (key[j] as i64) { ok = 0; break } j = j + 1 } 344 if ok == 1 { 345 var e: i64 = i + 16 346 while e + 4 <= reqn { 347 if req[e] == (13 as u8) { return 0 } 348 if hr_ae_lc(req[e] as i64) == 103 { if hr_ae_lc(req[e+1] as i64) == 122 { if hr_ae_lc(req[e+2] as i64) == 105 { if hr_ae_lc(req[e+3] as i64) == 112 { return 1 } } } } 349 e = e + 1 350 } 351 return 0 352 } 353 i = i + 1 354 } 355 return 0 356} 357 358// Wrapper: keeps all 8 existing call sites byte-identical (gz=0). Forward ref to hr_emit_bz is 359// legal -- PROVEN by nx_fwdref_probe, not assumed. 360func hr_emit_b(out: *u8, outcap: i64, statusline: *u8, ctype: *u8, body: *u8, bodyn: i64) -> i64 { 361 return hr_emit_bz(out, outcap, statusline, ctype, body, bodyn, 0) 362} 363 364func hr_emit_bz(out: *u8, outcap: i64, statusline: *u8, ctype: *u8, body: *u8, bodyn: i64, gz: i64) -> i64 { 365 // ZERO-ALLOCATION: scratch is a slice of the caller's OWN out buffer, never a per-request 366 // sys_mmap -- an mmap here is the leak class fixed in sd2_build_resp today, 30x larger. 367 // Guards are conservative so the fallback is always the untouched identity path. 368 var eb: *u8 = body 369 var ebn: i64 = bodyn 370 var egz: i64 = 0 371 // Scratch needs room for the OUTPUT only, not 2n: `body` is sys_read_file's own allocation and 372 // provably cannot alias `out`, so there is no in-place overlap to defend against. Worst-case 373 // gzip growth on incompressible input is ~5B per 64KB stored block + 18B header/trailer, so 374 // bodyn+8192 bounds it. This drops the entry guard from 3n to ~n, which is what lets a 4.4MB 375 // page qualify at all. The fit is then RE-CHECKED against the real compressed length and falls 376 // back to identity if it would collide -- `body` is untouched, so the fallback is always safe. 377 if gz == 1 { if bodyn > HR_MAGIC_1024 { if bodyn + HR_MAGIC_9216 < outcap { 378 let sc: *u8 = ((out as i64) + (outcap - (bodyn + HR_MAGIC_8192))) as *u8 379 let cl: i64 = gz_compress(body, bodyn, 2, sc) 380 if cl > 0 { if cl < bodyn { if cl + HR_MAGIC_1024 < outcap - (bodyn + HR_MAGIC_8192) { eb = sc; ebn = cl; egz = 1 } } } 381 } } } 382 // headers are < 800 bytes for any status/ctype string (CORS + long office ctypes + the SOTA security header set: CSP/HSTS/nosniff/X-Frame-Options/Referrer-Policy) 383 // ROOT FIX (2026-07-31, debt 1785513321). This was a BLANKET RESERVE: `bodyn + HR_MAGIC_1024 > outcap`, 384 // which for outcap=1024 is true for ANY non-empty body -- so hr_serve2's TOOBIG branch could never emit 385 // its own 500 and an oversize file became a SILENT CONNECTION DROP instead of an error. A guard that 386 // cannot be satisfied produces a bypass, not safety. nx_host_router2_test asserted the 500 and had been 387 // RED on that tooth, uncompiled and unnoticed. 388 // Now bounded PRECISELY: refuse an outcap too small to hold the header block at all, then check the 389 // ACTUAL accumulated header length against the body before writing a single body byte. 390 if outcap < HR_MAGIC_1024 { return 0 - 1 } 391 var j: i64 = 0 392 var k: i64 = 0 393 while statusline[k] != (0 as u8) { out[j] = statusline[k]; j = j + 1; k = k + 1 } 394 let h1: *u8 = "\r\nContent-Type: " as *u8 395 k = 0; while h1[k] != (0 as u8) { out[j] = h1[k]; j = j + 1; k = k + 1 } 396 k = 0; while ctype[k] != (0 as u8) { out[j] = ctype[k]; j = j + 1; k = k + 1 } 397 let h2: *u8 = "\r\nContent-Length: " as *u8 398 k = 0; while h2[k] != (0 as u8) { out[j] = h2[k]; j = j + 1; k = k + 1 } 399 j = j + hr_putdec(((out as i64 + j) as *u8), ebn) 400 if egz == 1 { 401 let hg: *u8 = "\r\nContent-Encoding: gzip\r\nVary: Accept-Encoding" as *u8 402 k = 0; while hg[k] != (0 as u8) { out[j] = hg[k]; j = j + 1; k = k + 1 } 403 } 404 // F1120 CROSS-ORIGIN ISOLATION (2026-07-28; /video/capprobe MEASURED crossOriginIsolated=false as 405 // the R1 blocker): COOP same-origin + COEP require-corp are what let a page use SharedArrayBuffer = 406 // wasm THREADS = tile-parallel sovereign encode (the 60fps+/4K multiplier). BLAST RADIUS NEAR-ZERO 407 // BY CONSTRUCTION: the CSP here is already default-src 'self', so every subresource is same-origin 408 // and CORP: same-origin covers them. A HEADER CHANGE KILLED THIS PRODUCT FOR 5 DAYS (seq1073) -- 409 // the video_canary tooth asserts these tokens too: a regression fails the same 300s pass it ships in. 410 // CACHEABILITY BY CONTENT TYPE (2026-07-31). This emitter hardcoded no-cache for EVERY response, 411 // images included, so a creative shipped on every served page was re-downloaded every single time. 412 // HTML MUST STAY no-cache: the slot rotates on a 60s window and the served-impression counter rides 413 // the HTML, so caching a page would freeze both rotation and billing. An asset is a different fact. 414 let hA: *u8 = "\r\nConnection: keep-alive\r\nKeep-Alive: timeout=65\r\nCache-Control: " as *u8 415 k = 0; while hA[k] != (0 as u8) { out[j] = hA[k]; j = j + 1; k = k + 1 } 416 var hr_is_html: i64 = 1 417 let hr_hm: *u8 = "text/html" as *u8 418 var hq: i64 = 0 419 while hq < 9 { if ctype[hq] != hr_hm[hq] { hr_is_html = 0; break } hq = hq + 1 } 420 // CACHE ONLY A SUCCESS (2026-09-02, debt 1788361379). A 4xx/5xx body is never an asset, whatever its 421 // content type. MEASURED on the live edge: the problem+json 503 emitted for a dead /search backend carried 422 // `public, max-age=3600` because this rule keyed on the ctype alone, so every JSON/fetch client was told 423 // to cache a sixteen-hour outage an hour at a time -- and it fired again on a cold query that overran the 424 // edge window minutes after the backend came back. The status line is already in hand: read its first 425 // digit (statusline is always "HTTP/1.1 <code> ...", so [9] is the hundreds digit) and cache only 2xx. 426 var hr_cacheable: i64 = 0 427 if hr_is_html == 0 { if statusline[9] == (50 as u8) { hr_cacheable = 1 } } 428 if hr_cacheable == 0 { 429 let hc1: *u8 = "no-cache" as *u8 430 k = 0; while hc1[k] != (0 as u8) { out[j] = hc1[k]; j = j + 1; k = k + 1 } 431 } else { 432 let hc2: *u8 = "public, max-age=" as *u8 433 k = 0; while hc2[k] != (0 as u8) { out[j] = hc2[k]; j = j + 1; k = k + 1 } 434 j = j + hr_putdec(((out as i64 + j) as *u8), HR_ASSET_MAXAGE) 435 } 436 let h3: *u8 = "\r\nAccess-Control-Allow-Origin: *\r\nX-Content-Type-Options: nosniff\r\nX-Frame-Options: SAMEORIGIN\r\nReferrer-Policy: strict-origin-when-cross-origin\r\nStrict-Transport-Security: max-age=63072000; includeSubDomains\r\nCross-Origin-Opener-Policy: same-origin\r\nCross-Origin-Embedder-Policy: require-corp\r\nCross-Origin-Resource-Policy: same-origin\r\nContent-Security-Policy: default-src 'self'; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob:; worker-src 'self' blob:; font-src 'self' data:; connect-src 'self' http://127.0.0.1:7862; media-src 'self' blob:; frame-ancestors 'self'; base-uri 'none'; object-src 'none'\r\nX-Served-By: nishi-substrate-v2\r\n\r\n" as *u8 437 k = 0; while h3[k] != (0 as u8) { out[j] = h3[k]; j = j + 1; k = k + 1 } 438 // MEASURED bound: j is the ACTUAL header length just emitted, not a guessed reserve. Checked before a 439 // single body byte is written, so the refusal is exact and the TOOBIG path can emit its own 500. 440 if j + ebn > outcap { return 0 - 1 } 441 var b: i64 = 0 442 while b < ebn { out[j] = eb[b]; j = j + 1; b = b + 1 } 443 return j 444} 445 446// Serve verdicts for hr_serve2 (sealed enum). 447const HR_S2_MISS: i64 = 0 // host known but file absent -> caller falls through to legacy routing 448const HR_S2_OK: i64 = 1 // 200 written 449const HR_S2_BAD: i64 = 2 // 400 written (traversal/malformed) 450const HR_S2_TOOBIG: i64 = 3 // 500 written (file exceeds outcap) 451 452// v2 pipeline: like hr_serve but (a) bounds-checked emit, (b) keep-alive, 453// (c) MISS verdict instead of a baked 404 when the file is absent -- the 454// daemon decides per host whether to fall through to its legacy routing 455// (nishifamily wiki) or emit a real 404 (andelinwest). Response length is 456// written to *out_n; the verdict is the return value. 457func hr_serve2(cfg: *u8, cfgn: i64, req: *u8, reqn: i64, out: *u8, outcap: i64, out_n: *i64) -> i64 { 458 out_n[0] = 0 459 let host: *u8 = sys_mmap(256) 460 let path: *u8 = sys_mmap(HR_MAGIC_4096) 461 let root: *u8 = sys_mmap(HR_MAGIC_1024) 462 let file: *u8 = sys_mmap(HR_MAGIC_5120) 463 let hn: i64 = hr_req_host(req, reqn, host, 256) 464 let pn: i64 = hr_req_path(req, reqn, path, HR_MAGIC_4096) 465 let rn: i64 = hr_lookup_root(cfg, cfgn, host, hn, root, HR_MAGIC_1024) 466 if rn == 0 { return HR_S2_MISS } 467 if hr_path_safe(path, pn) == 0 { 468 let b1: *u8 = "<!doctype html><meta charset=utf-8><title>400</title><h1>400 &mdash; bad path</h1>" as *u8 469 out_n[0] = hr_emit_b(out, outcap, "HTTP/1.1 400 Bad Request" as *u8, "text/html; charset=utf-8" as *u8, b1, hr_slen(b1)) 470 return HR_S2_BAD 471 } 472 let fnlen: i64 = hr_resolve(root, rn, path, pn, file, HR_MAGIC_5120) 473 let lenbox: *i64 = (sys_mmap(8)) as *i64 474 lenbox[0] = 0 475 let data: *u8 = sys_read_file(file, lenbox) 476 if (data as i64) == 0 { return HR_S2_MISS } 477 let dn: i64 = lenbox[0] 478 let ct: *u8 = hr_ctype(file, fnlen) 479 let w: i64 = hr_emit_bz(out, outcap, "HTTP/1.1 200 OK" as *u8, ct, data, dn, hr_accepts_gzip(req, reqn)) 480 if w < 0 { 481 let b3: *u8 = "<!doctype html><meta charset=utf-8><title>500</title><h1>500 &mdash; file exceeds serve buffer</h1>" as *u8 482 out_n[0] = hr_emit_b(out, outcap, "HTTP/1.1 500 Internal Server Error" as *u8, "text/html; charset=utf-8" as *u8, b3, hr_slen(b3)) 483 return HR_S2_TOOBIG 484 } 485 out_n[0] = w 486 return HR_S2_OK 487} 488 489// Real 404 for hosts that do NOT fall through (e.g. andelinwest.com). 490func hr_emit_404(out: *u8, outcap: i64) -> i64 { 491 let b2: *u8 = "<!doctype html><meta charset=utf-8><title>404</title><h1>404 &mdash; not found</h1>" as *u8 492 return hr_emit_b(out, outcap, "HTTP/1.1 404 Not Found" as *u8, "text/html; charset=utf-8" as *u8, b2, hr_slen(b2)) 493} 494 495// ===== v3: S-CLASS ROUTING -- clean URLs + canonical 301s, ONE resolver for every path ===== 496// (ADDITIVE: hr_serve/hr_serve2 above are byte-identical and untouched.) This mirrors the gated pure 497// engine nx_route.nx (nx_route_gate 5/5) against the LIVE filesystem so routing is a property of the 498// HOST, not per-page redirect stubs: 499// * CLEAN extensionless URLs serve, for BOTH layouts: /foo -> foo/index.html (dir) OR foo.html (flat). 500// * ONE CANONICAL url via REAL 301s: /foo.html, /foo/, /foo/index.html, /index.html all collapse to 501// the clean canonical -- BUT only when that clean target actually resolves to a file, so a legacy 502// .html route (served by fallthrough, not a docroot file) is never 301'd into a 404. 503// * dir-index keeps PRECEDENCE over .html (so an existing /games hub is never shadowed by a stale flat). 504// * traversal -> 400 ; nothing resolves -> MISS (caller falls through to legacy, unchanged). 505const HR_S2_REDIR: i64 = 4 // 301 written to out (out_n set); caller must NOT fall through 506const HR_S2_STREAM: i64 = 5 // headers written to out; BODY handed via hr_stream_body/bodyn -- the 507 // caller sends both through its own chunked TLS primitive. ZERO-CEILING 508 // static serving (debt 1785879638): no file-size constant exists on this 509 // path; anything the host can mmap streams. Body ptr/len ride module 510 // statics (scalars, not arrays -- the BSS-array crash class): the daemon 511 // forks per connection, so the pair is per-process and consumed before 512 // the next request in that process. 513static hr_stream_p: i64 = 0 514static hr_stream_n: i64 = 0 515func hr_stream_body() -> i64 { return hr_stream_p } 516func hr_stream_bodyn() -> i64 { return hr_stream_n } 517 518// header half of hr_emit_b, byte-identical headers (incl cacheability-by-ctype + the security set); 519// Content-Length = bodyn, but NO body byte is written -- the stream caller sends the body itself. 520func hr_decimal_len(v: i64) -> i64 { var x: i64=v;var n: i64=1;while x>=10 { n=n+1;x=x/10 };return n } 521func hr_emit_head(out: *u8, outcap: i64, statusline: *u8, ctype: *u8, bodyn: i64) -> i64 { 522 if bodyn<0 { return 0-1 } 523 let h1: *u8 = "\r\nContent-Type: " as *u8 524 let h2: *u8 = "\r\nContent-Length: " as *u8 525 let hA: *u8 = "\r\nConnection: keep-alive\r\nKeep-Alive: timeout=65\r\nCache-Control: " as *u8 526 let h3: *u8 = "\r\nAccess-Control-Allow-Origin: *\r\nX-Content-Type-Options: nosniff\r\nX-Frame-Options: SAMEORIGIN\r\nReferrer-Policy: strict-origin-when-cross-origin\r\nStrict-Transport-Security: max-age=63072000; includeSubDomains\r\nCross-Origin-Opener-Policy: same-origin\r\nCross-Origin-Embedder-Policy: require-corp\r\nCross-Origin-Resource-Policy: same-origin\r\nContent-Security-Policy: default-src 'self'; img-src 'self' data: blob:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' blob:; worker-src 'self' blob:; font-src 'self' data:; connect-src 'self' http://127.0.0.1:7862; media-src 'self' blob:; frame-ancestors 'self'; base-uri 'none'; object-src 'none'\r\nX-Served-By: nishi-substrate-v2\r\n\r\n" as *u8 527 var cache: *u8="no-cache" as *u8 528 var cache_digits: i64=0 529 if hr_ct_is_html(ctype)==0 && statusline[9]==(50 as u8) { 530 cache="public, max-age=" as *u8;cache_digits=hr_decimal_len(HR_ASSET_MAXAGE) 531 } 532 let needed: i64=hr_slen(statusline)+hr_slen(h1)+hr_slen(ctype)+hr_slen(h2)+hr_decimal_len(bodyn)+hr_slen(hA)+hr_slen(cache)+cache_digits+hr_slen(h3) 533 if (out as i64)==0 { return needed } 534 if needed>outcap { return 0-1 } 535 var j: i64 = 0 536 var k: i64 = 0 537 while statusline[k] != (0 as u8) { out[j] = statusline[k]; j = j + 1; k = k + 1 } 538 k = 0; while h1[k] != (0 as u8) { out[j] = h1[k]; j = j + 1; k = k + 1 } 539 k = 0; while ctype[k] != (0 as u8) { out[j] = ctype[k]; j = j + 1; k = k + 1 } 540 k = 0; while h2[k] != (0 as u8) { out[j] = h2[k]; j = j + 1; k = k + 1 } 541 j = j + hr_putdec(((out as i64 + j) as *u8), bodyn) 542 k = 0; while hA[k] != (0 as u8) { out[j] = hA[k]; j = j + 1; k = k + 1 } 543 var hh: i64 = 1 544 let hm: *u8 = "text/html" as *u8 545 var hq: i64 = 0 546 while hq < 9 { if ctype[hq] != hm[hq] { hh = 0; break } hq = hq + 1 } 547 if hh == 1 || statusline[9]!=(50 as u8) { 548 let hc1: *u8 = "no-cache" as *u8 549 k = 0; while hc1[k] != (0 as u8) { out[j] = hc1[k]; j = j + 1; k = k + 1 } 550 } else { 551 let hc2: *u8 = "public, max-age=" as *u8 552 k = 0; while hc2[k] != (0 as u8) { out[j] = hc2[k]; j = j + 1; k = k + 1 } 553 j = j + hr_putdec(((out as i64 + j) as *u8), HR_ASSET_MAXAGE) 554 } 555 k = 0; while h3[k] != (0 as u8) { out[j] = h3[k]; j = j + 1; k = k + 1 } 556 if j > outcap { return 0 - 1 } 557 return j 558} 559 560func hr_ends2(s: *u8, n: i64, suf: *u8, sufn: i64) -> i64 { 561 if sufn > n { return 0 } 562 var i: i64 = 0 563 while i < sufn { if s[n - sufn + i] != suf[i] { return 0 } i = i + 1 } 564 return 1 565} 566 567// Canonical clean form of path -> loc (NUL-terminated). Returns locn (>0 => a redirect is warranted), 568// or 0 when the path is already canonical. Order: /index.html before .html (the former is a suffix of it). 569func hr_canon(path: *u8, pn: i64, loc: *u8) -> i64 { 570 if pn <= 1 { return 0 } 571 if hr_ends2(path, pn, "/index.html" as *u8, 11) == 1 { 572 let m1: i64 = pn - 11 573 if m1 <= 0 { loc[0] = 47 as u8; loc[1] = 0 as u8; return 1 } 574 var i1: i64 = 0; while i1 < m1 { loc[i1] = path[i1]; i1 = i1 + 1 } loc[m1] = 0 as u8; return m1 575 } 576 if hr_ends2(path, pn, ".html" as *u8, 5) == 1 { 577 let m2: i64 = pn - 5 578 if m2 <= 0 { return 0 } 579 var i2: i64 = 0; while i2 < m2 { loc[i2] = path[i2]; i2 = i2 + 1 } loc[m2] = 0 as u8; return m2 580 } 581 if path[pn - 1] == (47 as u8) { 582 let m3: i64 = pn - 1 583 var i3: i64 = 0; while i3 < m3 { loc[i3] = path[i3]; i3 = i3 + 1 } loc[m3] = 0 as u8; return m3 584 } 585 return 0 586} 587 588// Join root (trailing '/' trimmed) + path + suffix into file; return length. 589func hr_join(root: *u8, rn: i64, path: *u8, pn: i64, suffix: *u8, file: *u8, cap: i64) -> i64 { 590 var j: i64 = 0; var i: i64 = 0 591 while i < rn { if j < cap - 1 { file[j] = root[i]; j = j + 1 } i = i + 1 } 592 if j > 0 { if file[j - 1] == (47 as u8) { j = j - 1 } } 593 i = 0 594 while i < pn { if j < cap - 1 { file[j] = path[i]; j = j + 1 } i = i + 1 } 595 if (suffix as i64) != 0 { 596 i = 0 597 while suffix[i] != (0 as u8) { if j < cap - 1 { file[j] = suffix[i]; j = j + 1 } i = i + 1 } 598 } 599 file[j] = 0 as u8 600 return j 601} 602 603// Resolve path -> the first existing candidate file (read PER REQUEST = hot content). Candidate order: 604// "/" -> index.html ; dotted last segment (asset) -> exact ; clean URL -> dir-index THEN .html. 605// Returns data ptr (0 = nothing resolved); sets *fnlen (file-path length, for MIME) + *dn (byte count). 606func hr_resolve_read(root: *u8, rn: i64, path: *u8, pn: i64, file: *u8, cap: i64, fnlen: *i64, dn: *i64) -> *u8 { 607 let lenbox: *i64 = (sys_mmap(8)) as *i64; lenbox[0] = 0 608 var data: *u8 = 0 as *u8 609 if pn == 1 { 610 fnlen[0] = hr_join(root, rn, path, pn, "index.html" as *u8, file, cap) 611 data = sys_read_file(file, lenbox) 612 } else { 613 var seg_dot: i64 = 0; var s: i64 = pn - 1 614 while s >= 0 { if path[s] == (47 as u8) { break } if path[s] == (46 as u8) { seg_dot = 1; break } s = s - 1 } 615 if seg_dot == 1 { 616 fnlen[0] = hr_join(root, rn, path, pn, 0 as *u8, file, cap) 617 data = sys_read_file(file, lenbox) 618 } else { 619 fnlen[0] = hr_join(root, rn, path, pn, "/index.html" as *u8, file, cap) 620 data = sys_read_file(file, lenbox) 621 if (data as i64) == 0 { 622 fnlen[0] = hr_join(root, rn, path, pn, ".html" as *u8, file, cap) 623 data = sys_read_file(file, lenbox) 624 } 625 } 626 } 627 dn[0] = lenbox[0] 628 return data 629} 630 631// Emit a 301 with Location (empty body, keep-alive). -1 if it would not fit. 632func hr_emit_redirect(out: *u8, outcap: i64, loc: *u8, locn: i64) -> i64 { 633 if locn + 256 > outcap { return 0 - 1 } 634 var j: i64 = 0; var k: i64 = 0 635 let s1: *u8 = "HTTP/1.1 301 Moved Permanently\r\nLocation: " as *u8 636 k = 0; while s1[k] != (0 as u8) { out[j] = s1[k]; j = j + 1; k = k + 1 } 637 k = 0; while k < locn { out[j] = loc[k]; j = j + 1; k = k + 1 } 638 let s2: *u8 = "\r\nContent-Length: 0\r\nConnection: keep-alive\r\nCache-Control: no-cache\r\nX-Served-By: nishi-host\r\n\r\n" as *u8 639 k = 0; while s2[k] != (0 as u8) { out[j] = s2[k]; j = j + 1; k = k + 1 } 640 return j 641} 642 643// ===== v3+slot helpers: universal ad-slot injection (ADDITIVE -- hr_serve3 below is untouched) ===== 644// hr_serve3_slot behaves byte-identically to hr_serve3 when slot_n==0 (gated). With slot bytes: a 645// text/html body containing </body> and NOT carrying the nx-ad-optout marker gets the slot inserted 646// before the LAST </body>; Content-Length stays correct by construction (merge happens before emit). 647// injected[0]=1 ONLY when the slot actually landed (the caller logs a served impression off it). 648 649func hr_ct_is_html(ct: *u8) -> i64 { 650 return hr_eq(ct, "text/html" as *u8, 9) 651} 652 653// index of the LAST "</body>" (case-insensitive) in body, or -1. 654func hr_find_close_body(body: *u8, bn: i64) -> i64 { 655 if bn < 7 { return 0 - 1 } 656 var i: i64 = bn - 7 657 while i >= 0 { 658 if body[i] == (60 as u8) { 659 if hr_ieq(((body as i64 + i) as *u8), "</body>" as *u8, 7) == 1 { return i } 660 } 661 i = i - 1 662 } 663 return 0 - 1 664} 665 666// page-level opt-out marker scan (any page may carry nx-ad-optout to refuse the slot). 667func hr_has_optout(body: *u8, bn: i64) -> i64 { 668 var i: i64 = 0 669 while i + 12 <= bn { 670 if body[i] == (110 as u8) { 671 if hr_eq(((body as i64 + i) as *u8), "nx-ad-optout" as *u8, 12) == 1 { return 1 } 672 } 673 i = i + 1 674 } 675 return 0 676} 677 678 679// ---- SLOT ANCHOR (2026-07-31): let a PAGE choose where its ad goes ------------------------------- 680// WHY: the slot was always injected before the closing body tag -- the absolute bottom of the document. 681// On a long reference page essentially nobody scrolls there, and the MRC rule needs 50% of the creative 682// in view for one CONTINUOUS second. So viewable impressions were structurally near-zero: we measured 683// honestly and still sold a position nobody sees. The honest number does not fix placement, it EXPOSES 684// it -- and this is the mechanism that lets it be fixed. 685// 686// A page opts in by placing the marker where it wants the ad. NO MARKER = the old behaviour, byte for 687// byte, so this cannot change a single existing page. Placement stays a PRODUCT decision made per page, 688// not an engineering default imposed on every site at once. 689const HR_SLOT_MARK: *u8 = "<!--nx-ad-slot-->" as *u8 690 691func hr_find_slot_anchor(d: *u8, n: i64) -> i64 { 692 var i: i64 = 0 693 while i + 17 <= n { 694 var k: i64 = 0 695 var m: i64 = 1 696 while k < 17 { if d[i + k] != HR_SLOT_MARK[k] { m = 0; break } k = k + 1 } 697 if m == 1 { return i } 698 i = i + 1 699 } 700 return hr_find_close_body(d, n) 701} 702 703func hr_serve3_slot(cfg: *u8, cfgn: i64, req: *u8, reqn: i64, out: *u8, outcap: i64, out_n: *i64, slot: *u8, slot_n: i64, injected: *i64) -> i64 { 704 injected[0] = 0 705 out_n[0] = 0 706 let host: *u8 = sys_mmap(256) 707 let path: *u8 = sys_mmap(HR_MAGIC_4096) 708 let root: *u8 = sys_mmap(HR_MAGIC_1024) 709 let file: *u8 = sys_mmap(HR_MAGIC_5120) 710 let hn: i64 = hr_req_host(req, reqn, host, 256) 711 let pn: i64 = hr_req_path(req, reqn, path, HR_MAGIC_4096) 712 let rn: i64 = hr_lookup_root(cfg, cfgn, host, hn, root, HR_MAGIC_1024) 713 if rn == 0 { return HR_S2_MISS } 714 if hr_path_safe(path, pn) == 0 { 715 let b1: *u8 = "<!doctype html><meta charset=utf-8><title>400</title><h1>400 &mdash; bad path</h1>" as *u8 716 out_n[0] = hr_emit_b(out, outcap, "HTTP/1.1 400 Bad Request" as *u8, "text/html; charset=utf-8" as *u8, b1, hr_slen(b1)) 717 return HR_S2_BAD 718 } 719 let ranged: i64=hr_try_file_range(root,rn,path,pn,req,reqn,out,outcap,out_n) 720 if ranged==HR_S2_FILE_STREAM { 721 sys_munmap(host,256);sys_munmap(path,HR_MAGIC_4096) 722 sys_munmap(root,HR_MAGIC_1024);sys_munmap(file,HR_MAGIC_5120) 723 return ranged 724 } 725 let fnlen: *i64 = (sys_mmap(8)) as *i64 726 let dn: *i64 = (sys_mmap(8)) as *i64 727 let loc: *u8 = sys_mmap(HR_MAGIC_4096) 728 let locn: i64 = hr_canon(path, pn, loc) 729 if locn > 0 { 730 let cfile: *u8 = sys_mmap(HR_MAGIC_5120) 731 let cdata: *u8 = hr_resolve_read(root, rn, loc, locn, cfile, HR_MAGIC_5120, fnlen, dn) 732 if (cdata as i64) != 0 { 733 // seq365: CARRY the ?query on the canonical 301 (resolve above used the PATH-only loc; 734 // append after resolve so filesystem lookup never sees query bytes). No-query requests 735 // emit byte-identical redirects to before. 736 let qbuf: *u8 = sys_mmap(HR_MAGIC_2048) 737 let qn: i64 = hr_req_query(req, reqn, qbuf, HR_MAGIC_2048) 738 var locq: i64 = locn 739 if qn > 0 { if locn + qn < HR_MAGIC_4095 { 740 var qi: i64 = 0 741 while qi < qn { loc[locn + qi] = qbuf[qi]; qi = qi + 1 } 742 locq = locn + qn 743 loc[locq] = 0 as u8 744 } } 745 out_n[0] = hr_emit_redirect(out, outcap, loc, locq) 746 if out_n[0] < 0 { out_n[0] = 0; return HR_S2_MISS } 747 return HR_S2_REDIR 748 } 749 } 750 let data: *u8 = hr_resolve_read(root, rn, path, pn, file, HR_MAGIC_5120, fnlen, dn) 751 if (data as i64) == 0 { return HR_S2_MISS } 752 let ct: *u8 = hr_ctype(file, fnlen[0]) 753 var body: *u8 = data 754 var bodyn: i64 = dn[0] 755 if slot_n > 0 { 756 if hr_ct_is_html(ct) == 1 { 757 let cb: i64 = hr_find_slot_anchor(data, bodyn) 758 if cb >= 0 { 759 let oo: i64 = hr_has_optout(data, bodyn) 760 if oo == 0 { 761 let mcap: i64 = bodyn + slot_n + 16 762 let merged: *u8 = sys_mmap(mcap) 763 var w2: i64 = 0 764 var a: i64 = 0 765 while a < cb { merged[w2] = data[a]; w2 = w2 + 1; a = a + 1 } 766 var b2: i64 = 0 767 while b2 < slot_n { merged[w2] = slot[b2]; w2 = w2 + 1; b2 = b2 + 1 } 768 while a < bodyn { merged[w2] = data[a]; w2 = w2 + 1; a = a + 1 } 769 body = merged 770 bodyn = w2 771 injected[0] = 1 772 } 773 } 774 } 775 } 776 let w: i64 = hr_emit_bz(out, outcap, "HTTP/1.1 200 OK" as *u8, ct, body, bodyn, hr_accepts_gzip(req, reqn)) 777 if w < 0 { 778 // ZERO-CEILING STREAM (debt 1785879638; operator: no self-imposed limits, no magic numbers): 779 // the body is ALREADY in memory -- emit headers only (they always fit any sane outcap) and 780 // hand the body pointer to the daemon, which sends both through the same chunked TLS send. 781 // No file-size constant exists on this path. 500 remains ONLY for an outcap below the header floor. 782 let hw: i64 = hr_emit_head(out, outcap, "HTTP/1.1 200 OK" as *u8, ct, bodyn) 783 if hw > 0 { 784 hr_stream_p = body as i64 785 hr_stream_n = bodyn 786 out_n[0] = hw 787 return HR_S2_STREAM 788 } 789 let b3: *u8 = "<!doctype html><meta charset=utf-8><title>500</title><h1>500 &mdash; file exceeds serve buffer</h1>" as *u8 790 out_n[0] = hr_emit_b(out, outcap, "HTTP/1.1 500 Internal Server Error" as *u8, "text/html; charset=utf-8" as *u8, b3, hr_slen(b3)) 791 return HR_S2_TOOBIG 792 } 793 out_n[0] = w 794 return HR_S2_OK 795} 796 797// v3 pipeline: canonical 301 (safe) + clean multi-candidate resolve. Verdicts: OK/MISS/BAD/TOOBIG/REDIR. 798func hr_serve3(cfg: *u8, cfgn: i64, req: *u8, reqn: i64, out: *u8, outcap: i64, out_n: *i64) -> i64 { 799 out_n[0] = 0 800 let host: *u8 = sys_mmap(256) 801 let path: *u8 = sys_mmap(HR_MAGIC_4096) 802 let root: *u8 = sys_mmap(HR_MAGIC_1024) 803 let file: *u8 = sys_mmap(HR_MAGIC_5120) 804 let hn: i64 = hr_req_host(req, reqn, host, 256) 805 let pn: i64 = hr_req_path(req, reqn, path, HR_MAGIC_4096) 806 let rn: i64 = hr_lookup_root(cfg, cfgn, host, hn, root, HR_MAGIC_1024) 807 if rn == 0 { return HR_S2_MISS } 808 if hr_path_safe(path, pn) == 0 { 809 let b1: *u8 = "<!doctype html><meta charset=utf-8><title>400</title><h1>400 &mdash; bad path</h1>" as *u8 810 out_n[0] = hr_emit_b(out, outcap, "HTTP/1.1 400 Bad Request" as *u8, "text/html; charset=utf-8" as *u8, b1, hr_slen(b1)) 811 return HR_S2_BAD 812 } 813 let fnlen: *i64 = (sys_mmap(8)) as *i64 814 let dn: *i64 = (sys_mmap(8)) as *i64 815 // canonical 301 -- only when the clean target actually resolves (never 301 to a 404) 816 let loc: *u8 = sys_mmap(HR_MAGIC_4096) 817 let locn: i64 = hr_canon(path, pn, loc) 818 if locn > 0 { 819 let cfile: *u8 = sys_mmap(HR_MAGIC_5120) 820 let cdata: *u8 = hr_resolve_read(root, rn, loc, locn, cfile, HR_MAGIC_5120, fnlen, dn) 821 if (cdata as i64) != 0 { 822 // seq365: CARRY the ?query on the canonical 301 (resolve above used the PATH-only loc; 823 // append after resolve so filesystem lookup never sees query bytes). No-query requests 824 // emit byte-identical redirects to before. 825 let qbuf: *u8 = sys_mmap(HR_MAGIC_2048) 826 let qn: i64 = hr_req_query(req, reqn, qbuf, HR_MAGIC_2048) 827 var locq: i64 = locn 828 if qn > 0 { if locn + qn < HR_MAGIC_4095 { 829 var qi: i64 = 0 830 while qi < qn { loc[locn + qi] = qbuf[qi]; qi = qi + 1 } 831 locq = locn + qn 832 loc[locq] = 0 as u8 833 } } 834 out_n[0] = hr_emit_redirect(out, outcap, loc, locq) 835 if out_n[0] < 0 { out_n[0] = 0; return HR_S2_MISS } 836 return HR_S2_REDIR 837 } 838 } 839 // resolve + serve the (canonical) path 840 let data: *u8 = hr_resolve_read(root, rn, path, pn, file, HR_MAGIC_5120, fnlen, dn) 841 if (data as i64) == 0 { return HR_S2_MISS } 842 let ct: *u8 = hr_ctype(file, fnlen[0]) 843 let w: i64 = hr_emit_b(out, outcap, "HTTP/1.1 200 OK" as *u8, ct, data, dn[0]) 844 if w < 0 { 845 let b3: *u8 = "<!doctype html><meta charset=utf-8><title>500</title><h1>500 &mdash; file exceeds serve buffer</h1>" as *u8 846 out_n[0] = hr_emit_b(out, outcap, "HTTP/1.1 500 Internal Server Error" as *u8, "text/html; charset=utf-8" as *u8, b3, hr_slen(b3)) 847 return HR_S2_TOOBIG 848 } 849 out_n[0] = w 850 return HR_S2_OK 851} 852static hr_file_reader: *NxFileReadRegion 853func hr_take_file_reader() -> *NxFileReadRegion { 854 let r: *NxFileReadRegion=hr_file_reader;hr_file_reader=0 as *NxFileReadRegion;return r 855} 856// Returns value offset, -1 absent, -2 duplicate. Only header lines are inspected. 857func hr_field(req: *u8,n: i64,name: *u8,len: *i64) -> i64 { 858 let nn: i64=hr_slen(name);var p: i64=0;var found: i64=0-1;len[0]=0 859 while p+1<n { if req[p]==(13 as u8) && req[p+1]==(10 as u8) { p=p+2;break };p=p+1 } 860 while p+1<n { 861 let start: i64=p 862 while p+1<n { if req[p]==(13 as u8) && req[p+1]==(10 as u8) { break };p=p+1 } 863 if p+1>=n || p==start { break } 864 if p-start>nn { 865 if hr_ieq(req+start,name,nn)==1 && req[start+nn]==(58 as u8) { 866 if found>=0 { return 0-2 } 867 var vs: i64=start+nn+1;var ve: i64=p 868 while vs<ve { if rh_ows(req[vs] as i64)==0 { break };vs=vs+1 } 869 while ve>vs { if rh_ows(req[ve-1] as i64)==0 { break };ve=ve-1 } 870 found=vs;len[0]=ve-vs 871 } 872 } 873 p=p+2 874 } 875 return found 876} 877func hr_emit_range_head(out: *u8,cap: i64,ct: *u8,r: *NxFileReadRegion,unsat: i64) -> i64 { 878 let prefix: *u8="Accept-Ranges: bytes\r\nContent-Range: bytes " as *u8 879 var extra: i64=hr_slen(prefix)+hr_decimal_len(r.total)+hr_slen("/\r\n\r\n" as *u8) 880 if unsat==1 { extra=extra+1 } else { extra=extra+hr_decimal_len(r.start)+hr_decimal_len(r.start+r.length-1)+1 } 881 var status: *u8="HTTP/1.1 206 Partial Content" as *u8 882 var bodylen: i64=r.length 883 if unsat==1 { status="HTTP/1.1 416 Range Not Satisfiable" as *u8;bodylen=0 } 884 let base: i64=hr_emit_head(out,cap-extra+2,status,ct,bodylen) 885 if base<0 { return base } 886 if (out as i64)==0 { return base-2+extra } 887 // Replace only the final empty line; all common headers stay owned by hr_emit_head. 888 var p: i64=base-2 889 p=p+hr_copy(out+p,prefix,hr_slen(prefix)) 890 if unsat==1 { out[p]=42 as u8;p=p+1 } else { 891 p=p+hr_putdec(out+p,r.start);out[p]=45 as u8;p=p+1 892 p=p+hr_putdec(out+p,r.start+r.length-1) 893 } 894 out[p]=47 as u8;p=p+1;p=p+hr_putdec(out+p,r.total) 895 p=p+hr_copy(out+p,"\r\n\r\n" as *u8,4) 896 return p 897} 898// Range optimization for untransformed, explicit static-file paths. Unsupported 899// multi-range/conditional requests retain the preexisting full-response path. 900func hr_try_file_range(root: *u8,rn: i64,path: *u8,pn: i64,req: *u8,reqn: i64,out: *u8,cap: i64,outn: *i64) -> i64 { 901 if reqn<4 { return HR_S2_MISS } 902 if hr_eq(req,"GET " as *u8,4)==0 { return HR_S2_MISS } 903 let span: *i64=sys_mmap(__size_of(i64)) as *i64 904 let conditional: i64=hr_field(req,reqn,"If-Range",span) 905 let at: i64=hr_field(req,reqn,"Range",span);let len: i64=span[0] 906 sys_munmap(span as *u8,__size_of(i64)) 907 if conditional!=(0-1) || at<0 { return HR_S2_MISS } 908 var dot: i64=0;var i: i64=pn 909 while i>0 { i=i-1;if path[i]==(47 as u8) { break };if path[i]==(46 as u8) { dot=1 } } 910 if dot==0 { return HR_S2_MISS } 911 let filecap: i64=rn+pn+2;let file: *u8=sys_mmap(filecap) 912 let fn: i64=hr_join(root,rn,path,pn,0 as *u8,file,filecap) 913 if fn<=0 { sys_munmap(file,filecap);return HR_S2_MISS } 914 let ct: *u8=hr_ctype(file,fn) 915 if hr_ct_is_html(ct)==1 { sys_munmap(file,filecap);return HR_S2_MISS } 916 let r: *NxFileReadRegion=sys_mmap(__size_of(NxFileReadRegion)) as *NxFileReadRegion 917 fio_region_init(r);let opened: i64=fio_region_open(file,r);sys_munmap(file,filecap) 918 if opened<0 { sys_munmap(r as *u8,__size_of(NxFileReadRegion));return HR_S2_MISS } 919 let range: *RangeSpec=sys_mmap(__size_of(RangeSpec)) as *RangeSpec 920 let parsed: i64=range_parse(req+at,len,r.total,range,1) 921 var selected: i64=0 922 if parsed==1 { selected=fio_region_select(r,range.start,range.end-range.start+1) } 923 if parsed==RH_ERR_UNSATISFIABLE { selected=fio_region_select(r,0,0) } 924 sys_munmap(range as *u8,__size_of(RangeSpec)) 925 if selected<0 || (parsed!=1 && parsed!=RH_ERR_UNSATISFIABLE) { 926 fio_region_close(r);sys_munmap(r as *u8,__size_of(NxFileReadRegion));return HR_S2_MISS 927 } 928 let headers: i64=hr_emit_range_head(out,cap,ct,r,(parsed==RH_ERR_UNSATISFIABLE) as i64) 929 if headers<0 { fio_region_close(r);sys_munmap(r as *u8,__size_of(NxFileReadRegion));return HR_S2_MISS } 930 hr_file_reader=r;outn[0]=headers;return HR_S2_FILE_STREAM 931}