nx_hls_resolve.nx source
↩ module page · 134 lines · 6617 B
1// nx_hls_resolve.nx -- X-DLP rung 1: resolve an HLS segment/variant URI against the
2// playlist's own URL -> an ABSOLUTE URL the sovereign fetch client can GET. HLS URIs
3// come in three shapes (RFC 8216 + RFC 3986 ยง5):
4// absolute "https://cdn/s.ts" -> use as-is
5// path-absolute "/v/s.ts" -> scheme://host + uri
6// relative "s0.ts" -> base-directory (up to last '/') + uri
7// Composes nx_hls_parse (rung 0). Pure string logic -> offline-gateable. Together
8// rungs 0+1 turn (playlist URL + bytes) into the concrete list of segment URLs to
9// fetch via the already-sovereign h2/https client. No JS, no curl. license_tier: ORIGINAL
10import "nx_hls_parse.nx"
11import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
12
13func hr_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
14// 1 iff buf[0:4] == "http"
15func hr_is_abs(uri: *u8, ulen: i64) -> i64 {
16 if ulen < 4 { return 0 }
17 if (uri[0] & 0xff) != 104 { return 0 } // h
18 if (uri[1] & 0xff) != 116 { return 0 } // t
19 if (uri[2] & 0xff) != 116 { return 0 } // t
20 if (uri[3] & 0xff) != 112 { return 0 } // p
21 return 1
22}
23
24// Resolve uri against base into out; return out length, or -1 on overflow / bad base.
25func nx_hls_resolve_uri(base: *u8, blen: i64, uri: *u8, ulen: i64, out: *u8, out_cap: i64) -> i64 {
26 // ---- absolute ----
27 if hr_is_abs(uri, ulen) == 1 {
28 if ulen > out_cap { return 0 - 1 }
29 var i: i64 = 0
30 while i < ulen { out[i] = uri[i]; i = i + 1 }
31 return ulen
32 }
33 // ---- locate scheme + host in base ----
34 let sc: i64 = hls_find(base, 0, blen, "://\x00" as *u8)
35 if sc < 0 { return 0 - 1 }
36 let after: i64 = sc + 3
37 var he: i64 = after
38 var g: i64 = 1
39 while g == 1 { if he >= blen { g = 0 } else { if (base[he] & 0xff) == 47 { g = 0 } else { he = he + 1 } } } // first '/' after host
40 // ---- path-absolute: scheme://host + uri ----
41 if ulen > 0 { if (uri[0] & 0xff) == 47 {
42 let n: i64 = he + ulen
43 if n > out_cap { return 0 - 1 }
44 var i: i64 = 0
45 while i < he { out[i] = base[i]; i = i + 1 }
46 var j: i64 = 0
47 while j < ulen { out[he + j] = uri[j]; j = j + 1 }
48 return n
49 } }
50 // ---- relative: base directory (up to last '/' at/after host) + uri ----
51 var found: i64 = he
52 var li: i64 = blen - 1
53 var g2: i64 = 1
54 while g2 == 1 { if li < he { g2 = 0 } else { if (base[li] & 0xff) == 47 { found = li; g2 = 0 } else { li = li - 1 } } }
55 let dirlen: i64 = found + 1
56 let n2: i64 = dirlen + ulen
57 if n2 > out_cap { return 0 - 1 }
58 var a: i64 = 0
59 while a < dirlen { out[a] = base[a]; a = a + 1 }
60 var b: i64 = 0
61 while b < ulen { out[dirlen + b] = uri[b]; b = b + 1 }
62 return n2
63}
64
65// ===================== GATE =====================
66func hrr_puts(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
67// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
68// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
69// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
70// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
71func hrr_putn(v: i64) -> i64 { nxi_out(v); return 0 }
72func hrr_eq(out: *u8, n: i64, want: *u8) -> i64 {
73 if n != hr_slen(want) { return 0 }
74 var i: i64 = 0
75 while i < n { if (out[i] & 0xff) != (want[i] & 0xff) { return 0 } i = i + 1 }
76 return 1
77}
78
79func main() -> i64 {
80 var pass: i64 = 0
81 var tot: i64 = 0
82 hrr_puts("nx_hls_resolve gate (X-DLP rung 1, RFC 3986 segment URL resolution)\n" as *u8)
83 let out: *u8 = sys_mmap(512)
84 let base: *u8 = "https://ex.com/a/b.m3u8\x00" as *u8
85 let bl: i64 = hr_slen(base)
86
87 // KAT1: relative -> base dir + uri
88 let u1: *u8 = "s0.ts\x00" as *u8
89 let n1: i64 = nx_hls_resolve_uri(base, bl, u1, hr_slen(u1), out, 512)
90 var r1: i64 = hrr_eq(out, n1, "https://ex.com/a/s0.ts\x00" as *u8)
91 if r1 == 1 { hrr_puts(" PASS KAT1 relative s0.ts -> https://ex.com/a/s0.ts\n" as *u8); pass=pass+1 } else { hrr_puts(" FAIL KAT1 relative got=" as *u8); sys_write(1, out, n1); hrr_puts("\n" as *u8) }
92 tot = tot + 1
93
94 // KAT2: path-absolute -> scheme://host + uri
95 let u2: *u8 = "/v/s.ts\x00" as *u8
96 let n2: i64 = nx_hls_resolve_uri(base, bl, u2, hr_slen(u2), out, 512)
97 var r2: i64 = hrr_eq(out, n2, "https://ex.com/v/s.ts\x00" as *u8)
98 if r2 == 1 { hrr_puts(" PASS KAT2 path-absolute /v/s.ts -> https://ex.com/v/s.ts\n" as *u8); pass=pass+1 } else { hrr_puts(" FAIL KAT2 path-abs got=" as *u8); sys_write(1, out, n2); hrr_puts("\n" as *u8) }
99 tot = tot + 1
100
101 // KAT3: absolute -> unchanged
102 let u3: *u8 = "https://cdn.x/seg.ts\x00" as *u8
103 let n3: i64 = nx_hls_resolve_uri(base, bl, u3, hr_slen(u3), out, 512)
104 var r3: i64 = hrr_eq(out, n3, "https://cdn.x/seg.ts\x00" as *u8)
105 if r3 == 1 { hrr_puts(" PASS KAT3 absolute -> unchanged\n" as *u8); pass=pass+1 } else { hrr_puts(" FAIL KAT3 absolute got=" as *u8); sys_write(1, out, n3); hrr_puts("\n" as *u8) }
106 tot = tot + 1
107
108 // KAT4 (end-to-end): parse a media playlist, resolve every segment to absolute.
109 let pl: *u8 = "#EXTM3U\n#EXTINF:6.0,\nseg0.ts\n#EXTINF:6.0,\nsub/seg1.ts\n\x00" as *u8
110 let entries: *i64 = sys_mmap(8*3*64) as *i64
111 let meta: *i64 = sys_mmap(8*8) as *i64
112 let cnt: i64 = nx_hls_parse(pl, hr_slen(pl), entries, 64, meta)
113 var r4: i64 = 1
114 if cnt != 2 { r4 = 0 }
115 if r4 == 1 {
116 // seg0 -> https://ex.com/a/seg0.ts
117 let s0: i64 = entries[0*3+0]; let l0: i64 = entries[0*3+1]
118 let rn0: i64 = nx_hls_resolve_uri(base, bl, (pl as i64 + s0) as *u8, l0, out, 512)
119 if hrr_eq(out, rn0, "https://ex.com/a/seg0.ts\x00" as *u8) == 0 { r4 = 0 }
120 }
121 if r4 == 1 {
122 // sub/seg1.ts -> https://ex.com/a/sub/seg1.ts
123 let s1: i64 = entries[1*3+0]; let l1: i64 = entries[1*3+1]
124 let rn1: i64 = nx_hls_resolve_uri(base, bl, (pl as i64 + s1) as *u8, l1, out, 512)
125 if hrr_eq(out, rn1, "https://ex.com/a/sub/seg1.ts\x00" as *u8) == 0 { r4 = 0 }
126 }
127 if r4 == 1 { hrr_puts(" PASS KAT4 end-to-end parse->resolve 2 segs to absolute URLs\n" as *u8); pass=pass+1 } else { hrr_puts(" FAIL KAT4 e2e\n" as *u8) }
128 tot = tot + 1
129
130 hrr_puts("---- nx_hls_resolve gate: passed " as *u8); hrr_putn(pass); hrr_puts(" / " as *u8); hrr_putn(tot); hrr_puts("\n" as *u8)
131 if pass == tot { sys_exit(0); return 0 }
132 sys_exit(1)
133 return 1
134}