From a209796c80cdb65f2b2f4a7ed227dc9ca29519bf Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Mon, 15 Jul 2019 16:25:33 +0200 Subject: [PATCH] MEDIUM: hlua: Remove code relying on the legacy HTTP mode HTTP applets are concerned and functions of the HTTP class too. --- src/hlua.c | 1056 +++++++--------------------------------------------- 1 file changed, 138 insertions(+), 918 deletions(-) diff --git a/src/hlua.c b/src/hlua.c index 0163b95de..c1cf83c45 100644 --- a/src/hlua.c +++ b/src/hlua.c @@ -156,8 +156,7 @@ static int hlua_panic_ljmp(lua_State *L) { longjmp(safe_ljmp_env, 1); } #define APPLET_DONE 0x01 /* applet processing is done. */ /* unused: 0x02 */ #define APPLET_HDR_SENT 0x04 /* Response header sent. */ -#define APPLET_CHUNKED 0x08 /* Use transfer encoding chunked. */ -#define APPLET_LAST_CHK 0x10 /* Last chunk sent. */ +/* unused: 0x08, 0x10 */ #define APPLET_HTTP11 0x20 /* Last chunk sent. */ #define APPLET_RSP_SENT 0x40 /* The response was fully sent */ @@ -239,14 +238,6 @@ struct hlua_mem_allocator { static struct hlua_mem_allocator hlua_global_allocator; -static const char error_500[] = - "HTTP/1.0 500 Internal Server Error\r\n" - "Cache-Control: no-cache\r\n" - "Connection: close\r\n" - "Content-Type: text/html\r\n" - "\r\n" - "

500 Internal Server Error

\nAn internal server error occurred.\n\n"; - /* These functions converts types between HAProxy internal args or * sample and LUA types. Another function permits to check if the * LUA stack contains arguments according with an required ARG_T @@ -3899,6 +3890,12 @@ static int hlua_applet_http_new(lua_State *L, struct appctx *ctx) struct stream_interface *si = ctx->owner; struct stream *s = si_strm(si); struct proxy *px = s->be; + struct htx *htx; + struct htx_blk *blk; + struct htx_sl *sl; + struct ist path; + unsigned long long len = 0; + int32_t pos; /* Check stack size. */ if (!lua_checkstack(L, 3)) @@ -3941,134 +3938,71 @@ static int hlua_applet_http_new(lua_State *L, struct appctx *ctx) return 0; lua_settable(L, -3); - if (IS_HTX_STRM(s)) { - /* HTX version */ - struct htx *htx = htxbuf(&s->req.buf); - struct htx_blk *blk; - struct htx_sl *sl; - struct ist path; - unsigned long long len = 0; - int32_t pos; + htx = htxbuf(&s->req.buf); + blk = htx_get_first_blk(htx); + BUG_ON(htx_get_blk_type(blk) != HTX_BLK_REQ_SL); + sl = htx_get_blk_ptr(htx, blk); - blk = htx_get_first_blk(htx); - BUG_ON(htx_get_blk_type(blk) != HTX_BLK_REQ_SL); - sl = htx_get_blk_ptr(htx, blk); + /* Stores the request method. */ + lua_pushstring(L, "method"); + lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)); + lua_settable(L, -3); - /* Stores the request method. */ - lua_pushstring(L, "method"); - lua_pushlstring(L, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)); - lua_settable(L, -3); + /* Stores the http version. */ + lua_pushstring(L, "version"); + lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)); + lua_settable(L, -3); - /* Stores the http version. */ - lua_pushstring(L, "version"); - lua_pushlstring(L, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)); - lua_settable(L, -3); + /* creates an array of headers. hlua_http_get_headers() crates and push + * the array on the top of the stack. + */ + lua_pushstring(L, "headers"); + htxn.s = s; + htxn.p = px; + htxn.dir = SMP_OPT_DIR_REQ; + if (!hlua_http_get_headers(L, &htxn, &htxn.s->txn->req)) + return 0; + lua_settable(L, -3); - /* creates an array of headers. hlua_http_get_headers() crates and push - * the array on the top of the stack. - */ - lua_pushstring(L, "headers"); - htxn.s = s; - htxn.p = px; - htxn.dir = SMP_OPT_DIR_REQ; - if (!hlua_http_get_headers(L, &htxn, &htxn.s->txn->req)) - return 0; - lua_settable(L, -3); + path = http_get_path(htx_sl_req_uri(sl)); + if (path.ptr) { + char *p, *q, *end; - path = http_get_path(htx_sl_req_uri(sl)); - if (path.ptr) { - char *p, *q, *end; - - p = path.ptr; - end = path.ptr + path.len; - q = p; - while (q < end && *q != '?') - q++; - - /* Stores the request path. */ - lua_pushstring(L, "path"); - lua_pushlstring(L, p, q - p); - lua_settable(L, -3); - - /* Stores the query string. */ - lua_pushstring(L, "qs"); - if (*q == '?') - q++; - lua_pushlstring(L, q, end - q); - lua_settable(L, -3); - } - - for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { - struct htx_blk *blk = htx_get_blk(htx, pos); - 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) - len += htx_get_blksz(blk); - } - if (htx->extra != ULLONG_MAX) - len += htx->extra; + p = path.ptr; + end = path.ptr + path.len; + q = p; + while (q < end && *q != '?') + q++; /* Stores the request path. */ - lua_pushstring(L, "length"); - lua_pushinteger(L, len); + lua_pushstring(L, "path"); + lua_pushlstring(L, p, q - p); + lua_settable(L, -3); + + /* Stores the query string. */ + lua_pushstring(L, "qs"); + if (*q == '?') + q++; + lua_pushlstring(L, q, end - q); lua_settable(L, -3); } - else { - /* Legacy HTTP version */ - struct http_txn *txn = s->txn; - const char *path; - const char *end; - const char *p; - /* Stores the request method. */ - lua_pushstring(L, "method"); - lua_pushlstring(L, ci_head(txn->req.chn), txn->req.sl.rq.m_l); - lua_settable(L, -3); + for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { + struct htx_blk *blk = htx_get_blk(htx, pos); + enum htx_blk_type type = htx_get_blk_type(blk); - /* Stores the http version. */ - lua_pushstring(L, "version"); - lua_pushlstring(L, ci_head(txn->req.chn) + txn->req.sl.rq.v, txn->req.sl.rq.v_l); - lua_settable(L, -3); - - /* creates an array of headers. hlua_http_get_headers() crates and push - * the array on the top of the stack. - */ - lua_pushstring(L, "headers"); - htxn.s = s; - htxn.p = px; - htxn.dir = SMP_OPT_DIR_REQ; - if (!hlua_http_get_headers(L, &htxn, &htxn.s->txn->req)) - return 0; - lua_settable(L, -3); - - /* Get path and qs */ - path = http_txn_get_path(txn); - if (path) { - end = ci_head(txn->req.chn) + txn->req.sl.rq.u + txn->req.sl.rq.u_l; - p = path; - while (p < end && *p != '?') - p++; - - /* Stores the request path. */ - lua_pushstring(L, "path"); - lua_pushlstring(L, path, p - path); - lua_settable(L, -3); - - /* Stores the query string. */ - lua_pushstring(L, "qs"); - if (*p == '?') - p++; - lua_pushlstring(L, p, end - p); - lua_settable(L, -3); - } - - /* Stores the request path. */ - lua_pushstring(L, "length"); - lua_pushinteger(L, txn->req.body_len); - lua_settable(L, -3); + if (type == HTX_BLK_EOM || type == HTX_BLK_TLR || type == HTX_BLK_EOT) + break; + if (type == HTX_BLK_DATA) + len += htx_get_blksz(blk); } + if (htx->extra != ULLONG_MAX) + len += htx->extra; + + /* Stores the request path. */ + lua_pushstring(L, "length"); + lua_pushinteger(L, len); + lua_settable(L, -3); /* Create an empty array of HTTP request headers. */ lua_pushstring(L, "response"); @@ -4203,7 +4137,7 @@ __LJMP static int hlua_applet_http_get_priv(lua_State *L) * consumes the data in the buffer. It returns a string containing the * data. This string can be empty. */ -__LJMP static int hlua_applet_htx_getline_yield(lua_State *L, int status, lua_KContext ctx) +__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx) { struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); struct stream_interface *si = appctx->appctx->owner; @@ -4273,7 +4207,7 @@ __LJMP static int hlua_applet_htx_getline_yield(lua_State *L, int status, lua_KC htx_to_buf(htx, &req->buf); if (!stop) { si_cant_get(si); - MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_htx_getline_yield, TICK_ETERNITY, 0)); + MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0)); } /* return the result. */ @@ -4282,63 +4216,6 @@ __LJMP static int hlua_applet_htx_getline_yield(lua_State *L, int status, lua_KC } -/* If expected data not yet available, it returns a yield. This function - * consumes the data in the buffer. It returns a string containing the - * data. This string can be empty. - */ -__LJMP static int hlua_applet_http_getline_yield(lua_State *L, int status, lua_KContext ctx) -{ - struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); - struct stream_interface *si = appctx->appctx->owner; - int ret; - const char *blk1; - size_t len1; - const char *blk2; - size_t len2; - - /* Check for the end of the data. */ - if (appctx->appctx->ctx.hlua_apphttp.left_bytes <= 0) { - luaL_pushresult(&appctx->b); - return 1; - } - - /* Read the maximum amount of data available. */ - ret = co_getline_nc(si_oc(si), &blk1, &len1, &blk2, &len2); - - /* Data not yet available. return yield. */ - if (ret == 0) { - si_cant_get(si); - MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_getline_yield, TICK_ETERNITY, 0)); - } - - /* End of data: commit the total strings and return. */ - if (ret < 0) { - luaL_pushresult(&appctx->b); - return 1; - } - - /* Ensure that the block 2 length is usable. */ - if (ret == 1) - len2 = 0; - - /* Copy the fisrt block caping to the length required. */ - if (len1 > appctx->appctx->ctx.hlua_apphttp.left_bytes) - len1 = appctx->appctx->ctx.hlua_apphttp.left_bytes; - luaL_addlstring(&appctx->b, blk1, len1); - appctx->appctx->ctx.hlua_apphttp.left_bytes -= len1; - - /* Copy the second block. */ - if (len2 > appctx->appctx->ctx.hlua_apphttp.left_bytes) - len2 = appctx->appctx->ctx.hlua_apphttp.left_bytes; - luaL_addlstring(&appctx->b, blk2, len2); - appctx->appctx->ctx.hlua_apphttp.left_bytes -= len2; - - /* Consume input channel output buffer data. */ - co_skip(si_oc(si), len1 + len2); - luaL_pushresult(&appctx->b); - return 1; -} - /* Check arguments for the function "hlua_channel_get_yield". */ __LJMP static int hlua_applet_http_getline(lua_State *L) { @@ -4347,17 +4224,14 @@ __LJMP static int hlua_applet_http_getline(lua_State *L) /* Initialise the string catenation. */ luaL_buffinit(L, &appctx->b); - if (IS_HTX_STRM(si_strm(appctx->appctx->owner))) - return MAY_LJMP(hlua_applet_htx_getline_yield(L, 0, 0)); - else - return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0)); + return MAY_LJMP(hlua_applet_http_getline_yield(L, 0, 0)); } /* If expected data not yet available, it returns a yield. This function * consumes the data in the buffer. It returns a string containing the * data. This string can be empty. */ -__LJMP static int hlua_applet_htx_recv_yield(lua_State *L, int status, lua_KContext ctx) +__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx) { struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); struct stream_interface *si = appctx->appctx->owner; @@ -4430,70 +4304,6 @@ __LJMP static int hlua_applet_htx_recv_yield(lua_State *L, int status, lua_KCont lua_replace(L, 2); } si_cant_get(si); - MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_htx_recv_yield, TICK_ETERNITY, 0)); - } - - /* return the result. */ - luaL_pushresult(&appctx->b); - return 1; -} - -/* If expected data not yet available, it returns a yield. This function - * consumes the data in the buffer. It returns a string containing the - * data. This string can be empty. - */ -__LJMP static int hlua_applet_http_recv_yield(lua_State *L, int status, lua_KContext ctx) -{ - struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); - struct stream_interface *si = appctx->appctx->owner; - int len = MAY_LJMP(luaL_checkinteger(L, 2)); - int ret; - const char *blk1; - size_t len1; - const char *blk2; - size_t len2; - - /* Read the maximum amount of data available. */ - ret = co_getblk_nc(si_oc(si), &blk1, &len1, &blk2, &len2); - - /* Data not yet available. return yield. */ - if (ret == 0) { - si_cant_get(si); - MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0)); - } - - /* End of data: commit the total strings and return. */ - if (ret < 0) { - luaL_pushresult(&appctx->b); - return 1; - } - - /* Ensure that the block 2 length is usable. */ - if (ret == 1) - len2 = 0; - - /* Copy the fisrt block caping to the length required. */ - if (len1 > len) - len1 = len; - luaL_addlstring(&appctx->b, blk1, len1); - len -= len1; - - /* Copy the second block. */ - if (len2 > len) - len2 = len; - luaL_addlstring(&appctx->b, blk2, len2); - len -= len2; - - /* Consume input channel output buffer data. */ - co_skip(si_oc(si), len1 + len2); - if (appctx->appctx->ctx.hlua_apphttp.left_bytes != -1) - appctx->appctx->ctx.hlua_apphttp.left_bytes -= len; - - /* If we are no other data available, yield waiting for new data. */ - if (len > 0) { - lua_pushinteger(L, len); - lua_replace(L, 2); - si_cant_get(si); MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_recv_yield, TICK_ETERNITY, 0)); } @@ -4516,27 +4326,12 @@ __LJMP static int hlua_applet_http_recv(lua_State *L) lua_pop(L, 1); } - if (IS_HTX_STRM(si_strm(appctx->appctx->owner))) { - /* HTX version */ - lua_pushinteger(L, len); + lua_pushinteger(L, len); - /* Initialise the string catenation. */ - luaL_buffinit(L, &appctx->b); + /* Initialise the string catenation. */ + luaL_buffinit(L, &appctx->b); - return MAY_LJMP(hlua_applet_htx_recv_yield(L, 0, 0)); - } - else { - /* Legacy HTTP version */ - /* Check the required length */ - if (len == -1 || len > appctx->appctx->ctx.hlua_apphttp.left_bytes) - len = appctx->appctx->ctx.hlua_apphttp.left_bytes; - lua_pushinteger(L, len); - - /* Initialise the string catenation. */ - luaL_buffinit(L, &appctx->b); - - return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0)); - } + return MAY_LJMP(hlua_applet_http_recv_yield(L, 0, 0)); } /* Append data in the output side of the buffer. This data is immediately @@ -4544,7 +4339,7 @@ __LJMP static int hlua_applet_http_recv(lua_State *L) * cannot contain the data, the function yields. The function returns -1 * if the channel is closed. */ -__LJMP static int hlua_applet_htx_send_yield(lua_State *L, int status, lua_KContext ctx) +__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx) { struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); struct stream_interface *si = appctx->appctx->owner; @@ -4580,50 +4375,11 @@ __LJMP static int hlua_applet_htx_send_yield(lua_State *L, int status, lua_KCont if (l < len) { snd_yield: htx_to_buf(htx, &res->buf); - si_rx_room_blk(si); - MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_htx_send_yield, TICK_ETERNITY, 0)); - } - - htx_to_buf(htx, &res->buf); - return 1; -} - -/* Append data in the output side of the buffer. This data is immediately - * sent. The function returns the amount of data written. If the buffer - * cannot contain the data, the function yields. The function returns -1 - * if the channel is closed. - */ -__LJMP static int hlua_applet_http_send_yield(lua_State *L, int status, lua_KContext ctx) -{ - size_t len; - struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); - const char *str = MAY_LJMP(luaL_checklstring(L, 2, &len)); - int l = MAY_LJMP(luaL_checkinteger(L, 3)); - struct stream_interface *si = appctx->appctx->owner; - struct channel *chn = si_ic(si); - int max; - - /* Get the max amount of data which can write as input in the channel. */ - max = channel_recv_max(chn); - if (max > (len - l)) - max = len - l; - - /* Copy data. */ - ci_putblk(chn, str + l, max); - - /* update counters. */ - l += max; - lua_pop(L, 1); - lua_pushinteger(L, l); - - /* If some data is not send, declares the situation to the - * applet, and returns a yield. - */ - if (l < len) { si_rx_room_blk(si); MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_send_yield, TICK_ETERNITY, 0)); } + htx_to_buf(htx, &res->buf); return 1; } @@ -4641,36 +4397,10 @@ __LJMP static int hlua_applet_http_send(lua_State *L) WILL_LJMP(lua_error(L)); } - if (IS_HTX_STRM(si_strm(appctx->appctx->owner))) { - /* HTX version */ - /* This interger is used for followinf the amount of data sent. */ - lua_pushinteger(L, 0); + /* This interger is used for followinf the amount of data sent. */ + lua_pushinteger(L, 0); - return MAY_LJMP(hlua_applet_htx_send_yield(L, 0, 0)); - } - else { - /* Legacy HTTP version */ - size_t len; - char hex[10]; - - MAY_LJMP(luaL_checklstring(L, 2, &len)); - - /* If transfer encoding chunked is selected, we surround the data - * by chunk data. - */ - if (appctx->appctx->ctx.hlua_apphttp.flags & APPLET_CHUNKED) { - snprintf(hex, 9, "%x", (unsigned int)len); - lua_pushfstring(L, "%s\r\n", hex); - lua_insert(L, 2); /* swap the last 2 entries. */ - lua_pushstring(L, "\r\n"); - lua_concat(L, 3); - } - - /* This interger is used for followinf the amount of data sent. */ - lua_pushinteger(L, 0); - - return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0)); - } + return MAY_LJMP(hlua_applet_http_send_yield(L, 0, 0)); } __LJMP static int hlua_applet_http_addheader(lua_State *L) @@ -4743,7 +4473,7 @@ __LJMP static int hlua_applet_http_status(lua_State *L) } -__LJMP static int hlua_applet_htx_send_response(lua_State *L) +__LJMP static int hlua_applet_http_send_response(lua_State *L) { struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); struct stream_interface *si = appctx->appctx->owner; @@ -4931,207 +4661,22 @@ __LJMP static int hlua_applet_htx_send_response(lua_State *L) * We will try send at once if its not possible, we give back the hand * waiting for more room. */ -__LJMP static int hlua_applet_htx_start_response_yield(lua_State *L, int status, lua_KContext ctx) +__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx) { struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); struct stream_interface *si = appctx->appctx->owner; struct channel *res = si_ic(si); if (co_data(res)) { - si_rx_room_blk(si); - MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_htx_start_response_yield, TICK_ETERNITY, 0)); - } - return MAY_LJMP(hlua_applet_htx_send_response(L)); -} - - -__LJMP static int hlua_applet_htx_start_response(lua_State *L) -{ - return MAY_LJMP(hlua_applet_htx_start_response_yield(L, 0, 0)); -} - -/* We will build the status line and the headers of the HTTP response. - * We will try send at once if its not possible, we give back the hand - * waiting for more room. - */ -__LJMP static int hlua_applet_http_start_response_yield(lua_State *L, int status, lua_KContext ctx) -{ - struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); - struct stream_interface *si = appctx->appctx->owner; - struct channel *chn = si_ic(si); - int ret; - size_t len; - const char *msg; - - /* Get the message as the first argument on the stack. */ - msg = MAY_LJMP(luaL_checklstring(L, 2, &len)); - - /* Send the message at once. */ - ret = ci_putblk(chn, msg, len); - - /* if ret == -2 or -3 the channel closed or the message si too - * big for the buffers. - */ - if (ret == -2 || ret == -3) { - hlua_pusherror(L, "Lua: 'start_response': response header block too big"); - WILL_LJMP(lua_error(L)); - } - - /* If ret is -1, we dont have room in the buffer, so we yield. */ - if (ret == -1) { si_rx_room_blk(si); MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_applet_http_start_response_yield, TICK_ETERNITY, 0)); } - - /* Headers sent, set the flag. */ - appctx->appctx->ctx.hlua_apphttp.flags |= APPLET_HDR_SENT; - return 0; + return MAY_LJMP(hlua_applet_http_send_response(L)); } + __LJMP static int hlua_applet_http_start_response(lua_State *L) { - struct buffer *tmp; - struct hlua_appctx *appctx = MAY_LJMP(hlua_checkapplet_http(L, 1)); - const char *name; - size_t name_len; - const char *value; - size_t value_len; - int id; - long long hdr_contentlength = -1; - int hdr_chunked = 0; - const char *reason; - - if (IS_HTX_STRM(si_strm(appctx->appctx->owner))) - return MAY_LJMP(hlua_applet_htx_start_response(L)); - - reason = appctx->appctx->ctx.hlua_apphttp.reason; - if (reason == NULL) - reason = http_get_reason(appctx->appctx->ctx.hlua_apphttp.status); - - tmp = get_trash_chunk(); - - /* Use the same http version than the request. */ - chunk_appendf(tmp, "HTTP/1.%c %d %s\r\n", - appctx->appctx->ctx.hlua_apphttp.flags & APPLET_HTTP11 ? '1' : '0', - appctx->appctx->ctx.hlua_apphttp.status, - reason); - - /* Get the array associated to the field "response" in the object AppletHTTP. */ - lua_pushvalue(L, 0); - if (lua_getfield(L, 1, "response") != LUA_TTABLE) { - hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'] missing.\n", - appctx->appctx->rule->arg.hlua_rule->fcn.name); - WILL_LJMP(lua_error(L)); - } - - /* Browse the list of headers. */ - lua_pushnil(L); - while(lua_next(L, -2) != 0) { - - /* We expect a string as -2. */ - if (lua_type(L, -2) != LUA_TSTRING) { - hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response'][] element must be a string. got %s.\n", - appctx->appctx->rule->arg.hlua_rule->fcn.name, - lua_typename(L, lua_type(L, -2))); - WILL_LJMP(lua_error(L)); - } - name = lua_tolstring(L, -2, &name_len); - - /* We expect an array as -1. */ - if (lua_type(L, -1) != LUA_TTABLE) { - hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'] element must be an table. got %s.\n", - appctx->appctx->rule->arg.hlua_rule->fcn.name, - name, - lua_typename(L, lua_type(L, -1))); - WILL_LJMP(lua_error(L)); - } - - /* Browse the table who is on the top of the stack. */ - lua_pushnil(L); - while(lua_next(L, -2) != 0) { - - /* We expect a number as -2. */ - if (lua_type(L, -2) != LUA_TNUMBER) { - hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'][] element must be a number. got %s.\n", - appctx->appctx->rule->arg.hlua_rule->fcn.name, - name, - lua_typename(L, lua_type(L, -2))); - WILL_LJMP(lua_error(L)); - } - id = lua_tointeger(L, -2); - - /* We expect a string as -2. */ - if (lua_type(L, -1) != LUA_TSTRING) { - hlua_pusherror(L, "Lua applet http '%s': AppletHTTP['response']['%s'][%d] element must be a string. got %s.\n", - appctx->appctx->rule->arg.hlua_rule->fcn.name, - name, id, - lua_typename(L, lua_type(L, -1))); - WILL_LJMP(lua_error(L)); - } - value = lua_tolstring(L, -1, &value_len); - - /* Catenate a new header. */ - if (tmp->data + name_len + 2 + value_len + 2 < tmp->size) { - memcpy(tmp->area + tmp->data, name, name_len); - tmp->data += name_len; - tmp->area[tmp->data++] = ':'; - tmp->area[tmp->data++] = ' '; - - memcpy(tmp->area + tmp->data, value, - value_len); - tmp->data += value_len; - tmp->area[tmp->data++] = '\r'; - tmp->area[tmp->data++] = '\n'; - } - - /* Protocol checks. */ - - /* Copy the header content length. The length conversion - * is done without control. If it contains a bad value, - * the content-length remains negative so that we can - * switch to either chunked encoding or close. - */ - if (name_len == 14 && strcasecmp("content-length", name) == 0) - strl2llrc(value, strlen(value), &hdr_contentlength); - - /* Check if the client annouces a transfer-encoding chunked it self. */ - if (name_len == 17 && value_len == 7 && - strcasecmp("transfer-encoding", name) == 0 && - strcasecmp("chunked", value) == 0) - hdr_chunked = 1; - - /* Remove the array from the stack, and get next element with a remaining string. */ - lua_pop(L, 1); - } - - /* Remove the array from the stack, and get next element with a remaining string. */ - lua_pop(L, 1); - } - - /* If we dont have a content-length set, and the HTTP version is 1.1 - * and the status code implies the presence of a message body, we must - * announce a transfer encoding chunked. This is required by haproxy - * for the keepalive compliance. If the applet annouces a transfer-encoding - * chunked itslef, don't do anything. - */ - if (hdr_contentlength < 0 && hdr_chunked == 0 && - (appctx->appctx->ctx.hlua_apphttp.flags & APPLET_HTTP11) && - appctx->appctx->ctx.hlua_apphttp.status >= 200 && - appctx->appctx->ctx.hlua_apphttp.status != 204 && - appctx->appctx->ctx.hlua_apphttp.status != 304) { - chunk_appendf(tmp, "Transfer-encoding: chunked\r\n"); - appctx->appctx->ctx.hlua_apphttp.flags |= APPLET_CHUNKED; - } - - /* Finalize headers. */ - chunk_appendf(tmp, "\r\n"); - - /* Remove the last entry and the array of headers */ - lua_pop(L, 2); - - /* Push the headers block. */ - lua_pushlstring(L, tmp->area, tmp->data); - return MAY_LJMP(hlua_applet_http_start_response_yield(L, 0, 0)); } @@ -5188,152 +4733,62 @@ static int hlua_http_new(lua_State *L, struct hlua_txn *txn) */ __LJMP static int hlua_http_get_headers(lua_State *L, struct hlua_txn *htxn, struct http_msg *msg) { + struct htx *htx; + int32_t pos; + /* Create the table. */ lua_newtable(L); if (!htxn->s->txn) return 1; - if (IS_HTX_STRM(htxn->s)) { - /* HTX version */ - struct htx *htx = htxbuf(&msg->chn->buf); - int32_t pos; - - for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { - struct htx_blk *blk = htx_get_blk(htx, pos); - enum htx_blk_type type = htx_get_blk_type(blk); - struct ist n, v; - int len; - - if (type == HTX_BLK_HDR) { - n = htx_get_blk_name(htx,blk); - v = htx_get_blk_value(htx, blk); - } - else if (type == HTX_BLK_EOH) - break; - else - continue; - - /* Check for existing entry: - * assume that the table is on the top of the stack, and - * push the key in the stack, the function lua_gettable() - * perform the lookup. - */ - lua_pushlstring(L, n.ptr, n.len); - lua_gettable(L, -2); - - switch (lua_type(L, -1)) { - case LUA_TNIL: - /* Table not found, create it. */ - lua_pop(L, 1); /* remove the nil value. */ - lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */ - lua_newtable(L); /* create and push empty table. */ - lua_pushlstring(L, v.ptr, v.len); /* push header value. */ - lua_rawseti(L, -2, 0); /* index header value (pop it). */ - lua_rawset(L, -3); /* index new table with header name (pop the values). */ - break; - - case LUA_TTABLE: - /* Entry found: push the value in the table. */ - len = lua_rawlen(L, -1); - lua_pushlstring(L, v.ptr, v.len); /* push header value. */ - lua_rawseti(L, -2, len+1); /* index header value (pop it). */ - lua_pop(L, 1); /* remove the table (it is stored in the main table). */ - break; - - default: - /* Other cases are errors. */ - hlua_pusherror(L, "internal error during the parsing of headers."); - WILL_LJMP(lua_error(L)); - } - } - } - else { - /* Legacy HTTP version */ - const char *cur_ptr, *cur_next, *p; - int old_idx, cur_idx; - struct hdr_idx_elem *cur_hdr; - const char *hn, *hv; - int hnl, hvl; - const char *in; - char *out; + htx = htxbuf(&msg->chn->buf); + for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) { + struct htx_blk *blk = htx_get_blk(htx, pos); + enum htx_blk_type type = htx_get_blk_type(blk); + struct ist n, v; int len; - /* Build array of headers. */ - old_idx = 0; - cur_next = ci_head(msg->chn) + hdr_idx_first_pos(&htxn->s->txn->hdr_idx); + if (type == HTX_BLK_HDR) { + n = htx_get_blk_name(htx,blk); + v = htx_get_blk_value(htx, blk); + } + else if (type == HTX_BLK_EOH) + break; + else + continue; - while (1) { - cur_idx = htxn->s->txn->hdr_idx.v[old_idx].next; - if (!cur_idx) + /* Check for existing entry: + * assume that the table is on the top of the stack, and + * push the key in the stack, the function lua_gettable() + * perform the lookup. + */ + lua_pushlstring(L, n.ptr, n.len); + lua_gettable(L, -2); + + switch (lua_type(L, -1)) { + case LUA_TNIL: + /* Table not found, create it. */ + lua_pop(L, 1); /* remove the nil value. */ + lua_pushlstring(L, n.ptr, n.len); /* push the header name as key. */ + lua_newtable(L); /* create and push empty table. */ + lua_pushlstring(L, v.ptr, v.len); /* push header value. */ + lua_rawseti(L, -2, 0); /* index header value (pop it). */ + lua_rawset(L, -3); /* index new table with header name (pop the values). */ break; - old_idx = cur_idx; - cur_hdr = &htxn->s->txn->hdr_idx.v[cur_idx]; - cur_ptr = cur_next; - cur_next = cur_ptr + cur_hdr->len + cur_hdr->cr + 1; + case LUA_TTABLE: + /* Entry found: push the value in the table. */ + len = lua_rawlen(L, -1); + lua_pushlstring(L, v.ptr, v.len); /* push header value. */ + lua_rawseti(L, -2, len+1); /* index header value (pop it). */ + lua_pop(L, 1); /* remove the table (it is stored in the main table). */ + break; - /* Now we have one full header at cur_ptr of len cur_hdr->len, - * and the next header starts at cur_next. We'll check - * this header in the list as well as against the default - * rule. - */ - - /* look for ': *'. */ - hn = cur_ptr; - for (p = cur_ptr; p < cur_ptr + cur_hdr->len && *p != ':'; p++); - if (p >= cur_ptr+cur_hdr->len) - continue; - hnl = p - hn; - p++; - while (p < cur_ptr+cur_hdr->len && ( *p == ' ' || *p == '\t' )) - p++; - if (p >= cur_ptr+cur_hdr->len) - continue; - hv = p; - hvl = cur_ptr+cur_hdr->len-p; - - /* Lowercase the key. Don't check the size of trash, it have - * the size of one buffer and the input data contains in one - * buffer. - */ - out = trash.area; - for (in=hn; ins)) { - struct htx *htx = htxbuf(&msg->chn->buf); - - htx_transform_header_str(htxn->s, msg->chn, htx, ist2(name, name_len), value, re, action); - } - else - http_transform_header_str(htxn->s, msg, name, name_len, value, re, action); + htx = htxbuf(&msg->chn->buf); + htx_transform_header_str(htxn->s, msg->chn, htx, ist2(name, name_len), value, re, action); regex_free(re); return 0; } @@ -5433,25 +4884,12 @@ __LJMP static inline int hlua_http_del_hdr(lua_State *L, struct hlua_txn *htxn, { size_t len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len)); + struct htx *htx = htxbuf(&msg->chn->buf); + struct http_hdr_ctx ctx; - if (IS_HTX_STRM(htxn->s)) { - /* HTX version */ - struct htx *htx = htxbuf(&msg->chn->buf); - struct http_hdr_ctx ctx; - - ctx.blk = NULL; - while (http_find_header(htx, ist2(name, len), &ctx, 1)) - http_remove_header(htx, &ctx); - } - else { - /* Legacy HTTP version */ - struct hdr_ctx ctx; - struct http_txn *txn = htxn->s->txn; - - ctx.idx = 0; - while (http_find_header2(name, len, ci_head(msg->chn), &txn->hdr_idx, &ctx)) - http_remove_header2(msg, &txn->hdr_idx, &ctx); - } + ctx.blk = NULL; + while (http_find_header(htx, ist2(name, len), &ctx, 1)) + http_remove_header(htx, &ctx); return 0; } @@ -5484,35 +4922,10 @@ __LJMP static inline int hlua_http_add_hdr(lua_State *L, struct hlua_txn *htxn, const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); size_t value_len; const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len)); - char *p; + struct htx *htx = htxbuf(&msg->chn->buf); - if (IS_HTX_STRM(htxn->s)) { - /* HTX version */ - struct htx *htx = htxbuf(&msg->chn->buf); - - lua_pushboolean(L, http_add_header(htx, ist2(name, name_len), - ist2(value, value_len))); - } - else { - /* Legacy HTTP version */ - /* Check length. */ - trash.data = value_len + name_len + 2; - if (trash.data > trash.size) - return 0; - - /* Creates the header string. */ - p = trash.area; - memcpy(p, name, name_len); - p += name_len; - *p = ':'; - p++; - *p = ' '; - p++; - memcpy(p, value, value_len); - - lua_pushboolean(L, http_header_add_tail2(msg, &htxn->s->txn->hdr_idx, - trash.area, trash.data) != 0); - } + lua_pushboolean(L, http_add_header(htx, ist2(name, name_len), + ist2(value, value_len))); return 0; } @@ -5565,7 +4978,7 @@ static int hlua_http_req_set_meth(lua_State *L) size_t name_len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); - lua_pushboolean(L, http_replace_req_line(0, name, name_len, htxn->p, htxn->s) != -1); + lua_pushboolean(L, htx_req_replace_stline(0, name, name_len, htxn->p, htxn->s) != -1); return 1; } @@ -5576,7 +4989,7 @@ static int hlua_http_req_set_path(lua_State *L) size_t name_len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); - lua_pushboolean(L, http_replace_req_line(1, name, name_len, htxn->p, htxn->s) != -1); + lua_pushboolean(L, htx_req_replace_stline(1, name, name_len, htxn->p, htxn->s) != -1); return 1; } @@ -5600,7 +5013,7 @@ static int hlua_http_req_set_query(lua_State *L) trash.data += name_len; lua_pushboolean(L, - http_replace_req_line(2, trash.area, trash.data, htxn->p, htxn->s) != -1); + htx_req_replace_stline(2, trash.area, trash.data, htxn->p, htxn->s) != -1); return 1; } @@ -5611,7 +5024,7 @@ static int hlua_http_req_set_uri(lua_State *L) size_t name_len; const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len)); - lua_pushboolean(L, http_replace_req_line(3, name, name_len, htxn->p, htxn->s) != -1); + lua_pushboolean(L, htx_req_replace_stline(3, name, name_len, htxn->p, htxn->s) != -1); return 1; } @@ -5622,7 +5035,7 @@ static int hlua_http_res_set_status(lua_State *L) unsigned int code = MAY_LJMP(luaL_checkinteger(L, 2)); const char *reason = MAY_LJMP(luaL_optlstring(L, 3, NULL, NULL)); - http_set_status(code, reason, htxn->s); + htx_res_set_status(code, reason, htxn->s); return 0; } @@ -5999,25 +5412,6 @@ __LJMP static int hlua_txn_done(lua_State *L) if (IS_HTX_STRM(htxn->s)) htx_reply_and_close(htxn->s, 0, NULL); else { - if (htxn->s->txn) { - /* HTTP mode, let's stay in sync with the stream */ - b_del(&ic->buf, htxn->s->txn->req.sov); - htxn->s->txn->req.next -= htxn->s->txn->req.sov; - htxn->s->txn->req.sov = 0; - - ic->analysers &= AN_REQ_HTTP_XFER_BODY; - oc->analysers = AN_RES_HTTP_XFER_BODY; - htxn->s->txn->req.msg_state = HTTP_MSG_CLOSED; - htxn->s->txn->rsp.msg_state = HTTP_MSG_DONE; - - /* Note that if we want to support keep-alive, we need - * to bypass the close/shutr_now calls below, but that - * may only be done if the HTTP request was already - * processed and the connection header is known (ie - * not during TCP rules). - */ - } - channel_auto_read(ic); channel_abort(ic); channel_auto_close(ic); @@ -7185,7 +6579,7 @@ static int hlua_applet_http_init(struct appctx *ctx, struct proxy *px, struct st return 1; } -static void hlua_applet_htx_fct(struct appctx *ctx) +static void hlua_applet_http_fct(struct appctx *ctx) { struct stream_interface *si = ctx->owner; struct stream *strm = si_strm(si); @@ -7355,180 +6749,6 @@ static void hlua_applet_htx_fct(struct appctx *ctx) goto done; } -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; - struct hlua *hlua = ctx->ctx.hlua_apphttp.hlua; - const char *blk1; - size_t len1; - const char *blk2; - size_t len2; - int ret; - - if (IS_HTX_STRM(strm)) - return hlua_applet_htx_fct(ctx); - - /* If the stream is disconnect or closed, ldo nothing. */ - if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) - 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) && - !(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) { - /* Store the max amount of bytes that we can read. */ - ctx->ctx.hlua_apphttp.left_bytes = strm->txn->req.body_len; - - /* We need to flush the request header. This left the body - * for the Lua. - */ - - /* Read the maximum amount of data available. */ - ret = co_getblk_nc(req, &blk1, &len1, &blk2, &len2); - if (ret == -1) - goto out; - - /* No data available, ask for more data. */ - if (ret == 1) - len2 = 0; - if (ret == 0) - len1 = 0; - if (len1 + len2 < strm->txn->req.eoh + strm->txn->req.eol) { - si_cant_get(si); - goto out; - } - - /* skip the requests bytes. */ - co_skip(req, strm->txn->req.eoh + strm->txn->req.eol); - } - - /* Executes The applet if it is not done. */ - if (!(ctx->ctx.hlua_apphttp.flags & APPLET_DONE)) { - - /* Execute the function. */ - switch (hlua_ctx_resume(hlua, 1)) { - /* finished. */ - case HLUA_E_OK: - ctx->ctx.hlua_apphttp.flags |= APPLET_DONE; - break; - - /* yield. */ - case HLUA_E_AGAIN: - if (hlua->wake_time != TICK_ETERNITY) - task_schedule(ctx->ctx.hlua_apphttp.task, hlua->wake_time); - goto out; - - /* finished with error. */ - case HLUA_E_ERRMSG: - /* Display log. */ - SEND_ERR(px, "Lua applet http '%s': %s.\n", - rule->arg.hlua_rule->fcn.name, lua_tostring(hlua->T, -1)); - lua_pop(hlua->T, 1); - goto error; - - case HLUA_E_ETMOUT: - SEND_ERR(px, "Lua applet http '%s': execution timeout.\n", - rule->arg.hlua_rule->fcn.name); - goto error; - - case HLUA_E_NOMEM: - SEND_ERR(px, "Lua applet http '%s': out of memory error.\n", - rule->arg.hlua_rule->fcn.name); - goto error; - - case HLUA_E_YIELD: /* unexpected */ - SEND_ERR(px, "Lua applet http '%s': yield not allowed.\n", - rule->arg.hlua_rule->fcn.name); - goto error; - - case HLUA_E_ERR: - /* Display log. */ - SEND_ERR(px, "Lua applet http '%s' return an unknown error.\n", - rule->arg.hlua_rule->fcn.name); - goto error; - - default: - goto error; - } - } - - 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; - - /* We must send the final chunk. */ - if (ctx->ctx.hlua_apphttp.flags & APPLET_CHUNKED && - !(ctx->ctx.hlua_apphttp.flags & APPLET_LAST_CHK)) { - - /* sent last chunk at once. */ - ret = ci_putblk(res, "0\r\n\r\n", 5); - - /* critical error. */ - if (ret == -2 || ret == -3) { - SEND_ERR(px, "Lua applet http '%s'cannont send last chunk.\n", - rule->arg.hlua_rule->fcn.name); - goto error; - } - - /* no enough space error. */ - if (ret == -1) { - si_rx_room_blk(si); - goto out; - } - - strm->txn->status = ctx->ctx.hlua_apphttp.status; - ctx->ctx.hlua_apphttp.flags |= (APPLET_LAST_CHK|APPLET_RSP_SENT); - } - } - - 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. - */ - 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; - ctx->ctx.hlua_apphttp.flags |= APPLET_DONE; - goto done; -} - static void hlua_applet_http_release(struct appctx *ctx) { task_destroy(ctx->ctx.hlua_apphttp.task);