mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-04-09 18:51:36 +00:00
MEDIUM: filters/lua: Be prepared to filter TCP payloads
For filters written in lua, the tcp payloads will be filtered using methods exposed by the Channel class. So the corrsponding C binding functions must be prepared to process payload in a filter context and not only in an action context. The main change is the offset where to start to process data in the channel buffer, and the length of these data. For an action, all input data are considered. But for a filter, it depends on what the filter is allow to forward when the tcp_payload callback function is called. It depends on previous calls but also on other filters. In addition, when the payload is modified by a lua filter, its context must be updated. Note also that channel functions cannot yield when called from a filter context. For now, it is not possible to define callbacks to filter data and the documentation has not been updated.
This commit is contained in:
parent
8c9e6bba0f
commit
a1ac5fb28e
397
src/hlua.c
397
src/hlua.c
@ -3009,7 +3009,7 @@ static int hlua_channel_new(lua_State *L, struct channel *channel)
|
||||
* filter is attached, NULL is returned and <offet> and <len> are not
|
||||
* initialized.
|
||||
*/
|
||||
static __maybe_unused struct filter *hlua_channel_filter(lua_State *L, int ud, struct channel *chn, size_t *offset, size_t *len)
|
||||
static struct filter *hlua_channel_filter(lua_State *L, int ud, struct channel *chn, size_t *offset, size_t *len)
|
||||
{
|
||||
struct filter *filter = NULL;
|
||||
|
||||
@ -3090,29 +3090,38 @@ static void _hlua_channel_delete(struct channel *chn, size_t offset, size_t len)
|
||||
* offset (0 by default) and a length (all remaining input data starting for the
|
||||
* offset by default). If there is not enough input data and more data can be
|
||||
* received, this function yields.
|
||||
*
|
||||
* From an action, All input data are considered. For a filter, the offset and
|
||||
* the length of input data to consider are retrieved from the filter context.
|
||||
*/
|
||||
__LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct channel *chn;
|
||||
int offset = 0, len = 0;
|
||||
struct filter *filter;
|
||||
size_t input, output;
|
||||
int offset, len;
|
||||
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
|
||||
if (!ci_data(chn) && channel_input_closed(chn)) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
output = co_data(chn);
|
||||
input = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &output, &input);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
offset = output;
|
||||
if (lua_gettop(L) > 1) {
|
||||
offset = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
if (offset < 0)
|
||||
offset = MAX(0, ci_data(chn) + offset);
|
||||
if (offset > ci_data(chn)) {
|
||||
offset = MAX(0, input + offset);
|
||||
offset += output;
|
||||
if (offset < output || offset > input + output) {
|
||||
lua_pushfstring(L, "offset out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
len = ci_data(chn) - offset;
|
||||
len = output + input - offset;
|
||||
if (lua_gettop(L) == 3) {
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
if (!len)
|
||||
@ -3125,16 +3134,16 @@ __LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KCon
|
||||
}
|
||||
}
|
||||
|
||||
if (offset + len > ci_data(chn)) {
|
||||
if (offset + len > output + input) {
|
||||
if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
|
||||
/* Yield waiting for more data, as requested */
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_data_yield, TICK_ETERNITY, 0));
|
||||
}
|
||||
len = ci_data(chn) - offset;
|
||||
len = output + input - offset;
|
||||
}
|
||||
|
||||
dup:
|
||||
_hlua_channel_dup(chn, L, co_data(chn) + offset, len);
|
||||
_hlua_channel_dup(chn, L, offset, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3145,29 +3154,38 @@ __LJMP static int hlua_channel_get_data_yield(lua_State *L, int status, lua_KCon
|
||||
* yields. If a length is explicitly specified, no more data are
|
||||
* copied. Otherwise, if no LF is found and more data can be received, this
|
||||
* function yields.
|
||||
*
|
||||
* From an action, All input data are considered. For a filter, the offset and
|
||||
* the length of input data to consider are retrieved from the filter context.
|
||||
*/
|
||||
__LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct channel *chn;
|
||||
int l, offset = 0, len = 0;
|
||||
struct filter *filter;
|
||||
size_t l, input, output;
|
||||
int offset, len;
|
||||
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
output = co_data(chn);
|
||||
input = ci_data(chn);
|
||||
|
||||
if (!ci_data(chn) && channel_input_closed(chn)) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
filter = hlua_channel_filter(L, 1, chn, &output, &input);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
offset = output;
|
||||
if (lua_gettop(L) > 1) {
|
||||
offset = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
if (offset < 0)
|
||||
offset = MAX(0, ci_data(chn) + offset);
|
||||
if (offset > ci_data(chn)) {
|
||||
offset = MAX(0, input + offset);
|
||||
offset += output;
|
||||
if (offset < output || offset > input + output) {
|
||||
lua_pushfstring(L, "offset out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
len = ci_data(chn) - offset;
|
||||
|
||||
len = output + input - offset;
|
||||
if (lua_gettop(L) == 3) {
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
if (!len)
|
||||
@ -3181,24 +3199,24 @@ __LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KCon
|
||||
}
|
||||
|
||||
for (l = 0; l < len; l++) {
|
||||
if (l + offset >= ci_data(chn))
|
||||
if (l + offset >= output + input)
|
||||
break;
|
||||
if (*(b_peek(&chn->buf, co_data(chn) + offset + l)) == '\n') {
|
||||
if (*(b_peek(&chn->buf, offset + l)) == '\n') {
|
||||
len = l+1;
|
||||
goto dup;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset + len > ci_data(chn)) {
|
||||
if (offset + len > output + input) {
|
||||
if (!HLUA_CANT_YIELD(hlua_gethlua(L)) && !channel_input_closed(chn) && channel_may_recv(chn)) {
|
||||
/* Yield waiting for more data */
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_get_line_yield, TICK_ETERNITY, 0));
|
||||
}
|
||||
len = ci_data(chn) - offset;
|
||||
len = output + input - offset;
|
||||
}
|
||||
|
||||
dup:
|
||||
_hlua_channel_dup(chn, L, co_data(chn) + offset, len);
|
||||
_hlua_channel_dup(chn, L, offset, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3206,11 +3224,15 @@ __LJMP static int hlua_channel_get_line_yield(lua_State *L, int status, lua_KCon
|
||||
*
|
||||
* Duplicate all input data foud in the channel's buffer. The data are not
|
||||
* removed from the buffer. This function relies on _hlua_channel_dup().
|
||||
*
|
||||
* From an action, All input data are considered. For a filter, the offset and
|
||||
* the length of input data to consider are retrieved from the filter context.
|
||||
*/
|
||||
__LJMP static int hlua_channel_dup(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
int offset = 0, len = 0;
|
||||
struct filter *filter;
|
||||
size_t offset, len;
|
||||
|
||||
MAY_LJMP(check_args(L, 1, "dup"));
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
@ -3218,9 +3240,14 @@ __LJMP static int hlua_channel_dup(lua_State *L)
|
||||
lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
offset = co_data(chn);
|
||||
len = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &offset, &len);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
if (!ci_data(chn) && channel_input_closed(chn)) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
@ -3235,11 +3262,15 @@ __LJMP static int hlua_channel_dup(lua_State *L)
|
||||
* Get all input data foud in the channel's buffer. The data are removed from
|
||||
* the buffer after the copy. This function relies on _hlua_channel_dup() and
|
||||
* _hlua_channel_delete().
|
||||
*
|
||||
* From an action, All input data are considered. For a filter, the offset and
|
||||
* the length of input data to consider are retrieved from the filter context.
|
||||
*/
|
||||
__LJMP static int hlua_channel_get(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
int offset = 0, len = 0;
|
||||
struct filter *filter;
|
||||
size_t offset, len;
|
||||
int ret;
|
||||
|
||||
MAY_LJMP(check_args(L, 1, "get"));
|
||||
@ -3248,9 +3279,14 @@ __LJMP static int hlua_channel_get(lua_State *L)
|
||||
lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
offset = co_data(chn);
|
||||
len = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &offset, &len);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
if (!ci_data(chn) && channel_input_closed(chn)) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
@ -3265,18 +3301,26 @@ __LJMP static int hlua_channel_get(lua_State *L)
|
||||
* and the last data does not contains a final '\n', the data are returned
|
||||
* without the final '\n'. When no more data are available, it returns nil
|
||||
* value.
|
||||
*
|
||||
* From an action, All input data are considered. For a filter, the offset and
|
||||
* the length of input data to consider are retrieved from the filter context.
|
||||
*/
|
||||
__LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct channel *chn;
|
||||
size_t l;
|
||||
int offset = 0, len = 0;
|
||||
struct filter *filter;
|
||||
size_t l, offset, len;
|
||||
int ret;
|
||||
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
|
||||
offset = co_data(chn);
|
||||
len = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &offset, &len);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
if (!ci_data(chn) && channel_input_closed(chn)) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
@ -3295,7 +3339,7 @@ __LJMP static int hlua_channel_getline_yield(lua_State *L, int status, lua_KCont
|
||||
}
|
||||
|
||||
dup:
|
||||
ret = _hlua_channel_dup(chn, L, co_data(chn) + offset, len);
|
||||
ret = _hlua_channel_dup(chn, L, offset, len);
|
||||
_hlua_channel_delete(chn, offset, ret);
|
||||
return 1;
|
||||
}
|
||||
@ -3359,23 +3403,39 @@ __LJMP static int hlua_channel_get_line(lua_State *L)
|
||||
* written string, or -1 if the channel is closed or if the buffer size is too
|
||||
* little for the data. 0 may be returned if nothing is copied. This function
|
||||
* does not yield.
|
||||
*
|
||||
* For a filter, the context is updated on success.
|
||||
*/
|
||||
__LJMP static int hlua_channel_append(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
struct filter *filter;
|
||||
const char *str;
|
||||
size_t len;
|
||||
size_t sz, offset, len;
|
||||
int ret;
|
||||
|
||||
MAY_LJMP(check_args(L, 2, "append"));
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
str = MAY_LJMP(luaL_checklstring(L, 2, &len));
|
||||
str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
|
||||
if (IS_HTX_STRM(chn_strm(chn))) {
|
||||
lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, len), co_data(chn) + ci_data(chn));
|
||||
offset = co_data(chn);
|
||||
len = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &offset, &len);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
|
||||
if (ret > 0 && filter) {
|
||||
struct hlua_flt_ctx *flt_ctx = filter->ctx;
|
||||
|
||||
flt_update_offsets(filter, chn, ret);
|
||||
flt_ctx->cur_len[CHN_IDX(chn)] += ret;
|
||||
}
|
||||
lua_pushinteger(L, ret);
|
||||
return 1;
|
||||
}
|
||||
@ -3384,12 +3444,15 @@ __LJMP static int hlua_channel_append(lua_State *L)
|
||||
* written string, or -1 if the channel is closed or if the buffer size is too
|
||||
* little for the data. 0 may be returned if nothing is copied. This function
|
||||
* does not yield.
|
||||
*
|
||||
* For a filter, the context is updated on success.
|
||||
*/
|
||||
__LJMP static int hlua_channel_prepend(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
struct filter *filter;
|
||||
const char *str;
|
||||
size_t sz;
|
||||
size_t sz, offset, len;
|
||||
int ret;
|
||||
|
||||
MAY_LJMP(check_args(L, 2, "prepend"));
|
||||
@ -3400,7 +3463,21 @@ __LJMP static int hlua_channel_prepend(lua_State *L)
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, sz), co_data(chn));
|
||||
offset = co_data(chn);
|
||||
len = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &offset, &len);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
|
||||
if (ret > 0 && filter) {
|
||||
struct hlua_flt_ctx *flt_ctx = filter->ctx;
|
||||
|
||||
flt_update_offsets(filter, chn, ret);
|
||||
flt_ctx->cur_len[CHN_IDX(chn)] += ret;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, ret);
|
||||
return 1;
|
||||
}
|
||||
@ -3409,35 +3486,54 @@ __LJMP static int hlua_channel_prepend(lua_State *L)
|
||||
* content. By default the string is appended at the end of input data. It
|
||||
* returns the length of the written string, or -1 if the channel is closed or
|
||||
* if the buffer size is too little for the data.
|
||||
*
|
||||
* For a filter, the context is updated on success.
|
||||
*/
|
||||
__LJMP static int hlua_channel_insert_data(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
struct filter *filter;
|
||||
const char *str;
|
||||
size_t sz;
|
||||
size_t sz, input, output;
|
||||
int ret, offset;
|
||||
|
||||
if (lua_gettop(L) < 2 || lua_gettop(L) > 3)
|
||||
WILL_LJMP(luaL_error(L, "'insert' expects at least 1 argument and at most 2 arguments"));
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
|
||||
offset = ci_data(chn);
|
||||
if (lua_gettop(L) > 2)
|
||||
|
||||
output = co_data(chn);
|
||||
input = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &output, &input);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
offset = input + output;
|
||||
if (lua_gettop(L) > 2) {
|
||||
offset = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
if (offset < 0)
|
||||
offset = MAX(0, input + offset);
|
||||
offset += output;
|
||||
|
||||
if (offset < output || offset > output + input) {
|
||||
lua_pushfstring(L, "offset out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
if (IS_HTX_STRM(chn_strm(chn))) {
|
||||
lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
offset = MAX(0, ci_data(chn) + offset);
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
|
||||
if (ret > 0 && filter) {
|
||||
struct hlua_flt_ctx *flt_ctx = filter->ctx;
|
||||
|
||||
if (offset > ci_data(chn)) {
|
||||
lua_pushfstring(L, "offset out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
flt_update_offsets(filter, chn, ret);
|
||||
flt_ctx->cur_len[CHN_IDX(chn)] += ret;
|
||||
}
|
||||
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, sz), co_data(chn) + offset);
|
||||
lua_pushinteger(L, ret);
|
||||
return 1;
|
||||
}
|
||||
@ -3445,80 +3541,142 @@ __LJMP static int hlua_channel_insert_data(lua_State *L)
|
||||
* content. By default all remaining data are removed (offset = 0 and len =
|
||||
* -1). It returns the length of the written string, or -1 if the channel is
|
||||
* closed or if the buffer size is too little for the data.
|
||||
*
|
||||
* For a filter, the context is updated on success.
|
||||
*/
|
||||
__LJMP static int hlua_channel_set_data(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
struct filter *filter;
|
||||
const char *str;
|
||||
size_t sz;
|
||||
int ret, offset = 0, len = -1;
|
||||
size_t sz, input, output;
|
||||
int ret, offset, len;
|
||||
|
||||
if (lua_gettop(L) < 2 || lua_gettop(L) > 4)
|
||||
WILL_LJMP(luaL_error(L, "'set' expects at least 1 argument and at most 3 arguments"));
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
|
||||
if (lua_gettop(L) > 2)
|
||||
offset = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
if (lua_gettop(L) == 4)
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 4));
|
||||
|
||||
if (IS_HTX_STRM(chn_strm(chn))) {
|
||||
lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
offset = MAX(0, ci_data(chn) + offset);
|
||||
if (len < 0)
|
||||
len = ci_data(chn) - offset;
|
||||
output = co_data(chn);
|
||||
input = ci_data(chn);
|
||||
|
||||
if (offset + len > ci_data(chn)) {
|
||||
lua_pushfstring(L, "offset or length out of range.");
|
||||
filter = hlua_channel_filter(L, 1, chn, &output, &input);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
offset = output;
|
||||
if (lua_gettop(L) > 2) {
|
||||
offset = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
if (offset < 0)
|
||||
offset = MAX(0, input + offset);
|
||||
offset += output;
|
||||
if (offset < output || offset > input + output) {
|
||||
lua_pushfstring(L, "offset out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
|
||||
len = output + input - offset;
|
||||
if (lua_gettop(L) == 4) {
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 4));
|
||||
if (!len)
|
||||
goto set;
|
||||
if (len == -1)
|
||||
len = output + input - offset;
|
||||
if (len < 0 || offset + len > output + input) {
|
||||
lua_pushfstring(L, "length out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
|
||||
set:
|
||||
/* Be sure we can copied the string once input data will be removed. */
|
||||
if (sz > c_room(chn) + len)
|
||||
lua_pushinteger(L, -1);
|
||||
else {
|
||||
_hlua_channel_delete(chn, co_data(chn) + offset, len);
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, sz), co_data(chn) + offset);
|
||||
_hlua_channel_delete(chn, offset, len);
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, sz), offset);
|
||||
if (filter) {
|
||||
struct hlua_flt_ctx *flt_ctx = filter->ctx;
|
||||
|
||||
len -= (ret > 0 ? ret : 0);
|
||||
flt_update_offsets(filter, chn, -len);
|
||||
flt_ctx->cur_len[CHN_IDX(chn)] -= len;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, ret);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Removes a given amount of input data at the given offset. By default all
|
||||
* intput data are removed (offset = 0 and len = -1). It returns the amount of
|
||||
* input data are removed (offset = 0 and len = -1). It returns the amount of
|
||||
* the removed data.
|
||||
*
|
||||
* For a filter, the context is updated on success.
|
||||
*/
|
||||
__LJMP static int hlua_channel_del_data(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
int offset = 0, len = -1;
|
||||
struct filter *filter;
|
||||
size_t input, output;
|
||||
int offset, len;
|
||||
|
||||
if (lua_gettop(L) < 1 || lua_gettop(L) > 3)
|
||||
WILL_LJMP(luaL_error(L, "'remove' expects at most 2 arguments"));
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
if (lua_gettop(L) > 1)
|
||||
offset = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
if (lua_gettop(L) == 3)
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
|
||||
if (IS_HTX_STRM(chn_strm(chn))) {
|
||||
lua_pushfstring(L, "Cannot manipulate HAProxy channels in HTTP mode.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
|
||||
if (offset < 0)
|
||||
offset = MAX(0, ci_data(chn) + offset);
|
||||
if (len < 0)
|
||||
len = ci_data(chn) - offset;
|
||||
output = co_data(chn);
|
||||
input = ci_data(chn);
|
||||
|
||||
if (offset + len > ci_data(chn)) {
|
||||
lua_pushfstring(L, "offset or length out of range.");
|
||||
filter = hlua_channel_filter(L, 1, chn, &output, &input);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
offset = output;
|
||||
if (lua_gettop(L) > 2) {
|
||||
offset = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
if (offset < 0)
|
||||
offset = MAX(0, input + offset);
|
||||
offset += output;
|
||||
if (offset < output || offset > input + output) {
|
||||
lua_pushfstring(L, "offset out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
|
||||
_hlua_channel_delete(chn, co_data(chn) + offset, len);
|
||||
len = output + input - offset;
|
||||
if (lua_gettop(L) == 4) {
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 4));
|
||||
if (!len)
|
||||
goto end;
|
||||
if (len == -1)
|
||||
len = output + input - offset;
|
||||
if (len < 0 || offset + len > output + input) {
|
||||
lua_pushfstring(L, "length out of range.");
|
||||
WILL_LJMP(lua_error(L));
|
||||
}
|
||||
}
|
||||
|
||||
_hlua_channel_delete(chn, offset, len);
|
||||
if (filter) {
|
||||
struct hlua_flt_ctx *flt_ctx = filter->ctx;
|
||||
|
||||
flt_update_offsets(filter, chn, -len);
|
||||
flt_ctx->cur_len[CHN_IDX(chn)] -= len;
|
||||
}
|
||||
|
||||
end:
|
||||
lua_pushinteger(L, len);
|
||||
return 1;
|
||||
}
|
||||
@ -3531,8 +3689,9 @@ __LJMP static int hlua_channel_del_data(lua_State *L)
|
||||
__LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct channel *chn;
|
||||
struct filter *filter;
|
||||
const char *str;
|
||||
size_t sz, len;
|
||||
size_t offset, len, sz;
|
||||
int l, ret;
|
||||
struct hlua *hlua;
|
||||
|
||||
@ -3547,38 +3706,51 @@ __LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext
|
||||
str = MAY_LJMP(luaL_checklstring(L, 2, &sz));
|
||||
l = MAY_LJMP(luaL_checkinteger(L, 3));
|
||||
|
||||
offset = co_data(chn);
|
||||
len = ci_data(chn);
|
||||
|
||||
filter = hlua_channel_filter(L, 1, chn, &offset, &len);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
|
||||
if (unlikely(channel_output_closed(chn))) {
|
||||
lua_pushinteger(L, -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if the buffer is available because HAProxy doesn't allocate
|
||||
* the request buffer if its not required.
|
||||
*/
|
||||
if (chn->buf.size == 0) {
|
||||
if (HLUA_CANT_YIELD(hlua_gethlua(L)))
|
||||
len = c_room(chn);
|
||||
if (len > sz -l) {
|
||||
if (filter) {
|
||||
lua_pushinteger(L, -1);
|
||||
return 1;
|
||||
si_rx_buff_blk(chn_prod(chn));
|
||||
MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_channel_send_yield, TICK_ETERNITY, 0));
|
||||
}
|
||||
len = sz - l;
|
||||
}
|
||||
|
||||
len = c_room(chn);
|
||||
if (len > sz - l)
|
||||
len = sz - l;
|
||||
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str+l, len), co_data(chn));
|
||||
ret = _hlua_channel_insert(chn, L, ist2(str, len), offset);
|
||||
if (ret == -1) {
|
||||
lua_pop(L, 1);
|
||||
lua_pushinteger(L, -1);
|
||||
return 1;
|
||||
}
|
||||
if (ret) {
|
||||
c_adv(chn, ret);
|
||||
if (filter) {
|
||||
struct hlua_flt_ctx *flt_ctx = filter->ctx;
|
||||
|
||||
|
||||
flt_update_offsets(filter, chn, ret);
|
||||
FLT_OFF(filter, chn) += ret;
|
||||
flt_ctx->cur_off[CHN_IDX(chn)] += ret;
|
||||
}
|
||||
else
|
||||
c_adv(chn, ret);
|
||||
|
||||
l += ret;
|
||||
lua_pop(L, 1);
|
||||
lua_pushinteger(L, l);
|
||||
}
|
||||
|
||||
if (l < sz) {
|
||||
/* Yield only if the channel's output is not empty.
|
||||
* Otherwise it means we cannot add more data. */
|
||||
@ -3602,6 +3774,8 @@ __LJMP static int hlua_channel_send_yield(lua_State *L, int status, lua_KContext
|
||||
/* Just a wrapper of "_hlua_channel_send". This wrapper permits
|
||||
* yield the LUA process, and resume it without checking the
|
||||
* input arguments.
|
||||
*
|
||||
* This function cannot be called from a filter.
|
||||
*/
|
||||
__LJMP static int hlua_channel_send(lua_State *L)
|
||||
{
|
||||
@ -3627,7 +3801,8 @@ __LJMP static int hlua_channel_send(lua_State *L)
|
||||
__LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
struct channel *chn;
|
||||
size_t len;
|
||||
struct filter *filter;
|
||||
size_t offset, len, fwd;
|
||||
int l, max;
|
||||
struct hlua *hlua;
|
||||
|
||||
@ -3639,21 +3814,36 @@ __LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KCont
|
||||
}
|
||||
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
len = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
fwd = MAY_LJMP(luaL_checkinteger(L, 2));
|
||||
l = MAY_LJMP(luaL_checkinteger(L, -1));
|
||||
|
||||
max = len - l;
|
||||
if (max > ci_data(chn))
|
||||
max = ci_data(chn);
|
||||
offset = co_data(chn);
|
||||
len = ci_data(chn);
|
||||
|
||||
channel_forward(chn, max);
|
||||
filter = hlua_channel_filter(L, 1, chn, &offset, &len);
|
||||
if (filter && !hlua_filter_from_payload(filter))
|
||||
WILL_LJMP(lua_error(L));
|
||||
|
||||
max = fwd - l;
|
||||
if (max > len)
|
||||
max = len;
|
||||
|
||||
if (filter) {
|
||||
struct hlua_flt_ctx *flt_ctx = filter->ctx;
|
||||
|
||||
FLT_OFF(filter, chn) += max;
|
||||
flt_ctx->cur_off[CHN_IDX(chn)] += max;
|
||||
flt_ctx->cur_len[CHN_IDX(chn)] -= max;
|
||||
}
|
||||
else
|
||||
channel_forward(chn, max);
|
||||
|
||||
l += max;
|
||||
lua_pop(L, 1);
|
||||
lua_pushinteger(L, l);
|
||||
|
||||
/* Check if it miss bytes to forward. */
|
||||
if (l < len) {
|
||||
if (l < fwd) {
|
||||
/* The the input channel or the output channel are closed, we
|
||||
* must return the amount of data forwarded.
|
||||
*/
|
||||
@ -3678,6 +3868,8 @@ __LJMP static int hlua_channel_forward_yield(lua_State *L, int status, lua_KCont
|
||||
|
||||
/* Just check the input and prepare the stack for the previous
|
||||
* function "hlua_channel_forward_yield"
|
||||
*
|
||||
* This function cannot be called from a filter.
|
||||
*/
|
||||
__LJMP static int hlua_channel_forward(lua_State *L)
|
||||
{
|
||||
@ -3699,15 +3891,22 @@ __LJMP static int hlua_channel_forward(lua_State *L)
|
||||
__LJMP static int hlua_channel_get_in_len(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
struct filter *filter;
|
||||
size_t output, input;
|
||||
|
||||
MAY_LJMP(check_args(L, 1, "input"));
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
if (IS_HTX_STRM(chn_strm(chn))) {
|
||||
|
||||
output = co_data(chn);
|
||||
input = ci_data(chn);
|
||||
filter = hlua_channel_filter(L, 1, chn, &output, &input);
|
||||
if (filter || !IS_HTX_STRM(chn_strm(chn)))
|
||||
lua_pushinteger(L, input);
|
||||
else {
|
||||
struct htx *htx = htxbuf(&chn->buf);
|
||||
|
||||
lua_pushinteger(L, htx->data - co_data(chn));
|
||||
}
|
||||
else
|
||||
lua_pushinteger(L, ci_data(chn));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -3754,10 +3953,16 @@ __LJMP static int hlua_channel_is_resp(lua_State *L)
|
||||
__LJMP static int hlua_channel_get_out_len(lua_State *L)
|
||||
{
|
||||
struct channel *chn;
|
||||
size_t output, input;
|
||||
|
||||
MAY_LJMP(check_args(L, 1, "output"));
|
||||
chn = MAY_LJMP(hlua_checkchannel(L, 1));
|
||||
lua_pushinteger(L, co_data(chn));
|
||||
|
||||
output = co_data(chn);
|
||||
input = ci_data(chn);
|
||||
hlua_channel_filter(L, 1, chn, &output, &input);
|
||||
|
||||
lua_pushinteger(L, output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user