code wiki / (root) / nx_http_response_parse_test.nx

nx_http_response_parse_test.nx source

↩ module page · 270 lines · 9737 B

1// nx_http_response_parse_test.nx -- KATs for HTTP/1.1 client-side 2// response parser. 3// 4// Covers: 5// K1 minimal 200 OK with Content-Length + body -> verdict OK, 6// code=200, body_len=5, body bytes = "hello" 7// K2 404 Not Found with Content-Length=0 -> verdict OK, 8// code=404, body_len=0 9// K3 chunked-encoded body (two chunks) -> dechunk yields 10// concatenated bytes 11// K4 case-insensitive header lookup -> finds "Content- 12// Type" via lowercase query 13// K5 malformed status line (bad version) -> verdict ERR_ 14// BAD_VERSION 15// K6 Transfer-Encoding: chunked classification -> transfer_kind 16// == NX_HTTP_BODY_CHUNKED 17// 18// Built per F7 post-order DFS. 19// expect_exit: 0 20// license_tier: ORIGINAL 21 22import "nx_syscalls.nx" 23import "nx_http_response_parse.nx" 24 25// ===== build_msg helpers (LEAF) ==================================== 26 27func t_write_str(out: *u8, off: i64, s: *u8, n: i64) -> i64 { 28 var i: i64 = 0 29 while i < n { out[off + i] = s[i]; i = i + 1 } 30 return off + n 31} 32 33func t_make_200_hello(out: *u8) -> i64 { 34 var p: i64 = 0 35 let line: *u8 = sys_mmap(64) 36 // "HTTP/1.1 200 OK\r\n" 37 line[0]=0x48; line[1]=0x54; line[2]=0x54; line[3]=0x50 38 line[4]=0x2f; line[5]=0x31; line[6]=0x2e; line[7]=0x31 39 line[8]=0x20; line[9]=0x32; line[10]=0x30; line[11]=0x30 40 line[12]=0x20; line[13]=0x4f; line[14]=0x4b 41 line[15]=0x0d; line[16]=0x0a 42 p = t_write_str(out, p, line, 17) 43 let cl: *u8 = sys_mmap(64) 44 cl[0]=0x43; cl[1]=0x6f; cl[2]=0x6e; cl[3]=0x74 // Cont 45 cl[4]=0x65; cl[5]=0x6e; cl[6]=0x74; cl[7]=0x2d // ent- 46 cl[8]=0x4c; cl[9]=0x65; cl[10]=0x6e; cl[11]=0x67 // Leng 47 cl[12]=0x74; cl[13]=0x68; cl[14]=0x3a; cl[15]=0x20 // th:_ 48 cl[16]=0x35 // 5 49 cl[17]=0x0d; cl[18]=0x0a // \r\n 50 cl[19]=0x0d; cl[20]=0x0a // \r\n 51 p = t_write_str(out, p, cl, 21) 52 let body: *u8 = sys_mmap(16) 53 body[0]=0x68; body[1]=0x65; body[2]=0x6c; body[3]=0x6c; body[4]=0x6f 54 p = t_write_str(out, p, body, 5) 55 return p 56} 57 58func t_make_404_empty(out: *u8) -> i64 { 59 var p: i64 = 0 60 let line: *u8 = sys_mmap(64) 61 // "HTTP/1.1 404 Not Found\r\n" 62 line[0]=0x48; line[1]=0x54; line[2]=0x54; line[3]=0x50 63 line[4]=0x2f; line[5]=0x31; line[6]=0x2e; line[7]=0x31 64 line[8]=0x20; line[9]=0x34; line[10]=0x30; line[11]=0x34 65 line[12]=0x20; line[13]=0x4e; line[14]=0x6f; line[15]=0x74 66 line[16]=0x20; line[17]=0x46; line[18]=0x6f; line[19]=0x75 67 line[20]=0x6e; line[21]=0x64 68 line[22]=0x0d; line[23]=0x0a 69 p = t_write_str(out, p, line, 24) 70 let cl: *u8 = sys_mmap(32) 71 cl[0]=0x43; cl[1]=0x6f; cl[2]=0x6e; cl[3]=0x74 72 cl[4]=0x65; cl[5]=0x6e; cl[6]=0x74; cl[7]=0x2d 73 cl[8]=0x4c; cl[9]=0x65; cl[10]=0x6e; cl[11]=0x67 74 cl[12]=0x74; cl[13]=0x68; cl[14]=0x3a; cl[15]=0x20 75 cl[16]=0x30 // 0 76 cl[17]=0x0d; cl[18]=0x0a 77 cl[19]=0x0d; cl[20]=0x0a 78 p = t_write_str(out, p, cl, 21) 79 return p 80} 81 82func t_make_chunked(out: *u8) -> i64 { 83 var p: i64 = 0 84 let line: *u8 = sys_mmap(64) 85 line[0]=0x48; line[1]=0x54; line[2]=0x54; line[3]=0x50 86 line[4]=0x2f; line[5]=0x31; line[6]=0x2e; line[7]=0x31 87 line[8]=0x20; line[9]=0x32; line[10]=0x30; line[11]=0x30 88 line[12]=0x20; line[13]=0x4f; line[14]=0x4b 89 line[15]=0x0d; line[16]=0x0a 90 p = t_write_str(out, p, line, 17) 91 let te: *u8 = sys_mmap(64) 92 // "Transfer-Encoding: chunked\r\n\r\n" 93 te[0]=0x54; te[1]=0x72; te[2]=0x61; te[3]=0x6e 94 te[4]=0x73; te[5]=0x66; te[6]=0x65; te[7]=0x72 95 te[8]=0x2d; te[9]=0x45; te[10]=0x6e; te[11]=0x63 96 te[12]=0x6f; te[13]=0x64; te[14]=0x69; te[15]=0x6e 97 te[16]=0x67; te[17]=0x3a; te[18]=0x20 98 te[19]=0x63; te[20]=0x68; te[21]=0x75; te[22]=0x6e 99 te[23]=0x6b; te[24]=0x65; te[25]=0x64 100 te[26]=0x0d; te[27]=0x0a; te[28]=0x0d; te[29]=0x0a 101 p = t_write_str(out, p, te, 30) 102 return p 103} 104 105// chunked body bytes: "5\r\nhello\r\n6\r\n world\r\n0\r\n\r\n" 106func t_make_chunked_body(out: *u8) -> i64 { 107 var p: i64 = 0 108 let buf: *u8 = sys_mmap(64) 109 // 5\r\n 110 buf[0]=0x35; buf[1]=0x0d; buf[2]=0x0a 111 // hello 112 buf[3]=0x68; buf[4]=0x65; buf[5]=0x6c; buf[6]=0x6c; buf[7]=0x6f 113 // \r\n 114 buf[8]=0x0d; buf[9]=0x0a 115 // 6\r\n 116 buf[10]=0x36; buf[11]=0x0d; buf[12]=0x0a 117 // " world" (space + world) 118 buf[13]=0x20; buf[14]=0x77; buf[15]=0x6f; buf[16]=0x72; buf[17]=0x6c; buf[18]=0x64 119 buf[19]=0x0d; buf[20]=0x0a 120 // 0\r\n\r\n 121 buf[21]=0x30; buf[22]=0x0d; buf[23]=0x0a 122 buf[24]=0x0d; buf[25]=0x0a 123 p = t_write_str(out, p, buf, 26) 124 return p 125} 126 127func t_make_200_with_ct(out: *u8) -> i64 { 128 var p: i64 = 0 129 let line: *u8 = sys_mmap(64) 130 line[0]=0x48; line[1]=0x54; line[2]=0x54; line[3]=0x50 131 line[4]=0x2f; line[5]=0x31; line[6]=0x2e; line[7]=0x31 132 line[8]=0x20; line[9]=0x32; line[10]=0x30; line[11]=0x30 133 line[12]=0x20; line[13]=0x4f; line[14]=0x4b 134 line[15]=0x0d; line[16]=0x0a 135 p = t_write_str(out, p, line, 17) 136 let ct: *u8 = sys_mmap(64) 137 // "Content-Type: text/html\r\n" 138 ct[0]=0x43; ct[1]=0x6f; ct[2]=0x6e; ct[3]=0x74 139 ct[4]=0x65; ct[5]=0x6e; ct[6]=0x74; ct[7]=0x2d 140 ct[8]=0x54; ct[9]=0x79; ct[10]=0x70; ct[11]=0x65 141 ct[12]=0x3a; ct[13]=0x20 142 ct[14]=0x74; ct[15]=0x65; ct[16]=0x78; ct[17]=0x74 143 ct[18]=0x2f; ct[19]=0x68; ct[20]=0x74; ct[21]=0x6d; ct[22]=0x6c 144 ct[23]=0x0d; ct[24]=0x0a 145 p = t_write_str(out, p, ct, 25) 146 let cl: *u8 = sys_mmap(32) 147 cl[0]=0x43; cl[1]=0x6f; cl[2]=0x6e; cl[3]=0x74 148 cl[4]=0x65; cl[5]=0x6e; cl[6]=0x74; cl[7]=0x2d 149 cl[8]=0x4c; cl[9]=0x65; cl[10]=0x6e; cl[11]=0x67 150 cl[12]=0x74; cl[13]=0x68; cl[14]=0x3a; cl[15]=0x20 151 cl[16]=0x33 152 cl[17]=0x0d; cl[18]=0x0a 153 cl[19]=0x0d; cl[20]=0x0a 154 p = t_write_str(out, p, cl, 21) 155 let body: *u8 = sys_mmap(8) 156 body[0]=0x61; body[1]=0x62; body[2]=0x63 157 p = t_write_str(out, p, body, 3) 158 return p 159} 160 161func t_make_bad_version(out: *u8) -> i64 { 162 var p: i64 = 0 163 let line: *u8 = sys_mmap(32) 164 // "FTP/9.9 200 OK\r\n\r\n" 165 line[0]=0x46; line[1]=0x54; line[2]=0x50 // FTP 166 line[3]=0x2f; line[4]=0x39; line[5]=0x2e; line[6]=0x39 167 line[7]=0x20; line[8]=0x32; line[9]=0x30; line[10]=0x30 168 line[11]=0x20; line[12]=0x4f; line[13]=0x4b 169 line[14]=0x0d; line[15]=0x0a 170 line[16]=0x0d; line[17]=0x0a 171 p = t_write_str(out, p, line, 18) 172 return p 173} 174 175// ===== KAT runners (post-order from leaf helpers) ================= 176 177func k1_minimal_200_hello() -> i64 { 178 let buf: *u8 = sys_mmap(256) 179 let n: i64 = t_make_200_hello(buf) 180 let r: *i64 = nx_http_resp_alloc() 181 let v: i64 = nx_http_response_parse(buf, n, r) 182 if v != NX_HTTP_RESP_OK { return 11 } 183 if r[1] != 200 { return 12 } 184 if r[8] != NX_HTTP_BODY_CONTENT_LENGTH { return 13 } 185 if r[7] != 5 { return 14 } 186 if (buf[r[6] + 0] & 0xff) != 0x68 { return 15 } // h 187 if (buf[r[6] + 4] & 0xff) != 0x6f { return 16 } // o 188 return 0 189} 190 191func k2_404_empty() -> i64 { 192 let buf: *u8 = sys_mmap(256) 193 let n: i64 = t_make_404_empty(buf) 194 let r: *i64 = nx_http_resp_alloc() 195 let v: i64 = nx_http_response_parse(buf, n, r) 196 if v != NX_HTTP_RESP_OK { return 21 } 197 if r[1] != 404 { return 22 } 198 if r[8] != NX_HTTP_BODY_CONTENT_LENGTH { return 23 } 199 if r[7] != 0 { return 24 } 200 return 0 201} 202 203func k3_chunked_decode() -> i64 { 204 let body: *u8 = sys_mmap(64) 205 let bn: i64 = t_make_chunked_body(body) 206 let out: *u8 = sys_mmap(64) 207 let dn: i64 = nx_http_dechunk(body, bn, out, 64) 208 if dn != 11 { return 31 } 209 if (out[0] & 0xff) != 0x68 { return 32 } // h 210 if (out[4] & 0xff) != 0x6f { return 33 } // o 211 if (out[5] & 0xff) != 0x20 { return 34 } // ' ' 212 if (out[6] & 0xff) != 0x77 { return 35 } // w 213 if (out[10] & 0xff) != 0x64 { return 36 } // d 214 return 0 215} 216 217func k4_header_lookup_ci() -> i64 { 218 let buf: *u8 = sys_mmap(256) 219 let n: i64 = t_make_200_with_ct(buf) 220 let r: *i64 = nx_http_resp_alloc() 221 let v: i64 = nx_http_response_parse(buf, n, r) 222 if v != NX_HTTP_RESP_OK { return 41 } 223 let nm: *u8 = sys_mmap(16) 224 // lowercase "content-type" 225 nm[0]=0x63; nm[1]=0x6f; nm[2]=0x6e; nm[3]=0x74 226 nm[4]=0x65; nm[5]=0x6e; nm[6]=0x74; nm[7]=0x2d 227 nm[8]=0x74; nm[9]=0x79; nm[10]=0x70; nm[11]=0x65 228 let vo: *i64 = sys_mmap(8) as *i64 229 let vl: *i64 = sys_mmap(8) as *i64 230 let f: i64 = nx_http_response_header(buf, n, r, nm, 12, vo, vl) 231 if f != 1 { return 42 } 232 if vl[0] != 9 { return 43 } // "text/html" 233 if (buf[vo[0]] & 0xff) != 0x74 { return 44 } // t 234 return 0 235} 236 237func k5_bad_version_rejected() -> i64 { 238 let buf: *u8 = sys_mmap(64) 239 let n: i64 = t_make_bad_version(buf) 240 let r: *i64 = nx_http_resp_alloc() 241 let v: i64 = nx_http_response_parse(buf, n, r) 242 if v != NX_HTTP_RESP_ERR_BAD_VERSION { return 51 } 243 return 0 244} 245 246func k6_chunked_classification() -> i64 { 247 let buf: *u8 = sys_mmap(256) 248 let n: i64 = t_make_chunked(buf) 249 let r: *i64 = nx_http_resp_alloc() 250 let v: i64 = nx_http_response_parse(buf, n, r) 251 if v != NX_HTTP_RESP_OK { return 61 } 252 if r[8] != NX_HTTP_BODY_CHUNKED { return 62 } 253 return 0 254} 255 256func main() -> i64 { 257 let r1: i64 = k1_minimal_200_hello() 258 if r1 != 0 { return r1 } 259 let r2: i64 = k2_404_empty() 260 if r2 != 0 { return r2 } 261 let r3: i64 = k3_chunked_decode() 262 if r3 != 0 { return r3 } 263 let r4: i64 = k4_header_lookup_ci() 264 if r4 != 0 { return r4 } 265 let r5: i64 = k5_bad_version_rejected() 266 if r5 != 0 { return r5 } 267 let r6: i64 = k6_chunked_classification() 268 if r6 != 0 { return r6 } 269 return 0 270}