blob: 17aee49f08425112f5ae5496a80955841d0dea97 [file] [log] [blame]
Andy Greence6a21d2011-03-06 13:32:53 +00001#include "private-libwebsockets.h"
2#include "extension-deflate-stream.h"
3#include <stdio.h>
4#include <string.h>
5#include <assert.h>
6
Andy Green66a36ff2011-04-29 17:43:06 +08007#define LWS_ZLIB_WINDOW_BITS 15
Andy Green26111bc2011-03-22 09:06:52 +00008#define LWS_ZLIB_MEMLEVEL 8
Andy Greence6a21d2011-03-06 13:32:53 +00009
10int lws_extension_callback_deflate_stream(
Andy Green46c2ea02011-03-22 09:04:01 +000011 struct libwebsocket_context *context,
12 struct libwebsocket_extension *ext,
13 struct libwebsocket *wsi,
Andy Greence6a21d2011-03-06 13:32:53 +000014 enum libwebsocket_extension_callback_reasons reason,
15 void *user, void *in, size_t len)
16{
17 struct lws_ext_deflate_stream_conn *conn =
18 (struct lws_ext_deflate_stream_conn *)user;
19 int n;
20 struct lws_tokens *eff_buf = (struct lws_tokens *)in;
21
22 switch (reason) {
23
24 /*
25 * for deflate-stream, both client and server sides act the same
26 */
27
28 case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
29 case LWS_EXT_CALLBACK_CONSTRUCT:
30 conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
31 conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
32 conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
Andy Green26111bc2011-03-22 09:06:52 +000033 n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS);
Andy Greence6a21d2011-03-06 13:32:53 +000034 if (n != Z_OK) {
35 fprintf(stderr, "deflateInit returned %d\n", n);
36 return 1;
37 }
Andy Green26111bc2011-03-22 09:06:52 +000038 n = deflateInit2(&conn->zs_out,
39 DEFLATE_STREAM_COMPRESSION_LEVEL, Z_DEFLATED,
40 -LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
41 Z_DEFAULT_STRATEGY);
Andy Greence6a21d2011-03-06 13:32:53 +000042 if (n != Z_OK) {
43 fprintf(stderr, "deflateInit returned %d\n", n);
44 return 1;
45 }
Andy Greencc012472011-11-07 19:53:23 +080046 debug("zlibs constructed\n");
David Galeanod58c6ab2013-01-09 18:03:28 +080047 conn->remaining_in = 0;
Andy Greence6a21d2011-03-06 13:32:53 +000048 break;
49
50 case LWS_EXT_CALLBACK_DESTROY:
51 (void)inflateEnd(&conn->zs_in);
52 (void)deflateEnd(&conn->zs_out);
Andy Greencc012472011-11-07 19:53:23 +080053 debug("zlibs destructed\n");
Andy Greence6a21d2011-03-06 13:32:53 +000054 break;
55
56 case LWS_EXT_CALLBACK_PACKET_RX_PREPARSE:
57
58 /*
59 * inflate the incoming compressed data
60 * Notice, length may be 0 and pointer NULL
61 * in the case we are flushing with nothing new coming in
62 */
David Galeanod58c6ab2013-01-09 18:03:28 +080063 if (conn->remaining_in)
64 {
65 conn->zs_in.next_in = conn->buf_in;
66 conn->zs_in.avail_in = conn->remaining_in;
67 conn->remaining_in = 0;
68 }
69 else
70 {
71 conn->zs_in.next_in = (unsigned char *)eff_buf->token;
72 conn->zs_in.avail_in = eff_buf->token_len;
73 }
Andy Greence6a21d2011-03-06 13:32:53 +000074
David Galeanod58c6ab2013-01-09 18:03:28 +080075 conn->zs_in.next_out = conn->buf_out;
76 conn->zs_in.avail_out = sizeof(conn->buf_out);
Andy Greence6a21d2011-03-06 13:32:53 +000077
78 n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
79 switch (n) {
80 case Z_NEED_DICT:
81 case Z_DATA_ERROR:
82 case Z_MEM_ERROR:
83 /*
84 * screwed.. close the connection... we will get a
85 * destroy callback to take care of closing nicely
86 */
87 fprintf(stderr, "zlib error inflate %d\n", n);
88 return -1;
89 }
90
91 /* rewrite the buffer pointers and length */
92
David Galeanod58c6ab2013-01-09 18:03:28 +080093 eff_buf->token = (char *)conn->buf_out;
94 eff_buf->token_len = sizeof(conn->buf_out) - conn->zs_in.avail_out;
95
96 /* copy avail data if not consumed */
97 if (conn->zs_in.avail_in > 0)
98 {
99 conn->remaining_in = conn->zs_in.avail_in;
100 memcpy(conn->buf_in, conn->zs_in.next_in, conn->zs_in.avail_in);
101 return 1;
102 }
Andy Greence6a21d2011-03-06 13:32:53 +0000103
104 /*
105 * if we filled the output buffer, signal that we likely have
106 * more and need to be called again
107 */
108
David Galeanod58c6ab2013-01-09 18:03:28 +0800109 if (eff_buf->token_len == sizeof(conn->buf_out))
Andy Greence6a21d2011-03-06 13:32:53 +0000110 return 1;
111
112 /* we don't need calling again until new input data comes */
113
114 return 0;
115
Andy Greenc44159f2011-03-07 07:08:18 +0000116 case LWS_EXT_CALLBACK_FLUSH_PENDING_TX:
Andy Greence6a21d2011-03-06 13:32:53 +0000117 case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
118
119 /*
120 * deflate the outgoing compressed data
121 */
122
123 conn->zs_out.next_in = (unsigned char *)eff_buf->token;
124 conn->zs_out.avail_in = eff_buf->token_len;
125
David Galeanod58c6ab2013-01-09 18:03:28 +0800126 conn->zs_out.next_out = conn->buf_out;
127 conn->zs_out.avail_out = sizeof(conn->buf_out);
Andy Greence6a21d2011-03-06 13:32:53 +0000128
Andy Greenc44159f2011-03-07 07:08:18 +0000129 n = Z_PARTIAL_FLUSH;
130 if (reason == LWS_EXT_CALLBACK_FLUSH_PENDING_TX)
131 n = Z_FULL_FLUSH;
132
133 n = deflate(&conn->zs_out, n);
Andy Greence6a21d2011-03-06 13:32:53 +0000134 if (n == Z_STREAM_ERROR) {
135 /*
136 * screwed.. close the connection... we will get a
137 * destroy callback to take care of closing nicely
138 */
139 fprintf(stderr, "zlib error deflate\n");
140
141 return -1;
142 }
143
144 /* rewrite the buffer pointers and length */
145
David Galeanod58c6ab2013-01-09 18:03:28 +0800146 eff_buf->token = (char *)conn->buf_out;
147 eff_buf->token_len = sizeof(conn->buf_out) - conn->zs_out.avail_out;
Andy Greence6a21d2011-03-06 13:32:53 +0000148
149 /*
150 * if we filled the output buffer, signal that we likely have
151 * more and need to be called again... even in deflate case
152 * we might sometimes need to spill more than came in
153 */
154
David Galeanod58c6ab2013-01-09 18:03:28 +0800155 if (eff_buf->token_len == sizeof(conn->buf_out))
Andy Greence6a21d2011-03-06 13:32:53 +0000156 return 1;
157
158 /* we don't need calling again until new input data comes */
159
Andy Greena41314f2011-05-23 10:00:03 +0100160 return 0;
161
162 default:
163 break;
Andy Greence6a21d2011-03-06 13:32:53 +0000164 }
165
166 return 0;
167}