code wiki / (root) / nx_http_redirect_test.nx

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}