code wiki / _hdl_build / nx_browse.nx

nx_browse.nx source

↩ module page · 186 lines · 9130 B

1// nx_browse.nx -- ONE-organ sovereign browse: read URL from _url.txt -> fetch the page (own DNS+TLS1.3+ 2// HTTP) -> ALSO fetch its <link rel=stylesheet> sheets (load.php) and append them as <style> blocks so 3// the render applies the PAGE'S OWN CSS (@media-filtered) -> styled PNG. 100% sovereign, no curl/V8/gcc. 4import "nx_syscalls.nx" 5import "nx_x509_trust_store.nx" 6import "nx_trust_store_load_from_certdata.nx" 7import "nx_https_get.nx" 8import "nx_http_response_parse.nx" 9import "nx_html_tokenizer.nx" 10import "nx_dom_query.nx" 11import "nx_html_entities.nx" 12import "nx_render_html.nx" 13 14func _bp(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } 15func _bn(fd: i64, v0: i64) -> i64 { 16 var v: i64 = v0 17 if v < 0 { let m: *u8=sys_mmap(8); m[0]=45 as u8; sys_write(fd,m,1); v = 0 - v } 18 let buf: *u8 = sys_mmap(24); var k: i64 = 0 19 if v == 0 { buf[0]=48 as u8; k=1 } 20 while v > 0 { buf[k]=(48+(v%10)) as u8; v=v/10; k=k+1 } 21 let ob: *u8 = sys_mmap(24); var o: i64=0 22 while o < k { ob[o]=buf[k-1-o]; o=o+1 } 23 sys_write(fd, ob, k); return 0 24} 25 26// Fetch a URL -> body buffer (lenbox[0]=length). 0 on failure. Reused for the page + each stylesheet. 27func _browse_fetch(url: *u8, store: *TrustStore, cr: *u8, priv: *u8, lenbox: *i64) -> *u8 { 28 let now: i64 = sys_now_realtime_sec() 29 let cap: i64 = 8388608 30 let buf: *u8 = sys_mmap(cap) 31 let n: i64 = nx_https_get(url, cr, priv, store, now, buf, cap) 32 if n < 0 { lenbox[0] = 0; return 0 as *u8 } 33 let r: *i64 = nx_http_resp_alloc() 34 let pv: i64 = nx_http_response_parse(buf, n, r) 35 var body: *u8 = buf 36 var body_len: i64 = n 37 if pv == NX_HTTP_RESP_OK { 38 let bo: i64 = r[6] 39 let kind: i64 = r[8] 40 body = ((buf as i64) + bo) as *u8 41 body_len = n - bo 42 if kind == NX_HTTP_BODY_CONTENT_LENGTH { body_len = r[7]; if body_len > n - bo { body_len = n - bo } } 43 if kind == NX_HTTP_BODY_CHUNKED { 44 let dcap: i64 = 8388608 45 let dbuf: *u8 = sys_mmap(dcap) 46 let dl: i64 = nx_http_dechunk(body, n - bo, dbuf, dcap) 47 if dl > 0 { body = dbuf; body_len = dl } 48 } 49 } 50 lenbox[0] = body_len 51 return body 52} 53// scheme://host prefix of url (everything before the 3rd '/'); returns length written to out. 54func _scheme_host(url: *u8, ulen: i64, out: *u8) -> i64 { 55 var slashes: i64 = 0 56 var i: i64 = 0 57 var o: i64 = 0 58 var keep: i64 = 1 59 while keep == 1 { 60 if i >= ulen { keep = 0 } 61 else { 62 let c: i64 = url[i] & 0xff 63 if c == 47 { slashes = slashes + 1; if slashes == 3 { keep = 0 } else { out[o]=c as u8; o=o+1; i=i+1 } } 64 else { out[o]=c as u8; o=o+1; i=i+1 } 65 } 66 } 67 return o 68} 69// does src[off..off+len) contain "stylesheet"? 70func _has_stylesheet(src: *u8, off: i64, len: i64) -> i64 { 71 let pat: *u8 = "stylesheet\x00" as *u8 72 if len < 10 { return 0 } 73 var i: i64 = 0 74 while i <= len - 10 { 75 var j: i64 = 0; var ok: i64 = 1 76 while j < 10 { if (src[off+i+j]&0xff) != (pat[j]&0xff) { ok = 0; j = 10 } else { j = j + 1 } } 77 if ok == 1 { return 1 } 78 i = i + 1 79 } 80 return 0 81} 82 83func main() -> i64 { 84 let lp: *i64 = sys_mmap(16) as *i64 85 let urlraw: *u8 = sys_read_file("_url.txt\x00" as *u8, lp) 86 var ulen: i64 = *lp 87 if ulen <= 0 { _bp(2, "nx_browse: no _url.txt\n" as *u8); return 1 } 88 var trimming: i64 = 1 89 while trimming == 1 { 90 if ulen <= 0 { trimming = 0 } 91 else { let c: i64 = urlraw[ulen-1] & 0xff 92 if c==10 { ulen=ulen-1 } else { if c==13 { ulen=ulen-1 } else { if c==32 { ulen=ulen-1 } else { if c==9 { ulen=ulen-1 } else { trimming = 0 } } } } } 93 } 94 if ulen <= 0 { _bp(2, "nx_browse: empty URL\n" as *u8); return 1 } 95 let url: *u8 = sys_mmap(ulen + 4) 96 var ui: i64 = 0 97 while ui < ulen { url[ui] = urlraw[ui]; ui = ui + 1 } 98 url[ulen] = 0 as u8 99 _bp(1, "nx_browse: fetching " as *u8); sys_write(1, url, ulen); _bp(1, "\n" as *u8) 100 101 var tr: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt\x00" as *u8, 300, 4194304) 102 if tr <= 0 { tr = nx_trust_store_load_from_certdata("/tmp/mozilla_certdata.txt\x00" as *u8, 300, 4194304) } 103 if tr <= 0 { _bp(2, "nx_browse: CA bundle load failed\n" as *u8); return 3 } 104 let store: *TrustStore = tr as *TrustStore 105 let cr: *u8 = sys_mmap(32) 106 let priv: *u8 = sys_mmap(32) 107 let ufd: i64 = sys_openat_rd("/dev/urandom\x00" as *u8) 108 if ufd >= 0 { sys_read(ufd, cr, 32); sys_read(ufd, priv, 32); sys_close(ufd) } 109 if ufd < 0 { var z: i64=0; while z<32 { cr[z]=(0xC0+z) as u8; priv[z]=(0xA0+z) as u8; z=z+1 } } 110 111 // ---- fetch the page ---- 112 let plb: *i64 = sys_mmap(8) as *i64 113 let body: *u8 = _browse_fetch(url, store, cr, priv, plb) 114 let body_len: i64 = plb[0] 115 if body == (0 as *u8) { _bp(2, "nx_browse: page fetch failed\n" as *u8); return 4 } 116 117 // save the fetched HTML so it can be inspected / re-rendered offline (debugging + the geometry tools) 118 let sfd: i64 = sys_openat_wr("knowledge/fetched/last_browse.html\x00" as *u8) 119 if sfd >= 0 { sys_write(sfd, body, body_len); sys_close(sfd) } 120 121 // ---- augmented HTML = page + each <link rel=stylesheet> fetched as a <style> block ---- 122 let AUGCAP: i64 = body_len + 16777216 123 let aug: *u8 = sys_mmap(AUGCAP) 124 var ao: i64 = 0 125 var bi: i64 = 0 126 while bi < body_len { aug[ao] = body[bi]; ao = ao + 1; bi = bi + 1 } 127 128 let lc: *HtmlCursor = sys_mmap(24) as *HtmlCursor 129 nx_html_cursor_init(lc, body, body_len) 130 let ltok: *HtmlToken = sys_mmap(56) as *HtmlToken 131 let ho: *i64 = sys_mmap(8) as *i64; let hl: *i64 = sys_mmap(8) as *i64 132 let ro: *i64 = sys_mmap(8) as *i64; let rl: *i64 = sys_mmap(8) as *i64 133 let csslb: *i64 = sys_mmap(8) as *i64 134 var nlinks: i64 = 0 135 var cssbytes: i64 = 0 136 var lkeep: i64 = 1 137 while lkeep == 1 { 138 nx_html_next_token(lc, ltok) 139 if ltok.kind == NX_HTML_TOK_EOF { lkeep = 0 } 140 else { 141 var islink: i64 = 0 142 if ltok.kind == NX_HTML_TOK_START_TAG { islink = 1 } 143 if ltok.kind == NX_HTML_TOK_SELF_CLOSING { islink = 1 } 144 if islink == 1 { if ltok.name_len == 4 { 145 if (body[ltok.name_off]&0xff)==108 { if (body[ltok.name_off+1]&0xff)==105 { if (body[ltok.name_off+2]&0xff)==110 { if (body[ltok.name_off+3]&0xff)==107 { 146 if nx_dom_find_attr(body, ltok.src_off, ltok.src_len, "rel\x00" as *u8, ro, rl) == 1 { 147 if _has_stylesheet(body, ro[0], rl[0]) == 1 { 148 if nx_dom_find_attr(body, ltok.src_off, ltok.src_len, "href\x00" as *u8, ho, hl) == 1 { 149 // decode entities in href (&amp;->&), then resolve to absolute 150 let dec: *u8 = sys_mmap(hl[0] + 16) 151 let decl: i64 = nx_html_decode_entities(body, ho[0], hl[0], dec, hl[0] + 16) 152 let absurl: *u8 = sys_mmap(decl + ulen + 16) 153 var absl: i64 = 0 154 if (dec[0]&0xff) == 104 { var z: i64=0; while z<decl { absurl[z]=dec[z]; z=z+1 } absl = decl } 155 else { if (dec[0]&0xff) == 47 { absl = _scheme_host(url, ulen, absurl); var z: i64=0; while z<decl { absurl[absl+z]=dec[z]; z=z+1 } absl = absl + decl } } 156 if absl > 0 { 157 absurl[absl] = 0 as u8 158 let css: *u8 = _browse_fetch(absurl, store, cr, priv, csslb) 159 if css != (0 as *u8) { if csslb[0] > 0 { 160 let st: *u8 = "<style>\x00" as *u8 161 var si: i64 = 0 162 while si < 7 { if ao < AUGCAP-1 { aug[ao]=st[si]; ao=ao+1 } si=si+1 } 163 var ci: i64 = 0 164 while ci < csslb[0] { if ao < AUGCAP-9 { aug[ao]=css[ci]; ao=ao+1 } ci=ci+1 } 165 let et: *u8 = "</style>\x00" as *u8 166 si = 0 167 while si < 8 { if ao < AUGCAP-1 { aug[ao]=et[si]; ao=ao+1 } si=si+1 } 168 nlinks = nlinks + 1 169 cssbytes = cssbytes + csslb[0] 170 } } 171 } 172 } 173 } 174 } 175 } } } } 176 } } 177 } 178 } 179 _bp(1, "nx_browse: fetched page " as *u8); _bn(1, body_len) 180 _bp(1, "B + " as *u8); _bn(1, nlinks); _bp(1, " stylesheets " as *u8); _bn(1, cssbytes); _bp(1, "B\n" as *u8) 181 182 let nb: i64 = nx_render_html_to_png(aug, ao, "knowledge/status/browse.png\x00" as *u8) 183 _bp(1, "nx_browse: rendered " as *u8); _bn(1, nb); _bp(1, " boxes -> knowledge/status/browse.png\n" as *u8) 184 if nb <= 0 { return 5 } 185 return 0 186}