nx_http_dechunk.nx source
↩ module page · 66 lines · 2813 B
1// nx_http_dechunk.nx -- sovereign HTTP/1.1 chunked transfer-encoding decoder.
2//
3// Fills the gap BOTH nx_html_to_text and nx_browse_text self-document as MISSING
4// ("Chunked transfer dechunking before render"). Decodes the wire framing
5// <hexsize>[;chunk-ext]CRLF <data> CRLF ... 0 CRLF [trailers] CRLF
6// into a contiguous body. Reusable across the whole browser/research stack
7// (UXF arc R1b needs it -- the Avro fetch returned BK=2 = chunked).
8//
9// DEFENSIVE AT THE BOUNDARY (Rule 12 -- network input is untrusted): any malformed
10// framing returns a negative verdict and NEVER writes out of bounds.
11// returns: decoded length (>=0) | (0-1) OVERFLOW (out_cap too small) | (0-2) MALFORMED
12// No firmware/persistent-hardware writes (Rule 26: fail-safe by construction).
13// license_tier: ORIGINAL
14import "nx_syscalls.nx"
15
16// hex nibble value of an ASCII byte, or (0-1) if it is not a hex digit.
17func hd_hexval(b: i64) -> i64 {
18 if b >= 0x30 { if b <= 0x39 { return b - 0x30 } } // 0-9
19 if b >= 0x61 { if b <= 0x66 { return b - 0x61 + 10 } } // a-f
20 if b >= 0x41 { if b <= 0x46 { return b - 0x41 + 10 } } // A-F
21 return 0 - 1
22}
23
24func nx_http_dechunk(src: *u8, n: i64, out: *u8, out_cap: i64) -> i64 {
25 var pos: i64 = 0
26 var outlen: i64 = 0
27 var done: i64 = 0
28 var size: i64 = 0
29 var digits: i64 = 0
30 var scanning: i64 = 0
31 var sl: i64 = 0
32 var k: i64 = 0
33 while done == 0 {
34 if pos >= n { return 0 - 2 }
35 // --- parse the hex chunk size ---
36 size = 0
37 digits = 0
38 scanning = 1
39 while scanning == 1 {
40 if pos >= n { return 0 - 2 }
41 let hv: i64 = hd_hexval(src[pos] as i64)
42 if hv < 0 { scanning = 0 } else { size = (size * 16) + hv; digits = digits + 1; pos = pos + 1 }
43 }
44 if digits == 0 { return 0 - 2 } // no hex size -> not chunked / malformed
45 // --- skip the remainder of the size line, through the LF ---
46 sl = 1
47 while sl == 1 {
48 if pos >= n { return 0 - 2 }
49 let c: i64 = src[pos] as i64
50 pos = pos + 1
51 if c == 0x0A { sl = 0 }
52 }
53 if size == 0 { done = 1 } else {
54 if (outlen + size) > out_cap { return 0 - 1 } // overflow guard (Rule 12)
55 if (pos + size) > n { return 0 - 2 } // truncated chunk
56 k = 0
57 while k < size { out[outlen + k] = src[pos + k]; k = k + 1 }
58 outlen = outlen + size
59 pos = pos + size
60 // skip the CRLF terminating the chunk data (tolerant of bare CR or LF)
61 if pos < n { if src[pos] == (0x0D as u8) { pos = pos + 1 } }
62 if pos < n { if src[pos] == (0x0A as u8) { pos = pos + 1 } }
63 }
64 }
65 return outlen
66}