nx_websocket_client_upgrade.nx
buildroot/runtime/nx_websocket_client_upgrade.nx
about
nx_websocket_client_upgrade.nx -- CLIENT-side WebSocket HTTP upgrade.
Sibling to nx_websocket_upgrade.nx (server-side). Sends the
HTTP/1.1 GET + Upgrade: websocket request on an already-connected
TCP fd, reads the server's response headers, validates the 101
status, the Upgrade/Connection headers, and the Sec-WebSocket-Accept
value against the SHA-1 + Base64 transform of the key we sent.
RFC 6455 §1.3 + §4.1 + §4.2 client side. After this returns OK,
the caller can use nx_websocket_stream's framer (just like the
server side does post-upgrade).
Request bytes built (CRLF line endings):
GET <path> HTTP/1.1\r\n
Host: <host>\r\n
Upgrade: websocket\r\n
Connection: Upgrade\r\n
Sec-WebSocket-Key: <24-char base64 of 16 random bytes>\r\n
Sec-WebSocket-Version: 13\r\n
\r\n
Response validation (RFC 6455 §4.2.2 + §4.1):
Status-line MUST begin "HTTP/1.1 101"
Upgrade: websocket (case-insensitive)
Connection: Upgrade (case-insensitive, may be comma-list)
Sec-WebSocket-Accept: <expected> (matches our key per §1.3 algo)
Composes:
nx_syscalls (sys_read / sys_write)
nx_websocket_handshake (ws_accept = SHA-1 + Base64 of key||GUID)
nx_rand (rand_bytes for 16-byte client key entropy)
nx_base64 (b64_encode for the 16-byte key)
Per Cardinals 9 (single-responsibility: ONE upgrade per call), 12
(defensive at boundary: every required header validated, status
strictly == 101), 22 (composition over re-implementation: ws_accept
is the authoritative SHA-1+Base64 transform), 14 (graceful
degradation: distinct sealed-enum verdicts for each failure mode
so caller can act differently on TIMEOUT vs BAD_STATUS).
dependencies 4 imports · 8 importers
imports: nx_syscalls.nxnx_websocket_handshake.nxnx_base64.nxnx_rand.nx
imported by: nx_friend_video_caller.nxnx_funcheck.nxnx_health_eval.nxnx_room_live_gate.nxnx_room_perf_gate.nxnx_signaling_v2_gate.nxnx_websocket_client_upgrade_test.nxnx_ws_client_session.nx
structs
| none |
consts
| 55 | const NX_WSCU_OK: i64 = 1 |
| 56 | const NX_WSCU_WRITE_FAIL: i64 = 2 |
| 57 | const NX_WSCU_READ_FAIL: i64 = 3 |
| 58 | const NX_WSCU_HEADERS_TOO_BIG: i64 = 4 |
| 59 | const NX_WSCU_BAD_STATUS: i64 = 5 // not "HTTP/1.1 101" |
| 60 | const NX_WSCU_BAD_UPGRADE: i64 = 6 |
| 61 | const NX_WSCU_BAD_CONNECTION: i64 = 7 |
| 62 | const NX_WSCU_BAD_ACCEPT: i64 = 8 // Sec-WebSocket-Accept mismatch |
| 63 | const NX_WSCU_KEY_TOO_BIG: i64 = 9 // host/path overflow scratch |
| 64 | const NX_WSCU_VERDICT_N: i64 = 10 |
functions
| 66 | func nx_wscu_verdict_is_valid(v: i64) -> i64 |
| 73 | func _wscu_tolower(c: u8) -> u8 called by 1: _wscu_eq_ci |
| 82 | func _wscu_eq_ci(buf: *u8, off: i64, end: i64, lit: *u8, lit_n: i64) -> i64 |
| 95 | func _wscu_eq_cs(buf: *u8, off: i64, end: i64, lit: *u8, lit_n: i64) -> i64 called by 1: nx_ws_client_validate_response |
| 106 | func _wscu_bytes_eq(a: *u8, b: *u8, n: i64) -> i64 called by 1: nx_ws_client_validate_response |
| 117 | func _wscu_find_header_end(buf: *u8, n: i64) -> i64 |
| 135 | func _wscu_read_headers(fd: i64, buf: *u8, cap: i64) -> i64 |
| 147 | func _wscu_write_n(fd: i64, buf: *u8, n: i64) -> i64 |
| 158 | func _wscu_next_line(buf: *u8, start: i64, end: i64) -> i64 called by 1: _wscu_find_header |
| 168 | func _wscu_skip_ws(buf: *u8, start: i64, end: i64) -> i64 called by 1: _wscu_find_header |
| 182 | func _wscu_eol(buf: *u8, start: i64, end: i64) -> i64 |
| 196 | func _wscu_find_header(buf: *u8, hdr_start: i64, hdr_end: i64, called by 1: nx_ws_client_validate_response calls 4: _wscu_eq_ci_wscu_skip_ws_wscu_eol_wscu_next_line |
| 218 | func _wscu_itoa(n: i64, out: *u8, cap: i64) -> i64 |
| 244 | func nx_ws_client_build_request( |
| 343 | func nx_ws_client_validate_response( |
| 416 | func nx_ws_client_upgrade( |
| 442 | func main() -> i64 |