code wiki / (root) / nx_http_dechunk.nx

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}