code wiki / (root) / nx_lib_http.nx

nx_lib_http.nx source

↩ module page · 163 lines · 6736 B

1// nx_lib_http.nx -- PURE HTTP routing/response for the sovereign library API. 2// No main, no sockets: request-path -> full HTTP response bytes, straight from 3// nx_lib_store via nx_lib_serve. Gateable in isolation; the daemon nx_lib_httpd 4// wraps it with the socket accept loop. 5// GET /api/works -> JSON array of work_hks 6// GET /api/work/<hk> -> JSON work record (200) or 404 7// license_tier: ORIGINAL 8import "nx_lib_serve.nx" 9import "nx_lib_index.nx" 10import "nx_lib_ingest.nx" 11import "nx_lib_ingest_tsv.nx" // nx_lib_ingest_buf -- the TSV ingest organ deleted by the 07-21 dedupe 12import "nx_lib_page.nx" 13 14func lhd_puts(buf: *u8, off: i64, s: *u8) -> i64 { 15 var o: i64 = off 16 var i: i64 = 0 17 while s[i] != (0 as u8) { buf[o] = s[i]; o = o + 1; i = i + 1 } 18 return o 19} 20 21// append decimal v; nxc2 has no % so mod = x-(x/10)*10. 22func lhd_putdec(buf: *u8, off: i64, v: i64) -> i64 { 23 if v == 0 { buf[off] = 48 as u8; return off + 1 } 24 let tmp: *u8 = sys_mmap(32) 25 var k: i64 = 0 26 var x: i64 = v 27 while x > 0 { tmp[k] = (48 + (x - (x / 10) * 10)) as u8; x = x / 10; k = k + 1 } 28 var o: i64 = off 29 var ri: i64 = k - 1 30 while ri >= 0 { buf[o] = tmp[ri]; o = o + 1; ri = ri - 1 } 31 return o 32} 33 34func lhd_eq(path: *u8, path_n: i64, s: *u8) -> i64 { 35 let sn: i64 = ls_strlen(s) 36 if sn != path_n { return 0 } 37 var i: i64 = 0 38 while i < sn { if path[i] != s[i] { return 0 } i = i + 1 } 39 return 1 40} 41 42func lhd_starts(path: *u8, path_n: i64, pre: *u8) -> i64 { 43 var i: i64 = 0 44 while pre[i] != (0 as u8) { 45 if i >= path_n { return 0 } 46 if path[i] != pre[i] { return 0 } 47 i = i + 1 48 } 49 return 1 50} 51 52// PURE: build the full HTTP response for a request path into out; return length. 53func lhd_response(path: *u8, path_n: i64, out: *u8) -> i64 { 54 // ---- /research edge-prefix alias (ADDITIVE 2026-07-02) ---- 55 // The sites edge routes `nishifamily.com /research 8095 stream` via proxy_routes.conf, 56 // and STREAM mode passes the RAW (unstripped) request through -- so accept the full 57 // /research prefix here by delegating to the identical stripped route. Buffered-mode 58 // clients (nx_http_proxy_relay strips before forwarding) are unaffected. 59 if lhd_starts(path, path_n, "/research" as *u8) == 1 { 60 if path_n == 9 { return lhd_page_home(("" as *u8), 0, out) } 61 let anc: i64 = path[9] as i64 62 if anc == 47 { return lhd_response(((path as i64) + 9) as *u8, path_n - 9, out) } 63 if anc == 63 { 64 // "/research?q=x" -> "/?q=x" (re-root the query form) 65 let ab: *u8 = sys_mmap(path_n + 8) 66 ab[0] = 47 as u8 67 var ai: i64 = 9 68 var ak: i64 = 1 69 while ai < path_n { ab[ak] = path[ai]; ak = ak + 1; ai = ai + 1 } 70 return lhd_response(ab, ak, out) 71 } 72 } 73 // ---- sovereign zero-JS HTML frontend (served before the JSON API) ---- 74 if lhd_eq(path, path_n, "/" as *u8) == 1 { return lhd_page_home(("" as *u8), 0, out) } 75 if lhd_starts(path, path_n, "/?" as *u8) == 1 { 76 let hqbuf: *u8 = sys_mmap(2048) 77 var hqs: i64 = 0 - 1 78 var hsi: i64 = 0 79 while hsi + 1 < path_n { if hqs < 0 { if path[hsi] == 113 as u8 { if path[hsi + 1] == 61 as u8 { hqs = hsi + 2 } } } hsi = hsi + 1 } 80 var hql: i64 = 0 81 if hqs >= 0 { 82 var hk: i64 = hqs 83 while hk < path_n { 84 let c: i64 = path[hk] as i64 85 if c == 38 { hk = path_n } 86 else { if c == 43 { hqbuf[hql] = 32 as u8; hql = hql + 1; hk = hk + 1 } else { hqbuf[hql] = path[hk]; hql = hql + 1; hk = hk + 1 } } 87 } 88 } 89 return lhd_page_home(hqbuf, hql, out) 90 } 91 if lhd_starts(path, path_n, "/work/" as *u8) == 1 { 92 return lhd_page_work(((path as i64) + 6) as *u8, path_n - 6, out) 93 } 94 95 let body: *u8 = sys_mmap(1048576) 96 var bn: i64 = 0 97 var ok: i64 = 0 98 if lhd_eq(path, path_n, "/api/works" as *u8) == 1 { 99 bn = nx_lib_serve_list(body) 100 ok = 1 101 } else { if lhd_starts(path, path_n, "/api/search" as *u8) == 1 { 102 // GET /api/search?q=<terms> ('+' -> space, '&' ends the value) 103 let qbuf: *u8 = sys_mmap(2048) 104 var qs: i64 = 0 - 1 105 var si: i64 = 0 106 while si + 1 < path_n { 107 if qs < 0 { if path[si] == 113 as u8 { if path[si + 1] == 61 as u8 { qs = si + 2 } } } 108 si = si + 1 109 } 110 var ql: i64 = 0 111 if qs >= 0 { 112 var kk: i64 = qs 113 while kk < path_n { 114 let c: i64 = path[kk] as i64 115 if c == 38 { kk = path_n } 116 else { 117 if c == 43 { qbuf[ql] = 32 as u8; ql = ql + 1; kk = kk + 1 } 118 else { qbuf[ql] = path[kk]; ql = ql + 1; kk = kk + 1 } 119 } 120 } 121 } 122 bn = nx_lib_index_search(qbuf, ql, body) // O(1) persisted inverted index 123 ok = 1 124 } else { if lhd_starts(path, path_n, "/api/work/" as *u8) == 1 { 125 let hkbuf: *u8 = sys_mmap(1024) 126 var i: i64 = 10 127 var k: i64 = 0 128 while i < path_n { hkbuf[k] = path[i]; k = k + 1; i = i + 1 } 129 hkbuf[k] = 0 as u8 130 let jl: i64 = nx_lib_serve_work(hkbuf, body) 131 if jl >= 0 { bn = jl; ok = 1 } 132 } } } 133 if ok == 0 { 134 let r404: *u8 = "HTTP/1.1 404 Not Found\r\nContent-Type: application/json\r\nContent-Length: 14\r\nConnection: close\r\n\r\n{\"error\":\"nf\"}" as *u8 135 return lhd_puts(out, 0, r404) 136 } 137 var o: i64 = 0 138 o = lhd_puts(out, o, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " as *u8) 139 o = lhd_putdec(out, o, bn) 140 o = lhd_puts(out, o, "\r\nCache-Control: no-store\r\nConnection: close\r\n\r\n" as *u8) 141 var j: i64 = 0 142 while j < bn { out[o] = body[j]; o = o + 1; j = j + 1 } 143 return o 144} 145 146// PURE: ingest a TSV request body into nx_lib_store, rebuild the search index, 147// return an HTTP 200 {"ingested":N}. Backs POST /api/ingest. Gateable. 148func lhd_ingest_response(body: *u8, body_n: i64, out: *u8) -> i64 { 149 let cnt: i64 = nx_lib_ingest_buf(body, body_n) 150 nx_lib_index_build() // reindex so new works are searchable 151 let jb: *u8 = sys_mmap(256) 152 var jo: i64 = 0 153 jo = lhd_puts(jb, jo, "{\"ingested\":" as *u8) 154 jo = lhd_putdec(jb, jo, cnt) 155 jo = lhd_puts(jb, jo, "}" as *u8) 156 var o: i64 = 0 157 o = lhd_puts(out, o, "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: " as *u8) 158 o = lhd_putdec(out, o, jo) 159 o = lhd_puts(out, o, "\r\nConnection: close\r\n\r\n" as *u8) 160 var j2: i64 = 0 161 while j2 < jo { out[o] = jb[j2]; o = o + 1; j2 = j2 + 1 } 162 return o 163}