code wiki / (root) / nx_ipp_codec_test.nx

nx_ipp_codec_test.nx source

↩ module page · 123 lines · 6445 B

1// nx_ipp_codec_test.nx -- gate for the sovereign IPP/1.1 wire codec (R0). 2// 3// Proves, with unique exit codes per invariant (no_silent_failure: you know exactly which broke): 4// 1x encode a Get-Printer-Attributes request byte-exactly per RFC 8010 (lengths re-derived 5// independently in this test, header/group/end bytes spot-checked, total length asserted) 6// 2x round-trip: parse every attribute back out by name, value bytes match 7// 3x parse a STOPPED-printer response and surface printer-state(=5) + printer-state-reasons 8// ('media-empty') -- the anti-silent-failure proof (Brother hides these; we surface them) 9// 4x defensive liar-kill: truncated header and a value-length overrun both yield NX_IPP_MALFORMED 10// 5x a missing attribute yields NX_IPP_NOT_FOUND (not a false hit, not MALFORMED) 11// 12// All inputs are constructed from the RFC byte-layout rules, independent of the encoder's own code, so 13// a bug in the encoder cannot mask a bug in the parser or vice-versa. 14// 15// expect_exit: 0 16// license_tier: ORIGINAL 17 18import "nx_syscalls.nx" 19import "nx_ipp_codec.nx" 20 21func 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 } 22 23func main() -> i64 { 24 let buf: *u8 = sys_mmap(2048) 25 26 // scratch out-cells for nx_ipp_find: [0]=tag [1]=voff [2]=vlen 27 let sc: *i64 = sys_mmap(64) as *i64 28 let p_tag: *i64 = sc 29 let p_voff: *i64 = ((sc as i64) + 8) as *i64 30 let p_vlen: *i64 = ((sc as i64) + 16) as *i64 31 let outv: *i64 = sys_mmap(16) as *i64 32 33 // ============ KAT 1: encode Get-Printer-Attributes request ============ 34 var o: i64 = nx_ipp_begin(buf, 1, 1, NX_IPP_OP_GET_PRINTER_ATTRIBUTES, 1) 35 if o != 8 { return 1 } 36 if (buf[0] as i64) != 1 { return 2 } // version major 37 if (buf[1] as i64) != 1 { return 3 } // version minor 38 if nx_ipp_op_id(buf) != 0x000b { return 4 } // operation-id 39 if nx_ipp_request_id(buf) != 1 { return 5 } // request-id 40 41 o = nx_ipp_group(buf, o, NX_IPP_GRP_OPERATION) 42 if (buf[8] as i64) != 0x01 { return 6 } // operation-attributes-tag 43 44 let n_chs: *u8 = "attributes-charset" 45 let n_lng: *u8 = "attributes-natural-language" 46 let n_uri: *u8 = "printer-uri" 47 let v_uri: *u8 = "ipp://h/ipp/print" 48 let n_ra: *u8 = "requested-attributes" 49 let v_ps: *u8 = "printer-state" 50 51 o = nx_ipp_attr(buf, o, NX_IPP_VT_CHARSET, n_chs, nx_ipp_strlen(n_chs), "utf-8", 5) 52 o = nx_ipp_attr(buf, o, NX_IPP_VT_NATLANG, n_lng, nx_ipp_strlen(n_lng), "en", 2) 53 o = nx_ipp_attr(buf, o, NX_IPP_VT_URI, n_uri, nx_ipp_strlen(n_uri), v_uri, nx_ipp_strlen(v_uri)) 54 o = nx_ipp_attr(buf, o, NX_IPP_VT_KEYWORD, n_ra, nx_ipp_strlen(n_ra), v_ps, nx_ipp_strlen(v_ps)) 55 o = nx_ipp_end(buf, o) 56 57 // independent length re-derivation (each attr = 1 + 2 + nlen + 2 + vlen): 58 // header 8 + group 1 59 // charset : 1+2+18+2+5 = 28 60 // natlang : 1+2+27+2+2 = 34 61 // uri : 1+2+11+2+17 = 33 62 // reqattr : 1+2+20+2+13 = 38 63 // end 1 => total 143 64 if o != 143 { return 10 } 65 if (buf[o - 1] as i64) != 0x03 { return 11 } // end-of-attributes-tag 66 67 // ============ KAT 2: round-trip parse the request ============ 68 if nx_ipp_find(buf, o, n_uri, p_tag, p_voff, p_vlen) != NX_IPP_OK { return 20 } 69 if p_tag[0] != NX_IPP_VT_URI { return 21 } 70 if p_vlen[0] != nx_ipp_strlen(v_uri) { return 22 } 71 if nx_ipp_name_eq(buf, p_voff[0], v_uri, p_vlen[0]) != 1 { return 23 } 72 73 if nx_ipp_find(buf, o, n_ra, p_tag, p_voff, p_vlen) != NX_IPP_OK { return 24 } 74 if p_tag[0] != NX_IPP_VT_KEYWORD { return 25 } 75 if nx_ipp_name_eq(buf, p_voff[0], v_ps, p_vlen[0]) != 1 { return 26 } 76 77 if nx_ipp_find(buf, o, n_chs, p_tag, p_voff, p_vlen) != NX_IPP_OK { return 27 } 78 if nx_ipp_name_eq(buf, p_voff[0], "utf-8", 5) != 1 { return 28 } 79 80 // ============ KAT 3: parse a STOPPED-printer response ============ 81 // Build it from the wire rules: a Get-Printer-Attributes RESPONSE with status successful-ok, 82 // printer-state(enum)=stopped(5), printer-state-reasons(1setOf keyword)={media-empty, marker-supply-low}. 83 let r: *u8 = sys_mmap(2048) 84 let n_pst: *u8 = "printer-state" 85 let n_psr: *u8 = "printer-state-reasons" 86 var p: i64 = nx_ipp_begin(r, 1, 1, NX_IPP_STATUS_OK, 1) 87 p = nx_ipp_group(r, p, NX_IPP_GRP_PRINTER) 88 p = nx_ipp_attr_int(r, p, NX_IPP_VT_ENUM, n_pst, nx_ipp_strlen(n_pst), NX_IPP_PSTATE_STOPPED) 89 p = nx_ipp_attr(r, p, NX_IPP_VT_KEYWORD, n_psr, nx_ipp_strlen(n_psr), "media-empty", 11) 90 p = nx_ipp_attr_add(r, p, NX_IPP_VT_KEYWORD, "marker-supply-low", 17) 91 p = nx_ipp_end(r, p) 92 93 if nx_ipp_status(r) != NX_IPP_STATUS_OK { return 30 } 94 // surface printer-state -> must read enum 5 (stopped) 95 if nx_ipp_get_enum(r, p, n_pst, sc, outv) != NX_IPP_OK { return 31 } 96 if outv[0] != NX_IPP_PSTATE_STOPPED { return 32 } 97 // surface the first printer-state-reasons value -> 'media-empty' (the reason Brother would hide) 98 if nx_ipp_find(r, p, n_psr, p_tag, p_voff, p_vlen) != NX_IPP_OK { return 33 } 99 if p_tag[0] != NX_IPP_VT_KEYWORD { return 34 } 100 if nx_ipp_name_eq(r, p_voff[0], "media-empty", 11) != 1 { return 35 } 101 102 // ============ KAT 4: defensive liar-kill ============ 103 // (a) buffer too short to even hold the 8-byte header 104 let tiny: *u8 = sys_mmap(64) 105 if nx_ipp_find(tiny, 5, "x", p_tag, p_voff, p_vlen) != NX_IPP_MALFORMED { return 40 } 106 107 // (b) value-length overrun: an attribute claims a 0x7fff-byte value that runs past the buffer 108 let bad: *u8 = sys_mmap(2048) 109 var b: i64 = nx_ipp_begin(bad, 1, 1, NX_IPP_STATUS_OK, 1) 110 b = nx_ipp_group(bad, b, NX_IPP_GRP_PRINTER) 111 bad[b] = NX_IPP_VT_ENUM as u8 112 b = b + 1 113 b = nx_ipp_put_u16(bad, b, 13) 114 b = nx_ipp_memcpy(bad, b, "printer-state", 13) 115 b = nx_ipp_put_u16(bad, b, 0x7fff) // lying length, no value bytes follow 116 if nx_ipp_find(bad, b, "printer-state", p_tag, p_voff, p_vlen) != NX_IPP_MALFORMED { return 41 } 117 118 // ============ KAT 5: missing attribute -> NOT_FOUND ============ 119 if nx_ipp_find(r, p, "no-such-attr", p_tag, p_voff, p_vlen) != NX_IPP_NOT_FOUND { return 50 } 120 121 t_puts("nx_ipp_codec: 5/5 KAT groups PASS (encode byte-exact + round-trip + state-reasons surfaced + liar-kill + not-found)\n") 122 return 0 123}