blob: 594399a2ffe02512204c05e75fdd9b6fc141d38c [file] [log] [blame]
William Lallemand82fe75c2012-10-23 10:25:10 +02001/*
2 * HTTP compression.
3 *
4 * Copyright 2012 Exceliance, David Du Colombier <dducolombier@exceliance.fr>
5 * William Lallemand <wlallemand@exceliance.fr>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 */
13
14#include <stdio.h>
Willy Tarreau34763642012-10-26 15:05:35 +020015
Willy Tarreau418b8c02015-03-29 03:32:06 +020016#if defined(USE_SLZ)
17#include <slz.h>
18#elif defined(USE_ZLIB)
Willy Tarreau34763642012-10-26 15:05:35 +020019/* Note: the crappy zlib and openssl libs both define the "free_func" type.
20 * That's a very clever idea to use such a generic name in general purpose
21 * libraries, really... The zlib one is easier to redefine than openssl's,
22 * so let's only fix this one.
23 */
24#define free_func zlib_free_func
William Lallemand82fe75c2012-10-23 10:25:10 +020025#include <zlib.h>
Willy Tarreau34763642012-10-26 15:05:35 +020026#undef free_func
William Lallemand08289f12012-10-31 11:19:18 +010027#endif /* USE_ZLIB */
William Lallemand82fe75c2012-10-23 10:25:10 +020028
Willy Tarreau36878032016-12-22 19:46:17 +010029#include <common/cfgparse.h>
William Lallemand82fe75c2012-10-23 10:25:10 +020030#include <common/compat.h>
William Lallemand2b502472012-10-30 14:30:39 +010031#include <common/memory.h>
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +020032#include <common/hathreads.h>
William Lallemand82fe75c2012-10-23 10:25:10 +020033
34#include <types/global.h>
35#include <types/compression.h>
36
William Lallemand727db8b2013-04-20 17:33:20 +020037#include <proto/acl.h>
William Lallemand82fe75c2012-10-23 10:25:10 +020038#include <proto/compression.h>
William Lallemandd85f9172012-11-09 17:05:39 +010039#include <proto/freq_ctr.h>
William Lallemand82fe75c2012-10-23 10:25:10 +020040#include <proto/proto_http.h>
Willy Tarreaue36cbcb2015-04-03 15:40:56 +020041#include <proto/stream.h>
William Lallemand82fe75c2012-10-23 10:25:10 +020042
William Lallemand2b502472012-10-30 14:30:39 +010043
Emeric Brun11f58862017-11-07 11:57:54 +010044#if defined(USE_SLZ) || defined(USE_ZLIB)
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +020045#ifdef USE_THREAD
46static HA_SPINLOCK_T comp_pool_lock;
47#endif
Emeric Brun11f58862017-11-07 11:57:54 +010048#endif
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +020049
William Lallemand2b502472012-10-30 14:30:39 +010050#ifdef USE_ZLIB
51
William Lallemand8b52bb32012-11-16 18:06:41 +010052static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size);
53static void free_zlib(void *opaque, void *ptr);
54
William Lallemand2b502472012-10-30 14:30:39 +010055/* zlib allocation */
56static struct pool_head *zlib_pool_deflate_state = NULL;
57static struct pool_head *zlib_pool_window = NULL;
58static struct pool_head *zlib_pool_prev = NULL;
59static struct pool_head *zlib_pool_head = NULL;
60static struct pool_head *zlib_pool_pending_buf = NULL;
61
William Lallemande3a7d992012-11-20 11:25:20 +010062long zlib_used_memory = 0;
William Lallemand9d5f5482012-11-07 16:12:57 +010063
Willy Tarreau36878032016-12-22 19:46:17 +010064static int global_tune_zlibmemlevel = 8; /* zlib memlevel */
65static int global_tune_zlibwindowsize = MAX_WBITS; /* zlib window size */
66
William Lallemand2b502472012-10-30 14:30:39 +010067#endif
68
William Lallemand072a2bf2012-11-20 17:01:01 +010069unsigned int compress_min_idle = 0;
William Lallemand8b52bb32012-11-16 18:06:41 +010070
Willy Tarreau9f640a12015-03-28 15:46:00 +010071static int identity_init(struct comp_ctx **comp_ctx, int level);
72static int identity_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
Willy Tarreau9787efa2015-03-28 19:17:31 +010073static int identity_flush(struct comp_ctx *comp_ctx, struct buffer *out);
74static int identity_finish(struct comp_ctx *comp_ctx, struct buffer *out);
Willy Tarreau9f640a12015-03-28 15:46:00 +010075static int identity_end(struct comp_ctx **comp_ctx);
76
Willy Tarreau418b8c02015-03-29 03:32:06 +020077#if defined(USE_SLZ)
78
79static int rfc1950_init(struct comp_ctx **comp_ctx, int level);
80static int rfc1951_init(struct comp_ctx **comp_ctx, int level);
81static int rfc1952_init(struct comp_ctx **comp_ctx, int level);
82static int rfc195x_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
83static int rfc195x_flush(struct comp_ctx *comp_ctx, struct buffer *out);
84static int rfc195x_finish(struct comp_ctx *comp_ctx, struct buffer *out);
85static int rfc195x_end(struct comp_ctx **comp_ctx);
86
87#elif defined(USE_ZLIB)
Willy Tarreau7b218772015-03-28 22:08:25 +010088
Willy Tarreau9f640a12015-03-28 15:46:00 +010089static int gzip_init(struct comp_ctx **comp_ctx, int level);
Willy Tarreauc91840a2015-03-28 17:00:39 +010090static int raw_def_init(struct comp_ctx **comp_ctx, int level);
Willy Tarreau9f640a12015-03-28 15:46:00 +010091static int deflate_init(struct comp_ctx **comp_ctx, int level);
92static int deflate_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
Willy Tarreau9787efa2015-03-28 19:17:31 +010093static int deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out);
94static int deflate_finish(struct comp_ctx *comp_ctx, struct buffer *out);
Willy Tarreau9f640a12015-03-28 15:46:00 +010095static int deflate_end(struct comp_ctx **comp_ctx);
Willy Tarreau7b218772015-03-28 22:08:25 +010096
Willy Tarreau9f640a12015-03-28 15:46:00 +010097#endif /* USE_ZLIB */
98
William Lallemand2b502472012-10-30 14:30:39 +010099
Cyril Bonté6162c432012-11-10 19:27:47 +0100100const struct comp_algo comp_algos[] =
William Lallemand82fe75c2012-10-23 10:25:10 +0200101{
Willy Tarreau7b218772015-03-28 22:08:25 +0100102 { "identity", 8, "identity", 8, identity_init, identity_add_data, identity_flush, identity_finish, identity_end },
Willy Tarreau418b8c02015-03-29 03:32:06 +0200103#if defined(USE_SLZ)
104 { "deflate", 7, "deflate", 7, rfc1950_init, rfc195x_add_data, rfc195x_flush, rfc195x_finish, rfc195x_end },
105 { "raw-deflate", 11, "deflate", 7, rfc1951_init, rfc195x_add_data, rfc195x_flush, rfc195x_finish, rfc195x_end },
106 { "gzip", 4, "gzip", 4, rfc1952_init, rfc195x_add_data, rfc195x_flush, rfc195x_finish, rfc195x_end },
107#elif defined(USE_ZLIB)
Willy Tarreau7b218772015-03-28 22:08:25 +0100108 { "deflate", 7, "deflate", 7, deflate_init, deflate_add_data, deflate_flush, deflate_finish, deflate_end },
109 { "raw-deflate", 11, "deflate", 7, raw_def_init, deflate_add_data, deflate_flush, deflate_finish, deflate_end },
110 { "gzip", 4, "gzip", 4, gzip_init, deflate_add_data, deflate_flush, deflate_finish, deflate_end },
William Lallemand82fe75c2012-10-23 10:25:10 +0200111#endif /* USE_ZLIB */
Willy Tarreau615105e2015-03-28 16:40:46 +0100112 { NULL, 0, NULL, 0, NULL , NULL, NULL, NULL, NULL }
William Lallemand82fe75c2012-10-23 10:25:10 +0200113};
114
115/*
116 * Add a content-type in the configuration
117 */
118int comp_append_type(struct comp *comp, const char *type)
119{
120 struct comp_type *comp_type;
121
Vincent Bernat02779b62016-04-03 13:48:43 +0200122 comp_type = calloc(1, sizeof(*comp_type));
William Lallemand82fe75c2012-10-23 10:25:10 +0200123 comp_type->name_len = strlen(type);
124 comp_type->name = strdup(type);
125 comp_type->next = comp->types;
126 comp->types = comp_type;
127 return 0;
128}
129
130/*
131 * Add an algorithm in the configuration
132 */
133int comp_append_algo(struct comp *comp, const char *algo)
134{
135 struct comp_algo *comp_algo;
136 int i;
137
Willy Tarreau615105e2015-03-28 16:40:46 +0100138 for (i = 0; comp_algos[i].cfg_name; i++) {
139 if (!strcmp(algo, comp_algos[i].cfg_name)) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200140 comp_algo = calloc(1, sizeof(*comp_algo));
William Lallemand82fe75c2012-10-23 10:25:10 +0200141 memmove(comp_algo, &comp_algos[i], sizeof(struct comp_algo));
142 comp_algo->next = comp->algos;
143 comp->algos = comp_algo;
144 return 0;
145 }
146 }
147 return -1;
148}
149
Willy Tarreaue1cc4b52016-08-10 21:17:06 +0200150#if defined(USE_ZLIB) || defined(USE_SLZ)
151static struct pool_head *pool_comp_ctx = NULL;
William Lallemand8b52bb32012-11-16 18:06:41 +0100152/*
153 * Alloc the comp_ctx
154 */
155static inline int init_comp_ctx(struct comp_ctx **comp_ctx)
156{
157#ifdef USE_ZLIB
158 z_stream *strm;
159
William Lallemande3a7d992012-11-20 11:25:20 +0100160 if (global.maxzlibmem > 0 && (global.maxzlibmem - zlib_used_memory) < sizeof(struct comp_ctx))
William Lallemand8b52bb32012-11-16 18:06:41 +0100161 return -1;
162#endif
163
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200164 if (unlikely(pool_comp_ctx == NULL)) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100165 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200166 if (unlikely(pool_comp_ctx == NULL))
167 pool_comp_ctx = create_pool("comp_ctx", sizeof(struct comp_ctx), MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100168 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200169 }
William Lallemand8b52bb32012-11-16 18:06:41 +0100170
171 *comp_ctx = pool_alloc2(pool_comp_ctx);
172 if (*comp_ctx == NULL)
173 return -1;
Willy Tarreau418b8c02015-03-29 03:32:06 +0200174#if defined(USE_SLZ)
175 (*comp_ctx)->direct_ptr = NULL;
176 (*comp_ctx)->direct_len = 0;
177 (*comp_ctx)->queued = NULL;
178#elif defined(USE_ZLIB)
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200179 HA_ATOMIC_ADD(&zlib_used_memory, sizeof(struct comp_ctx));
William Lallemand8b52bb32012-11-16 18:06:41 +0100180
181 strm = &(*comp_ctx)->strm;
182 strm->zalloc = alloc_zlib;
183 strm->zfree = free_zlib;
184 strm->opaque = *comp_ctx;
185#endif
186 return 0;
187}
188
189/*
190 * Dealloc the comp_ctx
191 */
192static inline int deinit_comp_ctx(struct comp_ctx **comp_ctx)
193{
194 if (!*comp_ctx)
195 return 0;
196
197 pool_free2(pool_comp_ctx, *comp_ctx);
198 *comp_ctx = NULL;
199
200#ifdef USE_ZLIB
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200201 HA_ATOMIC_SUB(&zlib_used_memory, sizeof(struct comp_ctx));
William Lallemand8b52bb32012-11-16 18:06:41 +0100202#endif
William Lallemand8b52bb32012-11-16 18:06:41 +0100203 return 0;
204}
Willy Tarreaue1cc4b52016-08-10 21:17:06 +0200205#endif
William Lallemand8b52bb32012-11-16 18:06:41 +0100206
William Lallemand82fe75c2012-10-23 10:25:10 +0200207
208/****************************
209 **** Identity algorithm ****
210 ****************************/
211
212/*
213 * Init the identity algorithm
214 */
Willy Tarreau9f640a12015-03-28 15:46:00 +0100215static int identity_init(struct comp_ctx **comp_ctx, int level)
William Lallemand82fe75c2012-10-23 10:25:10 +0200216{
217 return 0;
218}
219
220/*
221 * Process data
William Lallemandbf3ae612012-11-19 12:35:37 +0100222 * Return size of consumed data or -1 on error
William Lallemand82fe75c2012-10-23 10:25:10 +0200223 */
Willy Tarreau9f640a12015-03-28 15:46:00 +0100224static int identity_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out)
William Lallemand82fe75c2012-10-23 10:25:10 +0200225{
William Lallemandbf3ae612012-11-19 12:35:37 +0100226 char *out_data = bi_end(out);
227 int out_len = out->size - buffer_len(out);
228
William Lallemand82fe75c2012-10-23 10:25:10 +0200229 if (out_len < in_len)
230 return -1;
231
232 memcpy(out_data, in_data, in_len);
233
William Lallemandbf3ae612012-11-19 12:35:37 +0100234 out->i += in_len;
235
William Lallemand82fe75c2012-10-23 10:25:10 +0200236 return in_len;
237}
238
Willy Tarreau9787efa2015-03-28 19:17:31 +0100239static int identity_flush(struct comp_ctx *comp_ctx, struct buffer *out)
William Lallemand82fe75c2012-10-23 10:25:10 +0200240{
241 return 0;
242}
243
Willy Tarreau9787efa2015-03-28 19:17:31 +0100244static int identity_finish(struct comp_ctx *comp_ctx, struct buffer *out)
245{
246 return 0;
247}
248
Willy Tarreau418b8c02015-03-29 03:32:06 +0200249/*
250 * Deinit the algorithm
251 */
252static int identity_end(struct comp_ctx **comp_ctx)
William Lallemand82fe75c2012-10-23 10:25:10 +0200253{
254 return 0;
255}
256
Willy Tarreau418b8c02015-03-29 03:32:06 +0200257
258#ifdef USE_SLZ
259
260/* SLZ's gzip format (RFC1952). Returns < 0 on error. */
261static int rfc1952_init(struct comp_ctx **comp_ctx, int level)
262{
263 if (init_comp_ctx(comp_ctx) < 0)
264 return -1;
265
266 (*comp_ctx)->cur_lvl = !!level;
267 return slz_rfc1952_init(&(*comp_ctx)->strm, !!level);
268}
269
270/* SLZ's raw deflate format (RFC1951). Returns < 0 on error. */
271static int rfc1951_init(struct comp_ctx **comp_ctx, int level)
272{
273 if (init_comp_ctx(comp_ctx) < 0)
274 return -1;
275
276 (*comp_ctx)->cur_lvl = !!level;
277 return slz_rfc1951_init(&(*comp_ctx)->strm, !!level);
278}
279
280/* SLZ's zlib format (RFC1950). Returns < 0 on error. */
281static int rfc1950_init(struct comp_ctx **comp_ctx, int level)
282{
283 if (init_comp_ctx(comp_ctx) < 0)
284 return -1;
285
286 (*comp_ctx)->cur_lvl = !!level;
287 return slz_rfc1950_init(&(*comp_ctx)->strm, !!level);
288}
289
290/* Return the size of consumed data or -1. The output buffer is unused at this
291 * point, we only keep a reference to the input data or a copy of them if the
292 * reference is already used.
William Lallemand82fe75c2012-10-23 10:25:10 +0200293 */
Willy Tarreau418b8c02015-03-29 03:32:06 +0200294static int rfc195x_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out)
William Lallemand82fe75c2012-10-23 10:25:10 +0200295{
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200296 static THREAD_LOCAL struct buffer *tmpbuf = &buf_empty;
Willy Tarreau418b8c02015-03-29 03:32:06 +0200297
298 if (in_len <= 0)
299 return 0;
300
301 if (comp_ctx->direct_ptr && !comp_ctx->queued) {
302 /* data already being pointed to, we're in front of fragmented
303 * data and need a buffer now. We reuse the same buffer, as it's
304 * not used out of the scope of a series of add_data()*, end().
305 */
306 if (unlikely(!tmpbuf->size)) {
307 /* this is the first time we need the compression buffer */
308 if (b_alloc(&tmpbuf) == NULL)
309 return -1; /* no memory */
310 }
311 b_reset(tmpbuf);
312 memcpy(bi_end(tmpbuf), comp_ctx->direct_ptr, comp_ctx->direct_len);
313 tmpbuf->i += comp_ctx->direct_len;
314 comp_ctx->direct_ptr = NULL;
315 comp_ctx->direct_len = 0;
316 comp_ctx->queued = tmpbuf;
317 /* fall through buffer copy */
318 }
319
320 if (comp_ctx->queued) {
321 /* data already pending */
322 memcpy(bi_end(comp_ctx->queued), in_data, in_len);
323 comp_ctx->queued->i += in_len;
324 return in_len;
325 }
326
327 comp_ctx->direct_ptr = in_data;
328 comp_ctx->direct_len = in_len;
329 return in_len;
330}
331
332/* Compresses the data accumulated using add_data(), and optionally sends the
333 * format-specific trailer if <finish> is non-null. <out> is expected to have a
334 * large enough free non-wrapping space as verified by http_comp_buffer_init().
335 * The number of bytes emitted is reported.
336 */
337static int rfc195x_flush_or_finish(struct comp_ctx *comp_ctx, struct buffer *out, int finish)
338{
339 struct slz_stream *strm = &comp_ctx->strm;
340 const char *in_ptr;
341 int in_len;
342 int out_len;
343
344 in_ptr = comp_ctx->direct_ptr;
345 in_len = comp_ctx->direct_len;
346
347 if (comp_ctx->queued) {
348 in_ptr = comp_ctx->queued->p;
349 in_len = comp_ctx->queued->i;
350 }
351
352 out_len = out->i;
353
354 if (in_ptr)
355 out->i += slz_encode(strm, bi_end(out), in_ptr, in_len, !finish);
356
357 if (finish)
358 out->i += slz_finish(strm, bi_end(out));
359
360 out_len = out->i - out_len;
361
362 /* very important, we must wipe the data we've just flushed */
363 comp_ctx->direct_len = 0;
364 comp_ctx->direct_ptr = NULL;
365 comp_ctx->queued = NULL;
366
367 /* Verify compression rate limiting and CPU usage */
368 if ((global.comp_rate_lim > 0 && (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim)) || /* rate */
369 (idle_pct < compress_min_idle)) { /* idle */
370 if (comp_ctx->cur_lvl > 0)
371 strm->level = --comp_ctx->cur_lvl;
372 }
373 else if (comp_ctx->cur_lvl < global.tune.comp_maxlevel && comp_ctx->cur_lvl < 1) {
374 strm->level = ++comp_ctx->cur_lvl;
375 }
376
377 /* and that's all */
378 return out_len;
379}
380
381static int rfc195x_flush(struct comp_ctx *comp_ctx, struct buffer *out)
382{
383 return rfc195x_flush_or_finish(comp_ctx, out, 0);
384}
385
386static int rfc195x_finish(struct comp_ctx *comp_ctx, struct buffer *out)
387{
388 return rfc195x_flush_or_finish(comp_ctx, out, 1);
389}
390
391/* we just need to free the comp_ctx here, nothing was allocated */
392static int rfc195x_end(struct comp_ctx **comp_ctx)
393{
394 deinit_comp_ctx(comp_ctx);
William Lallemand82fe75c2012-10-23 10:25:10 +0200395 return 0;
396}
397
Willy Tarreau418b8c02015-03-29 03:32:06 +0200398#elif defined(USE_ZLIB) /* ! USE_SLZ */
William Lallemand82fe75c2012-10-23 10:25:10 +0200399
William Lallemand2b502472012-10-30 14:30:39 +0100400/*
401 * This is a tricky allocation function using the zlib.
402 * This is based on the allocation order in deflateInit2.
403 */
404static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size)
405{
406 struct comp_ctx *ctx = opaque;
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200407 static THREAD_LOCAL char round = 0; /* order in deflateInit2 */
William Lallemand2b502472012-10-30 14:30:39 +0100408 void *buf = NULL;
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100409 struct pool_head *pool = NULL;
William Lallemand2b502472012-10-30 14:30:39 +0100410
William Lallemande3a7d992012-11-20 11:25:20 +0100411 if (global.maxzlibmem > 0 && (global.maxzlibmem - zlib_used_memory) < (long)(items * size))
William Lallemand9d5f5482012-11-07 16:12:57 +0100412 goto end;
William Lallemand9d5f5482012-11-07 16:12:57 +0100413
William Lallemand2b502472012-10-30 14:30:39 +0100414 switch (round) {
415 case 0:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200416 if (zlib_pool_deflate_state == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100417 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200418 if (zlib_pool_deflate_state == NULL)
419 zlib_pool_deflate_state = create_pool("zlib_state", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100420 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200421 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100422 pool = zlib_pool_deflate_state;
423 ctx->zlib_deflate_state = buf = pool_alloc2(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100424 break;
425
426 case 1:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200427 if (zlib_pool_window == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100428 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200429 if (zlib_pool_window == NULL)
430 zlib_pool_window = create_pool("zlib_window", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100431 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200432 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100433 pool = zlib_pool_window;
434 ctx->zlib_window = buf = pool_alloc2(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100435 break;
436
437 case 2:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200438 if (zlib_pool_prev == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100439 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200440 if (zlib_pool_prev == NULL)
441 zlib_pool_prev = create_pool("zlib_prev", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100442 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200443 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100444 pool = zlib_pool_prev;
445 ctx->zlib_prev = buf = pool_alloc2(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100446 break;
447
448 case 3:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200449 if (zlib_pool_head == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100450 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200451 if (zlib_pool_head == NULL)
452 zlib_pool_head = create_pool("zlib_head", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100453 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200454 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100455 pool = zlib_pool_head;
456 ctx->zlib_head = buf = pool_alloc2(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100457 break;
458
459 case 4:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200460 if (zlib_pool_pending_buf == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100461 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200462 if (zlib_pool_pending_buf == NULL)
463 zlib_pool_pending_buf = create_pool("zlib_pending_buf", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100464 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200465 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100466 pool = zlib_pool_pending_buf;
467 ctx->zlib_pending_buf = buf = pool_alloc2(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100468 break;
469 }
William Lallemande3a7d992012-11-20 11:25:20 +0100470 if (buf != NULL)
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200471 HA_ATOMIC_ADD(&zlib_used_memory, pool->size);
William Lallemand9d5f5482012-11-07 16:12:57 +0100472
473end:
William Lallemand2b502472012-10-30 14:30:39 +0100474
Willy Tarreau46909852012-11-15 14:57:56 +0100475 /* deflateInit2() first allocates and checks the deflate_state, then if
476 * it succeeds, it allocates all other 4 areas at ones and checks them
477 * at the end. So we want to correctly count the rounds depending on when
478 * zlib is supposed to abort.
479 */
480 if (buf || round)
481 round = (round + 1) % 5;
William Lallemand2b502472012-10-30 14:30:39 +0100482 return buf;
483}
484
485static void free_zlib(void *opaque, void *ptr)
486{
487 struct comp_ctx *ctx = opaque;
Willy Tarreaub1fbd052012-11-10 17:49:37 +0100488 struct pool_head *pool = NULL;
William Lallemand2b502472012-10-30 14:30:39 +0100489
490 if (ptr == ctx->zlib_window)
William Lallemand9d5f5482012-11-07 16:12:57 +0100491 pool = zlib_pool_window;
William Lallemand2b502472012-10-30 14:30:39 +0100492 else if (ptr == ctx->zlib_deflate_state)
William Lallemand9d5f5482012-11-07 16:12:57 +0100493 pool = zlib_pool_deflate_state;
William Lallemand2b502472012-10-30 14:30:39 +0100494 else if (ptr == ctx->zlib_prev)
William Lallemand9d5f5482012-11-07 16:12:57 +0100495 pool = zlib_pool_prev;
William Lallemand2b502472012-10-30 14:30:39 +0100496 else if (ptr == ctx->zlib_head)
William Lallemand9d5f5482012-11-07 16:12:57 +0100497 pool = zlib_pool_head;
William Lallemand2b502472012-10-30 14:30:39 +0100498 else if (ptr == ctx->zlib_pending_buf)
William Lallemand9d5f5482012-11-07 16:12:57 +0100499 pool = zlib_pool_pending_buf;
William Lallemand2b502472012-10-30 14:30:39 +0100500
William Lallemand9d5f5482012-11-07 16:12:57 +0100501 pool_free2(pool, ptr);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200502 HA_ATOMIC_SUB(&zlib_used_memory, pool->size);
William Lallemand2b502472012-10-30 14:30:39 +0100503}
504
William Lallemand82fe75c2012-10-23 10:25:10 +0200505/**************************
506**** gzip algorithm ****
507***************************/
Willy Tarreau9f640a12015-03-28 15:46:00 +0100508static int gzip_init(struct comp_ctx **comp_ctx, int level)
William Lallemand82fe75c2012-10-23 10:25:10 +0200509{
William Lallemand8b52bb32012-11-16 18:06:41 +0100510 z_stream *strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200511
William Lallemand8b52bb32012-11-16 18:06:41 +0100512 if (init_comp_ctx(comp_ctx) < 0)
513 return -1;
William Lallemand9d5f5482012-11-07 16:12:57 +0100514
William Lallemand8b52bb32012-11-16 18:06:41 +0100515 strm = &(*comp_ctx)->strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200516
Willy Tarreau36878032016-12-22 19:46:17 +0100517 if (deflateInit2(strm, level, Z_DEFLATED, global_tune_zlibwindowsize + 16, global_tune_zlibmemlevel, Z_DEFAULT_STRATEGY) != Z_OK) {
William Lallemand8b52bb32012-11-16 18:06:41 +0100518 deinit_comp_ctx(comp_ctx);
William Lallemand82fe75c2012-10-23 10:25:10 +0200519 return -1;
William Lallemand8b52bb32012-11-16 18:06:41 +0100520 }
521
522 (*comp_ctx)->cur_lvl = level;
William Lallemand82fe75c2012-10-23 10:25:10 +0200523
524 return 0;
525}
Willy Tarreauc91840a2015-03-28 17:00:39 +0100526
527/* Raw deflate algorithm */
528static int raw_def_init(struct comp_ctx **comp_ctx, int level)
529{
530 z_stream *strm;
531
532 if (init_comp_ctx(comp_ctx) < 0)
533 return -1;
534
535 strm = &(*comp_ctx)->strm;
536
Willy Tarreau36878032016-12-22 19:46:17 +0100537 if (deflateInit2(strm, level, Z_DEFLATED, -global_tune_zlibwindowsize, global_tune_zlibmemlevel, Z_DEFAULT_STRATEGY) != Z_OK) {
Willy Tarreauc91840a2015-03-28 17:00:39 +0100538 deinit_comp_ctx(comp_ctx);
539 return -1;
540 }
541
542 (*comp_ctx)->cur_lvl = level;
543 return 0;
544}
545
William Lallemand82fe75c2012-10-23 10:25:10 +0200546/**************************
547**** Deflate algorithm ****
548***************************/
549
Willy Tarreau9f640a12015-03-28 15:46:00 +0100550static int deflate_init(struct comp_ctx **comp_ctx, int level)
William Lallemand82fe75c2012-10-23 10:25:10 +0200551{
William Lallemand8b52bb32012-11-16 18:06:41 +0100552 z_stream *strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200553
William Lallemand8b52bb32012-11-16 18:06:41 +0100554 if (init_comp_ctx(comp_ctx) < 0)
555 return -1;
556
557 strm = &(*comp_ctx)->strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200558
Willy Tarreau36878032016-12-22 19:46:17 +0100559 if (deflateInit2(strm, level, Z_DEFLATED, global_tune_zlibwindowsize, global_tune_zlibmemlevel, Z_DEFAULT_STRATEGY) != Z_OK) {
William Lallemand8b52bb32012-11-16 18:06:41 +0100560 deinit_comp_ctx(comp_ctx);
William Lallemand82fe75c2012-10-23 10:25:10 +0200561 return -1;
William Lallemand8b52bb32012-11-16 18:06:41 +0100562 }
563
564 (*comp_ctx)->cur_lvl = level;
William Lallemand82fe75c2012-10-23 10:25:10 +0200565
566 return 0;
567}
568
William Lallemandbf3ae612012-11-19 12:35:37 +0100569/* Return the size of consumed data or -1 */
Willy Tarreau9f640a12015-03-28 15:46:00 +0100570static int deflate_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out)
William Lallemand82fe75c2012-10-23 10:25:10 +0200571{
William Lallemand82fe75c2012-10-23 10:25:10 +0200572 int ret;
William Lallemandbf3ae612012-11-19 12:35:37 +0100573 z_stream *strm = &comp_ctx->strm;
574 char *out_data = bi_end(out);
575 int out_len = out->size - buffer_len(out);
William Lallemand82fe75c2012-10-23 10:25:10 +0200576
577 if (in_len <= 0)
578 return 0;
579
580
581 if (out_len <= 0)
582 return -1;
583
William Lallemand82fe75c2012-10-23 10:25:10 +0200584 strm->next_in = (unsigned char *)in_data;
585 strm->avail_in = in_len;
586 strm->next_out = (unsigned char *)out_data;
587 strm->avail_out = out_len;
588
589 ret = deflate(strm, Z_NO_FLUSH);
590 if (ret != Z_OK)
591 return -1;
592
593 /* deflate update the available data out */
William Lallemandbf3ae612012-11-19 12:35:37 +0100594 out->i += out_len - strm->avail_out;
William Lallemand82fe75c2012-10-23 10:25:10 +0200595
William Lallemandbf3ae612012-11-19 12:35:37 +0100596 return in_len - strm->avail_in;
William Lallemand82fe75c2012-10-23 10:25:10 +0200597}
598
Willy Tarreau9787efa2015-03-28 19:17:31 +0100599static int deflate_flush_or_finish(struct comp_ctx *comp_ctx, struct buffer *out, int flag)
William Lallemand82fe75c2012-10-23 10:25:10 +0200600{
601 int ret;
William Lallemand82fe75c2012-10-23 10:25:10 +0200602 int out_len = 0;
William Lallemand1c2d6222012-10-30 15:52:53 +0100603 z_stream *strm = &comp_ctx->strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200604
Willy Tarreaud8b8b532016-08-08 16:41:01 +0200605 strm->next_in = NULL;
606 strm->avail_in = 0;
William Lallemand82fe75c2012-10-23 10:25:10 +0200607 strm->next_out = (unsigned char *)bi_end(out);
608 strm->avail_out = out->size - buffer_len(out);
609
610 ret = deflate(strm, flag);
611 if (ret != Z_OK && ret != Z_STREAM_END)
612 return -1;
613
614 out_len = (out->size - buffer_len(out)) - strm->avail_out;
615 out->i += out_len;
616
William Lallemand072a2bf2012-11-20 17:01:01 +0100617 /* compression limit */
618 if ((global.comp_rate_lim > 0 && (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim)) || /* rate */
619 (idle_pct < compress_min_idle)) { /* idle */
620 /* decrease level */
621 if (comp_ctx->cur_lvl > 0) {
622 comp_ctx->cur_lvl--;
William Lallemandd85f9172012-11-09 17:05:39 +0100623 deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
624 }
William Lallemand072a2bf2012-11-20 17:01:01 +0100625
626 } else if (comp_ctx->cur_lvl < global.tune.comp_maxlevel) {
627 /* increase level */
628 comp_ctx->cur_lvl++ ;
629 deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
William Lallemandd85f9172012-11-09 17:05:39 +0100630 }
631
William Lallemand82fe75c2012-10-23 10:25:10 +0200632 return out_len;
633}
634
Willy Tarreau9787efa2015-03-28 19:17:31 +0100635static int deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out)
636{
637 return deflate_flush_or_finish(comp_ctx, out, Z_SYNC_FLUSH);
638}
639
640static int deflate_finish(struct comp_ctx *comp_ctx, struct buffer *out)
641{
642 return deflate_flush_or_finish(comp_ctx, out, Z_FINISH);
643}
644
Willy Tarreau9f640a12015-03-28 15:46:00 +0100645static int deflate_end(struct comp_ctx **comp_ctx)
William Lallemand82fe75c2012-10-23 10:25:10 +0200646{
William Lallemand8b52bb32012-11-16 18:06:41 +0100647 z_stream *strm = &(*comp_ctx)->strm;
648 int ret;
William Lallemand82fe75c2012-10-23 10:25:10 +0200649
William Lallemand8b52bb32012-11-16 18:06:41 +0100650 ret = deflateEnd(strm);
William Lallemand82fe75c2012-10-23 10:25:10 +0200651
William Lallemand8b52bb32012-11-16 18:06:41 +0100652 deinit_comp_ctx(comp_ctx);
653
654 return ret;
William Lallemand82fe75c2012-10-23 10:25:10 +0200655}
656
Willy Tarreau36878032016-12-22 19:46:17 +0100657/* config parser for global "tune.zlibmemlevel" */
658static int zlib_parse_global_memlevel(char **args, int section_type, struct proxy *curpx,
659 struct proxy *defpx, const char *file, int line,
660 char **err)
661{
662 if (too_many_args(1, args, err, NULL))
663 return -1;
664
665 if (*(args[1]) == 0) {
666 memprintf(err, "'%s' expects a numeric value between 1 and 9.", args[0]);
667 return -1;
668 }
669
670 global_tune_zlibmemlevel = atoi(args[1]);
671 if (global_tune_zlibmemlevel < 1 || global_tune_zlibmemlevel > 9) {
672 memprintf(err, "'%s' expects a numeric value between 1 and 9.", args[0]);
673 return -1;
674 }
675 return 0;
676}
677
678
679/* config parser for global "tune.zlibwindowsize" */
680static int zlib_parse_global_windowsize(char **args, int section_type, struct proxy *curpx,
681 struct proxy *defpx, const char *file, int line,
682 char **err)
683{
684 if (too_many_args(1, args, err, NULL))
685 return -1;
686
687 if (*(args[1]) == 0) {
688 memprintf(err, "'%s' expects a numeric value between 8 and 15.", args[0]);
689 return -1;
690 }
691
692 global_tune_zlibwindowsize = atoi(args[1]);
693 if (global_tune_zlibwindowsize < 8 || global_tune_zlibwindowsize > 15) {
694 memprintf(err, "'%s' expects a numeric value between 8 and 15.", args[0]);
695 return -1;
696 }
697 return 0;
698}
699
William Lallemand82fe75c2012-10-23 10:25:10 +0200700#endif /* USE_ZLIB */
701
Willy Tarreau36878032016-12-22 19:46:17 +0100702
703/* config keyword parsers */
704static struct cfg_kw_list cfg_kws = {ILH, {
705#ifdef USE_ZLIB
706 { CFG_GLOBAL, "tune.zlib.memlevel", zlib_parse_global_memlevel },
707 { CFG_GLOBAL, "tune.zlib.windowsize", zlib_parse_global_windowsize },
708#endif
709 { 0, NULL, NULL }
710}};
711
William Lallemand727db8b2013-04-20 17:33:20 +0200712__attribute__((constructor))
713static void __comp_fetch_init(void)
714{
Willy Tarreaub97c6fb2016-12-21 19:30:30 +0100715 char *ptr = NULL;
716 int i;
717
Willy Tarreau418b8c02015-03-29 03:32:06 +0200718#ifdef USE_SLZ
719 slz_make_crc_table();
720 slz_prepare_dist_table();
721#endif
Willy Tarreau36878032016-12-22 19:46:17 +0100722#if defined(USE_ZLIB) && defined(DEFAULT_MAXZLIBMEM)
723 global.tune.maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U,
724#endif
Willy Tarreaub97c6fb2016-12-21 19:30:30 +0100725#ifdef USE_ZLIB
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100726 HA_SPIN_INIT(&comp_pool_lock);
Willy Tarreaub97c6fb2016-12-21 19:30:30 +0100727 memprintf(&ptr, "Built with zlib version : " ZLIB_VERSION);
728 memprintf(&ptr, "%s\nRunning on zlib version : %s", ptr, zlibVersion());
729#elif defined(USE_SLZ)
730 memprintf(&ptr, "Built with libslz for stateless compression.");
Lukas Tribusb7323212017-01-11 14:24:35 +0000731#else
732 memprintf(&ptr, "Built without compression support (neither USE_ZLIB nor USE_SLZ are set).");
Willy Tarreaub97c6fb2016-12-21 19:30:30 +0100733#endif
734 memprintf(&ptr, "%s\nCompression algorithms supported :", ptr);
735
736 for (i = 0; comp_algos[i].cfg_name; i++)
737 memprintf(&ptr, "%s%s %s(\"%s\")", ptr, (i == 0 ? "" : ","), comp_algos[i].cfg_name, comp_algos[i].ua_name);
738
739 if (i == 0)
740 memprintf(&ptr, "%s none", ptr);
741
742 hap_register_build_opts(ptr, 1);
Willy Tarreau36878032016-12-22 19:46:17 +0100743 cfg_register_keywords(&cfg_kws);
William Lallemand727db8b2013-04-20 17:33:20 +0200744}