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
13 int lws_extension_callback_deflate_frame(
14 struct libwebsocket_context *context,
15 struct libwebsocket_extension *ext,
16 struct libwebsocket *wsi,
17 enum libwebsocket_extension_callback_reasons reason,
18 void *user, void *in, size_t len)
20 struct lws_ext_deflate_frame_conn *conn =
21 (struct lws_ext_deflate_frame_conn *)user;
22 struct lws_tokens *eff_buf = (struct lws_tokens *)in;
23 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 fprintf(stderr, "deflateInit returned %d", n);
42 n = deflateInit2(&conn->zs_out,
43 DEFLATE_FRAME_COMPRESSION_LEVEL, Z_DEFLATED,
44 -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
47 fprintf(stderr, "deflateInit returned %d", n);
50 conn->buf_pre_used = 0;
51 conn->buf_pre_length = 0;
52 conn->buf_in_length = MAX_USER_RX_BUFFER;
53 conn->buf_out_length = MAX_USER_RX_BUFFER;
54 conn->compressed_out = 0;
56 conn->buf_in = (unsigned char *)
57 malloc(LWS_SEND_BUFFER_PRE_PADDING +
59 LWS_SEND_BUFFER_POST_PADDING);
60 conn->buf_out = (unsigned char *)
61 malloc(LWS_SEND_BUFFER_PRE_PADDING +
62 conn->buf_out_length +
63 LWS_SEND_BUFFER_POST_PADDING);
64 fprintf(stderr, "zlibs constructed");
67 case LWS_EXT_CALLBACK_DESTROY:
74 conn->buf_pre_used = 0;
75 conn->buf_pre_length = 0;
76 conn->buf_in_length = 0;
77 conn->buf_out_length = 0;
78 conn->compressed_out = 0;
79 (void)inflateEnd(&conn->zs_in);
80 (void)deflateEnd(&conn->zs_out);
81 fprintf(stderr, "zlibs destructed");
84 case LWS_EXT_CALLBACK_PAYLOAD_RX:
85 if (!(wsi->rsv & 0x40))
89 * inflate the incoming payload
91 current_payload = eff_buf->token_len;
93 remaining_payload = wsi->rx_packet_length;
94 if (remaining_payload) {
95 total_payload = conn->buf_pre_used +
99 if (conn->buf_pre_length < total_payload) {
100 conn->buf_pre_length = total_payload;
104 (unsigned char *)malloc(total_payload + 4);
107 memcpy(conn->buf_pre + conn->buf_pre_used,
108 eff_buf->token, current_payload);
109 conn->buf_pre_used += current_payload;
111 eff_buf->token = NULL;
112 eff_buf->token_len = 0;
116 if (conn->buf_pre_used) {
117 total_payload = conn->buf_pre_used +
120 memcpy(conn->buf_pre + conn->buf_pre_used,
121 eff_buf->token, current_payload);
122 conn->buf_pre_used = 0;
124 conn->zs_in.next_in = conn->buf_pre;
126 total_payload = current_payload;
128 conn->zs_in.next_in = (unsigned char *)eff_buf->token;
131 conn->zs_in.next_in[total_payload + 0] = 0;
132 conn->zs_in.next_in[total_payload + 1] = 0;
133 conn->zs_in.next_in[total_payload + 2] = 0xff;
134 conn->zs_in.next_in[total_payload + 3] = 0xff;
136 conn->zs_in.avail_in = total_payload + 4;
138 conn->zs_in.next_out = conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING;
139 conn->zs_in.avail_out = conn->buf_in_length;
142 n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
148 * screwed.. close the connection... we will get a
149 * destroy callback to take care of closing nicely
151 fprintf(stderr, "zlib error inflate %d: %s",
156 if (conn->zs_in.avail_in > 0) {
157 size_t len_so_far = (conn->zs_in.next_out -
158 (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING));
159 unsigned char *new_buf;
160 conn->buf_in_length *= 2;
161 new_buf = (unsigned char *)
162 malloc(LWS_SEND_BUFFER_PRE_PADDING +
163 conn->buf_in_length +
164 LWS_SEND_BUFFER_POST_PADDING);
165 memcpy(new_buf + LWS_SEND_BUFFER_PRE_PADDING,
166 conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING,
169 conn->buf_in = new_buf;
170 conn->zs_in.next_out = (new_buf +
171 LWS_SEND_BUFFER_PRE_PADDING + len_so_far);
172 conn->zs_in.avail_out =
173 conn->buf_in_length - len_so_far;
178 /* rewrite the buffer pointers and length */
179 eff_buf->token = (char *)(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
180 eff_buf->token_len = (int)(conn->zs_in.next_out -
181 (conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING));
185 case LWS_EXT_CALLBACK_PAYLOAD_TX:
187 * deflate the outgoing payload
189 current_payload = eff_buf->token_len;
191 if (current_payload < MIN_SIZE_TO_DEFLATE)
194 conn->zs_out.next_in = (unsigned char *)eff_buf->token;
195 conn->zs_out.avail_in = current_payload;
197 conn->zs_out.next_out = conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING;
198 conn->zs_out.avail_out = conn->buf_out_length;
201 n = deflate(&conn->zs_out, Z_SYNC_FLUSH);
202 if (n == Z_STREAM_ERROR) {
204 * screwed.. close the connection... we will get a
205 * destroy callback to take care of closing nicely
207 fprintf(stderr, "zlib error deflate");
212 if (!conn->zs_out.avail_out) {
213 size_t len_so_far = (conn->zs_out.next_out -
215 LWS_SEND_BUFFER_PRE_PADDING));
216 unsigned char *new_buf;
217 conn->buf_out_length *= 2;
218 new_buf = (unsigned char *)
219 malloc(LWS_SEND_BUFFER_PRE_PADDING +
220 conn->buf_out_length +
221 LWS_SEND_BUFFER_POST_PADDING);
222 memcpy(new_buf + LWS_SEND_BUFFER_PRE_PADDING,
223 conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING,
226 conn->buf_out = new_buf;
227 conn->zs_out.next_out = (new_buf +
228 LWS_SEND_BUFFER_PRE_PADDING + len_so_far);
229 conn->zs_out.avail_out =
230 (conn->buf_out_length - len_so_far);
235 conn->compressed_out = 1;
237 /* rewrite the buffer pointers and length */
238 eff_buf->token = (char *)(conn->buf_out +
239 LWS_SEND_BUFFER_PRE_PADDING);
240 eff_buf->token_len = (int)(conn->zs_out.next_out -
241 (conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)) - 4;
245 case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
246 if (conn->compressed_out) {
247 conn->compressed_out = 0;
248 *((unsigned char *)eff_buf->token) |= 0x40;
252 case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION:
253 /* Avoid x-webkit-deflate-frame extension on client */
254 if (!strcmp((char *)in, "x-webkit-deflate-frame"))