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}