MEDIUM: compression: add a distinction between UA- and config- algorithms

Thanks to MSIE/IIS, the "deflate" name is ambigous. According to the RFC
it's a zlib-wrapped deflate stream, but IIS used to send only a raw deflate
stream, which is the only format MSIE understands for "deflate". The other
widely used browsers do support both formats. For this reason some people
prefer to emit a raw deflate stream on "deflate" to serve more users even
it that means violating the standards. Haproxy only follows the standard,
so they cannot do this.

This patch makes it possible to have one algorithm name in the configuration
and another one in the protocol. This will make it possible to have a new
configuration token to add a different algorithm so that users can decide if
they want a raw deflate or the standard one.
This commit is contained in:
Willy Tarreau 2015-03-28 16:40:46 +01:00
parent 9f640a1eab
commit 615105e7e8
4 changed files with 27 additions and 17 deletions

View File

@ -47,9 +47,19 @@ struct comp_ctx {
int cur_lvl;
};
/* Thanks to MSIE/IIS, the "deflate" name is ambigous, 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
* "deflate" and we'll need two algos for the same name, they are distinguished
* with the config name.
*/
struct comp_algo {
char *name;
int name_len;
char *cfg_name; /* config name */
int cfg_name_len;
char *ua_name; /* name for the user-agent */
int ua_name_len;
int (*init)(struct comp_ctx **comp_ctx, int level);
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 flag);

View File

@ -73,12 +73,12 @@ static int deflate_end(struct comp_ctx **comp_ctx);
const struct comp_algo comp_algos[] =
{
{ "identity", 8, identity_init, identity_add_data, identity_flush, identity_reset, identity_end },
{ "identity", 8, "identity", 8, identity_init, identity_add_data, identity_flush, identity_reset, identity_end },
#ifdef USE_ZLIB
{ "deflate", 7, deflate_init, deflate_add_data, deflate_flush, deflate_reset, deflate_end },
{ "gzip", 4, gzip_init, deflate_add_data, deflate_flush, deflate_reset, deflate_end },
{ "deflate", 7, "deflate", 7, deflate_init, deflate_add_data, deflate_flush, deflate_reset, deflate_end },
{ "gzip", 4, "gzip", 4, gzip_init, deflate_add_data, deflate_flush, deflate_reset, deflate_end },
#endif /* USE_ZLIB */
{ NULL, 0, NULL , NULL, NULL, NULL, NULL }
{ NULL, 0, NULL, 0, NULL , NULL, NULL, NULL, NULL }
};
/*
@ -104,8 +104,8 @@ int comp_append_algo(struct comp *comp, const char *algo)
struct comp_algo *comp_algo;
int i;
for (i = 0; comp_algos[i].name; i++) {
if (!strcmp(algo, comp_algos[i].name)) {
for (i = 0; comp_algos[i].cfg_name; i++) {
if (!strcmp(algo, comp_algos[i].cfg_name)) {
comp_algo = calloc(1, sizeof(struct comp_algo));
memmove(comp_algo, &comp_algos[i], sizeof(struct comp_algo));
comp_algo->next = comp->algos;
@ -669,8 +669,8 @@ smp_fetch_res_comp_algo(struct proxy *px, struct session *l4, void *l7, unsigned
smp->type = SMP_T_STR;
smp->flags = SMP_F_CONST;
smp->data.str.str = l4->comp_algo->name;
smp->data.str.len = l4->comp_algo->name_len;
smp->data.str.str = l4->comp_algo->cfg_name;
smp->data.str.len = l4->comp_algo->cfg_name_len;
return 1;
}

View File

@ -262,8 +262,8 @@ void display_build_opts()
{
int i;
for (i = 0; comp_algos[i].name; i++) {
printf("%s %s", (i == 0 ? "" : ","), comp_algos[i].name);
for (i = 0; comp_algos[i].cfg_name; i++) {
printf("%s %s(\"%s\")", (i == 0 ? "" : ","), comp_algos[i].cfg_name, comp_algos[i].ua_name);
}
if (i == 0) {
printf("none");

View File

@ -2309,7 +2309,7 @@ int select_compression_request_header(struct session *s, struct buffer *req)
for (comp_algo = comp_algo_back; comp_algo; comp_algo = comp_algo->next) {
if (*(ctx.line + ctx.val) == '*' ||
word_match(ctx.line + ctx.val, toklen, comp_algo->name, comp_algo->name_len)) {
word_match(ctx.line + ctx.val, toklen, comp_algo->ua_name, comp_algo->ua_name_len)) {
s->comp_algo = comp_algo;
best_q = q;
break;
@ -2333,7 +2333,7 @@ int select_compression_request_header(struct session *s, struct buffer *req)
/* identity is implicit does not require headers */
if ((s->be->comp && (comp_algo_back = s->be->comp->algos)) || (s->fe->comp && (comp_algo_back = s->fe->comp->algos))) {
for (comp_algo = comp_algo_back; comp_algo; comp_algo = comp_algo->next) {
if (comp_algo->name_len == 8 && memcmp(comp_algo->name, "identity", 8) == 0) {
if (comp_algo->cfg_name_len == 8 && memcmp(comp_algo->cfg_name, "identity", 8) == 0) {
s->comp_algo = comp_algo;
return 1;
}
@ -2445,11 +2445,11 @@ int select_compression_response_header(struct session *s, struct buffer *res)
* Accept-Encoding header, and SHOULD NOT be used in the Content-Encoding
* header.
*/
if (s->comp_algo->name_len != 8 || memcmp(s->comp_algo->name, "identity", 8) != 0) {
if (s->comp_algo->cfg_name_len != 8 || memcmp(s->comp_algo->cfg_name, "identity", 8) != 0) {
trash.len = 18;
memcpy(trash.str, "Content-Encoding: ", trash.len);
memcpy(trash.str + trash.len, s->comp_algo->name, s->comp_algo->name_len);
trash.len += s->comp_algo->name_len;
memcpy(trash.str + trash.len, s->comp_algo->ua_name, s->comp_algo->ua_name_len);
trash.len += s->comp_algo->ua_name_len;
trash.str[trash.len] = '\0';
http_header_add_tail2(&txn->rsp, &txn->hdr_idx, trash.str, trash.len);
}