code wiki / (root) / nx_ipp_transport_test.nx

nx_ipp_transport_test.nx source

↩ module page · 107 lines · 4930 B

1// nx_ipp_transport_test.nx -- offline gate for IPP-over-HTTP transport (R2). 2// 3// Proves the HTTP-framing/dechunk logic deterministically (no network), with unique exit codes: 4// 1x Content-Length response -> body extracted byte-exact, status 200, diagnoses BLOCKED (stopped) 5// 2x chunked response -> de-chunked body byte-exact, status 200 6// 3x status-line parse (503) + bad-http (no header terminator) -> sealed BAD_HTTP 7// 4x build_request round-trips: printer-uri == ipp://1.2.3.4/ipp/print, op = Get-Printer-Attributes 8// 9// The LIVE proof against the real Brother DCP-L2540DW is recorded separately (that run IS the 3rd-party 10// oracle for this non-novel protocol). This gate locks the framing so regressions are caught without it. 11// 12// expect_exit: 0 13// license_tier: ORIGINAL 14 15import "nx_syscalls.nx" 16import "nx_ipp_codec.nx" 17import "nx_printer_health.nx" 18import "nx_ipp_transport.nx" 19 20func t_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 21 22// append minimal lower-hex of v (no leading zeros) -- for chunk sizes 23func put_hex(buf: *u8, off: i64, v: i64) -> i64 { 24 let hx: *u8 = "0123456789abcdef" 25 if v == 0 { buf[off] = 48 as u8; return off + 1 } 26 let tmp: *u8 = sys_mmap(16) 27 var m: i64 = v 28 var k: i64 = 0 29 while m > 0 { tmp[k] = hx[m & 0xf]; m = m >> 4; k = k + 1 } 30 var o: i64 = off 31 var i: i64 = k - 1 32 while i >= 0 { buf[o] = tmp[i]; o = o + 1; i = i - 1 } 33 return o 34} 35 36func bytes_eq(x: *u8, y: *u8, n: i64) -> i64 { 37 var i: i64 = 0 38 while i < n { if (x[i] as i64) != (y[i] as i64) { return 0 } i = i + 1 } 39 return 1 40} 41 42func main() -> i64 { 43 let sc: *i64 = sys_mmap(64) as *i64 44 let out2: *i64 = sys_mmap(16) as *i64 45 let body: *u8 = sys_mmap(4096) 46 47 // a real IPP response body: STOPPED + media-empty 48 let ipp: *u8 = sys_mmap(2048) 49 var L: i64 = nx_ipp_begin(ipp, 1, 1, NX_IPP_STATUS_OK, 1) 50 L = nx_ipp_group(ipp, L, NX_IPP_GRP_PRINTER) 51 L = nx_ipp_attr_int(ipp, L, NX_IPP_VT_ENUM, "printer-state", 13, NX_IPP_PSTATE_STOPPED) 52 L = nx_ipp_attr(ipp, L, NX_IPP_VT_KEYWORD, "printer-state-reasons", 21, "media-empty", 11) 53 L = nx_ipp_end(ipp, L) 54 55 // ===== KAT 1: Content-Length (non-chunked) ===== 56 let r1: *u8 = sys_mmap(4096) 57 var t1: i64 = 0 58 t1 = nx_ipt_puts(r1, t1, "HTTP/1.1 200 OK\r\nContent-Type: application/ipp\r\nContent-Length: ") 59 t1 = nx_ipt_puti(r1, t1, L) 60 t1 = nx_ipt_puts(r1, t1, "\r\nConnection: close\r\n\r\n") 61 var j: i64 = 0 62 while j < L { r1[t1] = ipp[j]; t1 = t1 + 1; j = j + 1 } 63 if nx_ipt_extract_body(r1, t1, body, 4096, out2) != NX_IPT_OK { return 1 } 64 if out2[0] != 200 { return 2 } 65 if out2[1] != L { return 3 } 66 if bytes_eq(body, ipp, L) != 1 { return 4 } 67 if nx_printer_diagnose(body, out2[1], sc, sys_mmap(16) as *i64, sys_mmap(16) as *i64, sys_mmap(16) as *i64, sys_mmap(16) as *i64) != NX_PR_BLOCKED { return 5 } 68 69 // ===== KAT 2: chunked (single chunk + terminator), mixed-case header ===== 70 let r2: *u8 = sys_mmap(4096) 71 var t2: i64 = 0 72 t2 = nx_ipt_puts(r2, t2, "HTTP/1.1 200 OK\r\nTransfer-Encoding: CHUNKED\r\n\r\n") 73 t2 = put_hex(r2, t2, L) 74 t2 = nx_ipt_puts(r2, t2, "\r\n") 75 var j2: i64 = 0 76 while j2 < L { r2[t2] = ipp[j2]; t2 = t2 + 1; j2 = j2 + 1 } 77 t2 = nx_ipt_puts(r2, t2, "\r\n0\r\n\r\n") 78 if nx_ipt_extract_body(r2, t2, body, 4096, out2) != NX_IPT_OK { return 20 } 79 if out2[0] != 200 { return 21 } 80 if out2[1] != L { return 22 } 81 if bytes_eq(body, ipp, L) != 1 { return 23 } 82 83 // ===== KAT 3: status parse + bad-http ===== 84 let r3: *u8 = sys_mmap(512) 85 var t3: i64 = nx_ipt_puts(r3, 0, "HTTP/1.1 503 Service Unavailable\r\nContent-Length: 0\r\n\r\n") 86 if nx_ipt_extract_body(r3, t3, body, 4096, out2) != NX_IPT_OK { return 30 } 87 if out2[0] != 503 { return 31 } 88 // no header terminator -> BAD_HTTP (never silently "ok") 89 let r4: *u8 = sys_mmap(64) 90 let t4: i64 = nx_ipt_puts(r4, 0, "HTTP/1.1 200 OK garbage no crlfcrlf") 91 if nx_ipt_extract_body(r4, t4, body, 4096, out2) != NX_IPT_BAD_HTTP { return 32 } 92 // empty -> NO_RESP 93 if nx_ipt_extract_body(r4, 0, body, 4096, out2) != NX_IPT_NO_RESP { return 33 } 94 95 // ===== KAT 4: build_request round-trips through the codec parser ===== 96 let req: *u8 = sys_mmap(1024) 97 let rl: i64 = nx_ipt_build_request(req, 1, 2, 3, 4, "/ipp/print") 98 if nx_ipp_op_id(req) != NX_IPP_OP_GET_PRINTER_ATTRIBUTES { return 40 } 99 let p_tag: *i64 = sc 100 let p_voff: *i64 = ((sc as i64) + 8) as *i64 101 let p_vlen: *i64 = ((sc as i64) + 16) as *i64 102 if nx_ipp_find(req, rl, "printer-uri", p_tag, p_voff, p_vlen) != NX_IPP_OK { return 41 } 103 if nx_ipp_name_eq(req, p_voff[0], "ipp://1.2.3.4/ipp/print", 23) != 1 { return 42 } 104 105 t_puts("nx_ipp_transport: 4/4 KAT groups PASS (content-length + chunked + status/bad-http + request round-trip)\n") 106 return 0 107}