MEDIUM: stats: reimplement HTTP keep-alive on the stats page
This basically reimplements commitf3221f9
("MEDIUM: stats: add support for HTTP keep-alive on the stats page") which was reverted by commit51437d2
after Igor Chan reported a broken stats page caused by the bug fix by previous commit.
This commit is contained in:
parent
5a8ba60fe1
commit
af3cf70d7c
|
@ -31,6 +31,7 @@
|
|||
#define STAT_HIDE_DOWN 0x00000008 /* hide 'down' servers in the stats page */
|
||||
#define STAT_NO_REFRESH 0x00000010 /* do not automatically refresh the stats page */
|
||||
#define STAT_ADMIN 0x00000020 /* indicate a stats admin level */
|
||||
#define STAT_CHUNKED 0x00000040 /* use chunked encoding (HTTP/1.1) */
|
||||
#define STAT_BOUND 0x00800000 /* bound statistics to selected proxies/types/services */
|
||||
|
||||
#define STATS_TYPE_FE 0
|
||||
|
|
|
@ -4357,17 +4357,23 @@ static int stats_send_http_headers(struct stream_interface *si)
|
|||
struct appctx *appctx = objt_appctx(si->end);
|
||||
|
||||
chunk_printf(&trash,
|
||||
"HTTP/1.0 200 OK\r\n"
|
||||
"HTTP/1.%c 200 OK\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Type: %s\r\n",
|
||||
(appctx->ctx.stats.flags & STAT_CHUNKED) ? '1' : '0',
|
||||
(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);
|
||||
|
||||
chunk_appendf(&trash, "\r\n");
|
||||
/* 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");
|
||||
|
||||
s->txn.status = 200;
|
||||
s->logs.tv_request = now;
|
||||
|
@ -4453,8 +4459,53 @@ static void http_stats_io_handler(struct stream_interface *si)
|
|||
}
|
||||
|
||||
if (appctx->st0 == STAT_HTTP_DUMP) {
|
||||
unsigned int prev_len = si->ib->buf->i;
|
||||
unsigned int data_len;
|
||||
unsigned int last_len;
|
||||
unsigned int last_fwd;
|
||||
|
||||
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->ib->to_forward;
|
||||
si->ib->to_forward = 0;
|
||||
chunk_printf(&trash, "\r\n000000\r\n");
|
||||
if (bi_putchk(si->ib, &trash) == -1) {
|
||||
si->ib->to_forward = last_fwd;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
data_len = si->ib->buf->i;
|
||||
if (stats_dump_stat_to_buffer(si, s->be->uri_auth))
|
||||
appctx->st0 = STAT_HTTP_DONE;
|
||||
|
||||
last_len = si->ib->buf->i;
|
||||
|
||||
/* 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->ib->total -= (last_len - prev_len);
|
||||
si->ib->buf->i -= (last_len - prev_len);
|
||||
|
||||
if (last_len != data_len) {
|
||||
chunk_printf(&trash, "\r\n%06x\r\n", (last_len - data_len));
|
||||
bi_putchk(si->ib, &trash);
|
||||
|
||||
si->ib->total += (last_len - data_len);
|
||||
si->ib->buf->i += (last_len - data_len);
|
||||
}
|
||||
/* now re-enable forwarding */
|
||||
channel_forward(si->ib, last_fwd);
|
||||
}
|
||||
}
|
||||
|
||||
if (appctx->st0 == STAT_HTTP_POST) {
|
||||
|
@ -4469,8 +4520,17 @@ static void http_stats_io_handler(struct stream_interface *si)
|
|||
appctx->st0 = STAT_HTTP_DONE;
|
||||
}
|
||||
|
||||
if (appctx->st0 == STAT_HTTP_DONE)
|
||||
si_shutw(si);
|
||||
if (appctx->st0 == STAT_HTTP_DONE) {
|
||||
if (appctx->ctx.stats.flags & STAT_CHUNKED) {
|
||||
chunk_printf(&trash, "\r\n0\r\n\r\n");
|
||||
if (bi_putchk(si->ib, &trash) == -1)
|
||||
goto fail;
|
||||
}
|
||||
/* eat the whole request */
|
||||
bo_skip(si->ob, si->ob->buf->o);
|
||||
res->flags |= CF_READ_NULL;
|
||||
si_shutr(si);
|
||||
}
|
||||
|
||||
if ((res->flags & CF_SHUTR) && (si->state == SI_ST_EST))
|
||||
si_shutw(si);
|
||||
|
@ -4482,6 +4542,7 @@ static void http_stats_io_handler(struct stream_interface *si)
|
|||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
/* update all other flags and resync with the other side */
|
||||
si_update(si);
|
||||
|
||||
|
|
|
@ -2962,6 +2962,8 @@ int http_handle_stats(struct session *s, struct channel *req)
|
|||
appctx->st1 = appctx->st2 = 0;
|
||||
appctx->ctx.stats.st_code = STAT_STATUS_INIT;
|
||||
appctx->ctx.stats.flags |= STAT_FMT_HTML; /* assume HTML mode by default */
|
||||
if ((msg->flags & HTTP_MSGF_VER_11) && (s->txn.meth != HTTP_METH_HEAD))
|
||||
appctx->ctx.stats.flags |= STAT_CHUNKED;
|
||||
|
||||
uri = msg->chn->buf->p + msg->sl.rq.u;
|
||||
lookup = uri + uri_auth->uri_len;
|
||||
|
@ -3798,7 +3800,7 @@ int http_process_req_common(struct session *s, struct channel *req, int an_bit,
|
|||
s->flags |= SN_FINST_R;
|
||||
|
||||
req->analyse_exp = TICK_ETERNITY;
|
||||
req->analysers = 0;
|
||||
req->analysers = AN_REQ_HTTP_XFER_BODY;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue