- Update haproxy download URL and hash - Add new patches Signed-off-by: Christian Lachner <gladiac@gmail.com>lilik-openwrt-22.03
@ -1,32 +0,0 @@ | |||||
commit 032cff38c24d8359dc575423a94d19b6ad8bf848 | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Mon Jun 17 11:44:47 2019 +0200 | |||||
BUG/MEDIUM: h2/htx: Update data length of the HTX when the cookie list is built | |||||
When an H2 request is converted into an HTX message, All cookie headers are | |||||
grouped into one, each value separated by a semicolon (;). To do so, we add the | |||||
header "cookie" with the first value and then we update the value by appending | |||||
other cookies. But during this operation, only the size of the HTX block is | |||||
updated. And not the data length of the whole HTX message. | |||||
It is an old bug and it seems to work by chance till now. But it may lead to | |||||
undefined behaviour by time to time. | |||||
This patch must be backported to 2.0 and 1.9 | |||||
(cherry picked from commit 0c6de00d7c842a682bba7586ef34fb10f69ec63c) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/h2.c b/src/h2.c | |||||
index 9681aca5..32c1ef16 100644 | |||||
--- a/src/h2.c | |||||
+++ b/src/h2.c | |||||
@@ -737,6 +737,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms | |||||
goto fail; | |||||
htx_set_blk_value_len(blk, tl); | |||||
+ htx->data += vl+2; | |||||
*(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';'; | |||||
*(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' '; | |||||
memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl); |
@ -0,0 +1,81 @@ | |||||
commit 1bd140ea3fab97ccd37adf9d0c106d52af9e53fa | |||||
Author: William Lallemand <wlallemand@haproxy.com> | |||||
Date: Mon Jul 1 10:56:15 2019 +0200 | |||||
BUG/MINOR: mworker/cli: don't output a \n before the response | |||||
When using a level lower than admin on the master CLI, a \n is output | |||||
before the response, this is caused by the response of the "operator" or | |||||
"user" that are sent before the actual command. | |||||
To fix this problem we introduce the flag APPCTX_CLI_ST1_NOLF which ask | |||||
a command response to not be followed by the final \n. | |||||
This patch made a special case with the command operator and user | |||||
followed by a - so they are not followed by \n. | |||||
This patch must be backported to 2.0 and 1.9. | |||||
(cherry picked from commit ad03288e6b28d816abb443cf8c6d984a72bb91a6) | |||||
Signed-off-by: William Lallemand <wlallemand@haproxy.org> | |||||
diff --git a/include/types/applet.h b/include/types/applet.h | |||||
index c9e02d17..1f3a4983 100644 | |||||
--- a/include/types/applet.h | |||||
+++ b/include/types/applet.h | |||||
@@ -50,6 +50,7 @@ struct applet { | |||||
#define APPCTX_CLI_ST1_PROMPT (1 << 0) | |||||
#define APPCTX_CLI_ST1_PAYLOAD (1 << 1) | |||||
+#define APPCTX_CLI_ST1_NOLF (1 << 2) | |||||
/* Context of a running applet. */ | |||||
struct appctx { | |||||
diff --git a/src/cli.c b/src/cli.c | |||||
index 44ddc7bf..9a9f80f9 100644 | |||||
--- a/src/cli.c | |||||
+++ b/src/cli.c | |||||
@@ -821,7 +821,7 @@ static void cli_io_handler(struct appctx *appctx) | |||||
prompt = "\n> "; | |||||
} | |||||
else { | |||||
- if (!(appctx->st1 & APPCTX_CLI_ST1_PAYLOAD)) | |||||
+ if (!(appctx->st1 & (APPCTX_CLI_ST1_PAYLOAD|APPCTX_CLI_ST1_NOLF))) | |||||
prompt = "\n"; | |||||
} | |||||
@@ -848,6 +848,8 @@ static void cli_io_handler(struct appctx *appctx) | |||||
/* switch state back to GETREQ to read next requests */ | |||||
appctx->st0 = CLI_ST_GETREQ; | |||||
+ /* reactivate the \n at the end of the response for the next command */ | |||||
+ appctx->st1 &= ~APPCTX_CLI_ST1_NOLF; | |||||
} | |||||
} | |||||
@@ -1442,6 +1444,10 @@ static int cli_parse_show_lvl(char **args, char *payload, struct appctx *appctx, | |||||
/* parse and set the CLI level dynamically */ | |||||
static int cli_parse_set_lvl(char **args, char *payload, struct appctx *appctx, void *private) | |||||
{ | |||||
+ /* this will ask the applet to not output a \n after the command */ | |||||
+ if (!strcmp(args[1], "-")) | |||||
+ appctx->st1 |= APPCTX_CLI_ST1_NOLF; | |||||
+ | |||||
if (!strcmp(args[0], "operator")) { | |||||
if (!cli_has_level(appctx, ACCESS_LVL_OPER)) { | |||||
return 1; | |||||
@@ -2097,11 +2103,11 @@ int pcli_parse_request(struct stream *s, struct channel *req, char **errmsg, int | |||||
if (pcli_has_level(s, ACCESS_LVL_ADMIN)) { | |||||
goto end; | |||||
} else if (pcli_has_level(s, ACCESS_LVL_OPER)) { | |||||
- ci_insert_line2(req, 0, "operator", strlen("operator")); | |||||
- ret += strlen("operator") + 2; | |||||
+ ci_insert_line2(req, 0, "operator -", strlen("operator -")); | |||||
+ ret += strlen("operator -") + 2; | |||||
} else if (pcli_has_level(s, ACCESS_LVL_USER)) { | |||||
- ci_insert_line2(req, 0, "user", strlen("user")); | |||||
- ret += strlen("user") + 2; | |||||
+ ci_insert_line2(req, 0, "user -", strlen("user -")); | |||||
+ ret += strlen("user -") + 2; | |||||
} | |||||
} | |||||
end: |
@ -0,0 +1,30 @@ | |||||
commit aa2ecea6f711f50192476b26a5b1d767108bd761 | |||||
Author: Olivier Houchard <ohouchard@haproxy.com> | |||||
Date: Fri Jun 28 14:10:33 2019 +0200 | |||||
BUG/MEDIUM: ssl: Don't attempt to set alpn if we're not using SSL. | |||||
Checks use ssl_sock_set_alpn() to set the ALPN if check-alpn is used, however | |||||
check-alpn failed to check if the connection was indeed using SSL, and thus, | |||||
would crash if check-alpn was used on a non-SSL connection. Fix this by | |||||
making sure the connection uses SSL before attempting to set the ALPN. | |||||
This should be backported to 2.0 and 1.9. | |||||
(cherry picked from commit e488ea865a433d93efcb14c0c602918070c6b208) | |||||
Signed-off-by: Willy Tarreau <w@1wt.eu> | |||||
diff --git a/src/ssl_sock.c b/src/ssl_sock.c | |||||
index 05240063..c9fffbec 100644 | |||||
--- a/src/ssl_sock.c | |||||
+++ b/src/ssl_sock.c | |||||
@@ -6411,6 +6411,9 @@ void ssl_sock_set_alpn(struct connection *conn, const unsigned char *alpn, int l | |||||
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation | |||||
struct ssl_sock_ctx *ctx = conn->xprt_ctx; | |||||
+ if (!ssl_sock_is_ssl(conn)) | |||||
+ return; | |||||
+ | |||||
SSL_set_alpn_protos(ctx->ssl, alpn, len); | |||||
#endif | |||||
} |
@ -1,32 +0,0 @@ | |||||
commit 5a8549e68225070d0b79cbbb9c5f791e103685e7 | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Mon Jun 17 13:36:06 2019 +0200 | |||||
BUG/MINOR: lua/htx: Make txn.req_req_* and txn.res_rep_* HTX aware | |||||
These bindings were not updated to support HTX streams. | |||||
This patch must be backported to 2.0 and 1.9. It fixes the issue #124. | |||||
(cherry picked from commit ea418748dd22331e9798cfd8f5e25b436cd577e3) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/hlua.c b/src/hlua.c | |||||
index 28abd083..32f0e8db 100644 | |||||
--- a/src/hlua.c | |||||
+++ b/src/hlua.c | |||||
@@ -5375,7 +5375,13 @@ __LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct hlua_txn *htxn, | |||||
if (!(re = regex_comp(reg, 1, 1, NULL))) | |||||
WILL_LJMP(luaL_argerror(L, 3, "invalid regex")); | |||||
- http_transform_header_str(htxn->s, msg, name, name_len, value, re, action); | |||||
+ if (IS_HTX_STRM(htxn->s)) { | |||||
+ struct htx *htx = htxbuf(&msg->chn->buf); | |||||
+ | |||||
+ htx_transform_header_str(htxn->s, msg->chn, htx, ist2(name, name_len), value, re, action); | |||||
+ } | |||||
+ else | |||||
+ http_transform_header_str(htxn->s, msg, name, name_len, value, re, action); | |||||
regex_free(re); | |||||
return 0; | |||||
} |
@ -0,0 +1,35 @@ | |||||
commit 9fa93f6220a374f724491fd781d44d31f307671f | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Fri Jun 28 17:41:42 2019 +0200 | |||||
BUG/MEDIUM: mux-h1: Always release H1C if a shutdown for writes was reported | |||||
We must take care of this when the stream is detached from the | |||||
connection. Otherwise, on the server side, the connexion is inserted in the list | |||||
of idle connections of the session. But when reused, because the shutdown for | |||||
writes was already catched, nothing is sent to the server and the session is | |||||
blocked with a freezed connection. | |||||
This patch must be backported to 2.0 and 1.9. It is related to the issue #136 | |||||
reported on Github. | |||||
(cherry picked from commit 3ac0f43020e1cd77198020201e4e482a1c2ef8ac) | |||||
Signed-off-by: Willy Tarreau <w@1wt.eu> | |||||
diff --git a/src/mux_h1.c b/src/mux_h1.c | |||||
index 3d2bd8b8..e497e6f6 100644 | |||||
--- a/src/mux_h1.c | |||||
+++ b/src/mux_h1.c | |||||
@@ -2192,9 +2192,9 @@ static void h1_detach(struct conn_stream *cs) | |||||
} | |||||
} | |||||
- /* We don't want to close right now unless the connection is in error */ | |||||
- if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN|H1C_F_UPG_H2C)) || | |||||
- (h1c->conn->flags & CO_FL_ERROR) || !h1c->conn->owner) | |||||
+ /* We don't want to close right now unless the connection is in error or shut down for writes */ | |||||
+ if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTDOWN|H1C_F_UPG_H2C)) || | |||||
+ (h1c->conn->flags & (CO_FL_ERROR|CO_FL_SOCK_WR_SH)) || !h1c->conn->owner) | |||||
h1_release(h1c); | |||||
else { | |||||
tasklet_wakeup(h1c->wait_event.tasklet); |
@ -1,29 +0,0 @@ | |||||
commit 661bfc3d0e1b7756db59d00d86e316f694cae3c6 | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Mon Jun 17 14:07:46 2019 +0200 | |||||
BUG/MINOR: mux-h1: Add the header connection in lower case in outgoing messages | |||||
When necessary, this header is directly added in outgoing messages by the H1 | |||||
multiplexer. Because there is no HTX conversion first, the header name is not | |||||
converserted to its lower case version. So, it must be added in lower case by | |||||
the multiplexer. | |||||
This patch must be backported to 2.0 and 1.9. | |||||
(cherry picked from commit a110ecbd843e156dd01c6ac581c735be5e240d5b) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/mux_h1.c b/src/mux_h1.c | |||||
index 317f1a55..21deb354 100644 | |||||
--- a/src/mux_h1.c | |||||
+++ b/src/mux_h1.c | |||||
@@ -1642,7 +1642,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun | |||||
/* There is no "Connection:" header and | |||||
* it the conn_mode must be | |||||
* processed. So do it */ | |||||
- n = ist("Connection"); | |||||
+ n = ist("connection"); | |||||
v = ist(""); | |||||
h1_process_output_conn_mode(h1s, h1m, &v); | |||||
if (v.len) { |
@ -0,0 +1,51 @@ | |||||
commit afc313e6cd4be32f3c3d212e875d4dbcef8a0c70 | |||||
Author: Willy Tarreau <w@1wt.eu> | |||||
Date: Mon Jul 1 07:51:29 2019 +0200 | |||||
BUG/MEDIUM: checks: unblock signals in external checks | |||||
As discussed in issue #140, processes are forked with signals blocked | |||||
resulting in haproxy's kill being ignored. This happens when the command | |||||
takes more time to complete than the configured check timeout or interval. | |||||
Just calling "sleep 30" every second makes the problem obvious. | |||||
The fix simply consists in unblocking the signals in the child after the | |||||
fork. It needs to be backported to all stable branches containing external | |||||
checks and where signals are blocked on startup. It's unclear when it | |||||
started, but the following config exhibits the issue : | |||||
global | |||||
external-check | |||||
listen www | |||||
bind :8001 | |||||
timeout client 5s | |||||
timeout server 5s | |||||
timeout connect 5s | |||||
option external-check | |||||
external-check command "$PWD/sleep10.sh" | |||||
server local 127.0.0.1:80 check inter 200 | |||||
$ cat sleep10.sh | |||||
#!/bin/sh | |||||
exec /bin/sleep 10 | |||||
The "sleep" processes keep accumulating for 10 seconds and stabilize | |||||
around 25 when the bug is present. Just issuing "killall sleep" has no | |||||
effect on them, and stopping haproxy leaves these processes behind. | |||||
(cherry picked from commit 2df8cad0fea2d1a4ca8dd58f384df3c3c3f5d7ee) | |||||
Signed-off-by: Willy Tarreau <w@1wt.eu> | |||||
diff --git a/src/checks.c b/src/checks.c | |||||
index c175a752..e31eb173 100644 | |||||
--- a/src/checks.c | |||||
+++ b/src/checks.c | |||||
@@ -1997,6 +1997,7 @@ static int connect_proc_chk(struct task *t) | |||||
environ = check->envp; | |||||
extchk_setenv(check, EXTCHK_HAPROXY_SERVER_CURCONN, ultoa_r(s->cur_sess, buf, sizeof(buf))); | |||||
+ haproxy_unblock_signals(); | |||||
execvp(px->check_command, check->argv); | |||||
ha_alert("Failed to exec process for external health check: %s. Aborting.\n", | |||||
strerror(errno)); |
@ -1,253 +0,0 @@ | |||||
commit eaf650083924a697cde3379703984c5e7a5ebd41 | |||||
Author: Tim Duesterhus <tim@bastelstu.be> | |||||
Date: Mon Jun 17 16:10:07 2019 +0200 | |||||
BUG/MEDIUM: compression: Set Vary: Accept-Encoding for compressed responses | |||||
Make HAProxy set the `Vary: Accept-Encoding` response header if it compressed | |||||
the server response. | |||||
Technically the `Vary` header SHOULD also be set for responses that would | |||||
normally be compressed based off the current configuration, but are not due | |||||
to a missing or invalid `Accept-Encoding` request header or due to the | |||||
maximum compression rate being exceeded. | |||||
Not setting the header in these cases does no real harm, though: An | |||||
uncompressed response might be returned by a Cache, even if a compressed | |||||
one could be retrieved from HAProxy. This increases the traffic to the end | |||||
user if the cache is unable to compress itself, but it saves another | |||||
roundtrip to HAProxy. | |||||
see the discussion on the mailing list: https://www.mail-archive.com/haproxy@formilux.org/msg34221.html | |||||
Message-ID: 20190617121708.GA2964@1wt.eu | |||||
A small issue remains: The User-Agent is not added to the `Vary` header, | |||||
despite being relevant to the response. Adding the User-Agent header would | |||||
make responses effectively uncacheable and it's unlikely to see a Mozilla/4 | |||||
in the wild in 2019. | |||||
Add a reg-test to ensure the behaviour as described in this commit message. | |||||
see issue #121 | |||||
Should be backported to all branches with compression (i.e. 1.6+). | |||||
(cherry picked from commit 721d686bd10dc6993859f9026ad907753d1d2064) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/reg-tests/compression/vary.vtc b/reg-tests/compression/vary.vtc | |||||
new file mode 100644 | |||||
index 00000000..0a060e4b | |||||
--- /dev/null | |||||
+++ b/reg-tests/compression/vary.vtc | |||||
@@ -0,0 +1,187 @@ | |||||
+varnishtest "Compression sets Vary header" | |||||
+ | |||||
+#REQUIRE_VERSION=1.9 | |||||
+#REQUIRE_OPTION=ZLIB|SLZ | |||||
+ | |||||
+feature ignore_unknown_macro | |||||
+ | |||||
+server s1 { | |||||
+ rxreq | |||||
+ expect req.url == "/plain/accept-encoding-gzip" | |||||
+ expect req.http.accept-encoding == "gzip" | |||||
+ txresp \ | |||||
+ -hdr "Content-Type: text/plain" \ | |||||
+ -bodylen 100 | |||||
+ | |||||
+ rxreq | |||||
+ expect req.url == "/plain/accept-encoding-invalid" | |||||
+ expect req.http.accept-encoding == "invalid" | |||||
+ txresp \ | |||||
+ -hdr "Content-Type: text/plain" \ | |||||
+ -bodylen 100 | |||||
+ | |||||
+ rxreq | |||||
+ expect req.url == "/plain/accept-encoding-null" | |||||
+ expect req.http.accept-encoding == "<undef>" | |||||
+ txresp \ | |||||
+ -hdr "Content-Type: text/plain" \ | |||||
+ -bodylen 100 | |||||
+ | |||||
+ rxreq | |||||
+ expect req.url == "/html/accept-encoding-gzip" | |||||
+ expect req.http.accept-encoding == "gzip" | |||||
+ txresp \ | |||||
+ -hdr "Content-Type: text/html" \ | |||||
+ -bodylen 100 | |||||
+ | |||||
+ rxreq | |||||
+ expect req.url == "/html/accept-encoding-invalid" | |||||
+ expect req.http.accept-encoding == "invalid" | |||||
+ txresp \ | |||||
+ -hdr "Content-Type: text/html" \ | |||||
+ -bodylen 100 | |||||
+ | |||||
+ | |||||
+ rxreq | |||||
+ expect req.url == "/html/accept-encoding-null" | |||||
+ expect req.http.accept-encoding == "<undef>" | |||||
+ txresp \ | |||||
+ -hdr "Content-Type: text/html" \ | |||||
+ -bodylen 100 | |||||
+ | |||||
+ rxreq | |||||
+ expect req.url == "/dup-etag/accept-encoding-gzip" | |||||
+ expect req.http.accept-encoding == "gzip" | |||||
+ txresp \ | |||||
+ -hdr "Content-Type: text/plain" \ | |||||
+ -hdr "ETag: \"123\"" \ | |||||
+ -hdr "ETag: \"123\"" \ | |||||
+ -bodylen 100 | |||||
+} -repeat 2 -start | |||||
+ | |||||
+ | |||||
+haproxy h1 -conf { | |||||
+ defaults | |||||
+ mode http | |||||
+ ${no-htx} option http-use-htx | |||||
+ timeout connect 1s | |||||
+ timeout client 1s | |||||
+ timeout server 1s | |||||
+ | |||||
+ frontend fe-gzip | |||||
+ bind "fd@${fe_gzip}" | |||||
+ default_backend be-gzip | |||||
+ | |||||
+ backend be-gzip | |||||
+ compression algo gzip | |||||
+ compression type text/plain | |||||
+ server www ${s1_addr}:${s1_port} | |||||
+ | |||||
+ frontend fe-nothing | |||||
+ bind "fd@${fe_nothing}" | |||||
+ default_backend be-nothing | |||||
+ | |||||
+ backend be-nothing | |||||
+ server www ${s1_addr}:${s1_port} | |||||
+} -start | |||||
+ | |||||
+client c1 -connect ${h1_fe_gzip_sock} { | |||||
+ txreq -url "/plain/accept-encoding-gzip" \ | |||||
+ -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 "/plain/accept-encoding-invalid" \ | |||||
+ -hdr "Accept-Encoding: invalid" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/plain/accept-encoding-null" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/html/accept-encoding-gzip" \ | |||||
+ -hdr "Accept-Encoding: gzip" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/html/accept-encoding-invalid" \ | |||||
+ -hdr "Accept-Encoding: invalid" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/html/accept-encoding-null" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/dup-etag/accept-encoding-gzip" \ | |||||
+ -hdr "Accept-Encoding: gzip" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+} -run | |||||
+ | |||||
+# This Client duplicates c1, against the "nothing" frontend, ensuring no Vary header is ever set. | |||||
+client c2 -connect ${h1_fe_nothing_sock} { | |||||
+ txreq -url "/plain/accept-encoding-gzip" \ | |||||
+ -hdr "Accept-Encoding: gzip" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/plain/accept-encoding-invalid" \ | |||||
+ -hdr "Accept-Encoding: invalid" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/plain/accept-encoding-null" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/html/accept-encoding-gzip" \ | |||||
+ -hdr "Accept-Encoding: gzip" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/html/accept-encoding-invalid" \ | |||||
+ -hdr "Accept-Encoding: invalid" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/html/accept-encoding-null" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+ | |||||
+ txreq -url "/dup-etag/accept-encoding-gzip" \ | |||||
+ -hdr "Accept-Encoding: gzip" | |||||
+ rxresp | |||||
+ expect resp.status == 200 | |||||
+ expect resp.http.vary == "<undef>" | |||||
+ expect resp.bodylen == 100 | |||||
+} -run | |||||
diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c | |||||
index b04dcd14..37f237fe 100644 | |||||
--- a/src/flt_http_comp.c | |||||
+++ b/src/flt_http_comp.c | |||||
@@ -523,6 +523,9 @@ http_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *m | |||||
} | |||||
} | |||||
+ if (http_header_add_tail2(msg, &txn->hdr_idx, "Vary: Accept-Encoding", 21) < 0) | |||||
+ goto error; | |||||
+ | |||||
return 1; | |||||
error: | |||||
@@ -577,6 +580,9 @@ htx_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *ms | |||||
} | |||||
} | |||||
+ if (!http_add_header(htx, ist("Vary"), ist("Accept-Encoding"))) | |||||
+ goto error; | |||||
+ | |||||
return 1; | |||||
error: |
@ -0,0 +1,48 @@ | |||||
commit 52131680c42ddbfa6f2b5d109ffc79c28f44e42a | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Thu Jun 27 17:40:14 2019 +0200 | |||||
BUG/MINOR: mux-h1: Skip trailers for non-chunked outgoing messages | |||||
Unlike H1, H2 messages may contains trailers while the header "Content-Length" | |||||
is set. Indeed, because of the framed structure of HTTP/2, it is no longer | |||||
necessary to use the chunked transfer encoding. So Trailing HEADERS frames, | |||||
after all DATA frames, may be added on messages with an explicit content length. | |||||
But in H1, it is impossible to have trailers on non-chunked messages. So when | |||||
outgoing messages are formatted by the H1 multiplexer, if the message is not | |||||
chunked, all trailers must be dropped. | |||||
This patch must be backported to 2.0 and 1.9. However, the patch will have to be | |||||
adapted for the 1.9. | |||||
(cherry picked from commit 5433a0b0215c791b4165bddd360a254fa141c6e9) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/mux_h1.c b/src/mux_h1.c | |||||
index e497e6f6..e7d769b4 100644 | |||||
--- a/src/mux_h1.c | |||||
+++ b/src/mux_h1.c | |||||
@@ -1696,7 +1696,9 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun | |||||
goto done; | |||||
} | |||||
else if (type == HTX_BLK_EOT || type == HTX_BLK_TLR) { | |||||
- if (!chunk_memcat(&tmp, "0\r\n", 3)) | |||||
+ /* If the message is not chunked, never | |||||
+ * add the last chunk. */ | |||||
+ if ((h1m->flags & H1_MF_CHNK) && !chunk_memcat(&tmp, "0\r\n", 3)) | |||||
goto copy; | |||||
goto trailers; | |||||
} | |||||
@@ -1715,6 +1717,11 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun | |||||
goto error; | |||||
trailers: | |||||
h1m->state = H1_MSG_TRAILERS; | |||||
+ /* If the message is not chunked, ignore | |||||
+ * trailers. It may happen with H2 messages. */ | |||||
+ if (!(h1m->flags & H1_MF_CHNK)) | |||||
+ break; | |||||
+ | |||||
if (type == HTX_BLK_EOT) { | |||||
if (!chunk_memcat(&tmp, "\r\n", 2)) | |||||
goto copy; |
@ -1,66 +0,0 @@ | |||||
commit 8d09dc21dc913d1540d07d1019a51c430317eae1 | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Tue Jun 18 09:37:00 2019 +0200 | |||||
MINOR: htx: Add the function htx_change_blk_value_len() | |||||
As its name suggest, this function change the value length of a block. But it | |||||
also update the HTX message accordingly. It simplifies the HTX API. The function | |||||
htx_set_blk_value_len() is still available and must be used with caution because | |||||
this one does not update the HTX message. It just updates the HTX block. It | |||||
should be considered as an internal function. When possible, | |||||
htx_change_blk_value_len() should be used instead. | |||||
This function is used to fix a bug affecting the 2.0. So, this patch must be | |||||
backported to 2.0. | |||||
(cherry picked from commit bb0efcdd293de33607a6eba075971b49857375e2) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/include/common/htx.h b/include/common/htx.h | |||||
index 9631c618..7d15365a 100644 | |||||
--- a/include/common/htx.h | |||||
+++ b/include/common/htx.h | |||||
@@ -470,7 +470,41 @@ static inline struct htx_blk *htx_get_next_blk(const struct htx *htx, | |||||
} | |||||
/* Changes the size of the value. It is the caller responsibility to change the | |||||
- * value itself, make sure there is enough space and update allocated value. | |||||
+ * value itself, make sure there is enough space and update allocated | |||||
+ * value. This function updates the HTX message accordingly. | |||||
+ */ | |||||
+static inline void htx_change_blk_value_len(struct htx *htx, struct htx_blk *blk, uint32_t newlen) | |||||
+{ | |||||
+ enum htx_blk_type type = htx_get_blk_type(blk); | |||||
+ uint32_t oldlen, sz; | |||||
+ int32_t delta; | |||||
+ | |||||
+ sz = htx_get_blksz(blk); | |||||
+ switch (type) { | |||||
+ case HTX_BLK_HDR: | |||||
+ case HTX_BLK_TLR: | |||||
+ oldlen = (blk->info >> 8) & 0xfffff; | |||||
+ blk->info = (type << 28) + (newlen << 8) + (blk->info & 0xff); | |||||
+ break; | |||||
+ default: | |||||
+ oldlen = blk->info & 0xfffffff; | |||||
+ blk->info = (type << 28) + newlen; | |||||
+ break; | |||||
+ } | |||||
+ | |||||
+ /* Update HTTP message */ | |||||
+ delta = (newlen - oldlen); | |||||
+ htx->data += delta; | |||||
+ if (blk->addr+sz == htx->tail_addr) | |||||
+ htx->tail_addr += delta; | |||||
+ else if (blk->addr+sz == htx->head_addr) | |||||
+ htx->head_addr += delta; | |||||
+} | |||||
+ | |||||
+/* Changes the size of the value. It is the caller responsibility to change the | |||||
+ * value itself, make sure there is enough space and update allocated | |||||
+ * value. Unlike the function htx_change_blk_value_len(), this one does not | |||||
+ * update the HTX message. So it should be used with caution. | |||||
*/ | |||||
static inline void htx_set_blk_value_len(struct htx_blk *blk, uint32_t vlen) | |||||
{ |
@ -1,133 +0,0 @@ | |||||
commit 41dc8432f87622145390dc1b1467a5ee14ba184c | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Tue Jun 18 09:49:16 2019 +0200 | |||||
BUG/MEDIUM: htx: Fully update HTX message when the block value is changed | |||||
Everywhere the value length of a block is changed, calling the function | |||||
htx_set_blk_value_len(), the HTX message must be updated. But at many places, | |||||
because of the recent changes in the HTX structure, this update was only | |||||
partially done. tail_addr and head_addr values were not systematically updated. | |||||
In fact, the function htx_set_blk_value_len() was designed as an internal | |||||
function to the HTX API. And we used it from outside by convenience. But it is | |||||
really painfull and error prone to let the caller update the HTX message. So | |||||
now, we use the function htx_change_blk_value_len() wherever is possible. It | |||||
changes the value length of a block and updates the HTX message accordingly. | |||||
This patch must be backported to 2.0. | |||||
(cherry picked from commit 3e2638ee04407a1d9e9376f0c518f67fca7deaa4) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/h2.c b/src/h2.c | |||||
index 32c1ef16..990d602b 100644 | |||||
--- a/src/h2.c | |||||
+++ b/src/h2.c | |||||
@@ -736,8 +736,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms | |||||
if (tl > fs) | |||||
goto fail; | |||||
- htx_set_blk_value_len(blk, tl); | |||||
- htx->data += vl+2; | |||||
+ htx_change_blk_value_len(htx, blk, tl); | |||||
*(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';'; | |||||
*(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' '; | |||||
memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl); | |||||
diff --git a/src/http_htx.c b/src/http_htx.c | |||||
index 7322b337..bc26e5ba 100644 | |||||
--- a/src/http_htx.c | |||||
+++ b/src/http_htx.c | |||||
@@ -461,10 +461,7 @@ int http_remove_header(struct htx *htx, struct http_hdr_ctx *ctx) | |||||
} | |||||
/* Update the block content and its len */ | |||||
memmove(start, start+len, v.len-len); | |||||
- htx_set_blk_value_len(blk, v.len-len); | |||||
- | |||||
- /* Update HTX msg */ | |||||
- htx->data -= len; | |||||
+ htx_change_blk_value_len(htx, blk, v.len-len); | |||||
/* Finally update the ctx */ | |||||
ctx->value.ptr = start; | |||||
diff --git a/src/htx.c b/src/htx.c | |||||
index bfd136f4..81492598 100644 | |||||
--- a/src/htx.c | |||||
+++ b/src/htx.c | |||||
@@ -406,15 +406,8 @@ void htx_truncate(struct htx *htx, uint32_t offset) | |||||
offset -= sz; | |||||
continue; | |||||
} | |||||
- if (type == HTX_BLK_DATA) { | |||||
- htx_set_blk_value_len(blk, offset); | |||||
- htx->data -= (sz - offset); | |||||
- | |||||
- if (blk->addr+sz == htx->tail_addr) | |||||
- htx->tail_addr -= offset; | |||||
- else if (blk->addr+sz == htx->head_addr) | |||||
- htx->head_addr -= offset; | |||||
- } | |||||
+ if (type == HTX_BLK_DATA) | |||||
+ htx_change_blk_value_len(htx, blk, offset); | |||||
offset = 0; | |||||
} | |||||
while (blk) | |||||
@@ -522,14 +515,7 @@ struct htx_blk *htx_add_data_atonce(struct htx *htx, struct ist data) | |||||
/* Append data and update the block itself */ | |||||
ptr = htx_get_blk_ptr(htx, tailblk); | |||||
memcpy(ptr+sz, data.ptr, len); | |||||
- htx_set_blk_value_len(tailblk, sz+len); | |||||
- | |||||
- /* Update HTTP message */ | |||||
- htx->data += len; | |||||
- if (tailblk->addr+sz == htx->tail_addr) | |||||
- htx->tail_addr += len; | |||||
- else if (tailblk->addr+sz == htx->head_addr) | |||||
- htx->head_addr += len; | |||||
+ htx_change_blk_value_len(htx, tailblk, sz+len); | |||||
if (data.len == len) { | |||||
blk = tailblk; | |||||
@@ -988,14 +974,7 @@ size_t htx_add_data(struct htx *htx, const struct ist data) | |||||
/* Append data and update the block itself */ | |||||
ptr = htx_get_blk_ptr(htx, tailblk); | |||||
memcpy(ptr + sz, data.ptr, len); | |||||
- htx_set_blk_value_len(tailblk, sz + len); | |||||
- | |||||
- /* Update HTTP message */ | |||||
- htx->data += len; | |||||
- if (tailblk->addr+sz == htx->tail_addr) | |||||
- htx->tail_addr += len; | |||||
- else if (tailblk->addr+sz == htx->head_addr) | |||||
- htx->head_addr += len; | |||||
+ htx_change_blk_value_len(htx, tailblk, sz+len); | |||||
BUG_ON((int32_t)htx->tail_addr < 0); | |||||
BUG_ON((int32_t)htx->head_addr < 0); | |||||
diff --git a/src/proto_htx.c b/src/proto_htx.c | |||||
index 7f501366..d821e38c 100644 | |||||
--- a/src/proto_htx.c | |||||
+++ b/src/proto_htx.c | |||||
@@ -4314,10 +4314,8 @@ static void htx_manage_client_side_cookies(struct stream *s, struct channel *req | |||||
hdr_end = (preserve_hdr ? del_from : hdr_beg); | |||||
} | |||||
if ((hdr_end - hdr_beg) != ctx.value.len) { | |||||
- if (hdr_beg != hdr_end) { | |||||
- htx_set_blk_value_len(ctx.blk, hdr_end - hdr_beg); | |||||
- htx->data -= ctx.value.len - (hdr_end - hdr_beg); | |||||
- } | |||||
+ if (hdr_beg != hdr_end) | |||||
+ htx_change_blk_value_len(htx, ctx.blk, hdr_end - hdr_beg); | |||||
else | |||||
http_remove_header(htx, &ctx); | |||||
} | |||||
@@ -4495,8 +4493,7 @@ static void htx_manage_server_side_cookies(struct stream *s, struct channel *res | |||||
next += stripped_before; | |||||
hdr_end += stripped_before; | |||||
- htx_set_blk_value_len(ctx.blk, hdr_end - hdr_beg); | |||||
- htx->data -= ctx.value.len - (hdr_end - hdr_beg); | |||||
+ htx_change_blk_value_len(htx, ctx.blk, hdr_end - hdr_beg); | |||||
ctx.value.len = hdr_end - hdr_beg; | |||||
} | |||||
@ -0,0 +1,27 @@ | |||||
commit 33d58b51e0f1bf68603aa86c9125ae75d6964454 | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Mon Jul 1 16:17:30 2019 +0200 | |||||
BUG/MINOR: mux-h1: Don't return the empty chunk on HEAD responses | |||||
HEAD responses must not have any body payload. But, because of a bug, for chunk | |||||
reponses, the empty chunk was always added. | |||||
This patch fixes the Github issue #146. It must be backported to 2.0 and 1.9. | |||||
(cherry picked from commit b8fc304e8f996f0d9835e4d6524ef8961d3be076) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/mux_h1.c b/src/mux_h1.c | |||||
index e7d769b4..37cc8252 100644 | |||||
--- a/src/mux_h1.c | |||||
+++ b/src/mux_h1.c | |||||
@@ -1682,6 +1682,8 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun | |||||
h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR); | |||||
h1s->flags &= ~H1S_F_HAVE_O_CONN; | |||||
} | |||||
+ else if ((h1m->flags & H1_MF_RESP) && h1s->meth == HTTP_METH_HEAD) | |||||
+ h1m->state = H1_MSG_DONE; | |||||
else | |||||
h1m->state = H1_MSG_DATA; | |||||
break; |
@ -1,27 +0,0 @@ | |||||
commit 3d574a587dc3704e93bcd29b16d54d96069667b4 | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Tue Jun 18 12:22:38 2019 +0200 | |||||
BUG/MEDIUM: mux-h2: Reset padlen when several frames are demux | |||||
In the function h2_process_demux(), if several frames are parsed, the padding | |||||
length must be reset between each frame. Otherwise we may wrongly think a frame | |||||
has a padding block because the previous one was padded. | |||||
This patch must be backported to 2.0 and 1.9. | |||||
(cherry picked from commit dd2a5620d594523cd515a629e105a9a2b64345bb) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/mux_h2.c b/src/mux_h2.c | |||||
index d02168df..c06d5d68 100644 | |||||
--- a/src/mux_h2.c | |||||
+++ b/src/mux_h2.c | |||||
@@ -2316,6 +2316,7 @@ static void h2_process_demux(struct h2c *h2c) | |||||
break; | |||||
} | |||||
+ padlen = 0; | |||||
if (h2_ft_bit(hdr.ft) & H2_FT_PADDED_MASK && hdr.ff & H2_F_PADDED) { | |||||
/* If the frame is padded (HEADERS, PUSH_PROMISE or DATA), | |||||
* we read the pad length and drop it from the remaining |
@ -1,30 +0,0 @@ | |||||
commit 4fb65f421b4d650711e5d8b9dbcbf4bf589d26cc | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Wed Jun 19 09:25:58 2019 +0200 | |||||
BUG/MEDIUM: mux-h2: Remove the padding length when a DATA frame size is checked | |||||
When a DATA frame is processed for a message with a content-length, we first | |||||
take care to not have a frame size that exceeds the remaining to | |||||
read. Otherwise, an error is triggered. But we must remove the padding length | |||||
from the frame size because the padding is not included in the announced | |||||
content-length. | |||||
This patch must be backported to 2.0 and 1.9. | |||||
(cherry picked from commit 4f09ec812adbd9336cddc054660a7fb5cd54b459) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/mux_h2.c b/src/mux_h2.c | |||||
index c06d5d68..5bb85181 100644 | |||||
--- a/src/mux_h2.c | |||||
+++ b/src/mux_h2.c | |||||
@@ -2177,7 +2177,7 @@ static int h2c_frt_handle_data(struct h2c *h2c, struct h2s *h2s) | |||||
goto strm_err; | |||||
} | |||||
- if ((h2s->flags & H2_SF_DATA_CLEN) && h2c->dfl > h2s->body_len) { | |||||
+ if ((h2s->flags & H2_SF_DATA_CLEN) && (h2c->dfl - h2c->dpl) > h2s->body_len) { | |||||
/* RFC7540#8.1.2 */ | |||||
error = H2_ERR_PROTOCOL_ERROR; | |||||
goto strm_err; |
@ -1,39 +0,0 @@ | |||||
commit 3f0b1de623d09f8668db34c1be696f7245de7d50 | |||||
Author: Christopher Faulet <cfaulet@haproxy.com> | |||||
Date: Wed Jun 19 10:50:38 2019 +0200 | |||||
BUG/MEDIUM: lb_fwlc: Don't test the server's lb_tree from outside the lock | |||||
In the function fwlc_srv_reposition(), the server's lb_tree is tested from | |||||
outside the lock. So it is possible to remove it after the test and then call | |||||
eb32_insert() in fwlc_queue_srv() with a NULL root pointer, which is | |||||
invalid. Moving the test in the scope of the lock fixes the bug. | |||||
This issue was reported on Github, issue #126. | |||||
This patch must be backported to 2.0, 1.9 and 1.8. | |||||
(cherry picked from commit 1ae2a8878170ded922f2c4d32b6704af7689bbfd) | |||||
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com> | |||||
diff --git a/src/lb_fwlc.c b/src/lb_fwlc.c | |||||
index 174dc67e..5fa81739 100644 | |||||
--- a/src/lb_fwlc.c | |||||
+++ b/src/lb_fwlc.c | |||||
@@ -66,12 +66,11 @@ static inline void fwlc_queue_srv(struct server *s) | |||||
*/ | |||||
static void fwlc_srv_reposition(struct server *s) | |||||
{ | |||||
- if (!s->lb_tree) | |||||
- return; | |||||
- | |||||
HA_SPIN_LOCK(LBPRM_LOCK, &s->proxy->lbprm.lock); | |||||
- fwlc_dequeue_srv(s); | |||||
- fwlc_queue_srv(s); | |||||
+ if (s->lb_tree) { | |||||
+ fwlc_dequeue_srv(s); | |||||
+ fwlc_queue_srv(s); | |||||
+ } | |||||
HA_SPIN_UNLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock); | |||||
} | |||||
@ -1,40 +0,0 @@ | |||||
commit 9eae8935663bc0b27c23018e8cc24ae9a3e31732 | |||||
Author: Frédéric Lécaille <flecaille@haproxy.com> | |||||
Date: Thu Jun 20 09:31:04 2019 +0200 | |||||
BUG/MAJOR: sample: Wrong stick-table name parsing in "if/unless" ACL condition. | |||||
This bug was introduced by 1b8e68e commit which supposed the stick-table was always | |||||
stored in struct arg at parsing time. This is never the case with the usage of | |||||
"if/unless" conditions in stick-table declared as backends. In this case, this is | |||||
the name of the proxy which must be considered as the stick-table name. | |||||
This must be backported to 2.0. | |||||
(cherry picked from commit 9417f4534ad742eda35c4cc3d1ccb390f75ea4b1) | |||||
Signed-off-by: Willy Tarreau <w@1wt.eu> | |||||
diff --git a/src/sample.c b/src/sample.c | |||||
index 67f59e84..77ec9b1e 100644 | |||||
--- a/src/sample.c | |||||
+++ b/src/sample.c | |||||
@@ -1245,15 +1245,11 @@ int smp_resolve_args(struct proxy *p) | |||||
break; | |||||
case ARGT_TAB: | |||||
- if (!arg->data.str.data) { | |||||
- ha_alert("parsing [%s:%d] : missing table name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n", | |||||
- cur->file, cur->line, | |||||
- cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id); | |||||
- cfgerr++; | |||||
- continue; | |||||
- } | |||||
+ if (arg->data.str.data) | |||||
+ stktname = arg->data.str.area; | |||||
+ else | |||||
+ stktname = px->id; | |||||
- stktname = arg->data.str.area; | |||||
t = stktable_find_by_name(stktname); | |||||
if (!t) { | |||||
ha_alert("parsing [%s:%d] : unable to find table '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n", |