1 /* Experimental implementation for on-the-fly compression */
3 #error "This file must only be included, if USE_ZLIB is set"
6 #if !defined(MEM_LEVEL)
11 zalloc(void *opaque, uInt items, uInt size)
13 struct mg_connection *conn = (struct mg_connection *)opaque;
14 void *ret = mg_calloc_ctx(items, size, conn->phys_ctx);
15 (void)conn; /* mg_calloc_ctx makro might not need it */
22 zfree(void *opaque, void *address)
24 struct mg_connection *conn = (struct mg_connection *)opaque;
25 (void)conn; /* not required */
32 send_compressed_data(struct mg_connection *conn, struct mg_file *filep)
39 unsigned char in_buf[MG_BUF_LEN];
40 unsigned char out_buf[MG_BUF_LEN];
41 FILE *in_file = filep->access.fp;
43 /* Prepare state buffer. User server context memory allocation. */
44 memset(&zstream, 0, sizeof(zstream));
45 zstream.zalloc = zalloc;
46 zstream.zfree = zfree;
47 zstream.opaque = (void *)conn;
49 /* Initialize for GZIP compression (MAX_WBITS | 16) */
50 zret = deflateInit2(&zstream,
59 "GZIP init failed (%i): %s",
61 (zstream.msg ? zstream.msg : "<no error message>"));
66 /* Read until end of file */
68 zstream.avail_in = fread(in_buf, 1, MG_BUF_LEN, in_file);
69 if (ferror(in_file)) {
70 mg_cry_internal(conn, "fread failed: %s", strerror(ERRNO));
71 (void)deflateEnd(&zstream);
75 do_flush = (feof(in_file) ? Z_FINISH : Z_NO_FLUSH);
76 zstream.next_in = in_buf;
78 /* run deflate() on input until output buffer not full, finish
79 * compression if all of source has been read in */
81 zstream.avail_out = MG_BUF_LEN;
82 zstream.next_out = out_buf;
83 zret = deflate(&zstream, do_flush);
85 if (zret == Z_STREAM_ERROR) {
91 bytes_avail = MG_BUF_LEN - zstream.avail_out;
93 if (mg_send_chunk(conn, (char *)out_buf, bytes_avail) < 0) {
99 } while (zstream.avail_out == 0);
102 /* Forward write error */
106 if (zstream.avail_in != 0) {
107 /* all input will be used, otherwise GZIP is incomplete */
112 /* done when last data in file processed */
113 } while (do_flush != Z_FINISH);
115 if (zret != Z_STREAM_END) {
116 /* Error: We did not compress everything. */
117 mg_cry_internal(conn,
118 "GZIP incomplete (%i): %s",
120 (zstream.msg ? zstream.msg : "<no error message>"));
123 deflateEnd(&zstream);
125 /* Send "end of chunked data" marker */
126 mg_write(conn, "0\r\n\r\n", 5);
130 #if defined(USE_WEBSOCKET) && defined(MG_EXPERIMENTAL_INTERFACES)
132 websocket_deflate_initialize(struct mg_connection *conn, int server)
135 deflateInit2(&conn->websocket_deflate_state,
139 ? -1 * conn->websocket_deflate_server_max_windows_bits
140 : -1 * conn->websocket_deflate_client_max_windows_bits,
144 mg_cry_internal(conn,
145 "Websocket deflate init failed (%i): %s",
147 (conn->websocket_deflate_state.msg
148 ? conn->websocket_deflate_state.msg
149 : "<no error message>"));
150 deflateEnd(&conn->websocket_deflate_state);
155 &conn->websocket_inflate_state,
156 server ? -1 * conn->websocket_deflate_client_max_windows_bits
157 : -1 * conn->websocket_deflate_server_max_windows_bits);
159 mg_cry_internal(conn,
160 "Websocket inflate init failed (%i): %s",
162 (conn->websocket_inflate_state.msg
163 ? conn->websocket_inflate_state.msg
164 : "<no error message>"));
165 inflateEnd(&conn->websocket_inflate_state);
168 if ((conn->websocket_deflate_server_no_context_takeover && server)
169 || (conn->websocket_deflate_client_no_context_takeover && !server))
170 conn->websocket_deflate_flush = Z_FULL_FLUSH;
172 conn->websocket_deflate_flush = Z_SYNC_FLUSH;
174 conn->websocket_deflate_initialized = 1;
180 websocket_deflate_negotiate(struct mg_connection *conn)
182 const char *extensions = mg_get_header(conn, "Sec-WebSocket-Extensions");
184 if (extensions && !strncmp(extensions, "permessage-deflate", 18)) {
185 conn->accept_gzip = 1;
186 conn->websocket_deflate_client_max_windows_bits = 15;
187 conn->websocket_deflate_server_max_windows_bits = 15;
188 conn->websocket_deflate_server_no_context_takeover = 0;
189 conn->websocket_deflate_client_no_context_takeover = 0;
191 while (*extensions != '\0') {
192 if (*extensions == ';' || *extensions == ' ')
194 else if (!strncmp(extensions, "server_no_context_takeover", 26)) {
196 conn->websocket_deflate_server_no_context_takeover = 1;
197 } else if (!strncmp(extensions, "client_no_context_takeover", 26)) {
199 conn->websocket_deflate_client_no_context_takeover = 1;
200 } else if (!strncmp(extensions, "server_max_window_bits", 22)) {
202 if (*extensions == '=') {
204 if (*extensions == '"')
207 while (*extensions >= '0' && *extensions <= '9') {
208 val = val * 10 + (*extensions - '0');
211 if (val < 9 || val > 15) {
212 // The permessage-deflate spec specifies that a
213 // value of 8 is also allowed, but zlib doesn't accept
215 mg_cry_internal(conn,
216 "server-max-window-bits must be "
217 "between 9 and 15. Got %i",
220 conn->websocket_deflate_server_max_windows_bits = val;
221 if (*extensions == '"')
224 } else if (!strncmp(extensions, "client_max_window_bits", 22)) {
226 if (*extensions == '=') {
228 if (*extensions == '"')
231 while (*extensions >= '0' && *extensions <= '9') {
232 val = val * 10 + (*extensions - '0');
235 if (val < 9 || val > 15)
236 // The permessage-deflate spec specifies that a
237 // value of 8 is also allowed, but zlib doesn't
239 mg_cry_internal(conn,
240 "client-max-window-bits must be "
241 "between 9 and 15. Got %i",
244 conn->websocket_deflate_client_max_windows_bits = val;
245 if (*extensions == '"')
249 mg_cry_internal(conn,
250 "Unknown parameter %s for permessage-deflate",
256 conn->accept_gzip = 0;
258 conn->websocket_deflate_initialized = 0;
263 websocket_deflate_response(struct mg_connection *conn)
265 if (conn->accept_gzip) {
267 "Sec-WebSocket-Extensions: permessage-deflate; "
268 "server_max_window_bits=%i; "
269 "client_max_window_bits=%i"
271 conn->websocket_deflate_server_max_windows_bits,
272 conn->websocket_deflate_client_max_windows_bits,
273 conn->websocket_deflate_client_no_context_takeover
274 ? "; client_no_context_takeover"
276 conn->websocket_deflate_server_no_context_takeover
277 ? "; server_no_context_takeover"