code wiki / _hdl_build / nx_manga_search.nx

nx_manga_search.nx source

↩ module page · 371 lines · 21130 B

1// nx_manga_search.nx -- the SOURCE BROWSER backend (operator 2026-07-04: "i want the sites to choose to download or 2// translate like i could in media manager"). On-site SEARCH for the sources we support, served to the /library/manga 3// page so the operator picks a source, searches it, and taps a result to download -- the Mihon/media-manager model. 4// /api/msearch?src=mangadex&q=.. -> MangaDex API (/manga?title=) -> [{t,id,thumb,kind:series}] 5// /api/msearch?src=nhentai&q=.. -> nhentai /search/ HTML (its old API is 403'd) -> [{t,url,thumb,kind:gallery}] 6// /api/mfeed?id=<mangaId> -> MangaDex chapter feed -> [{ch,t,id}] (series -> chapters second level) 7// /api/thumb?u=<enc url> -> PROXY a cover through our sovereign Chrome client (beats Cloudflare/hotlink), 8// so thumbnails ALWAYS render in the browser regardless of referer checks. 9// All live fetches via nx_https_fetch_follow_chrome (Chrome-JA3 + RSA-PSS + honest UA). Parsers match REAL shapes 10// captured with the sovereign client. Reuses na_* (nx_manga_sites) + zs_* (nx_reader_zoomserve). license_tier: ORIGINAL 11import "nx_syscalls.nx" 12import "nx_x509_trust_store.nx" 13import "nx_trust_store_load_from_certdata.nx" 14import "nx_https_fetch_follow.nx" 15import "nx_manga_sites.nx" // na_find_from / na_apps 16import "nx_reader_zoomserve.nx" // zs_emit / zs_qval / zs_apps / zs_slen 17const MSS_MAGIC_4194304: i64 = 4194304 18const MSS_MAGIC_1536: i64 = 1536 19const MSS_MAGIC_2048: i64 = 2048 20const MSS_MAGIC_1024: i64 = 1024 21 22const MSS_FETCH_CAP: i64 = 2097152 // 2MB (mangadex/nhentai search pages ~40KB; covers up to ~1MB) 23const MSS_OUT_CAP: i64 = 131072 24 25func mss_slen(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 26 27// percent-encode a query into out (alnum + -_.~ pass; space + others -> %XX). returns len. 28func mss_qenc(src: *u8, n: i64, out: *u8) -> i64 { 29 let hx: *u8 = "0123456789ABCDEF" as *u8 30 var o: i64 = 0; var i: i64 = 0 31 while i < n { 32 let c: i64 = src[i] as i64 33 var safe: i64 = 0 34 if c >= 48 { if c <= 57 { safe = 1 } } 35 if c >= 65 { if c <= 90 { safe = 1 } } 36 if c >= 97 { if c <= 122 { safe = 1 } } 37 if c == 45 { safe = 1 } if c == 95 { safe = 1 } if c == 46 { safe = 1 } if c == 126 { safe = 1 } 38 if safe == 1 { out[o] = c as u8; o = o + 1 } 39 else { out[o] = 37 as u8; out[o+1] = hx[(c>>4)&0xf]; out[o+2] = hx[c&0xf]; o = o + 3 } 40 i = i + 1 41 } 42 out[o] = 0 as u8 43 return o 44} 45 46// starts-with at position: does buf[pos..] begin with the NUL-term literal `lit`? 47func mss_at(buf: *u8, n: i64, pos: i64, lit: *u8) -> i64 { 48 var j: i64 = 0 49 while lit[j] != (0 as u8) { if pos + j >= n { return 0 } if buf[pos+j] != lit[j] { return 0 } j = j + 1 } 50 return 1 51} 52 53// copy an already-JSON-escaped string value verbatim from src[from..] into dst[o..] until the UNescaped '"'. 54// returns new o; sets endp[0] to the index of that closing quote. (source is valid JSON -> its \" \\ \u pass through.) 55func mss_cpjval(dst: *u8, o: i64, src: *u8, from: i64, n: i64, cap: i64, endp: *i64) -> i64 { 56 var i: i64 = from 57 while i < n { 58 let c: i64 = src[i] as i64 59 if c == 92 { if i + 1 < n { if o < cap - 2 { dst[o] = src[i]; dst[o+1] = src[i+1]; o = o + 2 } i = i + 2 } else { i = n } } 60 else { if c == 34 { endp[0] = i; return o } if o < cap - 1 { dst[o] = src[i]; o = o + 1 } i = i + 1 } 61 } 62 endp[0] = n; return o 63} 64 65// append raw bytes with JSON-string escaping (for HTML-derived titles: escape " and \, drop < 0x20). stops at cap. 66func mss_jesc(dst: *u8, o: i64, src: *u8, from: i64, to: i64, cap: i64) -> i64 { 67 var i: i64 = from 68 while i < to { let c: i64 = src[i] as i64 69 if c == 34 { if o < cap-2 { dst[o]=92 as u8; dst[o+1]=34 as u8; o=o+2 } } 70 else { if c == 92 { if o < cap-2 { dst[o]=92 as u8; dst[o+1]=92 as u8; o=o+2 } } 71 else { if c >= 32 { if o < cap-1 { dst[o]=src[i] as u8; o=o+1 } } } } 72 i = i + 1 73 } 74 return o 75} 76 77// append a proxied-thumb field: ,"thumb":"api/thumb?u=<qenc(realUrl[us..ue))>" 78func mss_thumb_field(dst: *u8, o: i64, real: *u8, us: i64, ue: i64, cap: i64) -> i64 { 79 o = zs_apps(dst, o, ",\"thumb\":\"api/thumb?u=" as *u8) 80 let hx: *u8 = "0123456789ABCDEF" as *u8 81 var i: i64 = us 82 while i < ue { let c: i64 = real[i] as i64 83 var safe: i64 = 0 84 if c >= 48 { if c <= 57 { safe = 1 } } if c >= 65 { if c <= 90 { safe = 1 } } if c >= 97 { if c <= 122 { safe = 1 } } 85 if c == 45 { safe=1 } if c == 95 { safe=1 } if c == 46 { safe=1 } if c == 126 { safe=1 } 86 if safe == 1 { if o < cap-1 { dst[o]=c as u8; o=o+1 } } else { if o < cap-3 { dst[o]=37 as u8; dst[o+1]=hx[(c>>4)&0xf]; dst[o+2]=hx[c&0xf]; o=o+3 } } 87 i = i + 1 88 } 89 dst[o] = 34 as u8; o = o + 1 90 return o 91} 92 93// ---- MangaDex search JSON -> results. entries = `"id":"UUID","type":"manga"`; title = first attributes.title lang; 94// cover fileName from the manga's cover_art relationship -> uploads.mangadex.org/covers/<id>/<file>.256.jpg (proxied). 95func msearch_mangadex(json: *u8, jn: i64, out: *u8, cap: i64) -> i64 { 96 var o: i64 = zs_apps(out, 0, "{\"src\":\"mangadex\",\"kind\":\"series\",\"results\":[" as *u8) 97 var first: i64 = 1 98 let ep: *i64 = sys_mmap(8) as *i64 99 var pos: i64 = 0 100 var guard: i64 = 0 101 while guard < 200 { 102 guard = guard + 1 103 let idp: i64 = na_find_from(json, jn, "\"id\":\"" as *u8, pos) 104 if idp < 0 { guard = 200 } else { 105 let vs: i64 = idp + 6 106 let ve: i64 = na_find_from(json, jn, "\"" as *u8, vs) 107 if ve < 0 { guard = 200 } else { 108 pos = ve + 1 109 if mss_at(json, jn, ve, "\",\"type\":\"manga\"" as *u8) == 1 { 110 // this is a manga entry. bound = next manga 111 let nextm: i64 = na_find_from(json, jn, "\"type\":\"manga\"" as *u8, ve + 10) 112 var bound: i64 = jn; if nextm >= 0 { bound = nextm } 113 // title 114 let tp: i64 = na_find_from(json, jn, "\"title\":{" as *u8, ve) 115 if tp >= 0 { if tp < bound { 116 var a: i64 = tp + 9 117 var r1: i64 = 1; while r1 == 1 { if a >= jn { r1 = 0 } else { if (json[a] as i64)==58 { a=a+1; r1=0 } else { a=a+1 } } } 118 var r2: i64 = 1; while r2 == 1 { if a >= jn { r2 = 0 } else { if (json[a] as i64)==34 { a=a+1; r2=0 } else { a=a+1 } } } 119 if first == 0 { out[o] = 44 as u8; o = o + 1 } 120 first = 0 121 o = zs_apps(out, o, "{\"t\":\"" as *u8) 122 o = mss_cpjval(out, o, json, a, jn, cap, ep) 123 o = zs_apps(out, o, "\",\"id\":\"" as *u8) 124 var c: i64 = vs; while c < ve { if o < cap-1 { out[o]=json[c] as u8; o=o+1 } c=c+1 } 125 out[o] = 34 as u8; o = o + 1 126 // cover (optional): find cover_art then fileName, within [ve, bound) 127 let cvp: i64 = na_find_from(json, jn, "\"type\":\"cover_art\"" as *u8, ve) 128 if cvp >= 0 { if cvp < bound { 129 let fp: i64 = na_find_from(json, jn, "\"fileName\":\"" as *u8, cvp) 130 if fp >= 0 { if fp < bound { 131 let fs: i64 = fp + 12 132 let fe: i64 = na_find_from(json, jn, "\"" as *u8, fs) 133 if fe > fs { 134 // build the real cover url in a temp then proxy it 135 let cu: *u8 = sys_mmap(512); var co: i64 = 0 136 co = zs_apps(cu, co, "https://uploads.mangadex.org/covers/" as *u8) 137 var q: i64 = vs; while q < ve { cu[co]=json[q]; co=co+1; q=q+1 } 138 cu[co]=47 as u8; co=co+1 139 q = fs; while q < fe { cu[co]=json[q]; co=co+1; q=q+1 } 140 co = zs_apps(cu, co, ".256.jpg" as *u8); cu[co]=0 as u8 141 o = mss_thumb_field(out, o, cu, 0, co, cap) 142 } 143 } } 144 } } 145 o = zs_apps(out, o, "}" as *u8) 146 } } 147 } 148 } 149 } 150 } 151 o = zs_apps(out, o, "]}" as *u8); out[o] = 0 as u8 152 return o 153} 154 155// ---- nhentai search HTML -> galleries. card = <a href="/g/ID/" class="cover">..<img alt="TITLE" .. src="THUMB"..> 156func msearch_nhentai(html: *u8, hn: i64, out: *u8, cap: i64) -> i64 { 157 var o: i64 = zs_apps(out, 0, "{\"src\":\"nhentai\",\"kind\":\"gallery\",\"results\":[" as *u8) 158 var first: i64 = 1 159 var pos: i64 = 0 160 var guard: i64 = 0 161 while guard < 400 { 162 guard = guard + 1 163 let gp: i64 = na_find_from(html, hn, "href=\"/g/" as *u8, pos) 164 if gp < 0 { guard = 400 } else { 165 let ds: i64 = gp + 9 166 var de: i64 = ds 167 var rd: i64 = 1 168 while rd == 1 { if de >= hn { rd = 0 } else { let c: i64 = html[de] as i64; if c >= 48 { if c <= 57 { de = de + 1 } else { rd = 0 } } else { rd = 0 } } } 169 pos = gp + 9 // always advance past this href to avoid re-matching 170 // de now points at the first non-digit (should be '/'); require >=1 digit + a trailing '/' 171 if de > ds { if de < hn { if (html[de] as i64) == 47 { 172 // alt title + thumb are within this <a> block (before the next href="/g/) 173 let nextg: i64 = na_find_from(html, hn, "href=\"/g/" as *u8, de) 174 var bound: i64 = hn; if nextg >= 0 { bound = nextg } 175 let ap: i64 = na_find_from(html, hn, "alt=\"" as *u8, de) 176 let sp: i64 = na_find_from(html, hn, "src=\"" as *u8, de) 177 if ap >= 0 { if ap < bound { 178 let as2: i64 = ap + 5 179 let ae: i64 = na_find_from(html, hn, "\"" as *u8, as2) 180 if ae > as2 { 181 if first == 0 { out[o] = 44 as u8; o = o + 1 } 182 first = 0 183 o = zs_apps(out, o, "{\"t\":\"" as *u8) 184 o = mss_jesc(out, o, html, as2, ae, cap) 185 o = zs_apps(out, o, "\",\"url\":\"https://nhentai.net/g/" as *u8) 186 var c: i64 = ds; while c < de { if o < cap-1 { out[o]=html[c] as u8; o=o+1 } c=c+1 } 187 o = zs_apps(out, o, "/\"" as *u8) 188 if sp >= 0 { if sp < bound { 189 let ss: i64 = sp + 5 190 let se: i64 = na_find_from(html, hn, "\"" as *u8, ss) 191 if se > ss { o = mss_thumb_field(out, o, html, ss, se, cap) } 192 } } 193 o = zs_apps(out, o, "}" as *u8) 194 } 195 } } 196 } } } 197 } 198 } 199 o = zs_apps(out, o, "]}" as *u8); out[o] = 0 as u8 200 return o 201} 202 203// ---- MangaDex chapter feed -> [{ch,t,id}]. entries = `"id":"UUID","type":"chapter"`; ch=attributes.chapter. 204func mfeed_mangadex(json: *u8, jn: i64, out: *u8, cap: i64) -> i64 { 205 var o: i64 = zs_apps(out, 0, "{\"kind\":\"chapters\",\"results\":[" as *u8) 206 var first: i64 = 1 207 var pos: i64 = 0 208 var guard: i64 = 0 209 while guard < 400 { 210 guard = guard + 1 211 let idp: i64 = na_find_from(json, jn, "\"id\":\"" as *u8, pos) 212 if idp < 0 { guard = 400 } else { 213 let vs: i64 = idp + 6 214 let ve: i64 = na_find_from(json, jn, "\"" as *u8, vs) 215 if ve < 0 { guard = 400 } else { 216 pos = ve + 1 217 if mss_at(json, jn, ve, "\",\"type\":\"chapter\"" as *u8) == 1 { 218 let nextc: i64 = na_find_from(json, jn, "\"type\":\"chapter\"" as *u8, ve + 12) 219 var bound: i64 = jn; if nextc >= 0 { bound = nextc } 220 // chapter number 221 let cp: i64 = na_find_from(json, jn, "\"chapter\":\"" as *u8, ve) 222 var chs: i64 = 0; var che: i64 = 0 223 if cp >= 0 { if cp < bound { chs = cp + 11; che = na_find_from(json, jn, "\"" as *u8, chs) } } 224 if first == 0 { out[o] = 44 as u8; o = o + 1 } 225 first = 0 226 o = zs_apps(out, o, "{\"ch\":\"" as *u8) 227 if che > chs { var c: i64 = chs; while c < che { if o < cap-1 { out[o]=json[c] as u8; o=o+1 } c=c+1 } } else { o = zs_apps(out, o, "?" as *u8) } 228 o = zs_apps(out, o, "\",\"id\":\"" as *u8) 229 var c2: i64 = vs; while c2 < ve { if o < cap-1 { out[o]=json[c2] as u8; o=o+1 } c2=c2+1 } 230 o = zs_apps(out, o, "\"}" as *u8) 231 } 232 } 233 } 234 } 235 o = zs_apps(out, o, "]}" as *u8); out[o] = 0 as u8 236 return o 237} 238 239// urldecode enc[0..n) into dst (NUL-term). %XX + '+'->space. returns len. 240func mss_urldec(enc: *u8, n: i64, dst: *u8) -> i64 { 241 var i: i64 = 0; var o: i64 = 0 242 while i < n { 243 let c: i64 = enc[i] as i64 244 if c == 37 { if i + 2 < n { 245 let h1: i64 = enc[i+1] as i64; let h2: i64 = enc[i+2] as i64 246 var v1: i64 = h1-48; if h1>=97 {v1=h1-87} else { if h1>=65 {v1=h1-55} } 247 var v2: i64 = h2-48; if h2>=97 {v2=h2-87} else { if h2>=65 {v2=h2-55} } 248 dst[o] = ((v1*16)+v2) as u8; o=o+1; i=i+3 249 } else { i = n } } 250 else { if c == 43 { dst[o]=32 as u8; o=o+1; i=i+1 } else { dst[o]=enc[i] as u8; o=o+1; i=i+1 } } 251 } 252 dst[o] = 0 as u8 253 return o 254} 255 256// load the trust store (per-request; correctness-first). 0 on fail. 257func mss_store() -> i64 { return nx_trust_store_load_from_certdata("data/mozilla_certdata.txt" as *u8, 512, MSS_MAGIC_4194304) } 258 259// shared: fetch `url` (Chrome-JA3), parse (mangadex vs nhentai), emit the results JSON. Used by search/browse/random. 260func mss_emit_results(cfd: i64, url: *u8, is_md: i64) -> i64 { 261 let store: i64 = mss_store() 262 if store <= 0 { return zs_emit(cfd, "500 Internal Server Error" as *u8, "{\"err\":\"store\"}" as *u8) } 263 let buf: *u8 = sys_mmap(MSS_FETCH_CAP); let st: *i64 = sys_mmap(8) as *i64 264 let n: i64 = nx_https_fetch_follow_chrome(url, store as *TrustStore, buf, MSS_FETCH_CAP, 6, st) 265 if n <= 0 { return zs_emit(cfd, "502 Bad Gateway" as *u8, "{\"err\":\"fetch\",\"results\":[]}" as *u8) } 266 let out: *u8 = sys_mmap(MSS_OUT_CAP) 267 if is_md == 1 { msearch_mangadex(buf, n, out, MSS_OUT_CAP) } else { msearch_nhentai(buf, n, out, MSS_OUT_CAP) } 268 return zs_emit(cfd, "200 OK" as *u8, out) 269} 270 271// GET /api/msearch?src=<s>&q=<q> -> results JSON 272func mss_handle_search(cfd: i64, path: *u8, plen: i64) -> i64 { 273 let src: *u8 = sys_mmap(32); zs_qval(path, plen, "src" as *u8, src, 32) 274 let qraw: *u8 = sys_mmap(512); let ql: i64 = zs_qval(path, plen, "q" as *u8, qraw, 512) 275 if ql <= 0 { return zs_emit(cfd, "200 OK" as *u8, "{\"results\":[]}" as *u8) } 276 let qd: *u8 = sys_mmap(512); let qdl: i64 = mss_urldec(qraw, ql, qd) // q arrives urlencoded in the path 277 let qe: *u8 = sys_mmap(MSS_MAGIC_1536); mss_qenc(qd, qdl, qe) 278 let url: *u8 = sys_mmap(MSS_MAGIC_2048); var uo: i64 = 0 279 var is_md: i64 = 0 280 if mss_at(src, 32, 0, "mangadex" as *u8) == 1 { is_md = 1 } 281 if is_md == 1 { 282 uo = zs_apps(url, 0, "https://api.mangadex.org/manga?title=" as *u8) 283 uo = zs_apps(url, uo, qe) 284 uo = zs_apps(url, uo, "&limit=24&includes[]=cover_art&contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic" as *u8) 285 } else { 286 uo = zs_apps(url, 0, "https://nhentai.net/search/?q=" as *u8) 287 uo = zs_apps(url, uo, qe) 288 } 289 url[uo] = 0 as u8 290 return mss_emit_results(cfd, url, is_md) 291} 292 293// GET /api/mbrowse?src=<s>&mode=<popular|latest> -> the LANDING FEED (browse without typing; operator #1 ask). 294// Reuses the same parsers -- only the URL changes (mangadex order[], nhentai homepage = recent galleries). 295func mss_handle_browse(cfd: i64, path: *u8, plen: i64) -> i64 { 296 let src: *u8 = sys_mmap(32); zs_qval(path, plen, "src" as *u8, src, 32) 297 let mode: *u8 = sys_mmap(32); zs_qval(path, plen, "mode" as *u8, mode, 32) 298 var is_md: i64 = 0 299 if mss_at(src, 32, 0, "mangadex" as *u8) == 1 { is_md = 1 } 300 let url: *u8 = sys_mmap(MSS_MAGIC_2048); var uo: i64 = 0 301 if is_md == 1 { 302 uo = zs_apps(url, 0, "https://api.mangadex.org/manga?limit=24&includes[]=cover_art&contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic&hasAvailableChapters=true&order[" as *u8) 303 if mss_at(mode, 32, 0, "latest" as *u8) == 1 { uo = zs_apps(url, uo, "latestUploadedChapter]=desc" as *u8) } 304 else { uo = zs_apps(url, uo, "followedCount]=desc" as *u8) } 305 } else { 306 // nhentai homepage = the recent-galleries feed (same card HTML the search parser reads) 307 uo = zs_apps(url, 0, "https://nhentai.net/" as *u8) 308 } 309 url[uo] = 0 as u8 310 return mss_emit_results(cfd, url, is_md) 311} 312 313// GET /api/mrandom?src=<s> -> ONE random title (mangadex /manga/random -> series card). operator: modern UI "random". 314func mss_handle_random(cfd: i64, path: *u8, plen: i64) -> i64 { 315 let src: *u8 = sys_mmap(32); zs_qval(path, plen, "src" as *u8, src, 32) 316 var is_md: i64 = 0 317 if mss_at(src, 32, 0, "mangadex" as *u8) == 1 { is_md = 1 } 318 let url: *u8 = sys_mmap(MSS_MAGIC_1024) 319 if is_md == 1 { zs_apps(url, 0, "https://api.mangadex.org/manga/random?includes[]=cover_art&contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic" as *u8) } 320 else { zs_apps(url, 0, "https://nhentai.net/random/" as *u8) } // redirects to a /g/<id>/ gallery; parser reads it 321 return mss_emit_results(cfd, url, is_md) 322} 323 324// GET /api/mfeed?id=<mangaId> -> chapter list JSON (mangadex) 325func mss_handle_feed(cfd: i64, path: *u8, plen: i64) -> i64 { 326 let id: *u8 = sys_mmap(64); let idl: i64 = zs_qval(path, plen, "id" as *u8, id, 64) 327 if idl <= 0 { return zs_emit(cfd, "200 OK" as *u8, "{\"results\":[]}" as *u8) } 328 let url: *u8 = sys_mmap(MSS_MAGIC_1024); var uo: i64 = 0 329 uo = zs_apps(url, 0, "https://api.mangadex.org/manga/" as *u8) 330 uo = zs_apps(url, uo, id) 331 uo = zs_apps(url, uo, "/feed?translatedLanguage[]=en&order[chapter]=asc&limit=200&contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic" as *u8) 332 url[uo] = 0 as u8 333 let store: i64 = mss_store() 334 if store <= 0 { return zs_emit(cfd, "500 Internal Server Error" as *u8, "{\"err\":\"store\"}" as *u8) } 335 let buf: *u8 = sys_mmap(MSS_FETCH_CAP); let st: *i64 = sys_mmap(8) as *i64 336 let n: i64 = nx_https_fetch_follow_chrome(url, store as *TrustStore, buf, MSS_FETCH_CAP, 6, st) 337 if n <= 0 { return zs_emit(cfd, "502 Bad Gateway" as *u8, "{\"err\":\"fetch\",\"results\":[]}" as *u8) } 338 let out: *u8 = sys_mmap(MSS_OUT_CAP) 339 mfeed_mangadex(buf, n, out, MSS_OUT_CAP) 340 return zs_emit(cfd, "200 OK" as *u8, out) 341} 342 343// GET /api/thumb?u=<enc url> -> proxy the image bytes (content-type from the magic). Small images only. 344func mss_handle_thumb(cfd: i64, path: *u8, plen: i64) -> i64 { 345 let enc: *u8 = sys_mmap(MSS_MAGIC_2048); let el: i64 = zs_qval(path, plen, "u" as *u8, enc, MSS_MAGIC_2048) 346 if el <= 0 { return zs_emit(cfd, "400 Bad Request" as *u8, "no u" as *u8) } 347 let u: *u8 = sys_mmap(MSS_MAGIC_2048); mss_urldec(enc, el, u) 348 // allow-list hosts (no open proxy): mangadex covers + nhentai thumbs only 349 var okhost: i64 = 0 350 if na_find_from(u, mss_slen(u), "uploads.mangadex.org/" as *u8, 0) >= 0 { okhost = 1 } 351 if na_find_from(u, mss_slen(u), ".nhentai.net/" as *u8, 0) >= 0 { okhost = 1 } 352 if okhost == 0 { return zs_emit(cfd, "403 Forbidden" as *u8, "host" as *u8) } 353 let store: i64 = mss_store() 354 if store <= 0 { return zs_emit(cfd, "500 Internal Server Error" as *u8, "store" as *u8) } 355 let buf: *u8 = sys_mmap(MSS_FETCH_CAP); let st: *i64 = sys_mmap(8) as *i64 356 let n: i64 = nx_https_fetch_follow_chrome(u, store as *TrustStore, buf, MSS_FETCH_CAP, 4, st) 357 if n <= 0 { return zs_emit(cfd, "502 Bad Gateway" as *u8, "fetch" as *u8) } 358 // content-type from magic 359 var ct: *u8 = "image/jpeg" as *u8 360 if n > 12 { if (buf[0] as i64)==0x89 { ct = "image/png" as *u8 } if (buf[0] as i64)==0x47 { ct = "image/gif" as *u8 } if (buf[0] as i64)==0x52 { if (buf[8] as i64)==0x57 { ct = "image/webp" as *u8 } } } 361 let hdr: *u8 = sys_mmap(256); var ho: i64 = 0 362 ho = zs_apps(hdr, 0, "HTTP/1.1 200 OK\r\nContent-Type: " as *u8) 363 ho = zs_apps(hdr, ho, ct) 364 ho = zs_apps(hdr, ho, "\r\nCache-Control: max-age=86400\r\nContent-Length: " as *u8) 365 ho = zs_dec(hdr, ho, n) 366 ho = zs_apps(hdr, ho, "\r\nConnection: close\r\n\r\n" as *u8) 367 sys_write(cfd, hdr, ho) 368 sys_write(cfd, buf, n) 369 sys_close(cfd) 370 return 0 371}