code wiki / (root) / nx_pages_config.nx

nx_pages_config.nx source

↩ module page · 208 lines · 7387 B

1// nx_pages_config.nx -- D1.6 of NISHI_DEPLOY_ROADMAP. Loads vhost map 2// from a config file so nx_pages_daemon + nx_pages_https_daemon can be 3// deployed without recompiling for per-host doc-root changes. 4// 5// File format (one entry per line, very simple to keep the parser tiny): 6// 7// # nishifamily.com primary 8// vhost=nishifamily.com:/share/nishi-pages/dist 9// vhost=www.nishifamily.com:/share/nishi-pages/dist 10// vhost=andelinwest.com:/share/andelin-pages/dist 11// fallback=0 12// 13// Rules: 14// - Blank lines + lines starting with '#' are ignored. 15// - 'vhost=<host>:<root>' adds a vhost (order preserved; fallback_idx 16// references this 0-based ordering). 17// - 'fallback=<idx>' picks the fallback vhost. Omit -> no fallback. 18// - All other keys (http_port, https_port, cert_path, key_path) are 19// recognized but consumed via separate accessor functions; the 20// parser stores their string values into a flat string arena and 21// exposes lookup by name. 22// 23// Per NISHI_DEPLOY_ROADMAP D1.6. Companion: SIGHUP zero-downtime reload 24// is deferred to D1.6.5. 25 26import "nx_syscalls.nx" 27import "nx_pages_vhost.nx" 28 29const NX_PCFG_OK: i64 = 0 30const NX_PCFG_ERR_OPEN: i64 = 1 31const NX_PCFG_ERR_READ: i64 = 2 32const NX_PCFG_ERR_TOO_BIG: i64 = 3 33const NX_PCFG_ERR_PARSE: i64 = 4 34const NX_PCFG_ERR_VHOST_OOM: i64 = 5 35 36const NX_PCFG_MAX_FILE_BYTES: i64 = 65536 // 64 KB conf cap (V1) 37const NX_PCFG_MAX_VHOSTS: i64 = 64 38 39// ===== Byte helpers ================================================ 40 41func _pcfg_is_ws(b: i64) -> i64 { 42 if b == 0x20 { return 1 } 43 if b == 0x09 { return 1 } 44 return 0 45} 46 47func _pcfg_strlen(s: *u8) -> i64 { 48 var n: i64 = 0 49 while s[n] != 0 { n = n + 1 } 50 return n 51} 52 53func _pcfg_byte_eq(a: *u8, ao: i64, b: *u8, bo: i64, n: i64) -> i64 { 54 var i: i64 = 0 55 while i < n { 56 if a[ao + i] != b[bo + i] { return 0 } 57 i = i + 1 58 } 59 return 1 60} 61 62// Scan for the first occurrence of `needle_byte` within 63// [buf+start, buf+end). Returns position or `end` (sentinel). 64func _pcfg_find_byte(buf: *u8, start: i64, end: i64, needle: i64) -> i64 { 65 var p: i64 = start 66 var done: i64 = 0 67 while done == 0 { 68 if p >= end { done = 1 } 69 if done == 0 { 70 if buf[p] as i64 == needle { done = 1 } 71 if done == 0 { p = p + 1 } 72 } 73 } 74 return p 75} 76 77// Parse decimal i64 from buf[start..end-1]. Returns parsed value via 78// *out_val + 1 on success, 0 on failure. 79func _pcfg_parse_i64(buf: *u8, start: i64, end: i64, out_val: *i64) -> i64 { 80 if start >= end { return 0 } 81 var i: i64 = start 82 var sign: i64 = 1 83 if buf[i] == 0x2d { sign = -1; i = i + 1 } // '-' 84 if i >= end { return 0 } 85 var acc: i64 = 0 86 while i < end { 87 let b: i64 = buf[i] as i64 88 if b < 0x30 { return 0 } 89 if b > 0x39 { return 0 } 90 acc = acc * 10 + (b - 0x30) 91 i = i + 1 92 } 93 out_val[0] = acc * sign 94 return 1 95} 96 97// ===== Public: load a config file into a vhost table ================= 98// 99// Reads the file at `path`, parses vhost= and fallback= lines, populates 100// the caller-allocated NxVHostTable. Caller is responsible for the 101// arena + vhosts array sizing. 102// 103// Returns NX_PCFG_OK or one of the NX_PCFG_ERR_* codes. 104 105func nx_pages_config_load( 106 path: *u8, 107 t: *NxVHostTable, 108 cursor: *i64 109) -> i64 { 110 let file_len_box: *i64 = sys_mmap(8) as *i64 111 let buf: *u8 = sys_read_file(path, file_len_box) 112 if (buf as i64) == 0 { return NX_PCFG_ERR_OPEN } 113 let n: i64 = file_len_box[0] 114 if n <= 0 { return NX_PCFG_ERR_READ } 115 if n > NX_PCFG_MAX_FILE_BYTES { return NX_PCFG_ERR_TOO_BIG } 116 117 let vhost_key: *u8 = "vhost" as *u8 118 let fallback_key: *u8 = "fallback" as *u8 119 120 var pos: i64 = 0 121 while pos < n { 122 // Find end-of-line (LF) or end-of-file. 123 let lf: i64 = _pcfg_find_byte(buf, pos, n, 0x0a) 124 125 // Skip leading whitespace. Use done-flag pattern so ls stays 126 // at the captured first-non-ws position (the sentinel-exit 127 // anti-pattern would clobber it -- see feedback memo 128 // feedback-nishilang-sentinel-exit-clobbers-position). 129 var ls: i64 = pos 130 var ls_done: i64 = 0 131 while ls_done == 0 { 132 if ls >= lf { ls_done = 1 } 133 if ls_done == 0 { 134 if _pcfg_is_ws(buf[ls] as i64) == 1 { ls = ls + 1 } 135 if _pcfg_is_ws(buf[ls] as i64) == 0 { ls_done = 1 } 136 } 137 } 138 139 // Trim trailing CR if present. 140 var le: i64 = lf 141 if le > ls { 142 if buf[le - 1] == 0x0d { le = le - 1 } 143 } 144 145 // Skip blank lines + comments. 146 var is_blank: i64 = 0 147 if ls >= le { is_blank = 1 } 148 if is_blank == 0 { 149 if buf[ls] == 0x23 { is_blank = 1 } // '#' 150 } 151 152 if is_blank == 0 { 153 // Find '=' separator. 154 let eq: i64 = _pcfg_find_byte(buf, ls, le, 0x3d) 155 if eq < le { 156 let key_off: i64 = ls 157 let key_len: i64 = eq - ls 158 let val_off: i64 = eq + 1 159 let val_len: i64 = le - val_off 160 161 // vhost=<host>:<root> 162 if key_len == 5 { 163 if _pcfg_byte_eq(buf, key_off, vhost_key, 0 as i64, 5 as i64) == 1 { 164 // Find ':' inside the value. 165 let colon: i64 = _pcfg_find_byte(buf, val_off, val_off + val_len, 166 0x3a as i64) 167 if colon < val_off + val_len { 168 // Copy host + root into temp null-terminated cstrs. 169 let host_n: i64 = colon - val_off 170 let root_n: i64 = (val_off + val_len) - (colon + 1) 171 let host_cs: *u8 = sys_mmap(host_n + 1) 172 let root_cs: *u8 = sys_mmap(root_n + 1) 173 var hi: i64 = 0 174 while hi < host_n { 175 host_cs[hi] = buf[val_off + hi] 176 hi = hi + 1 177 } 178 host_cs[host_n] = 0 as u8 179 var ri: i64 = 0 180 while ri < root_n { 181 root_cs[ri] = buf[colon + 1 + ri] 182 ri = ri + 1 183 } 184 root_cs[root_n] = 0 as u8 185 if t.n_vhosts < NX_PCFG_MAX_VHOSTS { 186 nx_vhost_add(t, cursor, host_cs, root_cs) 187 } 188 } 189 } 190 } 191 // fallback=<idx> 192 if key_len == 8 { 193 if _pcfg_byte_eq(buf, key_off, fallback_key, 0 as i64, 8 as i64) == 1 { 194 let fb: *i64 = sys_mmap(8) as *i64 195 if _pcfg_parse_i64(buf, val_off, val_off + val_len, fb) == 1 { 196 nx_vhost_set_fallback(t, fb[0]) 197 } 198 } 199 } 200 } 201 } 202 203 // Advance to next line (past LF). 204 if lf < n { pos = lf + 1 } 205 if lf >= n { pos = n } 206 } 207 return NX_PCFG_OK 208}