nx_websocket_client_upgrade_test.nx source
↩ module page · 144 lines · 6252 B
1// nx_websocket_client_upgrade_test.nx -- KAT for CLIENT-side WebSocket
2// HTTP/1.1 upgrade per RFC 6455 §1.3 + §4.1 + §4.2.
3//
4// Covers:
5// T1: request-builder writes a syntactically correct GET upgrade
6// T2: validator accepts a canonical 101 response keyed by RFC's §1.3
7// worked example (key = "dGhlIHNhbXBsZSBub25jZQ==").
8// T3: validator rejects bad status line (200 instead of 101)
9// T4: validator rejects missing Upgrade header
10// T5: validator rejects missing Connection header
11// T6: validator rejects Sec-WebSocket-Accept that does not match
12// SHA-1+Base64 of the client key + RFC GUID (i.e., a forged
13// response or a real-but-mismatched-key bug).
14// T7: include_port_in_host=1 adds ":port" to Host header
15//
16// Per Cardinal 13 (additive-only data: this test is the new gate
17// for this module + it composes the SAME SHA-1+Base64 ws_accept
18// primitive the server side uses to AVOID re-implementing the
19// reference algorithm).
20//
21// expect_exit: 0
22// license_tier: ORIGINAL
23
24import "nx_syscalls.nx"
25import "nx_websocket_client_upgrade.nx"
26import "nx_websocket_handshake.nx"
27
28// Local helper: case-sensitive substring search; -1 if not found.
29func _t_find_sub(buf: *u8, n: i64, needle: *u8, nn: i64) -> i64 {
30 var i: i64 = 0
31 while i + nn <= n {
32 var j: i64 = 0
33 var hit: i64 = 1
34 while j < nn {
35 if buf[i + j] != needle[j] { hit = 0; j = nn }
36 j = j + 1
37 }
38 if hit == 1 { return i }
39 i = i + 1
40 }
41 return 0 - 1
42}
43
44// Build a canonical 101 response keyed by the §1.3 client_key.
45// Writes into out and returns total length.
46func _t_build_canonical_101(out: *u8) -> i64 {
47 // Sec-WebSocket-Accept for "dGhlIHNhbXBsZSBub25jZQ==" is
48 // "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=" per RFC 6455 §1.3.
49 let s: *u8 = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8
50 let n: i64 = 129
51 var i: i64 = 0
52 while i < n { out[i] = s[i]; i = i + 1 }
53 return n
54}
55
56func main() -> i64 {
57 // ---- T1: request-builder produces a syntactic GET upgrade ----
58 let req: *u8 = sys_mmap(1024)
59 let key24: *u8 = sys_mmap(32)
60 let host: *u8 = "192.168.8.227" as *u8
61 let path: *u8 = "/signal/test-room" as *u8
62 let rn: i64 = nx_ws_client_build_request(req, 1024,
63 host, 13,
64 path, 17,
65 8445, 0,
66 key24)
67 if rn < 0 { return 1 }
68 // Must start with "GET /signal/test-room HTTP/1.1\r\n"
69 let gp: *u8 = "GET /signal/test-room HTTP/1.1\r\n" as *u8
70 var i: i64 = 0
71 while i < 32 {
72 if req[i] != gp[i] { return 2 }
73 i = i + 1
74 }
75 // Must contain Host header
76 if _t_find_sub(req, rn, "Host: 192.168.8.227\r\n" as *u8, 21) < 0 { return 3 }
77 if _t_find_sub(req, rn, "Upgrade: websocket\r\n" as *u8, 20) < 0 { return 4 }
78 if _t_find_sub(req, rn, "Connection: Upgrade\r\n" as *u8, 21) < 0 { return 5 }
79 if _t_find_sub(req, rn, "Sec-WebSocket-Version: 13\r\n" as *u8, 27) < 0 { return 6 }
80 if _t_find_sub(req, rn, "Sec-WebSocket-Key: " as *u8, 19) < 0 { return 7 }
81 // Trailer "\r\n\r\n"
82 if req[rn - 4] != 13 as u8 { return 8 }
83 if req[rn - 3] != 10 as u8 { return 9 }
84 if req[rn - 2] != 13 as u8 { return 10 }
85 if req[rn - 1] != 10 as u8 { return 11 }
86
87 // ---- T2: validator accepts canonical 101 with RFC §1.3 key ----
88 let resp: *u8 = sys_mmap(512)
89 let rn2: i64 = _t_build_canonical_101(resp)
90 let fixed_key: *u8 = "dGhlIHNhbXBsZSBub25jZQ==" as *u8
91 let v2: i64 = nx_ws_client_validate_response(resp, rn2, fixed_key)
92 if v2 != NX_WSCU_OK { return 12 }
93
94 // ---- T3: bad status (200 instead of 101) ----
95 let resp3: *u8 = sys_mmap(512)
96 let s3: *u8 = "HTTP/1.1 200 OK\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8
97 var n3: i64 = 113
98 i = 0; while i < n3 { resp3[i] = s3[i]; i = i + 1 }
99 let v3: i64 = nx_ws_client_validate_response(resp3, n3, fixed_key)
100 if v3 != NX_WSCU_BAD_STATUS { return 13 }
101
102 // ---- T4: missing Upgrade header ----
103 let resp4: *u8 = sys_mmap(512)
104 let s4: *u8 = "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8
105 var n4: i64 = 113
106 i = 0; while i < n4 { resp4[i] = s4[i]; i = i + 1 }
107 let v4: i64 = nx_ws_client_validate_response(resp4, n4, fixed_key)
108 if v4 != NX_WSCU_BAD_UPGRADE { return 14 }
109
110 // ---- T5: missing Connection header ----
111 let resp5: *u8 = sys_mmap(512)
112 let s5: *u8 = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n" as *u8
113 var n5: i64 = 111
114 i = 0; while i < n5 { resp5[i] = s5[i]; i = i + 1 }
115 let v5: i64 = nx_ws_client_validate_response(resp5, n5, fixed_key)
116 if v5 != NX_WSCU_BAD_CONNECTION { return 15 }
117
118 // ---- T6: mismatched Sec-WebSocket-Accept ----
119 let resp6: *u8 = sys_mmap(512)
120 let s6: *u8 = "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: AAAAAAAAAAAAAAAAAAAAAAAAAAA=\r\n\r\n" as *u8
121 var n6: i64 = 129
122 i = 0; while i < n6 { resp6[i] = s6[i]; i = i + 1 }
123 let v6: i64 = nx_ws_client_validate_response(resp6, n6, fixed_key)
124 if v6 != NX_WSCU_BAD_ACCEPT { return 16 }
125
126 // ---- T7: include_port_in_host=1 adds ":port" ----
127 let req7: *u8 = sys_mmap(1024)
128 let key7: *u8 = sys_mmap(32)
129 let rn7: i64 = nx_ws_client_build_request(req7, 1024,
130 host, 13,
131 path, 17,
132 8445, 1,
133 key7)
134 if rn7 < 0 { return 17 }
135 if _t_find_sub(req7, rn7, "Host: 192.168.8.227:8445\r\n" as *u8, 26) < 0 {
136 return 18
137 }
138
139 // "PASS\n"
140 let ok: *u8 = sys_mmap(8)
141 ok[0]=80; ok[1]=65; ok[2]=83; ok[3]=83; ok[4]=10
142 sys_write(1, ok, 5)
143 return 0
144}