#include #include #include #include "talkingq_wss.h" #include "rws_handshake.h" static const char accept[] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="; static const char good[] = "HTTP/1.1 101 Switching Protocols\r\n" "uPgRaDe: WebSocket\r\nConnection: keep-alive, Upgrade\r\n" "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"; int main(void) { char host[64], path[128], data[RWS_HANDSHAKE_MAX + 20]; int port, status; size_t i, header; const char *bad[] = {"ws://example.com/ws", "https://example.com/ws", "wss:///ws", "wss://user@example.com/ws", "wss://example.com:0/ws", "wss://example.com:65536/ws", "wss://example.com:-1/ws", "wss://example.com:/ws", "wss://example.com:abc/ws", "wss://example.com/ws#frag", "wss://example.com/ws\r\nInjected:yes", "wss://example.com:99999999999999999999999/ws", "wss://example.com/bad path"}; assert(!talkingq_parse_wss_url(TALKINGQ_WSS_URL, host, sizeof(host), &port, path, sizeof(path))); assert(!strcmp(host, "banban.api.talkingq.com") && port == 443 && !strcmp(path, "/ws")); assert(!talkingq_parse_wss_url("wss://example.com", host, sizeof(host), &port, path, sizeof(path))); assert(port == 443 && !strcmp(path, "/ws")); assert(!talkingq_parse_wss_url("wss://example.com:8080/ws?x=y", host, sizeof(host), &port, path, sizeof(path))); assert(port == 8080 && !strcmp(path, "/ws?x=y")); for (i = 0; i < sizeof(bad)/sizeof(bad[0]); ++i) assert(talkingq_parse_wss_url(bad[i], host, sizeof(host), &port, path, sizeof(path)) == -1); assert(talkingq_parse_wss_url(TALKINGQ_WSS_URL, host, 3, &port, path, sizeof(path)) == -1); assert(talkingq_parse_wss_url(TALKINGQ_WSS_URL, host, sizeof(host), &port, path, 3) == -1); assert(talkingq_is_legacy_ws_url("ws://101.35.224.118:8080")); assert(talkingq_is_legacy_ws_url("ws://101.35.224.118:8080/ws")); assert(!talkingq_is_legacy_ws_url(TALKINGQ_WSS_URL)); assert(!talkingq_is_legacy_ws_url("ws://custom.example:8080/ws")); /* Every possible TLS fragment boundary, with no NUL terminator available. */ for (i = 0; i < sizeof(good)-1; ++i) { memset(data, 'X', sizeof(data)); memcpy(data, good, i); assert(rws_check_handshake(data, i, accept, &header, &status) == 0); } memcpy(data, good, sizeof(good)-1); ((unsigned char *)data)[sizeof(good)-1] = 0x81; data[sizeof(good)] = 0; assert(rws_check_handshake(data, sizeof(good)+1, accept, &header, &status) == 1); assert(status == 101 && header == sizeof(good)-1); assert(rws_check_handshake(data, sizeof(good)-1, "wrong", &header, &status) == -1); memcpy(data + 9, "404", 3); assert(rws_check_handshake(data, sizeof(good)-1, accept, &header, &status) == -1 && status == 404); strcpy(data, "HTTP/1.1 101 OK\r\nSec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"); assert(rws_check_handshake(data, strlen(data), accept, &header, &status) == -1); memcpy(data, good, sizeof(good)); strcpy(data + sizeof(good)-3, "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"); assert(rws_check_handshake(data, strlen(data), accept, &header, &status) == -1); memset(data, 'X', sizeof(data)); assert(rws_check_handshake(data, sizeof(data), accept, &header, &status) == -1); puts("PASS: WSS URL policy, legacy migration, fragmented upgrade, status, accept, headers and limits"); return 0; }