nx_http_redirect_test.nx source
↩ module page · 140 lines · 6256 B
1// nx_http_redirect_test.nx -- smoke for 3xx redirect emitter.
2//
3// expect_exit: 0
4//
5// license_tier: ORIGINAL
6
7import "nx_syscalls_x86_64.nx"
8import "nx_http_redirect.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 bytes_contains(haystack: *u8, h_n: i64, needle: *u8, n_n: i64) -> i64 {
20 if n_n > h_n { return 0 }
21 var i: i64 = 0
22 while i <= h_n - n_n {
23 if bytes_eq(((haystack as i64) + i) as *u8, needle, n_n) == 1 { return 1 }
24 i = i + 1
25 }
26 return 0
27}
28
29func main() -> i64 {
30 // ---- Kind + verdict enum ----
31 if nxr_kind_is_valid(NXR_PERMANENT_301) != 1 { return 1 }
32 if nxr_kind_is_valid(NXR_PERM_308) != 1 { return 2 }
33 if nxr_kind_is_valid(NXR_KIND_N) != 0 { return 3 }
34 if nxr_verdict_is_valid(NXR_OK) != 1 { return 4 }
35 if nxr_verdict_is_valid(NXR_VERDICT_N) != 0 { return 5 }
36
37 if nxr_kind_status_code(NXR_PERMANENT_301) != 301 { return 10 }
38 if nxr_kind_status_code(NXR_FOUND_302) != 302 { return 11 }
39 if nxr_kind_status_code(NXR_SEE_OTHER_303) != 303 { return 12 }
40 if nxr_kind_status_code(NXR_TEMP_307) != 307 { return 13 }
41 if nxr_kind_status_code(NXR_PERM_308) != 308 { return 14 }
42
43 if nxr_kind_is_permanent(NXR_PERMANENT_301) != 1 { return 20 }
44 if nxr_kind_is_permanent(NXR_PERM_308) != 1 { return 21 }
45 if nxr_kind_is_permanent(NXR_FOUND_302) != 0 { return 22 }
46 if nxr_kind_is_permanent(NXR_SEE_OTHER_303) != 0 { return 23 }
47 if nxr_kind_is_permanent(NXR_TEMP_307) != 0 { return 24 }
48
49 if bytes_eq(nxr_kind_reason(NXR_FOUND_302), "Found" as *u8, 5) != 1 { return 30 }
50 if bytes_eq(nxr_kind_reason(NXR_SEE_OTHER_303), "See Other" as *u8, 9) != 1 { return 31 }
51 if bytes_eq(nxr_kind_reason(NXR_PERM_308), "Permanent Redirect" as *u8, 18) != 1 { return 32 }
52
53 // ---- Location validator ----
54 if nxr_location_is_safe("/safe/path" as *u8, 10) != 1 { return 40 }
55 if nxr_location_is_safe("https://example.com/x" as *u8, 21) != 1 { return 41 }
56 // CRLF injection attempt
57 let bad_crlf: *u8 = sys_mmap(32)
58 bad_crlf[0] = 0x2f as u8; bad_crlf[1] = 0x78 as u8 // "/x"
59 bad_crlf[2] = 0x0d as u8; bad_crlf[3] = 0x0a as u8 // CRLF
60 bad_crlf[4] = 0x58 as u8 // X
61 if nxr_location_is_safe(bad_crlf, 5) != 0 { return 42 }
62 // NUL byte
63 let bad_nul: *u8 = sys_mmap(8)
64 bad_nul[0] = 0x2f as u8; bad_nul[1] = 0x00 as u8; bad_nul[2] = 0x58 as u8
65 if nxr_location_is_safe(bad_nul, 3) != 0 { return 43 }
66 // Empty
67 if nxr_location_is_safe("" as *u8, 0) != 0 { return 44 }
68
69 let out: *u8 = sys_mmap(2048)
70 let off: *i64 = sys_mmap(8) as *i64
71
72 // ---- 301 emit ----
73 off[0] = 0
74 if nx_http_emit_redirect(out, off, 2048, NXR_PERMANENT_301,
75 "/new-url" as *u8, 8) != NXR_OK { return 50 }
76 if bytes_contains(out, off[0], "HTTP/1.1 301 Moved Permanently\r\n" as *u8, 32) != 1 { return 51 }
77 if bytes_contains(out, off[0], "Location: /new-url\r\n" as *u8, 20) != 1 { return 52 }
78 if bytes_contains(out, off[0], "Cache-Control: public, max-age=86400\r\n" as *u8, 38) != 1 { return 53 }
79 if bytes_contains(out, off[0], "Content-Length: 0\r\n\r\n" as *u8, 21) != 1 { return 54 }
80
81 // ---- 302 emit (no Cache-Control) ----
82 off[0] = 0
83 if nx_http_emit_redirect(out, off, 2048, NXR_FOUND_302,
84 "/temp" as *u8, 5) != NXR_OK { return 60 }
85 if bytes_contains(out, off[0], "HTTP/1.1 302 Found\r\n" as *u8, 20) != 1 { return 61 }
86 if bytes_contains(out, off[0], "Location: /temp\r\n" as *u8, 17) != 1 { return 62 }
87 // 302 should NOT have Cache-Control: max-age (temporary)
88 if bytes_contains(out, off[0], "Cache-Control" as *u8, 13) != 0 { return 63 }
89
90 // ---- 303 emit (POST-then-GET) ----
91 off[0] = 0
92 if nx_http_emit_redirect(out, off, 2048, NXR_SEE_OTHER_303,
93 "/welcome" as *u8, 8) != NXR_OK { return 70 }
94 if bytes_contains(out, off[0], "HTTP/1.1 303 See Other\r\n" as *u8, 24) != 1 { return 71 }
95
96 // ---- 307 emit (method-preserving temp) ----
97 off[0] = 0
98 if nx_http_emit_redirect(out, off, 2048, NXR_TEMP_307,
99 "/other" as *u8, 6) != NXR_OK { return 80 }
100 if bytes_contains(out, off[0], "HTTP/1.1 307 Temporary Redirect\r\n" as *u8, 33) != 1 { return 81 }
101
102 // ---- 308 emit (method-preserving permanent) ----
103 off[0] = 0
104 if nx_http_emit_redirect(out, off, 2048, NXR_PERM_308,
105 "/new" as *u8, 4) != NXR_OK { return 90 }
106 if bytes_contains(out, off[0], "HTTP/1.1 308 Permanent Redirect\r\n" as *u8, 33) != 1 { return 91 }
107 if bytes_contains(out, off[0], "Cache-Control: public, max-age=86400" as *u8, 36) != 1 { return 92 }
108
109 // ---- BAD_LOCATION on CRLF injection ----
110 off[0] = 0
111 if nx_http_emit_redirect(out, off, 2048, NXR_PERMANENT_301,
112 bad_crlf, 5) != NXR_BAD_LOCATION { return 100 }
113
114 // ---- BAD_LOCATION on NUL ----
115 off[0] = 0
116 if nx_http_emit_redirect(out, off, 2048, NXR_PERMANENT_301,
117 bad_nul, 3) != NXR_BAD_LOCATION { return 101 }
118
119 // ---- Invalid kind ----
120 off[0] = 0
121 if nx_http_emit_redirect(out, off, 2048, 99,
122 "/x" as *u8, 2) != NXR_BAD_ARG { return 110 }
123
124 // ---- HTTP -> HTTPS convenience ----
125 off[0] = 0
126 if nx_http_emit_redirect_to_https(out, off, 2048,
127 "nishifamily.com" as *u8, 15,
128 "/audit/index.html" as *u8, 17) != NXR_OK { return 120 }
129 if bytes_contains(out, off[0], "HTTP/1.1 308 Permanent Redirect\r\n" as *u8, 33) != 1 { return 121 }
130 if bytes_contains(out, off[0],
131 "Location: https://nishifamily.com/audit/index.html\r\n" as *u8, 52) != 1 { return 122 }
132
133 // ---- BAD_ARG on https-helper with empty host/path ----
134 off[0] = 0
135 if nx_http_emit_redirect_to_https(out, off, 2048,
136 "" as *u8, 0,
137 "/x" as *u8, 2) != NXR_BAD_ARG { return 130 }
138
139 return 0
140}