blob: 911d0ac5aa5df8112a1209908c6e45496c49b86f [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 Tarreau12840be2021-04-22 14:14:22 +020016#if defined(USE_ZLIB)
Willy Tarreau34763642012-10-26 15:05:35 +020017/* Note: the crappy zlib and openssl libs both define the "free_func" type.
18 * That's a very clever idea to use such a generic name in general purpose
19 * libraries, really... The zlib one is easier to redefine than openssl's,
20 * so let's only fix this one.
21 */
22#define free_func zlib_free_func
William Lallemand82fe75c2012-10-23 10:25:10 +020023#include <zlib.h>
Willy Tarreau34763642012-10-26 15:05:35 +020024#undef free_func
William Lallemand08289f12012-10-31 11:19:18 +010025#endif /* USE_ZLIB */
William Lallemand82fe75c2012-10-23 10:25:10 +020026
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020027#include <haproxy/api.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020028#include <haproxy/cfgparse.h>
Willy Tarreau0a3bd392020-06-04 08:52:38 +020029#include <haproxy/compression-t.h>
Willy Tarreau0a3bd392020-06-04 08:52:38 +020030#include <haproxy/compression.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020031#include <haproxy/dynbuf.h>
Willy Tarreau66347942020-06-01 12:18:08 +020032#include <haproxy/freq_ctr.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <haproxy/global.h>
34#include <haproxy/pool.h>
35#include <haproxy/stream.h>
36#include <haproxy/thread.h>
William Lallemand82fe75c2012-10-23 10:25:10 +020037
William Lallemand2b502472012-10-30 14:30:39 +010038
Willy Tarreaue5489742018-11-26 14:44:03 +010039#if defined(USE_ZLIB)
Willy Tarreau86abe442018-11-25 20:12:18 +010040__decl_spinlock(comp_pool_lock);
Emeric Brun11f58862017-11-07 11:57:54 +010041#endif
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +020042
William Lallemand2b502472012-10-30 14:30:39 +010043#ifdef USE_ZLIB
44
William Lallemand8b52bb32012-11-16 18:06:41 +010045static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size);
46static void free_zlib(void *opaque, void *ptr);
47
William Lallemand2b502472012-10-30 14:30:39 +010048/* zlib allocation */
Willy Tarreauff882702021-04-10 17:23:00 +020049static struct pool_head *zlib_pool_deflate_state __read_mostly = NULL;
50static struct pool_head *zlib_pool_window __read_mostly = NULL;
51static struct pool_head *zlib_pool_prev __read_mostly = NULL;
52static struct pool_head *zlib_pool_head __read_mostly = NULL;
53static struct pool_head *zlib_pool_pending_buf __read_mostly = NULL;
William Lallemand2b502472012-10-30 14:30:39 +010054
William Lallemande3a7d992012-11-20 11:25:20 +010055long zlib_used_memory = 0;
William Lallemand9d5f5482012-11-07 16:12:57 +010056
Willy Tarreau36878032016-12-22 19:46:17 +010057static int global_tune_zlibmemlevel = 8; /* zlib memlevel */
58static int global_tune_zlibwindowsize = MAX_WBITS; /* zlib window size */
59
William Lallemand2b502472012-10-30 14:30:39 +010060#endif
61
William Lallemand072a2bf2012-11-20 17:01:01 +010062unsigned int compress_min_idle = 0;
William Lallemand8b52bb32012-11-16 18:06:41 +010063
Willy Tarreau9f640a12015-03-28 15:46:00 +010064static int identity_init(struct comp_ctx **comp_ctx, int level);
65static 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 +010066static int identity_flush(struct comp_ctx *comp_ctx, struct buffer *out);
67static int identity_finish(struct comp_ctx *comp_ctx, struct buffer *out);
Willy Tarreau9f640a12015-03-28 15:46:00 +010068static int identity_end(struct comp_ctx **comp_ctx);
69
Willy Tarreau418b8c02015-03-29 03:32:06 +020070#if defined(USE_SLZ)
71
72static int rfc1950_init(struct comp_ctx **comp_ctx, int level);
73static int rfc1951_init(struct comp_ctx **comp_ctx, int level);
74static int rfc1952_init(struct comp_ctx **comp_ctx, int level);
75static int rfc195x_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
76static int rfc195x_flush(struct comp_ctx *comp_ctx, struct buffer *out);
77static int rfc195x_finish(struct comp_ctx *comp_ctx, struct buffer *out);
78static int rfc195x_end(struct comp_ctx **comp_ctx);
79
80#elif defined(USE_ZLIB)
Willy Tarreau7b218772015-03-28 22:08:25 +010081
Willy Tarreau9f640a12015-03-28 15:46:00 +010082static int gzip_init(struct comp_ctx **comp_ctx, int level);
Willy Tarreauc91840a2015-03-28 17:00:39 +010083static int raw_def_init(struct comp_ctx **comp_ctx, int level);
Willy Tarreau9f640a12015-03-28 15:46:00 +010084static int deflate_init(struct comp_ctx **comp_ctx, int level);
85static 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 +010086static int deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out);
87static int deflate_finish(struct comp_ctx *comp_ctx, struct buffer *out);
Willy Tarreau9f640a12015-03-28 15:46:00 +010088static int deflate_end(struct comp_ctx **comp_ctx);
Willy Tarreau7b218772015-03-28 22:08:25 +010089
Willy Tarreau9f640a12015-03-28 15:46:00 +010090#endif /* USE_ZLIB */
91
William Lallemand2b502472012-10-30 14:30:39 +010092
Cyril Bonté6162c432012-11-10 19:27:47 +010093const struct comp_algo comp_algos[] =
William Lallemand82fe75c2012-10-23 10:25:10 +020094{
Willy Tarreau7b218772015-03-28 22:08:25 +010095 { "identity", 8, "identity", 8, identity_init, identity_add_data, identity_flush, identity_finish, identity_end },
Willy Tarreau418b8c02015-03-29 03:32:06 +020096#if defined(USE_SLZ)
97 { "deflate", 7, "deflate", 7, rfc1950_init, rfc195x_add_data, rfc195x_flush, rfc195x_finish, rfc195x_end },
98 { "raw-deflate", 11, "deflate", 7, rfc1951_init, rfc195x_add_data, rfc195x_flush, rfc195x_finish, rfc195x_end },
99 { "gzip", 4, "gzip", 4, rfc1952_init, rfc195x_add_data, rfc195x_flush, rfc195x_finish, rfc195x_end },
100#elif defined(USE_ZLIB)
Willy Tarreau7b218772015-03-28 22:08:25 +0100101 { "deflate", 7, "deflate", 7, deflate_init, deflate_add_data, deflate_flush, deflate_finish, deflate_end },
102 { "raw-deflate", 11, "deflate", 7, raw_def_init, deflate_add_data, deflate_flush, deflate_finish, deflate_end },
103 { "gzip", 4, "gzip", 4, gzip_init, deflate_add_data, deflate_flush, deflate_finish, deflate_end },
William Lallemand82fe75c2012-10-23 10:25:10 +0200104#endif /* USE_ZLIB */
Willy Tarreau615105e2015-03-28 16:40:46 +0100105 { NULL, 0, NULL, 0, NULL , NULL, NULL, NULL, NULL }
William Lallemand82fe75c2012-10-23 10:25:10 +0200106};
107
108/*
109 * Add a content-type in the configuration
110 */
111int comp_append_type(struct comp *comp, const char *type)
112{
113 struct comp_type *comp_type;
114
Vincent Bernat02779b62016-04-03 13:48:43 +0200115 comp_type = calloc(1, sizeof(*comp_type));
William Lallemand82fe75c2012-10-23 10:25:10 +0200116 comp_type->name_len = strlen(type);
117 comp_type->name = strdup(type);
118 comp_type->next = comp->types;
119 comp->types = comp_type;
120 return 0;
121}
122
123/*
124 * Add an algorithm in the configuration
125 */
126int comp_append_algo(struct comp *comp, const char *algo)
127{
128 struct comp_algo *comp_algo;
129 int i;
130
Willy Tarreau615105e2015-03-28 16:40:46 +0100131 for (i = 0; comp_algos[i].cfg_name; i++) {
Tim Duesterhuse5ff1412021-01-02 22:31:53 +0100132 if (strcmp(algo, comp_algos[i].cfg_name) == 0) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200133 comp_algo = calloc(1, sizeof(*comp_algo));
William Lallemand82fe75c2012-10-23 10:25:10 +0200134 memmove(comp_algo, &comp_algos[i], sizeof(struct comp_algo));
135 comp_algo->next = comp->algos;
136 comp->algos = comp_algo;
137 return 0;
138 }
139 }
140 return -1;
141}
142
Willy Tarreaue1cc4b52016-08-10 21:17:06 +0200143#if defined(USE_ZLIB) || defined(USE_SLZ)
Willy Tarreau8ceae722018-11-26 11:58:30 +0100144DECLARE_STATIC_POOL(pool_comp_ctx, "comp_ctx", sizeof(struct comp_ctx));
145
William Lallemand8b52bb32012-11-16 18:06:41 +0100146/*
147 * Alloc the comp_ctx
148 */
149static inline int init_comp_ctx(struct comp_ctx **comp_ctx)
150{
151#ifdef USE_ZLIB
152 z_stream *strm;
153
William Lallemande3a7d992012-11-20 11:25:20 +0100154 if (global.maxzlibmem > 0 && (global.maxzlibmem - zlib_used_memory) < sizeof(struct comp_ctx))
William Lallemand8b52bb32012-11-16 18:06:41 +0100155 return -1;
156#endif
157
Willy Tarreaubafbe012017-11-24 17:34:44 +0100158 *comp_ctx = pool_alloc(pool_comp_ctx);
William Lallemand8b52bb32012-11-16 18:06:41 +0100159 if (*comp_ctx == NULL)
160 return -1;
Willy Tarreau418b8c02015-03-29 03:32:06 +0200161#if defined(USE_SLZ)
162 (*comp_ctx)->direct_ptr = NULL;
163 (*comp_ctx)->direct_len = 0;
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200164 (*comp_ctx)->queued = BUF_NULL;
Willy Tarreau418b8c02015-03-29 03:32:06 +0200165#elif defined(USE_ZLIB)
Olivier Houchard43da3432019-03-08 18:50:27 +0100166 _HA_ATOMIC_ADD(&zlib_used_memory, sizeof(struct comp_ctx));
167 __ha_barrier_atomic_store();
William Lallemand8b52bb32012-11-16 18:06:41 +0100168
169 strm = &(*comp_ctx)->strm;
170 strm->zalloc = alloc_zlib;
171 strm->zfree = free_zlib;
172 strm->opaque = *comp_ctx;
173#endif
174 return 0;
175}
176
177/*
178 * Dealloc the comp_ctx
179 */
180static inline int deinit_comp_ctx(struct comp_ctx **comp_ctx)
181{
182 if (!*comp_ctx)
183 return 0;
184
Willy Tarreaubafbe012017-11-24 17:34:44 +0100185 pool_free(pool_comp_ctx, *comp_ctx);
William Lallemand8b52bb32012-11-16 18:06:41 +0100186 *comp_ctx = NULL;
187
188#ifdef USE_ZLIB
Olivier Houchard43da3432019-03-08 18:50:27 +0100189 _HA_ATOMIC_SUB(&zlib_used_memory, sizeof(struct comp_ctx));
190 __ha_barrier_atomic_store();
William Lallemand8b52bb32012-11-16 18:06:41 +0100191#endif
William Lallemand8b52bb32012-11-16 18:06:41 +0100192 return 0;
193}
Willy Tarreaue1cc4b52016-08-10 21:17:06 +0200194#endif
William Lallemand8b52bb32012-11-16 18:06:41 +0100195
William Lallemand82fe75c2012-10-23 10:25:10 +0200196
197/****************************
198 **** Identity algorithm ****
199 ****************************/
200
201/*
202 * Init the identity algorithm
203 */
Willy Tarreau9f640a12015-03-28 15:46:00 +0100204static int identity_init(struct comp_ctx **comp_ctx, int level)
William Lallemand82fe75c2012-10-23 10:25:10 +0200205{
206 return 0;
207}
208
209/*
210 * Process data
William Lallemandbf3ae612012-11-19 12:35:37 +0100211 * Return size of consumed data or -1 on error
William Lallemand82fe75c2012-10-23 10:25:10 +0200212 */
Willy Tarreau9f640a12015-03-28 15:46:00 +0100213static 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 +0200214{
Willy Tarreau8f9c72d2018-06-07 18:46:28 +0200215 char *out_data = b_tail(out);
Willy Tarreaueac52592018-06-15 13:59:36 +0200216 int out_len = b_room(out);
William Lallemandbf3ae612012-11-19 12:35:37 +0100217
William Lallemand82fe75c2012-10-23 10:25:10 +0200218 if (out_len < in_len)
219 return -1;
220
221 memcpy(out_data, in_data, in_len);
222
Olivier Houchardacd14032018-06-28 18:17:23 +0200223 b_add(out, in_len);
William Lallemandbf3ae612012-11-19 12:35:37 +0100224
William Lallemand82fe75c2012-10-23 10:25:10 +0200225 return in_len;
226}
227
Willy Tarreau9787efa2015-03-28 19:17:31 +0100228static int identity_flush(struct comp_ctx *comp_ctx, struct buffer *out)
William Lallemand82fe75c2012-10-23 10:25:10 +0200229{
230 return 0;
231}
232
Willy Tarreau9787efa2015-03-28 19:17:31 +0100233static int identity_finish(struct comp_ctx *comp_ctx, struct buffer *out)
234{
235 return 0;
236}
237
Willy Tarreau418b8c02015-03-29 03:32:06 +0200238/*
239 * Deinit the algorithm
240 */
241static int identity_end(struct comp_ctx **comp_ctx)
William Lallemand82fe75c2012-10-23 10:25:10 +0200242{
243 return 0;
244}
245
Willy Tarreau418b8c02015-03-29 03:32:06 +0200246
247#ifdef USE_SLZ
248
249/* SLZ's gzip format (RFC1952). Returns < 0 on error. */
250static int rfc1952_init(struct comp_ctx **comp_ctx, int level)
251{
252 if (init_comp_ctx(comp_ctx) < 0)
253 return -1;
254
255 (*comp_ctx)->cur_lvl = !!level;
256 return slz_rfc1952_init(&(*comp_ctx)->strm, !!level);
257}
258
259/* SLZ's raw deflate format (RFC1951). Returns < 0 on error. */
260static int rfc1951_init(struct comp_ctx **comp_ctx, int level)
261{
262 if (init_comp_ctx(comp_ctx) < 0)
263 return -1;
264
265 (*comp_ctx)->cur_lvl = !!level;
266 return slz_rfc1951_init(&(*comp_ctx)->strm, !!level);
267}
268
269/* SLZ's zlib format (RFC1950). Returns < 0 on error. */
270static int rfc1950_init(struct comp_ctx **comp_ctx, int level)
271{
272 if (init_comp_ctx(comp_ctx) < 0)
273 return -1;
274
275 (*comp_ctx)->cur_lvl = !!level;
276 return slz_rfc1950_init(&(*comp_ctx)->strm, !!level);
277}
278
279/* Return the size of consumed data or -1. The output buffer is unused at this
280 * point, we only keep a reference to the input data or a copy of them if the
281 * reference is already used.
William Lallemand82fe75c2012-10-23 10:25:10 +0200282 */
Willy Tarreau418b8c02015-03-29 03:32:06 +0200283static 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 +0200284{
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200285 static THREAD_LOCAL struct buffer tmpbuf = BUF_NULL;
Willy Tarreau418b8c02015-03-29 03:32:06 +0200286
287 if (in_len <= 0)
288 return 0;
289
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200290 if (comp_ctx->direct_ptr && b_is_null(&comp_ctx->queued)) {
Willy Tarreau418b8c02015-03-29 03:32:06 +0200291 /* data already being pointed to, we're in front of fragmented
292 * data and need a buffer now. We reuse the same buffer, as it's
293 * not used out of the scope of a series of add_data()*, end().
294 */
Willy Tarreau862ad822021-03-22 16:16:22 +0100295 if (b_alloc(&tmpbuf) == NULL)
296 return -1; /* no memory */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200297 b_reset(&tmpbuf);
298 memcpy(b_tail(&tmpbuf), comp_ctx->direct_ptr, comp_ctx->direct_len);
299 b_add(&tmpbuf, comp_ctx->direct_len);
Willy Tarreau418b8c02015-03-29 03:32:06 +0200300 comp_ctx->direct_ptr = NULL;
301 comp_ctx->direct_len = 0;
302 comp_ctx->queued = tmpbuf;
303 /* fall through buffer copy */
304 }
305
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200306 if (!b_is_null(&comp_ctx->queued)) {
Willy Tarreau418b8c02015-03-29 03:32:06 +0200307 /* data already pending */
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200308 memcpy(b_tail(&comp_ctx->queued), in_data, in_len);
309 b_add(&comp_ctx->queued, in_len);
Willy Tarreau418b8c02015-03-29 03:32:06 +0200310 return in_len;
311 }
312
313 comp_ctx->direct_ptr = in_data;
314 comp_ctx->direct_len = in_len;
315 return in_len;
316}
317
318/* Compresses the data accumulated using add_data(), and optionally sends the
319 * format-specific trailer if <finish> is non-null. <out> is expected to have a
320 * large enough free non-wrapping space as verified by http_comp_buffer_init().
321 * The number of bytes emitted is reported.
322 */
323static int rfc195x_flush_or_finish(struct comp_ctx *comp_ctx, struct buffer *out, int finish)
324{
325 struct slz_stream *strm = &comp_ctx->strm;
326 const char *in_ptr;
327 int in_len;
328 int out_len;
329
330 in_ptr = comp_ctx->direct_ptr;
331 in_len = comp_ctx->direct_len;
332
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200333 if (!b_is_null(&comp_ctx->queued)) {
334 in_ptr = b_head(&comp_ctx->queued);
335 in_len = b_data(&comp_ctx->queued);
Willy Tarreau418b8c02015-03-29 03:32:06 +0200336 }
337
Olivier Houchard0b662842018-06-29 18:16:31 +0200338 out_len = b_data(out);
Willy Tarreau418b8c02015-03-29 03:32:06 +0200339
340 if (in_ptr)
Olivier Houchardacd14032018-06-28 18:17:23 +0200341 b_add(out, slz_encode(strm, b_tail(out), in_ptr, in_len, !finish));
Willy Tarreau418b8c02015-03-29 03:32:06 +0200342
343 if (finish)
Olivier Houchardacd14032018-06-28 18:17:23 +0200344 b_add(out, slz_finish(strm, b_tail(out)));
Willy Tarreau418b8c02015-03-29 03:32:06 +0200345
Olivier Houchard0b662842018-06-29 18:16:31 +0200346 out_len = b_data(out) - out_len;
Willy Tarreau418b8c02015-03-29 03:32:06 +0200347
348 /* very important, we must wipe the data we've just flushed */
349 comp_ctx->direct_len = 0;
350 comp_ctx->direct_ptr = NULL;
Willy Tarreauc9fa0482018-07-10 17:43:27 +0200351 comp_ctx->queued = BUF_NULL;
Willy Tarreau418b8c02015-03-29 03:32:06 +0200352
353 /* Verify compression rate limiting and CPU usage */
354 if ((global.comp_rate_lim > 0 && (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim)) || /* rate */
Willy Tarreau81036f22019-05-20 19:24:50 +0200355 (ti->idle_pct < compress_min_idle)) { /* idle */
Willy Tarreau418b8c02015-03-29 03:32:06 +0200356 if (comp_ctx->cur_lvl > 0)
357 strm->level = --comp_ctx->cur_lvl;
358 }
359 else if (comp_ctx->cur_lvl < global.tune.comp_maxlevel && comp_ctx->cur_lvl < 1) {
360 strm->level = ++comp_ctx->cur_lvl;
361 }
362
363 /* and that's all */
364 return out_len;
365}
366
367static int rfc195x_flush(struct comp_ctx *comp_ctx, struct buffer *out)
368{
369 return rfc195x_flush_or_finish(comp_ctx, out, 0);
370}
371
372static int rfc195x_finish(struct comp_ctx *comp_ctx, struct buffer *out)
373{
374 return rfc195x_flush_or_finish(comp_ctx, out, 1);
375}
376
377/* we just need to free the comp_ctx here, nothing was allocated */
378static int rfc195x_end(struct comp_ctx **comp_ctx)
379{
380 deinit_comp_ctx(comp_ctx);
William Lallemand82fe75c2012-10-23 10:25:10 +0200381 return 0;
382}
383
Willy Tarreau418b8c02015-03-29 03:32:06 +0200384#elif defined(USE_ZLIB) /* ! USE_SLZ */
William Lallemand82fe75c2012-10-23 10:25:10 +0200385
William Lallemand2b502472012-10-30 14:30:39 +0100386/*
387 * This is a tricky allocation function using the zlib.
388 * This is based on the allocation order in deflateInit2.
389 */
390static void *alloc_zlib(void *opaque, unsigned int items, unsigned int size)
391{
392 struct comp_ctx *ctx = opaque;
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200393 static THREAD_LOCAL char round = 0; /* order in deflateInit2 */
William Lallemand2b502472012-10-30 14:30:39 +0100394 void *buf = NULL;
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100395 struct pool_head *pool = NULL;
William Lallemand2b502472012-10-30 14:30:39 +0100396
William Lallemande3a7d992012-11-20 11:25:20 +0100397 if (global.maxzlibmem > 0 && (global.maxzlibmem - zlib_used_memory) < (long)(items * size))
William Lallemand9d5f5482012-11-07 16:12:57 +0100398 goto end;
William Lallemand9d5f5482012-11-07 16:12:57 +0100399
William Lallemand2b502472012-10-30 14:30:39 +0100400 switch (round) {
401 case 0:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200402 if (zlib_pool_deflate_state == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100403 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200404 if (zlib_pool_deflate_state == NULL)
405 zlib_pool_deflate_state = create_pool("zlib_state", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100406 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200407 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100408 pool = zlib_pool_deflate_state;
Willy Tarreaubafbe012017-11-24 17:34:44 +0100409 ctx->zlib_deflate_state = buf = pool_alloc(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100410 break;
411
412 case 1:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200413 if (zlib_pool_window == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100414 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200415 if (zlib_pool_window == NULL)
416 zlib_pool_window = create_pool("zlib_window", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100417 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200418 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100419 pool = zlib_pool_window;
Willy Tarreaubafbe012017-11-24 17:34:44 +0100420 ctx->zlib_window = buf = pool_alloc(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100421 break;
422
423 case 2:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200424 if (zlib_pool_prev == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100425 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200426 if (zlib_pool_prev == NULL)
427 zlib_pool_prev = create_pool("zlib_prev", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100428 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200429 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100430 pool = zlib_pool_prev;
Willy Tarreaubafbe012017-11-24 17:34:44 +0100431 ctx->zlib_prev = buf = pool_alloc(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100432 break;
433
434 case 3:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200435 if (zlib_pool_head == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100436 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200437 if (zlib_pool_head == NULL)
438 zlib_pool_head = create_pool("zlib_head", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100439 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200440 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100441 pool = zlib_pool_head;
Willy Tarreaubafbe012017-11-24 17:34:44 +0100442 ctx->zlib_head = buf = pool_alloc(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100443 break;
444
445 case 4:
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200446 if (zlib_pool_pending_buf == NULL) {
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100447 HA_SPIN_LOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200448 if (zlib_pool_pending_buf == NULL)
449 zlib_pool_pending_buf = create_pool("zlib_pending_buf", size * items, MEM_F_SHARED);
Christopher Faulet2a944ee2017-11-07 10:42:54 +0100450 HA_SPIN_UNLOCK(COMP_POOL_LOCK, &comp_pool_lock);
Christopher Faulet8ca3b4b2017-07-25 11:07:15 +0200451 }
Willy Tarreau4f31fc22014-12-24 18:07:55 +0100452 pool = zlib_pool_pending_buf;
Willy Tarreaubafbe012017-11-24 17:34:44 +0100453 ctx->zlib_pending_buf = buf = pool_alloc(pool);
William Lallemand2b502472012-10-30 14:30:39 +0100454 break;
455 }
Olivier Houchard43da3432019-03-08 18:50:27 +0100456 if (buf != NULL) {
457 _HA_ATOMIC_ADD(&zlib_used_memory, pool->size);
458 __ha_barrier_atomic_store();
459 }
William Lallemand9d5f5482012-11-07 16:12:57 +0100460
461end:
William Lallemand2b502472012-10-30 14:30:39 +0100462
Willy Tarreau46909852012-11-15 14:57:56 +0100463 /* deflateInit2() first allocates and checks the deflate_state, then if
464 * it succeeds, it allocates all other 4 areas at ones and checks them
465 * at the end. So we want to correctly count the rounds depending on when
466 * zlib is supposed to abort.
467 */
468 if (buf || round)
469 round = (round + 1) % 5;
William Lallemand2b502472012-10-30 14:30:39 +0100470 return buf;
471}
472
473static void free_zlib(void *opaque, void *ptr)
474{
475 struct comp_ctx *ctx = opaque;
Willy Tarreaub1fbd052012-11-10 17:49:37 +0100476 struct pool_head *pool = NULL;
William Lallemand2b502472012-10-30 14:30:39 +0100477
478 if (ptr == ctx->zlib_window)
William Lallemand9d5f5482012-11-07 16:12:57 +0100479 pool = zlib_pool_window;
William Lallemand2b502472012-10-30 14:30:39 +0100480 else if (ptr == ctx->zlib_deflate_state)
William Lallemand9d5f5482012-11-07 16:12:57 +0100481 pool = zlib_pool_deflate_state;
William Lallemand2b502472012-10-30 14:30:39 +0100482 else if (ptr == ctx->zlib_prev)
William Lallemand9d5f5482012-11-07 16:12:57 +0100483 pool = zlib_pool_prev;
William Lallemand2b502472012-10-30 14:30:39 +0100484 else if (ptr == ctx->zlib_head)
William Lallemand9d5f5482012-11-07 16:12:57 +0100485 pool = zlib_pool_head;
William Lallemand2b502472012-10-30 14:30:39 +0100486 else if (ptr == ctx->zlib_pending_buf)
William Lallemand9d5f5482012-11-07 16:12:57 +0100487 pool = zlib_pool_pending_buf;
Willy Tarreaud999a492020-06-14 07:50:18 +0200488 else {
489 // never matched, just to silence gcc
490 ABORT_NOW();
491 return;
492 }
William Lallemand2b502472012-10-30 14:30:39 +0100493
Willy Tarreaubafbe012017-11-24 17:34:44 +0100494 pool_free(pool, ptr);
Olivier Houchard43da3432019-03-08 18:50:27 +0100495 _HA_ATOMIC_SUB(&zlib_used_memory, pool->size);
496 __ha_barrier_atomic_store();
William Lallemand2b502472012-10-30 14:30:39 +0100497}
498
William Lallemand82fe75c2012-10-23 10:25:10 +0200499/**************************
500**** gzip algorithm ****
501***************************/
Willy Tarreau9f640a12015-03-28 15:46:00 +0100502static int gzip_init(struct comp_ctx **comp_ctx, int level)
William Lallemand82fe75c2012-10-23 10:25:10 +0200503{
William Lallemand8b52bb32012-11-16 18:06:41 +0100504 z_stream *strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200505
William Lallemand8b52bb32012-11-16 18:06:41 +0100506 if (init_comp_ctx(comp_ctx) < 0)
507 return -1;
William Lallemand9d5f5482012-11-07 16:12:57 +0100508
William Lallemand8b52bb32012-11-16 18:06:41 +0100509 strm = &(*comp_ctx)->strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200510
Willy Tarreau36878032016-12-22 19:46:17 +0100511 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 +0100512 deinit_comp_ctx(comp_ctx);
William Lallemand82fe75c2012-10-23 10:25:10 +0200513 return -1;
William Lallemand8b52bb32012-11-16 18:06:41 +0100514 }
515
516 (*comp_ctx)->cur_lvl = level;
William Lallemand82fe75c2012-10-23 10:25:10 +0200517
518 return 0;
519}
Willy Tarreauc91840a2015-03-28 17:00:39 +0100520
521/* Raw deflate algorithm */
522static int raw_def_init(struct comp_ctx **comp_ctx, int level)
523{
524 z_stream *strm;
525
526 if (init_comp_ctx(comp_ctx) < 0)
527 return -1;
528
529 strm = &(*comp_ctx)->strm;
530
Willy Tarreau36878032016-12-22 19:46:17 +0100531 if (deflateInit2(strm, level, Z_DEFLATED, -global_tune_zlibwindowsize, global_tune_zlibmemlevel, Z_DEFAULT_STRATEGY) != Z_OK) {
Willy Tarreauc91840a2015-03-28 17:00:39 +0100532 deinit_comp_ctx(comp_ctx);
533 return -1;
534 }
535
536 (*comp_ctx)->cur_lvl = level;
537 return 0;
538}
539
William Lallemand82fe75c2012-10-23 10:25:10 +0200540/**************************
541**** Deflate algorithm ****
542***************************/
543
Willy Tarreau9f640a12015-03-28 15:46:00 +0100544static int deflate_init(struct comp_ctx **comp_ctx, int level)
William Lallemand82fe75c2012-10-23 10:25:10 +0200545{
William Lallemand8b52bb32012-11-16 18:06:41 +0100546 z_stream *strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200547
William Lallemand8b52bb32012-11-16 18:06:41 +0100548 if (init_comp_ctx(comp_ctx) < 0)
549 return -1;
550
551 strm = &(*comp_ctx)->strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200552
Willy Tarreau36878032016-12-22 19:46:17 +0100553 if (deflateInit2(strm, level, Z_DEFLATED, global_tune_zlibwindowsize, global_tune_zlibmemlevel, Z_DEFAULT_STRATEGY) != Z_OK) {
William Lallemand8b52bb32012-11-16 18:06:41 +0100554 deinit_comp_ctx(comp_ctx);
William Lallemand82fe75c2012-10-23 10:25:10 +0200555 return -1;
William Lallemand8b52bb32012-11-16 18:06:41 +0100556 }
557
558 (*comp_ctx)->cur_lvl = level;
William Lallemand82fe75c2012-10-23 10:25:10 +0200559
560 return 0;
561}
562
William Lallemandbf3ae612012-11-19 12:35:37 +0100563/* Return the size of consumed data or -1 */
Willy Tarreau9f640a12015-03-28 15:46:00 +0100564static 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 +0200565{
William Lallemand82fe75c2012-10-23 10:25:10 +0200566 int ret;
William Lallemandbf3ae612012-11-19 12:35:37 +0100567 z_stream *strm = &comp_ctx->strm;
Willy Tarreau8f9c72d2018-06-07 18:46:28 +0200568 char *out_data = b_tail(out);
Willy Tarreaueac52592018-06-15 13:59:36 +0200569 int out_len = b_room(out);
William Lallemand82fe75c2012-10-23 10:25:10 +0200570
571 if (in_len <= 0)
572 return 0;
573
574
575 if (out_len <= 0)
576 return -1;
577
William Lallemand82fe75c2012-10-23 10:25:10 +0200578 strm->next_in = (unsigned char *)in_data;
579 strm->avail_in = in_len;
580 strm->next_out = (unsigned char *)out_data;
581 strm->avail_out = out_len;
582
583 ret = deflate(strm, Z_NO_FLUSH);
584 if (ret != Z_OK)
585 return -1;
586
587 /* deflate update the available data out */
Olivier Houchardacd14032018-06-28 18:17:23 +0200588 b_add(out, out_len - strm->avail_out);
William Lallemand82fe75c2012-10-23 10:25:10 +0200589
William Lallemandbf3ae612012-11-19 12:35:37 +0100590 return in_len - strm->avail_in;
William Lallemand82fe75c2012-10-23 10:25:10 +0200591}
592
Willy Tarreau9787efa2015-03-28 19:17:31 +0100593static int deflate_flush_or_finish(struct comp_ctx *comp_ctx, struct buffer *out, int flag)
William Lallemand82fe75c2012-10-23 10:25:10 +0200594{
595 int ret;
William Lallemand82fe75c2012-10-23 10:25:10 +0200596 int out_len = 0;
William Lallemand1c2d6222012-10-30 15:52:53 +0100597 z_stream *strm = &comp_ctx->strm;
William Lallemand82fe75c2012-10-23 10:25:10 +0200598
Willy Tarreaud8b8b532016-08-08 16:41:01 +0200599 strm->next_in = NULL;
600 strm->avail_in = 0;
Willy Tarreau8f9c72d2018-06-07 18:46:28 +0200601 strm->next_out = (unsigned char *)b_tail(out);
Willy Tarreaueac52592018-06-15 13:59:36 +0200602 strm->avail_out = b_room(out);
William Lallemand82fe75c2012-10-23 10:25:10 +0200603
604 ret = deflate(strm, flag);
605 if (ret != Z_OK && ret != Z_STREAM_END)
606 return -1;
607
Willy Tarreaueac52592018-06-15 13:59:36 +0200608 out_len = b_room(out) - strm->avail_out;
Olivier Houchardacd14032018-06-28 18:17:23 +0200609 b_add(out, out_len);
William Lallemand82fe75c2012-10-23 10:25:10 +0200610
William Lallemand072a2bf2012-11-20 17:01:01 +0100611 /* compression limit */
612 if ((global.comp_rate_lim > 0 && (read_freq_ctr(&global.comp_bps_out) > global.comp_rate_lim)) || /* rate */
Willy Tarreau81036f22019-05-20 19:24:50 +0200613 (ti->idle_pct < compress_min_idle)) { /* idle */
William Lallemand072a2bf2012-11-20 17:01:01 +0100614 /* decrease level */
615 if (comp_ctx->cur_lvl > 0) {
616 comp_ctx->cur_lvl--;
William Lallemandd85f9172012-11-09 17:05:39 +0100617 deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
618 }
William Lallemand072a2bf2012-11-20 17:01:01 +0100619
620 } else if (comp_ctx->cur_lvl < global.tune.comp_maxlevel) {
621 /* increase level */
622 comp_ctx->cur_lvl++ ;
623 deflateParams(&comp_ctx->strm, comp_ctx->cur_lvl, Z_DEFAULT_STRATEGY);
William Lallemandd85f9172012-11-09 17:05:39 +0100624 }
625
William Lallemand82fe75c2012-10-23 10:25:10 +0200626 return out_len;
627}
628
Willy Tarreau9787efa2015-03-28 19:17:31 +0100629static int deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out)
630{
631 return deflate_flush_or_finish(comp_ctx, out, Z_SYNC_FLUSH);
632}
633
634static int deflate_finish(struct comp_ctx *comp_ctx, struct buffer *out)
635{
636 return deflate_flush_or_finish(comp_ctx, out, Z_FINISH);
637}
638
Willy Tarreau9f640a12015-03-28 15:46:00 +0100639static int deflate_end(struct comp_ctx **comp_ctx)
William Lallemand82fe75c2012-10-23 10:25:10 +0200640{
William Lallemand8b52bb32012-11-16 18:06:41 +0100641 z_stream *strm = &(*comp_ctx)->strm;
642 int ret;
William Lallemand82fe75c2012-10-23 10:25:10 +0200643
William Lallemand8b52bb32012-11-16 18:06:41 +0100644 ret = deflateEnd(strm);
William Lallemand82fe75c2012-10-23 10:25:10 +0200645
William Lallemand8b52bb32012-11-16 18:06:41 +0100646 deinit_comp_ctx(comp_ctx);
647
648 return ret;
William Lallemand82fe75c2012-10-23 10:25:10 +0200649}
650
Willy Tarreau36878032016-12-22 19:46:17 +0100651/* config parser for global "tune.zlibmemlevel" */
652static int zlib_parse_global_memlevel(char **args, int section_type, struct proxy *curpx,
Willy Tarreau5a1c7282021-03-09 16:55:18 +0100653 const struct proxy *defpx, const char *file, int line,
Willy Tarreau36878032016-12-22 19:46:17 +0100654 char **err)
655{
656 if (too_many_args(1, args, err, NULL))
657 return -1;
658
659 if (*(args[1]) == 0) {
660 memprintf(err, "'%s' expects a numeric value between 1 and 9.", args[0]);
661 return -1;
662 }
663
664 global_tune_zlibmemlevel = atoi(args[1]);
665 if (global_tune_zlibmemlevel < 1 || global_tune_zlibmemlevel > 9) {
666 memprintf(err, "'%s' expects a numeric value between 1 and 9.", args[0]);
667 return -1;
668 }
669 return 0;
670}
671
672
673/* config parser for global "tune.zlibwindowsize" */
674static int zlib_parse_global_windowsize(char **args, int section_type, struct proxy *curpx,
Willy Tarreau5a1c7282021-03-09 16:55:18 +0100675 const struct proxy *defpx, const char *file, int line,
Willy Tarreau36878032016-12-22 19:46:17 +0100676 char **err)
677{
678 if (too_many_args(1, args, err, NULL))
679 return -1;
680
681 if (*(args[1]) == 0) {
682 memprintf(err, "'%s' expects a numeric value between 8 and 15.", args[0]);
683 return -1;
684 }
685
686 global_tune_zlibwindowsize = atoi(args[1]);
687 if (global_tune_zlibwindowsize < 8 || global_tune_zlibwindowsize > 15) {
688 memprintf(err, "'%s' expects a numeric value between 8 and 15.", args[0]);
689 return -1;
690 }
691 return 0;
692}
693
William Lallemand82fe75c2012-10-23 10:25:10 +0200694#endif /* USE_ZLIB */
695
Willy Tarreau36878032016-12-22 19:46:17 +0100696
697/* config keyword parsers */
698static struct cfg_kw_list cfg_kws = {ILH, {
699#ifdef USE_ZLIB
700 { CFG_GLOBAL, "tune.zlib.memlevel", zlib_parse_global_memlevel },
701 { CFG_GLOBAL, "tune.zlib.windowsize", zlib_parse_global_windowsize },
702#endif
703 { 0, NULL, NULL }
704}};
705
Willy Tarreau0108d902018-11-25 19:14:37 +0100706INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
707
William Lallemand727db8b2013-04-20 17:33:20 +0200708__attribute__((constructor))
709static void __comp_fetch_init(void)
710{
Willy Tarreau36878032016-12-22 19:46:17 +0100711#if defined(USE_ZLIB) && defined(DEFAULT_MAXZLIBMEM)
Willy Tarreau3bfcd102018-11-26 10:24:45 +0100712 global.maxzlibmem = DEFAULT_MAXZLIBMEM * 1024U * 1024U;
Willy Tarreau36878032016-12-22 19:46:17 +0100713#endif
Willy Tarreau80713382018-11-26 10:19:54 +0100714}
715
716static void comp_register_build_opts(void)
717{
718 char *ptr = NULL;
719 int i;
720
Willy Tarreaub97c6fb2016-12-21 19:30:30 +0100721#ifdef USE_ZLIB
722 memprintf(&ptr, "Built with zlib version : " ZLIB_VERSION);
723 memprintf(&ptr, "%s\nRunning on zlib version : %s", ptr, zlibVersion());
724#elif defined(USE_SLZ)
725 memprintf(&ptr, "Built with libslz for stateless compression.");
Lukas Tribusb7323212017-01-11 14:24:35 +0000726#else
727 memprintf(&ptr, "Built without compression support (neither USE_ZLIB nor USE_SLZ are set).");
Willy Tarreaub97c6fb2016-12-21 19:30:30 +0100728#endif
729 memprintf(&ptr, "%s\nCompression algorithms supported :", ptr);
730
731 for (i = 0; comp_algos[i].cfg_name; i++)
732 memprintf(&ptr, "%s%s %s(\"%s\")", ptr, (i == 0 ? "" : ","), comp_algos[i].cfg_name, comp_algos[i].ua_name);
733
734 if (i == 0)
735 memprintf(&ptr, "%s none", ptr);
736
737 hap_register_build_opts(ptr, 1);
William Lallemand727db8b2013-04-20 17:33:20 +0200738}
Willy Tarreau80713382018-11-26 10:19:54 +0100739
740INITCALL0(STG_REGISTER, comp_register_build_opts);