int cur_lvl;
};
+/* Content types passed to the algorithms' init() functions, so that they can
+ * adapt their encoding to the contents. Algorithms which don't make any
+ * difference simply ignore them.
+ */
+enum comp_ctype {
+ COMP_CT_GENERIC = 0, /* unknown or binary contents */
+ COMP_CT_TEXT = 1, /* "text/..." contents */
+};
+
/* Thanks to MSIE/IIS, the "deflate" name is ambiguous, as according to the RFC
* it's a zlib-wrapped deflate stream, but MSIE only understands a raw deflate
* stream. For this reason some people prefer to emit a raw deflate stream on
char *ua_name; /* name for the user-agent */
int ua_name_len;
- int (*init)(struct comp_ctx **comp_ctx, int level);
+ int (*init)(struct comp_ctx **comp_ctx, int level, int ctype);
int (*add_data)(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
int (*flush)(struct comp_ctx *comp_ctx, struct buffer *out);
int (*finish)(struct comp_ctx *comp_ctx, struct buffer *out);
unsigned int compress_min_idle = 0;
-static int comp_identity_init(struct comp_ctx **comp_ctx, int level);
+static int comp_identity_init(struct comp_ctx **comp_ctx, int level, int ctype);
static int comp_identity_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
static int comp_identity_flush(struct comp_ctx *comp_ctx, struct buffer *out);
static int comp_identity_finish(struct comp_ctx *comp_ctx, struct buffer *out);
#if defined(USE_SLZ)
-static int comp_rfc1950_init(struct comp_ctx **comp_ctx, int level);
-static int comp_rfc1951_init(struct comp_ctx **comp_ctx, int level);
-static int comp_rfc1952_init(struct comp_ctx **comp_ctx, int level);
+static int comp_rfc1950_init(struct comp_ctx **comp_ctx, int level, int ctype);
+static int comp_rfc1951_init(struct comp_ctx **comp_ctx, int level, int ctype);
+static int comp_rfc1952_init(struct comp_ctx **comp_ctx, int level, int ctype);
static int comp_rfc195x_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
static int comp_rfc195x_flush(struct comp_ctx *comp_ctx, struct buffer *out);
static int comp_rfc195x_finish(struct comp_ctx *comp_ctx, struct buffer *out);
#elif defined(USE_ZLIB)
-static int comp_gzip_init(struct comp_ctx **comp_ctx, int level);
-static int comp_raw_def_init(struct comp_ctx **comp_ctx, int level);
-static int comp_deflate_init(struct comp_ctx **comp_ctx, int level);
+static int comp_gzip_init(struct comp_ctx **comp_ctx, int level, int ctype);
+static int comp_raw_def_init(struct comp_ctx **comp_ctx, int level, int ctype);
+static int comp_deflate_init(struct comp_ctx **comp_ctx, int level, int ctype);
static int comp_deflate_add_data(struct comp_ctx *comp_ctx, const char *in_data, int in_len, struct buffer *out);
static int comp_deflate_flush(struct comp_ctx *comp_ctx, struct buffer *out);
static int comp_deflate_finish(struct comp_ctx *comp_ctx, struct buffer *out);
/*
* Init the identity algorithm
*/
-static int comp_identity_init(struct comp_ctx **comp_ctx, int level)
+static int comp_identity_init(struct comp_ctx **comp_ctx, int level, int ctype)
{
return 0;
}
#ifdef USE_SLZ
+/* Selects SLZ's content type matching <ctype> on the stream of <comp_ctx>
+ * after its init. libslz has no dedicated macro for the content types, but
+ * they come right after SLZ_MAX_OVERHEAD(), which is thus used to detect an
+ * older external libslz that doesn't support them, in which case the default
+ * encoding is always used.
+ */
+static inline void comp_slz_set_ctype(struct comp_ctx *comp_ctx, int ctype)
+{
+#if defined(SLZ_MAX_OVERHEAD)
+ if (ctype == COMP_CT_TEXT)
+ slz_set_content_type(&comp_ctx->strm, SLZ_CT_TEXT);
+#endif
+}
+
/* SLZ's gzip format (RFC1952). Returns < 0 on error. */
-static int comp_rfc1952_init(struct comp_ctx **comp_ctx, int level)
+static int comp_rfc1952_init(struct comp_ctx **comp_ctx, int level, int ctype)
{
if (init_comp_ctx(comp_ctx) < 0)
return -1;
(*comp_ctx)->cur_lvl = level;
- return slz_rfc1952_init(&(*comp_ctx)->strm, level);
+ if (slz_rfc1952_init(&(*comp_ctx)->strm, level) < 0)
+ return -1;
+ comp_slz_set_ctype(*comp_ctx, ctype);
+ return 0;
}
/* SLZ's raw deflate format (RFC1951). Returns < 0 on error. */
-static int comp_rfc1951_init(struct comp_ctx **comp_ctx, int level)
+static int comp_rfc1951_init(struct comp_ctx **comp_ctx, int level, int ctype)
{
if (init_comp_ctx(comp_ctx) < 0)
return -1;
(*comp_ctx)->cur_lvl = level;
- return slz_rfc1951_init(&(*comp_ctx)->strm, level);
+ if (slz_rfc1951_init(&(*comp_ctx)->strm, level) < 0)
+ return -1;
+ comp_slz_set_ctype(*comp_ctx, ctype);
+ return 0;
}
/* SLZ's zlib format (RFC1950). Returns < 0 on error. */
-static int comp_rfc1950_init(struct comp_ctx **comp_ctx, int level)
+static int comp_rfc1950_init(struct comp_ctx **comp_ctx, int level, int ctype)
{
if (init_comp_ctx(comp_ctx) < 0)
return -1;
(*comp_ctx)->cur_lvl = level;
- return slz_rfc1950_init(&(*comp_ctx)->strm, level);
+ if (slz_rfc1950_init(&(*comp_ctx)->strm, level) < 0)
+ return -1;
+ comp_slz_set_ctype(*comp_ctx, ctype);
+ return 0;
}
/* Return the size of consumed data. The caller is responsible for guaranteeing
/**************************
**** gzip algorithm ****
***************************/
-static int comp_gzip_init(struct comp_ctx **comp_ctx, int level)
+static int comp_gzip_init(struct comp_ctx **comp_ctx, int level, int ctype)
{
z_stream *strm;
}
/* Raw deflate algorithm */
-static int comp_raw_def_init(struct comp_ctx **comp_ctx, int level)
+static int comp_raw_def_init(struct comp_ctx **comp_ctx, int level, int ctype)
{
z_stream *strm;
**** Deflate algorithm ****
***************************/
-static int comp_deflate_init(struct comp_ctx **comp_ctx, int level)
+static int comp_deflate_init(struct comp_ctx **comp_ctx, int level, int ctype)
{
z_stream *strm;
struct http_hdr_ctx ctx;
struct comp_type *comp_type;
unsigned int comp_minsize = 0;
+ int ctype = COMP_CT_GENERIC;
ctx.blk = NULL;
/* Already compressed, don't bother */
*/
ctx.blk = NULL;
if (http_find_header(htx, ist("Content-Type"), &ctx, 1)) {
+ /* text contents may be encoded differently by the algorithm */
+ if (ctx.value.len >= 5 && strncasecmp("text/", ctx.value.ptr, 5) == 0)
+ ctype = COMP_CT_TEXT;
+
if ((s->be->comp && (comp_type = s->be->comp->types_req)) ||
(strm_fe(s)->comp && (comp_type = strm_fe(s)->comp->types_req))) {
for (; comp_type; comp_type = comp_type->next) {
goto fail; /* no algo selected: nothing to do */
/* initialize compression */
- if (st->comp_algo->init(&st->comp_ctx, global.tune.comp_maxlevel) < 0)
+ if (st->comp_algo->init(&st->comp_ctx, global.tune.comp_maxlevel, ctype) < 0)
goto fail;
return;
struct http_hdr_ctx ctx;
struct comp_type *comp_type;
unsigned int comp_minsize = 0;
+ int ctype = COMP_CT_GENERIC;
/* no common compression algorithm was found in request header */
if (st->comp_algo == NULL)
if (ctx.value.len >= 9 && strncasecmp("multipart", ctx.value.ptr, 9) == 0)
goto fail;
+ /* text contents may be encoded differently by the algorithm */
+ if (ctx.value.len >= 5 && strncasecmp("text/", ctx.value.ptr, 5) == 0)
+ ctype = COMP_CT_TEXT;
+
if ((s->be->comp && (comp_type = s->be->comp->types_res)) ||
(strm_fe(s)->comp && (comp_type = strm_fe(s)->comp->types_res))) {
for (; comp_type; comp_type = comp_type->next) {
goto fail;
/* initialize compression */
- if (st->comp_algo->init(&st->comp_ctx, global.tune.comp_maxlevel) < 0)
+ if (st->comp_algo->init(&st->comp_ctx, global.tune.comp_maxlevel, ctype) < 0)
goto fail;
msg->flags |= HTTP_MSGF_COMPRESSING;
return 1;
goto end;
}
- if (proxy->comp->algos_res->init(&ctx, 9) == 0)
+ if (proxy->comp->algos_res->init(&ctx, 9, COMP_CT_GENERIC) == 0)
proxy->comp->algos_res->end(&ctx);
else {
memprintf(err, "'%s' : Can't init '%s' algorithm.",
goto end;
}
- if (proxy->comp->algo_req->init(&ctx, 9) == 0)
+ if (proxy->comp->algo_req->init(&ctx, 9, COMP_CT_GENERIC) == 0)
proxy->comp->algo_req->end(&ctx);
else {
memprintf(err, "'%s' : Can't init '%s' algorithm.",