From: Christopher Faulet Date: Mon, 15 Jul 2019 19:56:43 +0000 (+0200) Subject: MINOR: stats: Remove code relying on the legacy HTTP mode X-Git-Tag: v2.1-dev2~356 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7f8890b1907518075d53d5a9e558a06bcd9676f;p=thirdparty%2Fhaproxy.git MINOR: stats: Remove code relying on the legacy HTTP mode The part of the applet dealing with raw buffer was removed, for the HTTP part only. So the old functions stats_send_http_headers() and stats_send_http_redirect() were removed and replaced by the htx ones. The legacy applet I/O handler was replaced by the htx one. And the parsing of POST data was purged of the legacy HTTP code. --- diff --git a/src/stats.c b/src/stats.c index d40e0890cc..6744163242 100644 --- a/src/stats.c +++ b/src/stats.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include #include @@ -272,24 +271,16 @@ static int stats_putchk(struct channel *chn, struct htx *htx, struct buffer *chk 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 htx_blk *blk; - struct ist uri; - - blk = htx_get_head_blk(htx); - BUG_ON(htx_get_blk_type(blk) != HTX_BLK_REQ_SL); - ALREADY_CHECKED(blk); - uri = htx_sl_req_uri(htx_get_blk_ptr(htx, blk)); - p = uri.ptr; - } - else - p = co_head(si_oc(si)); - - return p + appctx->ctx.stats.scope_str; + struct channel *req = si_oc(si); + struct htx *htx = htxbuf(&req->buf); + struct htx_blk *blk; + struct ist uri; + + blk = htx_get_head_blk(htx); + BUG_ON(htx_get_blk_type(blk) != HTX_BLK_REQ_SL); + ALREADY_CHECKED(blk); + uri = htx_sl_req_uri(htx_get_blk_ptr(htx, blk)); + return uri.ptr + appctx->ctx.stats.scope_str; } /* @@ -2778,57 +2769,35 @@ static int stats_process_http_post(struct stream_interface *si) struct buffer *temp = get_trash_chunk(); - if (IS_HTX_STRM(s)) { - struct htx *htx = htxbuf(&s->req.buf); - struct htx_blk *blk; + struct htx *htx = htxbuf(&s->req.buf); + struct htx_blk *blk; - /* we need more data */ - if (s->txn->req.msg_state < HTTP_MSG_DONE) { - /* check if we can receive more */ - if (htx_free_data_space(htx) <= global.tune.maxrewrite) { - appctx->ctx.stats.st_code = STAT_STATUS_EXCD; - goto out; - } - goto wait; + /* we need more data */ + if (s->txn->req.msg_state < HTTP_MSG_DONE) { + /* check if we can receive more */ + if (htx_free_data_space(htx) <= global.tune.maxrewrite) { + appctx->ctx.stats.st_code = STAT_STATUS_EXCD; + goto out; } + goto wait; + } - /* The request was fully received. Copy data */ - blk = htx_get_head_blk(htx); - while (blk) { - enum htx_blk_type type = htx_get_blk_type(blk); + /* The request was fully received. Copy data */ + blk = htx_get_head_blk(htx); + while (blk) { + enum htx_blk_type type = htx_get_blk_type(blk); - if (type == HTX_BLK_EOM || type == HTX_BLK_TLR || type == HTX_BLK_EOT) - break; - if (type == HTX_BLK_DATA) { - struct ist v = htx_get_blk_value(htx, blk); - - if (!chunk_memcat(temp, v.ptr, v.len)) { - appctx->ctx.stats.st_code = STAT_STATUS_EXCD; - goto out; - } - } - blk = htx_get_next_blk(htx, blk); - } - } - else { - int reql; + if (type == HTX_BLK_EOM || type == HTX_BLK_TLR || type == HTX_BLK_EOT) + break; + if (type == HTX_BLK_DATA) { + struct ist v = htx_get_blk_value(htx, blk); - /* we need more data */ - if (s->txn->req.msg_state < HTTP_MSG_DONE) { - /* check if we can receive more */ - if (c_room(&s->req) <= global.tune.maxrewrite) { + if (!chunk_memcat(temp, v.ptr, v.len)) { appctx->ctx.stats.st_code = STAT_STATUS_EXCD; goto out; } - goto wait; } - reql = co_getblk(si_oc(si), temp->area, s->txn->req.body_len, - s->txn->req.eoh + 2); - if (reql <= 0) { - appctx->ctx.stats.st_code = STAT_STATUS_EXCD; - goto out; - } - temp->data = reql; + blk = htx_get_next_blk(htx, blk); } first_param = temp->area; @@ -3119,7 +3088,7 @@ static int stats_process_http_post(struct stream_interface *si) } -static int stats_send_htx_headers(struct stream_interface *si, struct htx *htx) +static int stats_send_http_headers(struct stream_interface *si, struct htx *htx) { struct stream *s = si_strm(si); struct uri_auth *uri = s->be->uri_auth; @@ -3168,7 +3137,7 @@ static int stats_send_htx_headers(struct stream_interface *si, struct htx *htx) } -static int stats_send_htx_redirect(struct stream_interface *si, struct htx *htx) +static int stats_send_http_redirect(struct stream_interface *si, struct htx *htx) { char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN]; struct stream *s = si_strm(si); @@ -3226,90 +3195,13 @@ full: return 0; } -static int stats_send_http_headers(struct stream_interface *si) -{ - struct stream *s = si_strm(si); - struct uri_auth *uri = s->be->uri_auth; - struct appctx *appctx = __objt_appctx(si->end); - - chunk_printf(&trash, - "HTTP/1.1 200 OK\r\n" - "Cache-Control: no-cache\r\n" - "Connection: close\r\n" - "Content-Type: %s\r\n", - (appctx->ctx.stats.flags & STAT_FMT_HTML) ? "text/html" : "text/plain"); - - if (uri->refresh > 0 && !(appctx->ctx.stats.flags & STAT_NO_REFRESH)) - chunk_appendf(&trash, "Refresh: %d\r\n", - uri->refresh); - - /* we don't send the CRLF in chunked mode, it will be sent with the first chunk's size */ - - if (appctx->ctx.stats.flags & STAT_CHUNKED) - chunk_appendf(&trash, "Transfer-Encoding: chunked\r\n"); - else - chunk_appendf(&trash, "\r\n"); - - if (ci_putchk(si_ic(si), &trash) == -1) { - si_rx_room_blk(si); - return 0; - } - - return 1; -} - -static int stats_send_http_redirect(struct stream_interface *si) -{ - char scope_txt[STAT_SCOPE_TXT_MAXLEN + sizeof STAT_SCOPE_PATTERN]; - struct stream *s = si_strm(si); - struct uri_auth *uri = s->be->uri_auth; - struct appctx *appctx = __objt_appctx(si->end); - - /* 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) { - 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); - scope_txt[strlen(STAT_SCOPE_PATTERN) + appctx->ctx.stats.scope_len] = 0; - } - - /* We don't want to land on the posted stats page because a refresh will - * repost the data. We don't want this to happen on accident so we redirect - * the browse to the stats page with a GET. - */ - chunk_printf(&trash, - "HTTP/1.1 303 See Other\r\n" - "Cache-Control: no-cache\r\n" - "Content-Type: text/plain\r\n" - "Connection: close\r\n" - "Location: %s;st=%s%s%s%s\r\n" - "Content-length: 0\r\n" - "\r\n", - uri->uri_prefix, - ((appctx->ctx.stats.st_code > STAT_STATUS_INIT) && - (appctx->ctx.stats.st_code < STAT_STATUS_SIZE) && - stat_status_codes[appctx->ctx.stats.st_code]) ? - stat_status_codes[appctx->ctx.stats.st_code] : - stat_status_codes[STAT_STATUS_UNKN], - (appctx->ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "", - (appctx->ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "", - scope_txt); - - if (ci_putchk(si_ic(si), &trash) == -1) { - si_rx_room_blk(si); - return 0; - } - - return 1; -} - /* This I/O handler runs as an applet embedded in a stream interface. It is * used to send HTTP stats over a TCP socket. The mechanism is very simple. * appctx->st0 contains the operation in progress (dump, done). The handler * automatically unregisters itself once transfer is complete. */ -static void htx_stats_io_handler(struct appctx *appctx) +static void http_stats_io_handler(struct appctx *appctx) { struct stream_interface *si = appctx->owner; struct stream *s = si_strm(si); @@ -3334,7 +3226,7 @@ static void htx_stats_io_handler(struct appctx *appctx) /* all states are processed in sequence */ if (appctx->st0 == STAT_HTTP_HEAD) { - if (stats_send_htx_headers(si, res_htx)) { + if (stats_send_http_headers(si, res_htx)) { if (s->txn->meth == HTTP_METH_HEAD) appctx->st0 = STAT_HTTP_DONE; else @@ -3355,7 +3247,7 @@ static void htx_stats_io_handler(struct appctx *appctx) } if (appctx->st0 == STAT_HTTP_LAST) { - if (stats_send_htx_redirect(si, res_htx)) + if (stats_send_http_redirect(si, res_htx)) appctx->st0 = STAT_HTTP_DONE; } @@ -3396,145 +3288,6 @@ static void htx_stats_io_handler(struct appctx *appctx) si_stop_get(si); } - -/* This I/O handler runs as an applet embedded in a stream interface. It is - * used to send HTTP stats over a TCP socket. The mechanism is very simple. - * appctx->st0 contains the operation in progress (dump, done). The handler - * automatically unregisters itself once transfer is complete. - */ -static void http_stats_io_handler(struct appctx *appctx) -{ - struct stream_interface *si = appctx->owner; - struct stream *s = si_strm(si); - struct channel *req = si_oc(si); - struct channel *res = si_ic(si); - - if (IS_HTX_STRM(s)) - return htx_stats_io_handler(appctx); - - if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) - goto out; - - /* Check if the input buffer is available. */ - if (res->buf.size == 0) { - /* already subscribed, we'll be called later once the buffer is - * available. - */ - goto out; - } - - /* check that the output is not closed */ - if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR)) - appctx->st0 = STAT_HTTP_END; - - /* all states are processed in sequence */ - if (appctx->st0 == STAT_HTTP_HEAD) { - if (stats_send_http_headers(si)) { - if (s->txn->meth == HTTP_METH_HEAD) - appctx->st0 = STAT_HTTP_DONE; - else - appctx->st0 = STAT_HTTP_DUMP; - } - } - - if (appctx->st0 == STAT_HTTP_DUMP) { - unsigned int prev_len = ci_data(si_ic(si)); - unsigned int data_len; - unsigned int last_len; - unsigned int last_fwd = 0; - - if (appctx->ctx.stats.flags & STAT_CHUNKED) { - /* One difficulty we're facing is that we must prevent - * the input data from being automatically forwarded to - * the output area. For this, we temporarily disable - * forwarding on the channel. - */ - last_fwd = si_ic(si)->to_forward; - si_ic(si)->to_forward = 0; - chunk_printf(&trash, "\r\n000000\r\n"); - if (ci_putchk(si_ic(si), &trash) == -1) { - si_rx_room_blk(si); - si_ic(si)->to_forward = last_fwd; - goto out; - } - } - - data_len = ci_data(si_ic(si)); - if (stats_dump_stat_to_buffer(si, NULL, s->be->uri_auth)) - appctx->st0 = STAT_HTTP_DONE; - - last_len = ci_data(si_ic(si)); - - /* Now we must either adjust or remove the chunk size. This is - * not easy because the chunk size might wrap at the end of the - * buffer, so we pretend we have nothing in the buffer, we write - * the size, then restore the buffer's contents. Note that we can - * only do that because no forwarding is scheduled on the stats - * applet. - */ - if (appctx->ctx.stats.flags & STAT_CHUNKED) { - si_ic(si)->total -= (last_len - prev_len); - b_sub(si_ib(si), (last_len - prev_len)); - - if (last_len != data_len) { - chunk_printf(&trash, "\r\n%06x\r\n", (last_len - data_len)); - if (ci_putchk(si_ic(si), &trash) == -1) - si_rx_room_blk(si); - - si_ic(si)->total += (last_len - data_len); - b_add(si_ib(si), last_len - data_len); - } - /* now re-enable forwarding */ - channel_forward(si_ic(si), last_fwd); - } - } - - if (appctx->st0 == STAT_HTTP_POST) { - if (stats_process_http_post(si)) - appctx->st0 = STAT_HTTP_LAST; - else if (si_oc(si)->flags & CF_SHUTR) - appctx->st0 = STAT_HTTP_DONE; - } - - if (appctx->st0 == STAT_HTTP_LAST) { - if (stats_send_http_redirect(si)) - appctx->st0 = STAT_HTTP_DONE; - } - - if (appctx->st0 == STAT_HTTP_DONE) { - if (appctx->ctx.stats.flags & STAT_CHUNKED) { - chunk_printf(&trash, "\r\n0\r\n\r\n"); - if (ci_putchk(si_ic(si), &trash) == -1) { - si_rx_room_blk(si); - goto out; - } - } - appctx->st0 = STAT_HTTP_END; - } - - if (appctx->st0 == STAT_HTTP_END) { - if (!(res->flags & CF_SHUTR)) { - res->flags |= CF_READ_NULL; - si_shutr(si); - } - - /* eat the whole request */ - if (co_data(req)) - co_skip(si_oc(si), co_data(si_oc(si))); - } - - out: - /* we have left the request in the buffer for the case where we - * process a POST, and this automatically re-enables activity on - * read. It's better to indicate that we want to stop reading when - * we're sending, so that we know there's at most one direction - * deciding to wake the applet up. It saves it from looping when - * emitting large blocks into small TCP windows. - */ - if (!channel_is_empty(res)) - si_stop_get(si); -} - /* Dump all fields from into using the "show info" format (name: value) */ static int stats_dump_info_fields(struct buffer *out, const struct field *info)