2 * ./lib/extension-permessage-deflate.c
4 * Copyright (C) 2016 Andy Green <andy@warmcat.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 #include "private-libwebsockets.h"
23 #include "extension-permessage-deflate.h"
28 #define LWS_ZLIB_MEMLEVEL 8
30 const struct lws_ext_options lws_ext_pm_deflate_options[] = {
31 /* public RFC7692 settings */
32 { "server_no_context_takeover", EXTARG_NONE },
33 { "client_no_context_takeover", EXTARG_NONE },
34 { "server_max_window_bits", EXTARG_OPT_DEC },
35 { "client_max_window_bits", EXTARG_OPT_DEC },
36 /* ones only user code can set */
37 { "rx_buf_size", EXTARG_DEC },
38 { "tx_buf_size", EXTARG_DEC },
39 { "compression_level", EXTARG_DEC },
40 { "mem_level", EXTARG_DEC },
41 { NULL, 0 }, /* sentinel */
45 lws_extension_pmdeflate_restrict_args(struct lws *wsi,
46 struct lws_ext_pm_deflate_priv *priv)
50 /* cap the RX buf at the nearest power of 2 to protocol rx buf */
52 n = wsi->context->pt_serv_buf_size;
53 if (wsi->protocol->rx_buffer_size)
54 n = wsi->protocol->rx_buffer_size;
57 while (n >= 1 << (extra + 1))
60 if (extra < priv->args[PMD_RX_BUF_PWR2]) {
61 priv->args[PMD_RX_BUF_PWR2] = extra;
62 lwsl_err(" Capping pmd rx to %d\n", 1 << extra);
67 lws_extension_callback_pm_deflate(struct lws_context *context,
68 const struct lws_extension *ext,
70 enum lws_extension_callback_reasons reason,
71 void *user, void *in, size_t len)
73 struct lws_ext_pm_deflate_priv *priv =
74 (struct lws_ext_pm_deflate_priv *)user;
75 struct lws_tokens *eff_buf = (struct lws_tokens *)in;
76 static unsigned char trail[] = { 0, 0, 0xff, 0xff };
77 int n, ret = 0, was_fin = 0, extra;
78 struct lws_ext_option_arg *oa;
81 case LWS_EXT_CB_NAMED_OPTION_SET:
85 for (n = 0; n < ARRAY_SIZE(lws_ext_pm_deflate_options); n++)
86 if (!strcmp(lws_ext_pm_deflate_options[n].name, oa->option_name))
89 if (n == ARRAY_SIZE(lws_ext_pm_deflate_options))
95 case LWS_EXT_CB_OPTION_SET:
97 lwsl_info("%s: option set: idx %d, %s, len %d\n", __func__,
98 oa->option_index, oa->start, oa->len);
100 priv->args[oa->option_index] = atoi(oa->start);
102 priv->args[oa->option_index] = 1;
104 lws_extension_pmdeflate_restrict_args(wsi, priv);
107 case LWS_EXT_CB_OPTION_CONFIRM:
108 if (priv->args[PMD_SERVER_MAX_WINDOW_BITS] < 8 ||
109 priv->args[PMD_SERVER_MAX_WINDOW_BITS] > 15 ||
110 priv->args[PMD_CLIENT_MAX_WINDOW_BITS] < 8 ||
111 priv->args[PMD_CLIENT_MAX_WINDOW_BITS] > 15)
115 case LWS_EXT_CB_CLIENT_CONSTRUCT:
116 case LWS_EXT_CB_CONSTRUCT:
118 n = context->pt_serv_buf_size;
119 if (wsi->protocol->rx_buffer_size)
120 n = wsi->protocol->rx_buffer_size;
123 lwsl_err(" permessage-deflate requires the protocol (%s) to have an RX buffer >= 128\n",
124 wsi->protocol->name);
129 priv = lws_zalloc(sizeof(*priv));
130 *((void **)user) = priv;
131 lwsl_ext("%s: LWS_EXT_CB_*CONSTRUCT\n", __func__);
132 memset(priv, 0, sizeof(*priv));
134 /* fill in pointer to options list */
136 *((const struct lws_ext_options **)in) =
137 lws_ext_pm_deflate_options;
141 case LWS_EXT_CB_OPTION_DEFAULT:
143 /* set the public, RFC7692 defaults... */
145 priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER] = 0,
146 priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER] = 0;
147 priv->args[PMD_SERVER_MAX_WINDOW_BITS] = 15;
148 priv->args[PMD_CLIENT_MAX_WINDOW_BITS] = 15;
150 /* ...and the ones the user code can override */
152 priv->args[PMD_RX_BUF_PWR2] = 10; /* ie, 1024 */
153 priv->args[PMD_TX_BUF_PWR2] = 10; /* ie, 1024 */
154 priv->args[PMD_COMP_LEVEL] = 1;
155 priv->args[PMD_MEM_LEVEL] = 8;
157 lws_extension_pmdeflate_restrict_args(wsi, priv);
160 case LWS_EXT_CB_DESTROY:
161 lwsl_ext("%s: LWS_EXT_CB_DESTROY\n", __func__);
162 lws_free(priv->buf_rx_inflated);
163 lws_free(priv->buf_tx_deflated);
165 (void)inflateEnd(&priv->rx);
167 (void)deflateEnd(&priv->tx);
171 case LWS_EXT_CB_PAYLOAD_RX:
172 lwsl_ext(" %s: LWS_EXT_CB_PAYLOAD_RX: in %d, existing in %d\n",
173 __func__, eff_buf->token_len, priv->rx.avail_in);
174 if (!(wsi->u.ws.rsv_first_msg & 0x40))
178 for (n = 0; n < eff_buf->token_len; n++) {
179 printf("%02X ", (unsigned char)eff_buf->token[n]);
186 if (inflateInit2(&priv->rx, -priv->args[PMD_SERVER_MAX_WINDOW_BITS]) != Z_OK) {
187 lwsl_err("%s: iniflateInit failed\n", __func__);
191 if (!priv->buf_rx_inflated)
192 priv->buf_rx_inflated = lws_malloc(LWS_PRE + 7 + 5 +
193 (1 << priv->args[PMD_RX_BUF_PWR2]));
194 if (!priv->buf_rx_inflated) {
195 lwsl_err("%s: OOM\n", __func__);
200 * We have to leave the input stream alone if we didn't
201 * finish with it yet. The input stream is held in the wsi
202 * rx buffer by the caller, so this assumption is safe while
203 * we block new rx while draining the existing rx
205 if (eff_buf->token && eff_buf->token_len) {
206 priv->rx.next_in = (unsigned char *)eff_buf->token;
207 priv->rx.avail_in = eff_buf->token_len;
209 priv->rx.next_out = priv->buf_rx_inflated + LWS_PRE;
210 eff_buf->token = (char *)priv->rx.next_out;
211 priv->rx.avail_out = 1 << priv->args[PMD_RX_BUF_PWR2];
213 if (priv->rx_held_valid) {
214 lwsl_ext("-- RX piling on held byte --\n");
215 *(priv->rx.next_out++) = priv->rx_held;
216 priv->rx.avail_out--;
217 priv->rx_held_valid = 0;
222 * - he has no remaining input content for this message, and
223 * - and this is the final fragment, and
224 * - we used everything that could be drained on the input side
226 * ...then put back the 00 00 FF FF the sender stripped as our
229 if (!priv->rx.avail_in && wsi->u.ws.final &&
230 !wsi->u.ws.rx_packet_length) {
231 lwsl_ext("RX APPEND_TRAILER-DO\n");
233 priv->rx.next_in = trail;
234 priv->rx.avail_in = sizeof(trail);
237 n = inflate(&priv->rx, Z_NO_FLUSH);
238 lwsl_ext("inflate ret %d, avi %d, avo %d, wsifinal %d\n", n,
239 priv->rx.avail_in, priv->rx.avail_out, wsi->u.ws.final);
245 lwsl_info("zlib error inflate %d: %s\n",
250 * If we did not already send in the 00 00 FF FF, and he's
251 * out of input, he did not EXACTLY fill the output buffer
252 * (which is ambiguous and we will force it to go around
253 * again by withholding a byte), and he's otherwise working on
254 * being a FIN fragment, then do the FIN message processing
255 * of faking up the 00 00 FF FF that the sender stripped.
257 if (!priv->rx.avail_in && wsi->u.ws.final &&
258 !wsi->u.ws.rx_packet_length && !was_fin &&
259 priv->rx.avail_out /* ambiguous as to if it is the end */
261 lwsl_ext("RX APPEND_TRAILER-DO\n");
263 priv->rx.next_in = trail;
264 priv->rx.avail_in = sizeof(trail);
265 n = inflate(&priv->rx, Z_SYNC_FLUSH);
266 lwsl_ext("RX trailer inf returned %d, avi %d, avo %d\n", n,
267 priv->rx.avail_in, priv->rx.avail_out);
273 lwsl_info("zlib error inflate %d: %s\n",
279 * we must announce in our returncode now if there is more
280 * output to be expected from inflate, so we can decide to
281 * set the FIN bit on this bufferload or not. However zlib
282 * is ambiguous when we exactly filled the inflate buffer. It
283 * does not give us a clue as to whether we should understand
284 * that to mean he ended on a buffer boundary, or if there is
285 * more in the pipeline.
287 * So to work around that safely, if it used all output space
288 * exactly, we ALWAYS say there is more coming and we withhold
289 * the last byte of the buffer to guarantee that is true.
291 * That still leaves us at least one byte to finish with a FIN
292 * on, even if actually nothing more is coming from the next
293 * inflate action itself.
295 if (!priv->rx.avail_out) { /* he used all available out buf */
296 lwsl_ext("-- rx grabbing held --\n");
297 /* snip the last byte and hold it for next time */
298 priv->rx_held = *(--priv->rx.next_out);
299 priv->rx_held_valid = 1;
302 eff_buf->token_len = (char *)priv->rx.next_out - eff_buf->token;
303 priv->count_rx_between_fin += eff_buf->token_len;
305 lwsl_ext(" %s: RX leaving with new effbuff len %d, "
306 "ret %d, rx.avail_in=%d, TOTAL RX since FIN %ld\n",
307 __func__, eff_buf->token_len, priv->rx_held_valid,
308 priv->rx.avail_in, priv->count_rx_between_fin);
311 priv->count_rx_between_fin = 0;
312 if (priv->args[PMD_SERVER_NO_CONTEXT_TAKEOVER]) {
313 (void)inflateEnd(&priv->rx);
318 for (n = 0; n < eff_buf->token_len; n++)
319 putchar(eff_buf->token[n]);
323 return priv->rx_held_valid;
325 case LWS_EXT_CB_PAYLOAD_TX:
328 if (deflateInit2(&priv->tx, priv->args[PMD_COMP_LEVEL],
330 -priv->args[PMD_CLIENT_MAX_WINDOW_BITS +
331 !wsi->vhost->listen_port],
332 priv->args[PMD_MEM_LEVEL],
333 Z_DEFAULT_STRATEGY) != Z_OK) {
334 lwsl_ext("inflateInit2 failed\n");
338 if (!priv->buf_tx_deflated)
339 priv->buf_tx_deflated = lws_malloc(LWS_PRE + 7 + 5 +
340 (1 << priv->args[PMD_TX_BUF_PWR2]));
341 if (!priv->buf_tx_deflated) {
342 lwsl_err("%s: OOM\n", __func__);
346 if (eff_buf->token) {
347 lwsl_ext("%s: TX: eff_buf length %d\n", __func__,
349 priv->tx.next_in = (unsigned char *)eff_buf->token;
350 priv->tx.avail_in = eff_buf->token_len;
354 for (n = 0; n < eff_buf->token_len; n++) {
355 printf("%02X ", (unsigned char)eff_buf->token[n]);
362 priv->tx.next_out = priv->buf_tx_deflated + LWS_PRE + 5;
363 eff_buf->token = (char *)priv->tx.next_out;
364 priv->tx.avail_out = 1 << priv->args[PMD_TX_BUF_PWR2];
366 n = deflate(&priv->tx, Z_SYNC_FLUSH);
367 if (n == Z_STREAM_ERROR) {
368 lwsl_ext("%s: Z_STREAM_ERROR\n", __func__);
372 if (priv->tx_held_valid) {
373 priv->tx_held_valid = 0;
374 if (priv->tx.avail_out == 1 << priv->args[PMD_TX_BUF_PWR2])
376 * we can get a situation he took something in
377 * but did not generate anything out, at the end
378 * of a message (eg, next thing he sends is 80
379 * 00, a zero length FIN, like Authobahn can
381 * If we have come back as a FIN, we must not
382 * place the pending trailer 00 00 FF FF, just
383 * the 1 byte of live data
385 *(--eff_buf->token) = priv->tx_held[0];
387 /* he generated data, prepend whole pending */
389 for (n = 0; n < 5; n++)
390 eff_buf->token[n] = priv->tx_held[n];
394 priv->compressed_out = 1;
395 eff_buf->token_len = (int)(priv->tx.next_out -
396 (unsigned char *)eff_buf->token);
399 * we must announce in our returncode now if there is more
400 * output to be expected from inflate, so we can decide to
401 * set the FIN bit on this bufferload or not. However zlib
402 * is ambiguous when we exactly filled the inflate buffer. It
403 * does not give us a clue as to whether we should understand
404 * that to mean he ended on a buffer boundary, or if there is
405 * more in the pipeline.
407 * Worse, the guy providing the stuff we are sending may not
408 * know until after that this was, actually, the last chunk,
409 * that can happen even if we did not fill the output buf, ie
410 * he may send after this a zero-length FIN fragment.
412 * This is super difficult because we must snip the last 4
413 * bytes in the case this is the last compressed output of the
414 * message. The only way to deal with it is defer sending the
415 * last 5 bytes of each frame until the next one, when we will
416 * be in a position to understand if that has a FIN or not.
419 extra = !!(len & LWS_WRITE_NO_FIN) || !priv->tx.avail_out;
421 if (eff_buf->token_len >= 4 + extra) {
422 lwsl_ext("tx held %d\n", 4 + extra);
423 priv->tx_held_valid = extra;
424 for (n = 3 + extra; n >= 0; n--)
425 priv->tx_held[n] = *(--priv->tx.next_out);
426 eff_buf->token_len -= 4 + extra;
428 lwsl_ext(" TX rewritten with new effbuff len %d, ret %d\n",
429 eff_buf->token_len, !priv->tx.avail_out);
431 return !priv->tx.avail_out; /* 1 == have more tx pending */
433 case LWS_EXT_CB_PACKET_TX_PRESEND:
434 if (!priv->compressed_out)
436 priv->compressed_out = 0;
438 if ((*(eff_buf->token) & 0x80) && priv->args[PMD_CLIENT_NO_CONTEXT_TAKEOVER]) {
439 (void)deflateEnd(&priv->tx);
443 n = *(eff_buf->token) & 15;
444 /* set RSV1, but not on CONTINUATION */
445 if (n == LWSWSOPC_TEXT_FRAME || n == LWSWSOPC_BINARY_FRAME)
446 *eff_buf->token |= 0x40;
448 for (n = 0; n < eff_buf->token_len; n++) {
449 printf("%02X ", (unsigned char)eff_buf->token[n]);
455 lwsl_ext("%s: tx opcode 0x%02X\n", __func__,
456 (unsigned char)*eff_buf->token);