code wiki / _hdl_build / nx_media_multiround_gate.nx
nx_media_multiround_gate.nx source
↩ module page · 139 lines · 7127 B
1import "nx_gate_gn.nx"
2import "nx_gate_base.nx"
3// nx_media_multiround_gate.nx -- proves MULTI-ROUND real-network capture: a page fetches a config/api URL,
4// and the RESPONSE drives the NEXT fetch (the signed manifest). Single-round pending-capture MISSES it (it
5// only sees the config URL). Multi-round SERVICES the config fetch (canned bytes here; real TLS in the CLI),
6// drains the promise chain, and the manifest fetch appears in the NEXT round -> captured. This is exactly
7// the signed-URL / round-2-module shape. Hermetic (a canned responder plays the server). license_tier: ORIGINAL expect_exit: 0
8import "nx_syscalls.nx"
9import "nx_js_eval.nx"
10import "nx_media_jsexec.nx"
11import "nx_gate_verdict.nx"
12
13func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
14" as *u8); return ok }
15func gsl(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
16
17// canned "server": maps a config/api URL to a JSON body whose fields drive the next fetch. (In the live CLI
18// this is nx_https_fetch_follow of the real URL.) Returns body length (0 = no canned response -> resolve empty).
19func canned(url: *u8, ul: i64, out: *u8, ocap: i64) -> i64 {
20 var body: *u8 = "" as *u8
21 if mjx_contains(url, ul, "cfg" as *u8, 3) == 1 { body = "{\"host\":\"https://cdn/signed\"}" as *u8 }
22 if mjx_contains(url, ul, "step1" as *u8, 5) == 1 { body = "{\"next\":\"https://api/step2\"}" as *u8 }
23 if mjx_contains(url, ul, "step2" as *u8, 5) == 1 { body = "{\"stream\":\"https://cdn/deep/master.m3u8\"}" as *u8 }
24 let bl: i64 = gsl(body)
25 var i: i64 = 0
26 while i < bl { if i < (ocap - 1) { out[i] = body[i] } i = i + 1 }
27 out[bl] = 0 as u8
28 return bl
29}
30// append url to the seen buffer if new; state[0]=len, state[1]=count.
31func seen_add(seen: *u8, state: *i64, url: *u8, ul: i64, cap: i64) -> i64 {
32 let sl: i64 = state[0]
33 if mjx_contains(seen, sl, url, ul) == 1 { return 0 }
34 if (sl + ul + 1) < cap {
35 var nl: i64 = sl
36 var k: i64 = 0
37 while k < ul { seen[nl] = url[k]; nl = nl + 1; k = k + 1 }
38 seen[nl] = 10 as u8; nl = nl + 1
39 seen[nl] = 0 as u8
40 state[0] = nl; state[1] = state[1] + 1
41 }
42 return 1
43}
44
45// SINGLE-ROUND: run the page, capture the media it fetches in round 1 ONLY (no servicing). Returns media count.
46func single_round_media(page: *u8, plen: i64, seen: *u8, cap: i64) -> i64 {
47 let ob: *i64 = sys_mmap(16) as *i64
48 js_run_source_keep(page, plen, ob)
49 let genv: *i64 = (ob[1]) as *i64
50 if (genv as i64) == 0 { return 0 }
51 let state: *i64 = sys_mmap(16) as *i64; state[0] = 0; state[1] = 0
52 let ubuf: *u8 = sys_mmap(2048)
53 let total: i64 = js_pending_total(genv)
54 var i: i64 = 0
55 while i < total { let ul: i64 = js_pending_url(genv, i, ubuf, 2048); if mjx_is_media_url(ubuf, ul) == 1 { seen_add(seen, state, ubuf, ul, cap) } i = i + 1 }
56 return state[1]
57}
58
59// MULTI-ROUND: run the page, then SERVICE each unserviced pending (media -> collect + resolve empty; config ->
60// serve canned body) and DRAIN, up to maxrounds, until no new work. Captures media discovered across rounds.
61func multiround_media(page: *u8, plen: i64, seen: *u8, cap: i64, maxrounds: i64) -> i64 {
62 let ob: *i64 = sys_mmap(16) as *i64
63 js_run_source_keep(page, plen, ob)
64 let ctx: *i64 = (ob[0]) as *i64
65 let genv: *i64 = (ob[1]) as *i64
66 if (genv as i64) == 0 { return 0 }
67 let state: *i64 = sys_mmap(16) as *i64; state[0] = 0; state[1] = 0
68 let ubuf: *u8 = sys_mmap(2048)
69 let body: *u8 = sys_mmap(4096)
70 var round: i64 = 0
71 var go: i64 = 1
72 while go == 1 {
73 if round >= maxrounds { go = 0 }
74 else {
75 let total: i64 = js_pending_total(genv)
76 var did: i64 = 0
77 var i: i64 = 0
78 while i < total {
79 if js_pending_serviced(genv, i) == 0 {
80 let ul: i64 = js_pending_url(genv, i, ubuf, 2048)
81 if mjx_is_media_url(ubuf, ul) == 1 {
82 seen_add(seen, state, ubuf, ul, cap)
83 js_pending_service(ctx, genv, i, 200, "" as *u8, 0) // resolve empty (don't recurse into media)
84 } else {
85 let bl: i64 = canned(ubuf, ul, body, 4096)
86 js_pending_service(ctx, genv, i, 200, body, bl)
87 }
88 did = 1
89 }
90 i = i + 1
91 }
92 if did == 0 { go = 0 } else { el_drain(ctx, genv); round = round + 1 }
93 }
94 }
95 return state[1]
96}
97func seen_has(seen: *u8, want: *u8) -> i64 { return mjx_contains(seen, gsl(seen), want, gsl(want)) }
98
99func main() -> i64 {
100 gw("media-multiround SOVEREIGN gate (service config fetch -> drain -> capture the round-2 manifest)\n" as *u8)
101 var pass: i64 = 0
102 var ttl: i64 = 0
103
104 // A page whose CONFIG response drives the manifest fetch (the signed-URL shape).
105 let page2: *u8 = "fetch('https://api/cfg').then(function(r){return r.json();}).then(function(c){ fetch(c.host+'/master.m3u8'); });" as *u8
106
107 // T1: SINGLE-ROUND misses it -> 0 media (only the non-media config URL is pending in round 1).
108 let s1: *u8 = sys_mmap(4096)
109 let c1: i64 = single_round_media(page2, gsl(page2), s1, 4096)
110 ttl=ttl+1; pass=pass+grow("T1 single-round captures 0 media (the gap)\x00" as *u8, (c1 == 0) as i64)
111
112 // T2: MULTI-ROUND services the config, drains, captures the round-2 manifest.
113 let s2: *u8 = sys_mmap(4096)
114 let c2: i64 = multiround_media(page2, gsl(page2), s2, 4096, 4)
115 var t2: i64 = 1
116 if c2 != 1 { t2 = 0 }
117 if seen_has(s2, "https://cdn/signed/master.m3u8\x00" as *u8) == 0 { t2 = 0 }
118 ttl=ttl+1; pass=pass+grow("T2 multi-round captures https://cdn/signed/master.m3u8\x00" as *u8, t2)
119
120 // T3: DEEP CHAIN (config -> api2 -> manifest) needs 3 rounds; multi-round follows it.
121 let page3: *u8 = "fetch('https://api/step1').then(function(r){return r.json();}).then(function(c){ return fetch(c.next); }).then(function(r){return r.json();}).then(function(d){ fetch(d.stream); });" as *u8
122 let s3: *u8 = sys_mmap(4096)
123 let c3: i64 = multiround_media(page3, gsl(page3), s3, 4096, 5)
124 var t3: i64 = 1
125 if c3 != 1 { t3 = 0 }
126 if seen_has(s3, "https://cdn/deep/master.m3u8\x00" as *u8) == 0 { t3 = 0 }
127 ttl=ttl+1; pass=pass+grow("T3 deep chain (3 rounds) captures https://cdn/deep/master.m3u8\x00" as *u8, t3)
128
129 gw("pass=" as *u8); gn(pass); gw("/" as *u8); gn(ttl); gw("\n" as *u8)
130 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
131 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
132 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
133 let ctr__dry: *i64 = gv_ctr()
134 ctr__dry[0] = pass
135 ctr__dry[1] = ttl
136 let rc__dry: i64 = gv_verdict("MEDIA-MULTIROUND-GATE" as *u8, ctr__dry, "multi-round: service config -> drain -> capture the manifest a single round misses)" as *u8)
137 sys_exit(rc__dry)
138 return rc__dry
139}