BUG/MEDIUM: cache/stats: Wait to have the request before sending the response
It seems obvious. On a classical workflow, the request headers analysis is finished when these applets are woken up for the first time. So they don't take care to really have the request to start to process it and to send the response. But with a filter, it is possible to stop the request analysis after the applet creation. If this happens for the stats applet, this leads to a crash because we retrieve the request start-line without checking if it is available. For the cache applet, the response is just immediatly sent. And here it is a problem if the compression is enabled. In that case too, this may lead to a crash because the compression may be enabled but not initialized. For a true server, there is no issue because the connection cannot be established. The server is chosen only after the request analysis. The issue with applets is that once created, an applet is quickly switched to the established state. So it is probably a point that must be carefully reviewed and probably reworked. In the mean time, as a fix, in the cache and the stats applet, we just take care to have the request before sending the response. This will do the trick. The patch must be backported as far as 2.6. On 2.6, the patch must be adapted.
This commit is contained in:
parent
5fc12b0afd
commit
afc50f2445
26
src/cache.c
26
src/cache.c
|
@ -1783,12 +1783,23 @@ static void http_cache_io_handler(struct appctx *appctx)
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
size_t ret;
|
size_t ret;
|
||||||
|
|
||||||
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
|
if (applet_fl_test(appctx, APPCTX_FL_INBLK_ALLOC|APPCTX_FL_OUTBLK_ALLOC|APPCTX_FL_OUTBLK_FULL))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
if (applet_fl_test(appctx, APPCTX_FL_FASTFWD) && se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD))
|
if (applet_fl_test(appctx, APPCTX_FL_FASTFWD) && se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
if (appctx->st0 == HTX_CACHE_INIT) {
|
||||||
|
if (!appctx_get_buf(appctx, &appctx->inbuf) || htx_is_empty(htxbuf(&appctx->inbuf)))
|
||||||
|
goto wait_request;
|
||||||
|
|
||||||
|
ctx->next = block_ptr(cache_ptr);
|
||||||
|
ctx->offset = sizeof(*cache_ptr);
|
||||||
|
ctx->sent = 0;
|
||||||
|
ctx->rem_data = 0;
|
||||||
|
appctx->st0 = HTX_CACHE_HEADER;
|
||||||
|
}
|
||||||
|
|
||||||
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
@ -1802,14 +1813,6 @@ static void http_cache_io_handler(struct appctx *appctx)
|
||||||
len = first->len - sizeof(*cache_ptr) - ctx->sent;
|
len = first->len - sizeof(*cache_ptr) - ctx->sent;
|
||||||
res_htx = htx_from_buf(&appctx->outbuf);
|
res_htx = htx_from_buf(&appctx->outbuf);
|
||||||
|
|
||||||
if (appctx->st0 == HTX_CACHE_INIT) {
|
|
||||||
ctx->next = block_ptr(cache_ptr);
|
|
||||||
ctx->offset = sizeof(*cache_ptr);
|
|
||||||
ctx->sent = 0;
|
|
||||||
ctx->rem_data = 0;
|
|
||||||
appctx->st0 = HTX_CACHE_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appctx->st0 == HTX_CACHE_HEADER) {
|
if (appctx->st0 == HTX_CACHE_HEADER) {
|
||||||
struct ist meth;
|
struct ist meth;
|
||||||
|
|
||||||
|
@ -1884,6 +1887,11 @@ static void http_cache_io_handler(struct appctx *appctx)
|
||||||
appctx->sedesc->iobuf.flags &= ~IOBUF_FL_FF_BLOCKED;
|
appctx->sedesc->iobuf.flags &= ~IOBUF_FL_FF_BLOCKED;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
wait_request:
|
||||||
|
/* Wait for the request before starting to deliver the response */
|
||||||
|
applet_need_more_data(appctx);
|
||||||
|
return;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
/* Sent and HTTP error 500 */
|
/* Sent and HTTP error 500 */
|
||||||
b_reset(&appctx->outbuf);
|
b_reset(&appctx->outbuf);
|
||||||
|
|
|
@ -1973,6 +1973,11 @@ static void http_stats_io_handler(struct appctx *appctx)
|
||||||
if (applet_fl_test(appctx, APPCTX_FL_FASTFWD) && se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD))
|
if (applet_fl_test(appctx, APPCTX_FL_FASTFWD) && se_fl_test(appctx->sedesc, SE_FL_MAY_FASTFWD_PROD))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (appctx->st0 != STAT_HTTP_END) {
|
||||||
|
if (!appctx_get_buf(appctx, &appctx->inbuf) || htx_is_empty(htxbuf(&appctx->inbuf)))
|
||||||
|
goto wait_request;
|
||||||
|
}
|
||||||
|
|
||||||
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -2062,6 +2067,13 @@ static void http_stats_io_handler(struct appctx *appctx)
|
||||||
}
|
}
|
||||||
else if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_FULL))
|
else if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_FULL))
|
||||||
applet_wont_consume(appctx);
|
applet_wont_consume(appctx);
|
||||||
|
return;
|
||||||
|
|
||||||
|
wait_request:
|
||||||
|
/* Wait for the request before starting to deliver the response */
|
||||||
|
applet_need_more_data(appctx);
|
||||||
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t http_stats_fastfwd(struct appctx *appctx, struct buffer *buf,
|
static size_t http_stats_fastfwd(struct appctx *appctx, struct buffer *buf,
|
||||||
|
|
Loading…
Reference in New Issue