1 #include "private-libwebsockets.h"
2 #include "extension-deflate-frame.h"
7 #define LWS_ZLIB_WINDOW_BITS 15
8 #define LWS_ZLIB_MEMLEVEL 8
10 #define MIN_SIZE_TO_DEFLATE 4
12 int lws_extension_callback_deflate_frame(
13 struct libwebsocket_context *context,
14 struct libwebsocket_extension *ext,
15 struct libwebsocket *wsi,
16 enum libwebsocket_extension_callback_reasons reason,
17 void *user, void *in, size_t len)
19 struct lws_ext_deflate_frame_conn *conn =
20 (struct lws_ext_deflate_frame_conn *)user;
21 struct lws_tokens *eff_buf = (struct lws_tokens *)in;
22 size_t current_payload, remaining_payload, total_payload;
29 * for deflate-frame, both client and server sides act the same
32 case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
33 case LWS_EXT_CALLBACK_CONSTRUCT:
34 conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
35 conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
36 conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
37 n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS);
39 lwsl_ext("deflateInit returned %d\n", n);
42 n = deflateInit2(&conn->zs_out,
43 (context->listen_port ?
44 DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER :
45 DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT),
47 -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
50 lwsl_ext("deflateInit2 returned %d\n", n);
53 conn->buf_pre_used = 0;
54 conn->buf_pre_length = 0;
55 conn->buf_in_length = MAX_USER_RX_BUFFER;
56 conn->buf_out_length = MAX_USER_RX_BUFFER;
57 conn->compressed_out = 0;
59 conn->buf_in = (unsigned char *)
60 malloc(LWS_SEND_BUFFER_PRE_PADDING +
62 LWS_SEND_BUFFER_POST_PADDING);
65 conn->buf_out = (unsigned char *)
66 malloc(LWS_SEND_BUFFER_PRE_PADDING +
67 conn->buf_out_length +
68 LWS_SEND_BUFFER_POST_PADDING);
71 lwsl_ext("zlibs constructed\n");
74 lwsl_err("Out of mem\n");
75 (void)inflateEnd(&conn->zs_in);
76 (void)deflateEnd(&conn->zs_out);
79 case LWS_EXT_CALLBACK_DESTROY:
84 conn->buf_pre_used = 0;
85 conn->buf_pre_length = 0;
86 conn->buf_in_length = 0;
87 conn->buf_out_length = 0;
88 conn->compressed_out = 0;
89 (void)inflateEnd(&conn->zs_in);
90 (void)deflateEnd(&conn->zs_out);
91 lwsl_ext("zlibs destructed\n");
94 case LWS_EXT_CALLBACK_PAYLOAD_RX:
95 if (!(wsi->u.ws.rsv & 0x40))
99 * inflate the incoming payload
101 current_payload = eff_buf->token_len;
103 remaining_payload = wsi->u.ws.rx_packet_length;
104 if (remaining_payload) {
105 total_payload = conn->buf_pre_used +
109 if (conn->buf_pre_length < total_payload) {
110 conn->buf_pre_length = total_payload;
114 (unsigned char *)malloc(total_payload + 4);
115 if (!conn->buf_pre) {
116 lwsl_err("Out of memory\n");
121 memcpy(conn->buf_pre + conn->buf_pre_used,
122 eff_buf->token, current_payload);
123 conn->buf_pre_used += current_payload;
125 eff_buf->token = NULL;
126 eff_buf->token_len = 0;
130 if (conn->buf_pre_used) {
131 total_payload = conn->buf_pre_used +
134 memcpy(conn->buf_pre + conn->buf_pre_used,
135 eff_buf->token, current_payload);
136 conn->buf_pre_used = 0;
138 conn->zs_in.next_in = conn->buf_pre;
140 total_payload = current_payload;
142 conn->zs_in.next_in = (unsigned char *)eff_buf->token;
145 conn->zs_in.next_in[total_payload + 0] = 0;
146 conn->zs_in.next_in[total_payload + 1] = 0;
147 conn->zs_in.next_in[total_payload + 2] = 0xff;
148 conn->zs_in.next_in[total_payload + 3] = 0xff;
150 conn->zs_in.avail_in = total_payload + 4;
152 conn->zs_in.next_out = conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING;
153 conn->zs_in.avail_out = conn->buf_in_length;
156 n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
163 * screwed.. close the connection... we will get a
164 * destroy callback to take care of closing nicely
166 lwsl_err("zlib error inflate %d: %s\n",
171 if (conn->zs_in.avail_out)
174 len_so_far = conn->zs_in.next_out -
175 (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
177 conn->buf_in_length *= 2;
178 if (conn->buf_in_length > LWS_MAX_ZLIB_CONN_BUFFER) {
179 lwsl_ext("zlib in buffer tried to exceed "
180 "max allowed of %u\n",
181 LWS_MAX_ZLIB_CONN_BUFFER);
184 conn->buf_in = (unsigned char *)realloc(conn->buf_in,
185 LWS_SEND_BUFFER_PRE_PADDING +
186 conn->buf_in_length +
187 LWS_SEND_BUFFER_POST_PADDING);
189 lwsl_err("Out of memory\n");
193 "deflate-frame ext RX did realloc to %ld\n",
194 conn->buf_in_length);
195 conn->zs_in.next_out = conn->buf_in +
196 LWS_SEND_BUFFER_PRE_PADDING + len_so_far;
197 conn->zs_in.avail_out =
198 conn->buf_in_length - len_so_far;
201 /* rewrite the buffer pointers and length */
202 eff_buf->token = (char *)(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
203 eff_buf->token_len = (int)(conn->zs_in.next_out -
204 (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING));
208 case LWS_EXT_CALLBACK_PAYLOAD_TX:
210 * deflate the outgoing payload
212 current_payload = eff_buf->token_len;
214 if (current_payload < MIN_SIZE_TO_DEFLATE)
217 conn->zs_out.next_in = (unsigned char *)eff_buf->token;
218 conn->zs_out.avail_in = current_payload;
220 conn->zs_out.next_out = conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING;
221 conn->zs_out.avail_out = conn->buf_out_length;
224 n = deflate(&conn->zs_out, Z_SYNC_FLUSH);
225 if (n == Z_STREAM_ERROR) {
227 * screwed.. close the connection... we will get a
228 * destroy callback to take care of closing nicely
230 lwsl_ext("zlib error deflate\n");
235 if (conn->zs_out.avail_out)
238 len_so_far = (conn->zs_out.next_out -
240 LWS_SEND_BUFFER_PRE_PADDING));
241 conn->buf_out_length *= 2;
242 if (conn->buf_out_length > LWS_MAX_ZLIB_CONN_BUFFER) {
243 lwsl_ext("zlib out buffer tried to exceed "
244 "max allowed of %u\n",
245 LWS_MAX_ZLIB_CONN_BUFFER);
248 conn->buf_out = (unsigned char *)realloc(
250 LWS_SEND_BUFFER_PRE_PADDING +
251 conn->buf_out_length +
252 LWS_SEND_BUFFER_POST_PADDING);
253 if (!conn->buf_out) {
254 lwsl_err("Out of memory\n");
258 "deflate-frame ext TX did realloc to %ld\n",
259 conn->buf_in_length);
261 conn->zs_out.next_out = (conn->buf_out +
262 LWS_SEND_BUFFER_PRE_PADDING + len_so_far);
263 conn->zs_out.avail_out =
264 (conn->buf_out_length - len_so_far);
267 conn->compressed_out = 1;
269 /* rewrite the buffer pointers and length */
270 eff_buf->token = (char *)(conn->buf_out +
271 LWS_SEND_BUFFER_PRE_PADDING);
272 eff_buf->token_len = (int)(conn->zs_out.next_out -
273 (conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)) - 4;
277 case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
278 if (conn->compressed_out) {
279 conn->compressed_out = 0;
280 *((unsigned char *)eff_buf->token) |= 0x40;
284 case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION:
285 /* Avoid x-webkit-deflate-frame extension on client */
286 if (!strcmp((char *)in, "x-webkit-deflate-frame"))