diff --git a/src/hlua.c b/src/hlua.c index c95eb374e..1667b4ab2 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -159,6 +159,7 @@ static int hlua_panic_ljmp(lua_State *L) { longjmp(safe_ljmp_env, 1); } #define APPLET_CHUNKED 0x08 /* Use transfer encoding chunked. */ #define APPLET_LAST_CHK 0x10 /* Last chunk sent. */ #define APPLET_HTTP11 0x20 /* Last chunk sent. */ +#define APPLET_RSP_SENT 0x40 /* The response was fully sent */ /* The main Lua execution context. */ struct hlua gL; @@ -7299,7 +7300,7 @@ static void hlua_applet_htx_fct(struct appctx *ctx) goto out; } /* check that the output is not closed */ - if (res->flags & (CF_SHUTW|CF_SHUTW_NOW)) + if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR)) ctx->ctx.hlua_apphttp.flags |= APPLET_DONE; /* Set the currently running flag. */ @@ -7352,7 +7353,7 @@ static void hlua_applet_htx_fct(struct appctx *ctx) case HLUA_E_AGAIN: if (hlua->wake_time != TICK_ETERNITY) task_schedule(ctx->ctx.hlua_apphttp.task, hlua->wake_time); - return; + goto out; /* finished with error. */ case HLUA_E_ERRMSG: @@ -7389,6 +7390,9 @@ static void hlua_applet_htx_fct(struct appctx *ctx) } if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) { + if (ctx->ctx.hlua_apphttp.flags & APPLET_RSP_SENT) + goto done; + if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) goto error; @@ -7398,40 +7402,27 @@ static void hlua_applet_htx_fct(struct appctx *ctx) goto out; } channel_add_input(res, 1); + strm->txn->status = ctx->ctx.hlua_apphttp.status; + ctx->ctx.hlua_apphttp.flags |= APPLET_RSP_SENT; } done: if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) { - /* eat the whole request */ - req_htx = htxbuf(&req->buf); - htx_reset(req_htx); - htx_to_buf(req_htx, &req->buf); - co_set_data(req, 0); - res->flags |= CF_READ_NULL; - si_shutr(si); - } - - if ((res->flags & CF_SHUTR) && (si->state == SI_ST_EST)) - si_shutw(si); - - if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) { - if ((req->flags & CF_SHUTW) && (si->state == SI_ST_EST)) { - si_shutr(si); + if (!(res->flags & CF_SHUTR)) { res->flags |= CF_READ_NULL; + si_shutr(si); + } + + /* eat the whole request */ + if (co_data(req)) { + req_htx = htx_from_buf(&req->buf); + co_htx_skip(req, req_htx, co_data(req)); + htx_to_buf(req_htx, &req->buf); } } 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. - */ htx_to_buf(res_htx, &res->buf); - if (!channel_is_empty(res)) - si_stop_get(si); return; error: @@ -7460,6 +7451,7 @@ static void hlua_applet_http_fct(struct appctx *ctx) { struct stream_interface *si = ctx->owner; struct stream *strm = si_strm(si); + struct channel *req = si_oc(si); struct channel *res = si_ic(si); struct act_rule *rule = ctx->rule; struct proxy *px = strm->be; @@ -7475,7 +7467,16 @@ static void hlua_applet_http_fct(struct appctx *ctx) /* If the stream is disconnect or closed, ldo nothing. */ if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) - return; + goto out; + + /* Check if the input buffer is avalaible. */ + if (!b_size(&res->buf)) { + si_rx_room_blk(si); + goto out; + } + /* check that the output is not closed */ + if (res->flags & (CF_SHUTW|CF_SHUTW_NOW|CF_SHUTR)) + ctx->ctx.hlua_apphttp.flags |= APPLET_DONE; /* Set the currently running flag. */ if (!HLUA_IS_RUNNING(hlua) && @@ -7488,9 +7489,9 @@ static void hlua_applet_http_fct(struct appctx *ctx) */ /* Read the maximum amount of data available. */ - ret = co_getblk_nc(si_oc(si), &blk1, &len1, &blk2, &len2); + ret = co_getblk_nc(req, &blk1, &len1, &blk2, &len2); if (ret == -1) - return; + goto out; /* No data available, ask for more data. */ if (ret == 1) @@ -7499,11 +7500,11 @@ static void hlua_applet_http_fct(struct appctx *ctx) len1 = 0; if (len1 + len2 < strm->txn->req.eoh + strm->txn->req.eol) { si_cant_get(si); - return; + goto out; } /* skip the requests bytes. */ - co_skip(si_oc(si), strm->txn->req.eoh + strm->txn->req.eol); + co_skip(req, strm->txn->req.eoh + strm->txn->req.eol); } /* Executes The applet if it is not done. */ @@ -7520,7 +7521,7 @@ static void hlua_applet_http_fct(struct appctx *ctx) case HLUA_E_AGAIN: if (hlua->wake_time != TICK_ETERNITY) task_schedule(ctx->ctx.hlua_apphttp.task, hlua->wake_time); - return; + goto out; /* finished with error. */ case HLUA_E_ERRMSG: @@ -7557,6 +7558,9 @@ static void hlua_applet_http_fct(struct appctx *ctx) } if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) { + if (ctx->ctx.hlua_apphttp.flags & APPLET_RSP_SENT) + goto done; + if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) goto error; @@ -7577,39 +7581,44 @@ static void hlua_applet_http_fct(struct appctx *ctx) /* no enough space error. */ if (ret == -1) { si_rx_room_blk(si); - return; + goto out; } - /* set the last chunk sent. */ - ctx->ctx.hlua_apphttp.flags |= APPLET_LAST_CHK; + strm->txn->status = ctx->ctx.hlua_apphttp.status; + ctx->ctx.hlua_apphttp.flags |= (APPLET_LAST_CHK|APPLET_RSP_SENT); } - - /* close the connection. */ - - /* status */ - strm->txn->status = ctx->ctx.hlua_apphttp.status; - - /* eat the whole request */ - co_skip(si_oc(si), co_data(si_oc(si))); - res->flags |= CF_READ_NULL; - si_shutr(si); - - return; } -error: + done: + if (ctx->ctx.hlua_apphttp.flags & APPLET_DONE) { + if (!(res->flags & CF_SHUTR)) { + res->flags |= CF_READ_NULL; + si_shutr(si); + } + + /* eat the whole request */ + if (co_data(req)) + co_skip(req, co_data(req)); + } + + out: + return; + + error: /* If we are in HTTP mode, and we are not send any * data, return a 500 server error in best effort: * if there is no room available in the buffer, * just close the connection. */ - ci_putblk(res, error_500, strlen(error_500)); + if (!(ctx->ctx.hlua_apphttp.flags & APPLET_HDR_SENT)) { + channel_erase(res); + ci_putblk(res, error_500, strlen(error_500)); + } if (!(strm->flags & SF_ERR_MASK)) strm->flags |= SF_ERR_RESOURCE; - si_shutw(si); - si_shutr(si); ctx->ctx.hlua_apphttp.flags |= APPLET_DONE; + goto done; } static void hlua_applet_http_release(struct appctx *ctx)