MINOR: compression: Improve the way Vary header is added

When a message is compressed, A "Vary" header is added with
"accept-encoding" value. However, a new header is always added, regardless
there is already a Vary header or not. In addition, if there is already a
Vary header, there is no check on values to be sure "accept-encoding" value
is not already there. So it is possible to have it twice.

To improve this part, we now test Vary header values and "accept-encoding"
is only added if it was not found. In addition, "accept-encoding" value is
appended to the last Vary header found, if any. Otherwise, a new header is
added.
This commit is contained in:
Christopher Faulet 2023-05-25 11:18:21 +02:00
parent c8bb9aeb07
commit 535dd920df
2 changed files with 141 additions and 3 deletions

View File

@ -59,6 +59,56 @@ server s1 {
} -repeat 2 -start
server s2 {
rxreq
expect req.url == "/vary/no-vary"
expect req.http.accept-encoding == "gzip"
txresp \
-hdr "Content-Type: text/plain" \
-bodylen 100
rxreq
expect req.url == "/vary/accept-encoding"
expect req.http.accept-encoding == "gzip"
txresp \
-hdr "Content-Type: text/plain" \
-hdr "Vary: Accept-Encoding" \
-bodylen 100
rxreq
expect req.url == "/vary/other"
expect req.http.accept-encoding == "gzip"
txresp \
-hdr "Content-Type: text/plain" \
-hdr "Vary: Other" \
-bodylen 100
rxreq
expect req.url == "/vary/accept-encoding-and-other"
expect req.http.accept-encoding == "gzip"
txresp \
-hdr "Content-Type: text/plain" \
-hdr "Vary: Accept-Encoding,Other" \
-bodylen 100
rxreq
expect req.url == "/vary/other-and-accept-encoding"
expect req.http.accept-encoding == "gzip"
txresp \
-hdr "Content-Type: text/plain" \
-hdr "Vary: Other,Accept-Encoding" \
-bodylen 100
rxreq
expect req.url == "/vary/empty"
expect req.http.accept-encoding == "gzip"
txresp \
-hdr "Content-Type: text/plain" \
-hdr "Vary: " \
-bodylen 100
} -start
haproxy h1 -conf {
global
# WT: limit false-positives causing "HTTP header incomplete" due to
@ -87,6 +137,16 @@ haproxy h1 -conf {
backend be-nothing
server www ${s1_addr}:${s1_port}
frontend fe-vary
bind "fd@${fe_vary}"
default_backend be-vary
backend be-vary
compression algo gzip
compression type text/plain
server www ${s2_addr}:${s2_port}
} -start
client c1 -connect ${h1_fe_gzip_sock} {
@ -189,3 +249,60 @@ client c2 -connect ${h1_fe_nothing_sock} {
expect resp.http.vary == "<undef>"
expect resp.bodylen == 100
} -run
client c3 -connect ${h1_fe_vary_sock} {
txreq -url "/vary/no-vary" \
-hdr "Accept-Encoding: gzip"
rxresp
expect resp.status == 200
expect resp.http.content-encoding == "gzip"
expect resp.http.vary == "Accept-Encoding"
gunzip
expect resp.bodylen == 100
txreq -url "/vary/accept-encoding" \
-hdr "Accept-Encoding: gzip"
rxresp
expect resp.status == 200
expect resp.http.content-encoding == "gzip"
expect resp.http.vary == "Accept-Encoding"
gunzip
expect resp.bodylen == 100
txreq -url "/vary/other" \
-hdr "Accept-Encoding: gzip"
rxresp
expect resp.status == 200
expect resp.http.content-encoding == "gzip"
expect resp.http.vary == "Other,Accept-Encoding"
gunzip
expect resp.bodylen == 100
txreq -url "/vary/accept-encoding-and-other" \
-hdr "Accept-Encoding: gzip"
rxresp
expect resp.status == 200
expect resp.http.content-encoding == "gzip"
expect resp.http.vary == "Accept-Encoding,Other"
gunzip
expect resp.bodylen == 100
txreq -url "/vary/other-and-accept-encoding" \
-hdr "Accept-Encoding: gzip"
rxresp
expect resp.status == 200
expect resp.http.content-encoding == "gzip"
expect resp.http.vary == "Other,Accept-Encoding"
gunzip
expect resp.bodylen == 100
txreq -url "/vary/empty" \
-hdr "Accept-Encoding: gzip"
rxresp
expect resp.status == 200
expect resp.http.content-encoding == "gzip"
expect resp.http.vary == "Accept-Encoding"
gunzip
expect resp.bodylen == 100
} -run

View File

@ -408,7 +408,7 @@ set_compression_header(struct comp_state *st, struct stream *s, struct http_msg
{
struct htx *htx = htxbuf(&msg->chn->buf);
struct htx_sl *sl;
struct http_hdr_ctx ctx;
struct http_hdr_ctx ctx, last_vary;
struct comp_algo *comp_algo;
int comp_index;
@ -454,8 +454,29 @@ set_compression_header(struct comp_state *st, struct stream *s, struct http_msg
}
}
if (!http_add_header(htx, ist("Vary"), ist("Accept-Encoding")))
goto error;
/* Add "Vary: Accept-Encoding" header but only if it is not found. */
ctx.blk = NULL;
last_vary.blk = NULL;
while (http_find_header(htx, ist("Vary"), &ctx, 0)) {
if (isteqi(ctx.value, ist("Accept-Encoding")))
break;
last_vary = ctx;
}
/* No "Accept-Encoding" value found. */
if (ctx.blk == NULL) {
if (last_vary.blk == NULL) {
/* No Vary header found at all. Add our header */
if (!http_add_header(htx, ist("Vary"), ist("Accept-Encoding")))
goto error;
}
else {
/* At least one Vary header found. Append the value to
* the last one.
*/
if (!http_append_header_value(htx, &last_vary, ist("Accept-Encoding")))
goto error;
}
}
/*
* Add Content-Encoding header when it's not identity encoding.