nx_http_header_find_test.nx source
↩ module page · 142 lines · 5942 B
1// nx_http_header_find_test.nx -- smoke for case-insensitive header search.
2//
3// expect_exit: 0
4//
5// license_tier: ORIGINAL
6
7import "nx_syscalls_x86_64.nx"
8import "nx_http_header_find.nx"
9
10func bytes_eq(a: *u8, b: *u8, n: i64) -> i64 {
11 var i: i64 = 0
12 while i < n {
13 if a[i] != b[i] { return 0 }
14 i = i + 1
15 }
16 return 1
17}
18
19func emit(buf: *u8, off: i64, s: *u8) -> i64 {
20 var i: i64 = 0
21 while s[i] != 0 {
22 buf[off + i] = s[i]
23 i = i + 1
24 }
25 return off + i
26}
27
28func main() -> i64 {
29 // ---- Verdict enum ----
30 if nxhf_verdict_is_valid(NXHF_FOUND) != 1 { return 1 }
31 if nxhf_verdict_is_valid(NXHF_VERDICT_N) != 0 { return 2 }
32 if bytes_eq(nxhf_verdict_name(NXHF_FOUND), "FOUND" as *u8, 5) != 1 { return 3 }
33 if bytes_eq(nxhf_verdict_name(NXHF_NOT_FOUND), "NOT_FOUND" as *u8, 9) != 1 { return 4 }
34
35 // ---- tolower / eq_ci ----
36 if nxhf_tolower(0x41) != 0x61 { return 10 } // A -> a
37 if nxhf_tolower(0x5a) != 0x7a { return 11 } // Z -> z
38 if nxhf_tolower(0x61) != 0x61 { return 12 } // a -> a
39 if nxhf_tolower(0x30) != 0x30 { return 13 } // 0 -> 0
40
41 if nxhf_eq_ci("Content-Type" as *u8, "content-type" as *u8, 12) != 1 { return 20 }
42 if nxhf_eq_ci("X-Foo" as *u8, "X-FOO" as *u8, 5) != 1 { return 21 }
43 if nxhf_eq_ci("abc" as *u8, "abd" as *u8, 3) != 0 { return 22 }
44
45 // ---- Build canonical response header block ----
46 let buf: *u8 = sys_mmap(1024)
47 var o: i64 = 0
48 o = emit(buf, o, "HTTP/1.1 200 OK\r\n" as *u8)
49 o = emit(buf, o, "Content-Type: application/json\r\n" as *u8)
50 o = emit(buf, o, "Replay-Nonce: oFvnlFP1wIhRlYS2jTaXbA\r\n" as *u8)
51 o = emit(buf, o, "Content-Length: 42\r\n" as *u8)
52 o = emit(buf, o, "Server: nishi-http/0.1\r\n" as *u8)
53 o = emit(buf, o, "\r\n" as *u8)
54
55 // ---- Find Content-Type ----
56 let voff: *i64 = sys_mmap(8) as *i64
57 let vlen: *i64 = sys_mmap(8) as *i64
58 let rc1: i64 = nx_http_header_find(buf, o, "Content-Type" as *u8, 12,
59 voff, vlen)
60 if rc1 != NXHF_FOUND { return 30 }
61 if vlen[0] != 16 { return 31 }
62 let v1_ptr: *u8 = ((buf as i64) + voff[0]) as *u8
63 if bytes_eq(v1_ptr, "application/json" as *u8, 16) != 1 { return 32 }
64
65 // ---- Case-insensitive: find "content-type" (lowercase) ----
66 let rc2: i64 = nx_http_header_find(buf, o, "content-type" as *u8, 12,
67 voff, vlen)
68 if rc2 != NXHF_FOUND { return 40 }
69 if vlen[0] != 16 { return 41 }
70
71 // ---- Find Replay-Nonce (the ACME use case) ----
72 let rc3: i64 = nx_http_header_find(buf, o, "Replay-Nonce" as *u8, 12,
73 voff, vlen)
74 if rc3 != NXHF_FOUND { return 50 }
75 if vlen[0] != 22 { return 51 }
76 let v3_ptr: *u8 = ((buf as i64) + voff[0]) as *u8
77 if bytes_eq(v3_ptr, "oFvnlFP1wIhRlYS2jTaXbA" as *u8, 22) != 1 { return 52 }
78
79 // ---- Case-insensitive: find "REPLAY-NONCE" ----
80 let rc4: i64 = nx_http_header_find(buf, o, "REPLAY-NONCE" as *u8, 12,
81 voff, vlen)
82 if rc4 != NXHF_FOUND { return 60 }
83 if vlen[0] != 22 { return 61 }
84
85 // ---- NOT_FOUND ----
86 let rc5: i64 = nx_http_header_find(buf, o, "Set-Cookie" as *u8, 10,
87 voff, vlen)
88 if rc5 != NXHF_NOT_FOUND { return 70 }
89
90 // ---- Content-Length value ----
91 let rc6: i64 = nx_http_header_find(buf, o, "Content-Length" as *u8, 14,
92 voff, vlen)
93 if rc6 != NXHF_FOUND { return 80 }
94 if vlen[0] != 2 { return 81 }
95 let v6_ptr: *u8 = ((buf as i64) + voff[0]) as *u8
96 if v6_ptr[0] != 0x34 as u8 { return 82 } // '4'
97 if v6_ptr[1] != 0x32 as u8 { return 83 } // '2'
98
99 // ---- Server (single token, no spaces) ----
100 let rc7: i64 = nx_http_header_find(buf, o, "Server" as *u8, 6,
101 voff, vlen)
102 if rc7 != NXHF_FOUND { return 90 }
103 if vlen[0] != 14 { return 91 }
104 let v7_ptr: *u8 = ((buf as i64) + voff[0]) as *u8
105 if bytes_eq(v7_ptr, "nishi-http/0.1" as *u8, 14) != 1 { return 92 }
106
107 // ---- LF-only line endings (RFC 7230 ยง3.5 tolerance) ----
108 let buf2: *u8 = sys_mmap(256)
109 var o2: i64 = 0
110 o2 = emit(buf2, o2, "HTTP/1.1 200 OK\n" as *u8)
111 o2 = emit(buf2, o2, "X-Token: abc123\n" as *u8)
112 o2 = emit(buf2, o2, "\n" as *u8)
113 let rc8: i64 = nx_http_header_find(buf2, o2, "X-Token" as *u8, 7,
114 voff, vlen)
115 if rc8 != NXHF_FOUND { return 100 }
116 if vlen[0] != 6 { return 101 }
117 let v8_ptr: *u8 = ((buf2 as i64) + voff[0]) as *u8
118 if bytes_eq(v8_ptr, "abc123" as *u8, 6) != 1 { return 102 }
119
120 // ---- Whitespace trim around value ----
121 let buf3: *u8 = sys_mmap(256)
122 var o3: i64 = 0
123 o3 = emit(buf3, o3, "HTTP/1.1 200 OK\r\n" as *u8)
124 o3 = emit(buf3, o3, "X-Pad: spaced-value \r\n" as *u8)
125 o3 = emit(buf3, o3, "\r\n" as *u8)
126 let rc9: i64 = nx_http_header_find(buf3, o3, "X-Pad" as *u8, 5,
127 voff, vlen)
128 if rc9 != NXHF_FOUND { return 110 }
129 if vlen[0] != 12 { return 111 }
130 let v9_ptr: *u8 = ((buf3 as i64) + voff[0]) as *u8
131 if bytes_eq(v9_ptr, "spaced-value" as *u8, 12) != 1 { return 112 }
132
133 // ---- BAD_ARG paths ----
134 if nx_http_header_find(0 as *u8, 100, "X" as *u8, 1, voff, vlen) != NXHF_BAD_ARG { return 120 }
135 if nx_http_header_find(buf, 0, "X" as *u8, 1, voff, vlen) != NXHF_BAD_ARG { return 121 }
136 if nx_http_header_find(buf, 100, 0 as *u8, 1, voff, vlen) != NXHF_BAD_ARG { return 122 }
137 if nx_http_header_find(buf, 100, "X" as *u8, 0, voff, vlen) != NXHF_BAD_ARG { return 123 }
138 if nx_http_header_find(buf, 100, "X" as *u8, 1, 0 as *i64, vlen) != NXHF_BAD_ARG { return 124 }
139 if nx_http_header_find(buf, 100, "X" as *u8, 1, voff, 0 as *i64) != NXHF_BAD_ARG { return 125 }
140
141 return 0
142}