#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;
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. */
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:
}
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;
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:
{
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;
/* 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) &&
*/
/* 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)
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. */
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:
}
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;
/* 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;
+ 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 */
- co_skip(si_oc(si), co_data(si_oc(si)));
- res->flags |= CF_READ_NULL;
- si_shutr(si);
-
- return;
+ if (co_data(req))
+ co_skip(req, co_data(req));
}
-error:
+ 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)