code wiki / _hdl_build / nx_clean_url.nx

nx_clean_url.nx source

↩ module page · 85 lines · 3942 B

1// nx_clean_url.nx -- S-class CLEAN (extensionless) URL support for the Nishi hosting layer. Operator: "make sure 2// the urls dont need html." Two parts: 3// (1) cu_resolve(request_path) -> doc-root file: the GENERAL rule the sites daemon is missing today (it only 4// hardcodes per-page redirects). "/" -> index.html ; "/foo/" -> foo/index.html ; "/foo" (no ext) -> foo.html 5// (the clean URL) ; "/a.css" (has ext) -> served as-is. Traversal (".." ) REJECTED by construction. 6// (2) cu_audit_links(html) -> count of hrefs that still carry ".html" (so our generated pages can be PROVEN to 7// link cleanly). cu_link_is_clean(href) is the single-link predicate. 8// Sovereign primitive (nx_syscalls only); ready to wire into nx_sites_daemon_v2 (coordinate w/ the hosting 9// workstream -- it's the live production binary). license_tier: ORIGINAL 10import "nx_syscalls.nx" 11 12func cu_app(out: *u8, pos: i64, cap: i64, s: *u8) -> i64 { 13 var p: i64 = pos; var i: i64 = 0 14 while s[i] != (0 as u8) { if p < cap { out[p] = s[i]; p = p + 1 } i = i + 1 } 15 return p 16} 17func cu_match_at(s: *u8, i: i64, n: i64, pat: *u8, plen: i64) -> i64 { 18 if i + plen > n { return 0 } 19 var j: i64 = 0 20 while j < plen { if s[i+j] != pat[j] { return 0 } j = j + 1 } 21 return 1 22} 23// is `needle` a substring of hay[lo..hi)? 24func cu_find_sub(hay: *u8, lo: i64, hi: i64, needle: *u8, nlen: i64) -> i64 { 25 var i: i64 = lo 26 while i + nlen <= hi { if cu_match_at(hay, i, hi, needle, nlen) == 1 { return 1 } i = i + 1 } 27 return 0 28} 29// path contains ".." anywhere -> traversal 30func cu_has_traversal(path: *u8, n: i64) -> i64 { 31 var i: i64 = 0 32 while i + 1 < n { if path[i] == (46 as u8) { if path[i+1] == (46 as u8) { return 1 } } i = i + 1 } 33 return 0 34} 35// does the last path segment (after the final '/') contain a '.' (i.e., it already has a file extension)? 36func cu_seg_has_dot(path: *u8, n: i64) -> i64 { 37 var seg: i64 = 0; var i: i64 = 0 38 while i < n { if path[i] == (47 as u8) { seg = i + 1 } i = i + 1 } 39 var j: i64 = seg 40 while j < n { if path[j] == (46 as u8) { return 1 } j = j + 1 } 41 return 0 42} 43// resolve a REQUEST path (no query string) to a doc-root-relative FILE path. returns length, or -1 if rejected. 44func cu_resolve(path: *u8, n: i64, out: *u8, cap: i64) -> i64 { 45 if cu_has_traversal(path, n) == 1 { return 0 - 1 } 46 var s: i64 = 0 47 if n > 0 { if path[0] == (47 as u8) { s = 1 } } 48 var p: i64 = 0 49 var i: i64 = s 50 while i < n { if p < cap - 1 { out[p] = path[i]; p = p + 1 } i = i + 1 } 51 if p == 0 { 52 p = cu_app(out, 0, cap, "index.html" as *u8) // "/" -> index.html 53 } else { 54 if out[p-1] == (47 as u8) { 55 p = cu_app(out, p, cap, "index.html" as *u8) // "/foo/" -> foo/index.html 56 } else { 57 if cu_seg_has_dot(path, n) == 0 { 58 p = cu_app(out, p, cap, ".html" as *u8) // "/foo" -> foo.html (the clean URL) 59 } 60 // else: already has an extension -> serve as-is 61 } 62 } 63 if p < cap { out[p] = 0 as u8 } 64 return p 65} 66// 1 if a single href is clean (carries no ".html"); 0 otherwise. (Anchors "#x" and "/x" are clean.) 67func cu_link_is_clean(href: *u8) -> i64 { 68 var n: i64 = 0; while href[n] != (0 as u8) { n = n + 1 } 69 if cu_find_sub(href, 0, n, ".html" as *u8, 5) == 1 { return 0 } 70 return 1 71} 72// count hrefs in a built page whose value still carries ".html" (0 == fully clean-linked). 73func cu_audit_links(html: *u8, n: i64) -> i64 { 74 var c: i64 = 0 75 var i: i64 = 0 76 while i + 6 <= n { 77 if cu_match_at(html, i, n, "href=\"" as *u8, 6) == 1 { 78 var j: i64 = i + 6 79 while j < n { if html[j] == (34 as u8) { break } j = j + 1 } // closing quote 80 if cu_find_sub(html, i + 6, j, ".html" as *u8, 5) == 1 { c = c + 1 } 81 i = j + 1 82 } else { i = i + 1 } 83 } 84 return c 85}