- Add new patches (see https://www.haproxy.org/bugs/bugs-1.8.19.html) - Raise PKG_RELEASE to 4 Signed-off-by: Christian Lachner <gladiac@gmail.com>
92 lines
3.6 KiB
Diff
92 lines
3.6 KiB
Diff
commit 3c6ad99924236bf8b7741030bd163aacb820d451
|
|
Author: Christopher Faulet <cfaulet@haproxy.com>
|
|
Date: Wed Feb 27 15:30:57 2019 +0100
|
|
|
|
BUG/MAJOR: stats: Fix how huge POST data are read from the channel
|
|
|
|
When the body length is greater than a chunk size (so if length of POST data
|
|
exceeds the buffer size), the requests is rejected with the status code
|
|
STAT_STATUS_EXCD. Otherwise the stats applet will wait to have all the data to
|
|
copy and parse them. But there is a problem when the total request size
|
|
(including the headers) is just lower than the buffer size but greater the
|
|
buffer size less the reserve. In such case, the body length is considered as
|
|
enough small to be processed but not entierly received. So the stats applet
|
|
waits for more data. But because outgoing data are still there, the channel's
|
|
buffer is considered as full and nothing more can be read, leading to a freeze
|
|
of the session.
|
|
|
|
Note this bug is pretty easy to reproduce with the legacy HTTP. It is harder
|
|
with the HTX but still possible. To fix the bug, in the stats applet, when the
|
|
request is not fully received, we check if at least the reserve remains
|
|
available the channel's buffer.
|
|
|
|
This patch must be backported as far as 1.5. But because the HTX does not exist
|
|
in 1.8 and lower, it will have to be adapted for these versions.
|
|
|
|
(cherry picked from commit 2f9a41d52b28b88d44aab063bb2b88025a388981)
|
|
Signed-off-by: Willy Tarreau <w@1wt.eu>
|
|
(cherry picked from commit 18a5b1eece7e12047c1dc371c42f72d9d129ce0a)
|
|
[cf: HTX code removed and calls to the new buffer API replaced to use the old
|
|
one]
|
|
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
|
|
|
|
diff --git a/src/stats.c b/src/stats.c
|
|
index 4973bb8a..0a6c15f6 100644
|
|
--- a/src/stats.c
|
|
+++ b/src/stats.c
|
|
@@ -2441,6 +2441,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
|
|
"Action not processed because of invalid parameters."
|
|
"<ul>"
|
|
"<li>The action is maybe unknown.</li>"
|
|
+ "<li>Invalid key parameter (empty or too long).</li>"
|
|
"<li>The backend name is probably unknown or ambiguous (duplicated names).</li>"
|
|
"<li>Some server names are probably unknown or ambiguous (duplicated names in the backend).</li>"
|
|
"</ul>"
|
|
@@ -2634,17 +2635,20 @@ static int stats_process_http_post(struct stream_interface *si)
|
|
int reql;
|
|
|
|
temp = get_trash_chunk();
|
|
- if (temp->size < s->txn->req.body_len) {
|
|
- /* too large request */
|
|
- appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
|
|
- goto out;
|
|
- }
|
|
|
|
+ /* we need more data */
|
|
+ if (s->txn->req.msg_state < HTTP_MSG_DONE) {
|
|
+ /* check if we can receive more */
|
|
+ if (buffer_total_space(s->req.buf) <= global.tune.maxrewrite) {
|
|
+ appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
|
|
+ goto out;
|
|
+ }
|
|
+ goto wait;
|
|
+ }
|
|
reql = co_getblk(si_oc(si), temp->str, s->txn->req.body_len, s->txn->req.eoh + 2);
|
|
if (reql <= 0) {
|
|
- /* we need more data */
|
|
- appctx->ctx.stats.st_code = STAT_STATUS_NONE;
|
|
- return 0;
|
|
+ appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
|
|
+ goto out;
|
|
}
|
|
|
|
first_param = temp->str;
|
|
@@ -2673,7 +2677,7 @@ static int stats_process_http_post(struct stream_interface *si)
|
|
strncpy(key, cur_param + poffset, plen);
|
|
key[plen - 1] = '\0';
|
|
} else {
|
|
- appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
|
|
+ appctx->ctx.stats.st_code = STAT_STATUS_ERRP;
|
|
goto out;
|
|
}
|
|
|
|
@@ -2929,6 +2933,9 @@ static int stats_process_http_post(struct stream_interface *si)
|
|
}
|
|
out:
|
|
return 1;
|
|
+ wait:
|
|
+ appctx->ctx.stats.st_code = STAT_STATUS_NONE;
|
|
+ return 0;
|
|
}
|
|
|
|
|