BUG/MEDIUM: stats: Get the right scope pointer depending on HTX is used or not

For HTX streams, the scope pointer is relative to the URI in the start-line. But
for streams using the legacy HTTP representation, the scope pointer is relative
to the beginning of output data in the channel's buffer. So we must be careful
to use the right one depending on the HTX is used or not.

Because the start-line is used to get de scope pointer, it is important to keep
it after the parsing of post paramters. So now, instead of removing blocks when
read in the function stats_process_http_post(), we just move on next, leaving it
in the HTX message.

Thanks to Pieter (PiBa-NL) to report this bug.

This patch must be backported to 1.9.
This commit is contained in:
Christopher Faulet 2019-01-14 11:07:34 +01:00 committed by Willy Tarreau
parent daa356bd7d
commit ed7a066b45
2 changed files with 45 additions and 21 deletions

View File

@ -4887,8 +4887,8 @@ static int htx_handle_stats(struct stream *s, struct channel *req)
h += strlen(STAT_SCOPE_INPUT_NAME) + 1;
h2 = h;
appctx->ctx.stats.scope_str = h2 - s->txn->uri;
while (h <= end) {
appctx->ctx.stats.scope_str = h2 - HTX_SL_REQ_UPTR(sl);
while (h < end) {
if (*h == ';' || *h == '&' || *h == ' ')
break;
itx++;

View File

@ -55,6 +55,7 @@
#include <proto/fd.h>
#include <proto/freq_ctr.h>
#include <proto/frontend.h>
#include <proto/http_htx.h>
#include <proto/log.h>
#include <proto/pattern.h>
#include <proto/pipe.h>
@ -257,6 +258,23 @@ static int stats_putchk(struct channel *chn, struct htx *htx, struct buffer *chk
return 1;
}
static const char *stats_scope_ptr(struct appctx *appctx, struct stream_interface *si)
{
const char *p;
if (IS_HTX_STRM(si_strm(si))) {
struct channel *req = si_oc(si);
struct htx *htx = htxbuf(&req->buf);
struct ist uri = htx_sl_req_uri(http_find_stline(htx));
p = uri.ptr;
}
else
p = co_head(si_oc(si));
return p + appctx->ctx.stats.scope_str;
}
/*
* http_stats_io_handler()
* -> stats_dump_stat_to_buffer() // same as above, but used for CSV or HTML
@ -1912,8 +1930,10 @@ static void stats_dump_html_px_hdr(struct stream_interface *si, struct proxy *px
/* scope_txt = search pattern + search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
scope_txt[0] = 0;
if (appctx->ctx.stats.scope_len) {
const char *scope_ptr = stats_scope_ptr(appctx, si);
strcpy(scope_txt, STAT_SCOPE_PATTERN);
memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), co_head(si_oc(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), scope_ptr, appctx->ctx.stats.scope_len);
scope_txt[strlen(STAT_SCOPE_PATTERN) + appctx->ctx.stats.scope_len] = 0;
}
@ -2075,9 +2095,12 @@ int stats_dump_proxy_to_buffer(struct stream_interface *si, struct htx *htx,
/* if the user has requested a limited output and the proxy
* name does not match, skip it.
*/
if (appctx->ctx.stats.scope_len &&
strnistr(px->id, strlen(px->id), co_head(si_oc(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len) == NULL)
return 1;
if (appctx->ctx.stats.scope_len) {
const char *scope_ptr = stats_scope_ptr(appctx, si);
if (strnistr(px->id, strlen(px->id), scope_ptr, appctx->ctx.stats.scope_len) == NULL)
return 1;
}
if ((appctx->ctx.stats.flags & STAT_BOUND) &&
(appctx->ctx.stats.iid != -1) &&
@ -2347,6 +2370,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
struct appctx *appctx = __objt_appctx(si->end);
unsigned int up = (now.tv_sec - start_date.tv_sec);
char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN];
const char *scope_ptr = stats_scope_ptr(appctx, si);
/* WARNING! this has to fit the first packet too.
* We are around 3.5 kB, add adding entries will
@ -2405,7 +2429,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
);
/* scope_txt = search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
memcpy(scope_txt, co_head(si_oc(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
memcpy(scope_txt, scope_ptr, appctx->ctx.stats.scope_len);
scope_txt[appctx->ctx.stats.scope_len] = '\0';
chunk_appendf(&trash,
@ -2417,7 +2441,7 @@ static void stats_dump_html_info(struct stream_interface *si, struct uri_auth *u
scope_txt[0] = 0;
if (appctx->ctx.stats.scope_len) {
strcpy(scope_txt, STAT_SCOPE_PATTERN);
memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), co_head(si_oc(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), scope_ptr, appctx->ctx.stats.scope_len);
scope_txt[strlen(STAT_SCOPE_PATTERN) + appctx->ctx.stats.scope_len] = 0;
}
@ -2719,7 +2743,13 @@ static int stats_process_http_post(struct stream_interface *si)
struct htx_blk *blk;
size_t count = co_data(&s->req);
/* Remove the headers */
/* we need more data */
if (htx->extra || htx->data > count) {
appctx->ctx.stats.st_code = STAT_STATUS_NONE;
return 0;
}
/* Skip the headers */
blk = htx_get_head_blk(htx);
while (count && blk) {
enum htx_blk_type type = htx_get_blk_type(blk);
@ -2731,25 +2761,18 @@ static int stats_process_http_post(struct stream_interface *si)
}
count -= sz;
co_set_data(&s->req, co_data(&s->req) - sz);
blk = htx_remove_blk(htx, blk);
blk = htx_get_next_blk(htx, blk);
if (type == HTX_BLK_EOH)
break;
}
/* too large request */
if (htx->data + htx->extra > b_size(temp)) {
if (count > b_size(temp)) {
appctx->ctx.stats.st_code = STAT_STATUS_EXCD;
goto out;
}
/* we need more data */
if (htx->extra || htx->data > count) {
appctx->ctx.stats.st_code = STAT_STATUS_NONE;
return 0;
}
while (count && blk) {
enum htx_blk_type type = htx_get_blk_type(blk);
uint32_t sz = htx_get_blksz(blk);
@ -2766,8 +2789,7 @@ static int stats_process_http_post(struct stream_interface *si)
}
count -= sz;
co_set_data(&s->req, co_data(&s->req) - sz);
blk = htx_remove_blk(htx, blk);
blk = htx_get_next_blk(htx, blk);
}
}
else {
@ -3135,8 +3157,10 @@ static int stats_send_htx_redirect(struct stream_interface *si, struct htx *htx)
/* scope_txt = search pattern + search query, appctx->ctx.stats.scope_len is always <= STAT_SCOPE_TXT_MAXLEN */
scope_txt[0] = 0;
if (appctx->ctx.stats.scope_len) {
const char *scope_ptr = stats_scope_ptr(appctx, si);
strcpy(scope_txt, STAT_SCOPE_PATTERN);
memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), co_head(si_oc(si)) + appctx->ctx.stats.scope_str, appctx->ctx.stats.scope_len);
memcpy(scope_txt + strlen(STAT_SCOPE_PATTERN), scope_ptr, appctx->ctx.stats.scope_len);
scope_txt[strlen(STAT_SCOPE_PATTERN) + appctx->ctx.stats.scope_len] = 0;
}