code wiki / (root) / nx_acme_response_test.nx

nx_acme_response_test.nx source

↩ module page · 164 lines · 7245 B

1// nx_acme_response_test.nx -- smoke for the ACME response parser. 2// 3// Covers: 4// 1. Verdict enum gates 5// 2. Status-code parse for several values 6// 3. Body offset finder (CRLF CRLF + LF LF tolerance) 7// 4. Full parse of a canned ACME new-account response 8// 5. Replay-Nonce extraction 9// 6. Location extraction 10// 7. Body offset/length correctness 11// 8. is_success / is_client_error / should_retry predicates 12// 9. BAD_ARG paths 13// 14// expect_exit: 0 15// 16// license_tier: ORIGINAL 17 18import "nx_syscalls_x86_64.nx" 19import "nx_acme_response.nx" 20 21func bytes_eq(a: *u8, b: *u8, n: i64) -> i64 { 22 var i: i64 = 0 23 while i < n { 24 if a[i] != b[i] { return 0 } 25 i = i + 1 26 } 27 return 1 28} 29 30func emit(buf: *u8, off: i64, s: *u8) -> i64 { 31 var i: i64 = 0 32 while s[i] != 0 { 33 buf[off + i] = s[i] 34 i = i + 1 35 } 36 return off + i 37} 38 39func main() -> i64 { 40 // ---- Verdict enum ---- 41 if nxar_verdict_is_valid(NXAR_OK) != 1 { return 1 } 42 if nxar_verdict_is_valid(NXAR_BAD_ARG) != 1 { return 2 } 43 if nxar_verdict_is_valid(NXAR_VERDICT_N) != 0 { return 3 } 44 if bytes_eq(nxar_verdict_name(NXAR_OK), "OK" as *u8, 2) != 1 { return 4 } 45 if bytes_eq(nxar_verdict_name(NXAR_BAD_STATUS_LINE), 46 "BAD_STATUS_LINE" as *u8, 15) != 1 { return 5 } 47 48 // ---- Status-code parser ---- 49 if nxar_parse_status_code("HTTP/1.1 200 OK\r\n" as *u8, 17) != 200 { return 10 } 50 if nxar_parse_status_code("HTTP/1.1 201 Created\r\n" as *u8, 22) != 201 { return 11 } 51 if nxar_parse_status_code("HTTP/1.1 204 No Content\r\n" as *u8, 25) != 204 { return 12 } 52 if nxar_parse_status_code("HTTP/1.0 400 Bad Request\r\n" as *u8, 26) != 400 { return 13 } 53 if nxar_parse_status_code("HTTP/1.1 429 Too Many\r\n" as *u8, 23) != 429 { return 14 } 54 if nxar_parse_status_code("HTTP/1.1 503 Service Unavailable\r\n" as *u8, 34) != 503 { return 15 } 55 // Out-of-range 56 if nxar_parse_status_code("HTTP/1.1 099 X\r\n" as *u8, 16) != -1 { return 16 } 57 if nxar_parse_status_code("HTTP/1.1 700 X\r\n" as *u8, 16) != -1 { return 17 } 58 // Too short 59 if nxar_parse_status_code("HTTP/1.1 20" as *u8, 11) != -1 { return 18 } 60 61 // ---- Body offset finder ---- 62 let bo_buf: *u8 = sys_mmap(256) 63 var bo_n: i64 = emit(bo_buf, 0, "HTTP/1.1 200 OK\r\nFoo: bar\r\n\r\nBODY" as *u8) 64 let off_crlf: i64 = nxar_find_body_offset(bo_buf, bo_n) 65 if off_crlf != 29 { return 20 } // body starts at offset 29 ("BODY") 66 if bo_buf[off_crlf] != 0x42 as u8 { return 21 } // 'B' 67 68 // LF-only tolerance 69 bo_n = emit(bo_buf, 0, "HTTP/1.1 200 OK\nFoo: bar\n\nBODY" as *u8) 70 let off_lf: i64 = nxar_find_body_offset(bo_buf, bo_n) 71 if off_lf != 26 { return 22 } 72 if bo_buf[off_lf] != 0x42 as u8 { return 23 } 73 74 // Missing boundary 75 if nxar_find_body_offset("HTTP/1.1 200" as *u8, 12) != -1 { return 24 } 76 77 // ---- Canned ACME new-account 201 response ---- 78 let resp_buf: *u8 = sys_mmap(2048) 79 var rn: i64 = 0 80 rn = emit(resp_buf, rn, "HTTP/1.1 201 Created\r\n" as *u8) 81 rn = emit(resp_buf, rn, "Server: nishi-acme/0.1\r\n" as *u8) 82 rn = emit(resp_buf, rn, "Replay-Nonce: oFvnlFP1wIhRlYS2jTaXbA\r\n" as *u8) 83 rn = emit(resp_buf, rn, "Location: https://acme/acct/12345\r\n" as *u8) 84 rn = emit(resp_buf, rn, "Content-Type: application/json\r\n" as *u8) 85 rn = emit(resp_buf, rn, "Content-Length: 42\r\n" as *u8) 86 rn = emit(resp_buf, rn, "\r\n" as *u8) 87 rn = emit(resp_buf, rn, "{\"status\":\"valid\",\"contact\":[\"mailto:e@x\"]}" as *u8) 88 89 let ar_raw: *u8 = sys_mmap(ACME_RESPONSE_BYTES) 90 let ar: *AcmeResponse = ar_raw as *AcmeResponse 91 let pv: i64 = nx_acme_response_parse(resp_buf, rn, ar) 92 if pv != NXAR_OK { return 30 } 93 if ar.status_code != 201 { return 31 } 94 if ar.nonce_len != 22 { return 32 } 95 let nonce_ptr: *u8 = ((resp_buf as i64) + ar.nonce_off) as *u8 96 if bytes_eq(nonce_ptr, "oFvnlFP1wIhRlYS2jTaXbA" as *u8, 22) != 1 { return 33 } 97 if ar.location_len != 23 { return 34 } 98 let loc_ptr: *u8 = ((resp_buf as i64) + ar.location_off) as *u8 99 if bytes_eq(loc_ptr, "https://acme/acct/12345" as *u8, 23) != 1 { return 35 } 100 // body 101 if ar.body_len != 43 { return 36 } 102 let body_ptr: *u8 = ((resp_buf as i64) + ar.body_off) as *u8 103 if bytes_eq(body_ptr, 104 "{\"status\":\"valid\",\"contact\":[\"mailto:e@x\"]}" as *u8, 105 43) != 1 { return 37 } 106 107 // ---- Predicates ---- 108 if nx_acme_response_is_success(ar) != 1 { return 40 } 109 if nx_acme_response_is_client_error(ar) != 0 { return 41 } 110 if nx_acme_response_should_retry(ar) != 0 { return 42 } 111 112 // ---- 400 case: client_error true, retry false ---- 113 let err_buf: *u8 = sys_mmap(256) 114 var en: i64 = 0 115 en = emit(err_buf, en, "HTTP/1.1 400 Bad Request\r\n" as *u8) 116 en = emit(err_buf, en, "Content-Type: application/problem+json\r\n" as *u8) 117 en = emit(err_buf, en, "\r\n" as *u8) 118 en = emit(err_buf, en, "{\"type\":\"badNonce\"}" as *u8) 119 let ar2: *AcmeResponse = (sys_mmap(ACME_RESPONSE_BYTES)) as *AcmeResponse 120 let pv2: i64 = nx_acme_response_parse(err_buf, en, ar2) 121 if pv2 != NXAR_OK { return 50 } 122 if ar2.status_code != 400 { return 51 } 123 if nx_acme_response_is_success(ar2) != 0 { return 52 } 124 if nx_acme_response_is_client_error(ar2) != 1 { return 53 } 125 if nx_acme_response_should_retry(ar2) != 0 { return 54 } 126 // Replay-Nonce absent in this response. 127 if ar2.nonce_len != 0 { return 55 } 128 if ar2.location_len != 0 { return 56 } 129 130 // ---- 429 case: retry true ---- 131 let r429_buf: *u8 = sys_mmap(256) 132 var r429_n: i64 = 0 133 r429_n = emit(r429_buf, r429_n, "HTTP/1.1 429 Too Many Requests\r\n" as *u8) 134 r429_n = emit(r429_buf, r429_n, "Retry-After: 30\r\n" as *u8) 135 r429_n = emit(r429_buf, r429_n, "Replay-Nonce: xyz\r\n" as *u8) 136 r429_n = emit(r429_buf, r429_n, "\r\n" as *u8) 137 let ar3: *AcmeResponse = (sys_mmap(ACME_RESPONSE_BYTES)) as *AcmeResponse 138 if nx_acme_response_parse(r429_buf, r429_n, ar3) != NXAR_OK { return 60 } 139 if ar3.status_code != 429 { return 61 } 140 if nx_acme_response_should_retry(ar3) != 1 { return 62 } 141 if ar3.nonce_len != 3 { return 63 } 142 143 // ---- 503 case: retry true ---- 144 let r503_buf: *u8 = sys_mmap(256) 145 var r503_n: i64 = 0 146 r503_n = emit(r503_buf, r503_n, "HTTP/1.1 503 Service Unavailable\r\n" as *u8) 147 r503_n = emit(r503_buf, r503_n, "\r\n" as *u8) 148 let ar4: *AcmeResponse = (sys_mmap(ACME_RESPONSE_BYTES)) as *AcmeResponse 149 if nx_acme_response_parse(r503_buf, r503_n, ar4) != NXAR_OK { return 70 } 150 if nx_acme_response_should_retry(ar4) != 1 { return 71 } 151 152 // ---- BAD_ARG paths ---- 153 if nx_acme_response_parse(0 as *u8, 100, ar) != NXAR_BAD_ARG { return 80 } 154 if nx_acme_response_parse(resp_buf, 100, 0 as *AcmeResponse) != NXAR_BAD_ARG { return 81 } 155 if nx_acme_response_parse(resp_buf, 0, ar) != NXAR_BAD_ARG { return 82 } 156 157 // ---- BAD_STATUS_LINE ---- 158 if nx_acme_response_parse("garbage\r\n\r\nBODY" as *u8, 15, ar) != NXAR_BAD_STATUS_LINE { return 90 } 159 160 // ---- NO_HEADER_END ---- 161 if nx_acme_response_parse("HTTP/1.1 200 OK\r\nFoo: bar\r\n" as *u8, 27, ar) != NXAR_NO_HEADER_END { return 100 } 162 163 return 0 164}