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 (&->&), 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}