@@ -32,20 +32,116 @@ int SSL;
3232#include <stdio.h>
3333#include <stdlib.h>
3434#include <string.h>
35+ #include <zlib.h>
3536
3637/* Whatever type we selected (compressed or not) */
3738unsigned char * web_socket_request ;
38- int web_socket_request_size ;
39+ int web_socket_request_size , web_socket_request_response_size ;
40+
41+ int server_will_compress = 0 ;
3942
4043char * upgrade_request ;
4144int upgrade_request_length ;
4245
46+ #include <stdlib.h>
47+ #include <stdio.h>
48+ #include <string.h>
49+ #include <zlib.h>
50+ #include <time.h>
51+
4352/* Compressed message */
44- unsigned char web_socket_request_deflate [13 ] = {
45- 130 | 64 , 128 | 7 ,
46- 0 , 0 , 0 , 0 ,
47- 0xf2 , 0x48 , 0xcd , 0xc9 , 0xc9 , 0x07 , 0x00
48- };
53+ unsigned char * web_socket_request_deflate ;
54+ int web_socket_request_deflate_size ;
55+
56+ int init_deflated_message (int size ) {
57+
58+ // Create a JSON message of the specified size
59+ static const char placeholder [] = "{\"placeholder\":\"An elaborate placeholder with lots of data\",\"description\":\"A longer piece of text that is used to pad out the JSON to around 300 bytes, containing random info about a user profile.\",\"company\":\"Contoso\",\"address\":{\"street\":\"One Microsoft Way\",\"city\":\"Redmond\",\"state\":\"WA\",\"zip\":\"98052\"},\"skills\":[\"C\",\"C++\",\"Rust\",\"Go\",\"JavaScript\"],\"projects\":[{\"name\":\"SampleProject\",\"linesOfCode\":1234},{\"name\":\"AnotherProject\",\"linesOfCode\":2345}],\"misc\":{\"favoriteQuotes\":[\"Hello World\",\"Lorem Ipsum\",\"Carpe Diem\"]}}" ;
60+ char * json_message = malloc (size );
61+ int placeholder_len = sizeof (placeholder ) - 1 ;
62+ for (int i = 0 ; i < size ; i += placeholder_len ) {
63+ int copy_len = (i + placeholder_len <= size ) ? placeholder_len : size - i ;
64+ memcpy (json_message + i , placeholder , copy_len );
65+ }
66+
67+ // Compress the JSON message using raw DEFLATE
68+ z_stream defstream ;
69+ defstream .zalloc = Z_NULL ;
70+ defstream .zfree = Z_NULL ;
71+ defstream .opaque = Z_NULL ;
72+
73+ deflateInit2 (& defstream , Z_DEFAULT_COMPRESSION , Z_DEFLATED , - MAX_WBITS , 8 , Z_DEFAULT_STRATEGY );
74+ uLongf compressed_max_size = deflateBound (& defstream , (uLong )size );
75+ Bytef * compressed_data = (Bytef * )malloc (compressed_max_size );
76+
77+ defstream .avail_in = (uInt )size ;
78+ defstream .next_in = (Bytef * )json_message ;
79+ defstream .avail_out = (uInt )compressed_max_size ;
80+ defstream .next_out = compressed_data ;
81+
82+ int res = deflate (& defstream , Z_SYNC_FLUSH );
83+ if (res != Z_OK ) {
84+ printf ("Deflation failed: %d\n" , res );
85+ exit (1 );
86+ }
87+ uLongf compressed_size = defstream .total_out ;
88+ deflateEnd (& defstream );
89+ free (json_message );
90+
91+ // Generate random 4-byte mask
92+ srand ((unsigned int )time (NULL ));
93+ unsigned char mask [4 ];
94+ for (int i = 0 ; i < 4 ; i ++ ) {
95+ mask [i ] = 0 ;//(unsigned char)(rand() % 256);
96+ }
97+
98+ // Apply mask to compressed data
99+ for (uLongf i = 0 ; i < compressed_size ; i ++ ) {
100+ compressed_data [i ] ^= mask [i % 4 ];
101+ }
102+
103+ // Build WebSocket frame header
104+ unsigned char header [14 ];
105+ int header_len ;
106+
107+ if (compressed_size <= 125 ) {
108+ header_len = 6 ;
109+ header [0 ] = 0xC2 ; // FIN + RSV1 + Opcode 2
110+ header [1 ] = 0x80 | compressed_size ; // Mask bit + length
111+ memcpy (header + 2 , mask , 4 );
112+ } else if (compressed_size <= 65535 ) {
113+ header_len = 8 ;
114+ header [0 ] = 0xC2 ;
115+ header [1 ] = 0x80 | 126 ;
116+ header [2 ] = (compressed_size >> 8 ) & 0xFF ;
117+ header [3 ] = compressed_size & 0xFF ;
118+ memcpy (header + 4 , mask , 4 );
119+ } else {
120+ header_len = 14 ;
121+ header [0 ] = 0xC2 ;
122+ header [1 ] = 0x80 | 127 ;
123+ for (int i = 0 ; i < 8 ; i ++ ) {
124+ header [2 + i ] = (compressed_size >> (56 - i * 8 )) & 0xFF ;
125+ }
126+ memcpy (header + 10 , mask , 4 );
127+ }
128+
129+ // Combine header and masked compressed data
130+ web_socket_request_deflate_size = header_len + compressed_size ;
131+ web_socket_request_deflate = malloc (web_socket_request_deflate_size );
132+ memcpy (web_socket_request_deflate , header , header_len );
133+ memcpy (web_socket_request_deflate + header_len , compressed_data , compressed_size );
134+
135+
136+ // for (int i = 0; i < web_socket_request_deflate_size; i++) {
137+ // printf("%02X ", web_socket_request_deflate[i]);
138+ // }
139+
140+
141+ free (compressed_data );
142+
143+ return web_socket_request_deflate_size ;
144+ }
49145
50146/* Not compressed */
51147unsigned char web_socket_request_text_small [126 ] = {130 , 128 | 20 , 1 , 2 , 3 , 4 };
@@ -97,7 +193,7 @@ char request_deflate[] = "GET / HTTP/1.1\r\n"
97193 "Upgrade: websocket\r\n"
98194 "Connection: Upgrade\r\n"
99195 "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n"
100- "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits \r\n"
196+ "Sec-WebSocket-Extensions: permessage-deflate\r\n"
101197 "Host: server.example.com\r\n"
102198 "Sec-WebSocket-Version: 13\r\n\r\n" ;
103199
@@ -195,7 +291,7 @@ struct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int l
195291 if (http_socket -> outstanding_bytes == 0 ) {
196292 /* We got exactly the correct amount of bytes back, send another message */
197293 http_socket -> offset = us_socket_write (SSL , s , (char * ) web_socket_request , web_socket_request_size , 0 );
198- http_socket -> outstanding_bytes = web_socket_request_size - 4 ;
294+ http_socket -> outstanding_bytes = web_socket_request_response_size - 4 ; // minus 4 because of mask
199295
200296 /* Increase stats */
201297 responses ++ ;
@@ -211,7 +307,7 @@ struct us_socket_t *on_http_socket_data(struct us_socket_t *s, char *data, int l
211307 http_socket -> offset = us_socket_write (SSL , s , (char * ) web_socket_request , web_socket_request_size , 0 );
212308
213309 /* Server will echo back the same message minus 4 bytes for mask */
214- http_socket -> outstanding_bytes = web_socket_request_size - 4 ;
310+ http_socket -> outstanding_bytes = web_socket_request_response_size - 4 ;
215311 http_socket -> is_upgraded = 1 ;
216312 }
217313 }
@@ -260,9 +356,35 @@ int main(int argc, char **argv) {
260356 connections = atoi (argv [1 ]);
261357 SSL = atoi (argv [4 ]);
262358 if (atoi (argv [5 ])) {
359+
360+
361+ /* Use the size if provided */
362+ int size = 5 ;
363+ if (argc == 7 ) {
364+ size = atoi (argv [6 ]);
365+ }
366+
367+ init_deflated_message (size );
368+
369+ printf ("Using message size of %d bytes compressed down to %d bytes\n" , size , web_socket_request_deflate_size );
370+
263371 /* Set up deflate */
264372 web_socket_request = web_socket_request_deflate ;
265- web_socket_request_size = sizeof (web_socket_request_deflate );
373+ web_socket_request_size = web_socket_request_deflate_size ;//sizeof(web_socket_request_deflate);
374+
375+ /* Depending on whether the server will comress or not, we expect either the same or different length back */
376+ if (server_will_compress ) {
377+ web_socket_request_response_size = web_socket_request_size ;
378+ } else {
379+
380+ if (size <= 125 ) {
381+ web_socket_request_response_size = 6 + size ;
382+ } else if (size <= 65535 ) {
383+ web_socket_request_response_size = 8 + size ;
384+ } else {
385+ web_socket_request_response_size = 14 + size ;
386+ }
387+ }
266388
267389 upgrade_request = request_deflate ;
268390 upgrade_request_length = sizeof (request_deflate ) - 1 ;
@@ -288,6 +410,7 @@ int main(int argc, char **argv) {
288410
289411 web_socket_request = web_socket_request_text ;
290412 web_socket_request_size = web_socket_request_text_size ;
413+ web_socket_request_response_size = web_socket_request_size ;
291414
292415 upgrade_request = request_text ;
293416 upgrade_request_length = sizeof (request_text ) - 1 ;
0 commit comments