mirror of
http://git.haproxy.org/git/haproxy.git
synced 2026-02-14 06:49:17 +02:00
MINOR: lua: create and register HTTP class
This class is accessible via the TXN object. It is created only if the attached proxy have HTTP mode. It contain all the HTTP manipulation functions: - req_get_headers - req_del_header - req_rep_header - req_rep_value - req_add_header - req_set_header - req_set_method - req_set_path - req_set_query - req_set_uri - res_get_headers - res_del_header - res_rep_header - res_rep_value - res_add_header - res_set_header
This commit is contained in:
committed by
Willy Tarreau
parent
2cce3538ca
commit
08504f4e19
465
src/hlua.c
465
src/hlua.c
@@ -73,6 +73,7 @@ static int class_socket_ref;
|
||||
static int class_channel_ref;
|
||||
static int class_fetches_ref;
|
||||
static int class_converters_ref;
|
||||
static int class_http_ref;
|
||||
|
||||
/* Global Lua execution timeout. By default Lua, execution linked
|
||||
* with session (actions, sample-fetches and converters) have a
|
||||
@@ -2858,6 +2859,361 @@ __LJMP static int hlua_run_sample_conv(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
* Class HTTP
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/* Returns a struct hlua_txn if the stack entry "ud" is
|
||||
* a class session, otherwise it throws an error.
|
||||
*/
|
||||
__LJMP static struct hlua_txn *hlua_checkhttp(lua_State *L, int ud)
|
||||
{
|
||||
return (struct hlua_txn *)MAY_LJMP(hlua_checkudata(L, ud, class_http_ref));
|
||||
}
|
||||
|
||||
/* This function creates and push in the stack a HTTP object
|
||||
* according with a current TXN.
|
||||
*/
|
||||
static int hlua_http_new(lua_State *L, struct hlua_txn *txn)
|
||||
{
|
||||
struct hlua_txn *ht;
|
||||
|
||||
/* Check stack size. */
|
||||
if (!lua_checkstack(L, 3))
|
||||
return 0;
|
||||
|
||||
/* Create the object: obj[0] = userdata.
|
||||
* Note that the base of the Converters object is the
|
||||
* same than the TXN object.
|
||||
*/
|
||||
lua_newtable(L);
|
||||
ht = lua_newuserdata(L, sizeof(struct hlua_txn));
|
||||
lua_rawseti(L, -2, 0);
|
||||
|
||||
ht->s = txn->s;
|
||||
ht->p = txn->p;
|
||||
ht->l7 = txn->l7;
|
||||
|
||||
/* Pop a class session metatable and affect it to the table. */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, class_http_ref);
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function creates ans returns an array of HTTP headers.
|
||||
* This function does not fails. It is used as wrapper with the
|
||||
* 2 following functions.
|
||||
*/
|
||||
__LJMP static int hlua_http_get_headers(lua_State *L, struct hlua_txn *htxn, struct http_msg *msg)
|
||||
{
|
||||
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;
|
||||
|
||||
/* Create the table. */
|
||||
lua_newtable(L);
|
||||
|
||||
/* Build array of headers. */
|
||||
old_idx = 0;
|
||||
cur_next = msg->chn->buf->p + hdr_idx_first_pos(&htxn->s->txn.hdr_idx);
|
||||
|
||||
while (1) {
|
||||
cur_idx = htxn->s->txn.hdr_idx.v[old_idx].next;
|
||||
if (!cur_idx)
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Push values in the table. */
|
||||
lua_pushlstring(L, hn, hnl);
|
||||
lua_pushlstring(L, hv, hvl);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_req_get_headers(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 1, "req_get_headers"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return hlua_http_get_headers(L, htxn, &htxn->s->txn.req);
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_res_get_headers(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 1, "res_get_headers"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return hlua_http_get_headers(L, htxn, &htxn->s->txn.rsp);
|
||||
}
|
||||
|
||||
/* This function replace full header, or just a value in
|
||||
* the request or in the response. It is a wrapper fir the
|
||||
* 4 following functions.
|
||||
*/
|
||||
__LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct hlua_txn *htxn,
|
||||
struct http_msg *msg, int action)
|
||||
{
|
||||
size_t name_len;
|
||||
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
|
||||
const char *reg = MAY_LJMP(luaL_checkstring(L, 3));
|
||||
const char *value = MAY_LJMP(luaL_checkstring(L, 4));
|
||||
struct my_regex re;
|
||||
|
||||
if (!regex_comp(reg, &re, 1, 1, NULL))
|
||||
WILL_LJMP(luaL_argerror(L, 3, "invalid regex"));
|
||||
|
||||
http_transform_header_str(htxn->s, msg, name, name_len, value, &re, action);
|
||||
regex_free(&re);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_req_rep_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.req, HTTP_REQ_ACT_REPLACE_HDR));
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_res_rep_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 4, "res_rep_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.rsp, HTTP_RES_ACT_REPLACE_HDR));
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_req_rep_val(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 4, "req_rep_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.req, HTTP_REQ_ACT_REPLACE_VAL));
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_res_rep_val(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 4, "res_rep_val"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return MAY_LJMP(hlua_http_rep_hdr(L, htxn, &htxn->s->txn.rsp, HTTP_RES_ACT_REPLACE_VAL));
|
||||
}
|
||||
|
||||
/* This function deletes all the occurences of an header.
|
||||
* It is a wrapper for the 2 following functions.
|
||||
*/
|
||||
__LJMP static inline int hlua_http_del_hdr(lua_State *L, struct hlua_txn *htxn, struct http_msg *msg)
|
||||
{
|
||||
size_t len;
|
||||
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
|
||||
struct hdr_ctx ctx;
|
||||
struct http_txn *txn = &htxn->s->txn;
|
||||
|
||||
ctx.idx = 0;
|
||||
while (http_find_header2(name, len, msg->chn->buf->p, &txn->hdr_idx, &ctx))
|
||||
http_remove_header2(msg, &txn->hdr_idx, &ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_req_del_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 2, "req_del_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return hlua_http_del_hdr(L, htxn, &htxn->s->txn.req);
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_res_del_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 2, "req_del_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return hlua_http_del_hdr(L, htxn, &htxn->s->txn.rsp);
|
||||
}
|
||||
|
||||
/* This function adds an header. It is a wrapper used by
|
||||
* the 2 following functions.
|
||||
*/
|
||||
__LJMP static inline int hlua_http_add_hdr(lua_State *L, struct hlua_txn *htxn, struct http_msg *msg)
|
||||
{
|
||||
size_t name_len;
|
||||
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;
|
||||
|
||||
/* Check length. */
|
||||
trash.len = value_len + name_len + 2;
|
||||
if (trash.len > trash.size)
|
||||
return 0;
|
||||
|
||||
/* Creates the header string. */
|
||||
p = trash.str;
|
||||
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.str, trash.len) != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_req_add_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "req_add_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return hlua_http_add_hdr(L, htxn, &htxn->s->txn.req);
|
||||
}
|
||||
|
||||
__LJMP static int hlua_http_res_add_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "res_add_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
return hlua_http_add_hdr(L, htxn, &htxn->s->txn.rsp);
|
||||
}
|
||||
|
||||
static int hlua_http_req_set_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "req_set_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
hlua_http_del_hdr(L, htxn, &htxn->s->txn.req);
|
||||
return hlua_http_add_hdr(L, htxn, &htxn->s->txn.req);
|
||||
}
|
||||
|
||||
static int hlua_http_res_set_hdr(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *htxn;
|
||||
|
||||
MAY_LJMP(check_args(L, 3, "res_set_hdr"));
|
||||
htxn = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
|
||||
hlua_http_del_hdr(L, htxn, &htxn->s->txn.rsp);
|
||||
return hlua_http_add_hdr(L, htxn, &htxn->s->txn.rsp);
|
||||
}
|
||||
|
||||
/* This function set the method. */
|
||||
static int hlua_http_req_set_meth(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *s = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
size_t name_len;
|
||||
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
|
||||
struct http_txn *txn = &s->s->txn;
|
||||
|
||||
lua_pushboolean(L, http_replace_req_line(0, name, name_len, s->p, s->s, txn) != -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function set the method. */
|
||||
static int hlua_http_req_set_path(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *s = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
size_t name_len;
|
||||
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
|
||||
struct http_txn *txn = &s->s->txn;
|
||||
|
||||
lua_pushboolean(L, http_replace_req_line(1, name, name_len, s->p, s->s, txn) != -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function set the query-string. */
|
||||
static int hlua_http_req_set_query(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *s = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
size_t name_len;
|
||||
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
|
||||
struct http_txn *txn = &s->s->txn;
|
||||
|
||||
/* Check length. */
|
||||
if (name_len > trash.size - 1) {
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Add the mark question as prefix. */
|
||||
chunk_reset(&trash);
|
||||
trash.str[trash.len++] = '?';
|
||||
memcpy(trash.str + trash.len, name, name_len);
|
||||
trash.len += name_len;
|
||||
|
||||
lua_pushboolean(L, http_replace_req_line(2, trash.str, trash.len, s->p, s->s, txn) != -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* This function set the uri. */
|
||||
static int hlua_http_req_set_uri(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *s = MAY_LJMP(hlua_checkhttp(L, 1));
|
||||
size_t name_len;
|
||||
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &name_len));
|
||||
struct http_txn *txn = &s->s->txn;
|
||||
|
||||
lua_pushboolean(L, http_replace_req_line(3, name, name_len, s->p, s->s, txn) != -1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
@@ -2976,6 +3332,16 @@ static int hlua_txn_new(lua_State *L, struct session *s, struct proxy *p, void *
|
||||
return 0;
|
||||
lua_settable(L, -3);
|
||||
|
||||
/* Creates the HTTP object is the current proxy allows http. */
|
||||
lua_pushstring(L, "http");
|
||||
if (p->mode == PR_MODE_HTTP) {
|
||||
if (!hlua_http_new(L, hs))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
lua_pushnil(L);
|
||||
lua_settable(L, -3);
|
||||
|
||||
/* Pop a class sesison metatable and affect it to the userdata. */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, class_txn_ref);
|
||||
lua_setmetatable(L, -2);
|
||||
@@ -3056,65 +3422,6 @@ __LJMP static int hlua_txn_close(lua_State *L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function is an LUA binding. It creates ans returns
|
||||
* an array of HTTP headers. This function does not fails.
|
||||
*/
|
||||
static int hlua_session_get_headers(lua_State *L)
|
||||
{
|
||||
struct hlua_txn *s = MAY_LJMP(hlua_checktxn(L, 1));
|
||||
struct session *sess = s->s;
|
||||
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;
|
||||
|
||||
/* Create the table. */
|
||||
lua_newtable(L);
|
||||
|
||||
/* Build array of headers. */
|
||||
old_idx = 0;
|
||||
cur_next = sess->req.buf->p + hdr_idx_first_pos(&sess->txn.hdr_idx);
|
||||
|
||||
while (1) {
|
||||
cur_idx = sess->txn.hdr_idx.v[old_idx].next;
|
||||
if (!cur_idx)
|
||||
break;
|
||||
old_idx = cur_idx;
|
||||
|
||||
cur_hdr = &sess->txn.hdr_idx.v[cur_idx];
|
||||
cur_ptr = cur_next;
|
||||
cur_next = cur_ptr + cur_hdr->len + cur_hdr->cr + 1;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* Push values in the table. */
|
||||
lua_pushlstring(L, hn, hnl);
|
||||
lua_pushlstring(L, hv, hvl);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
__LJMP static int hlua_sleep_yield(lua_State *L, int status, lua_KContext ctx)
|
||||
{
|
||||
int wakeup_ms = lua_tointeger(L, -1);
|
||||
@@ -4253,6 +4560,45 @@ void hlua_init(void)
|
||||
lua_setfield(gL.T, LUA_REGISTRYINDEX, CLASS_CONVERTERS); /* register class session. */
|
||||
class_converters_ref = luaL_ref(gL.T, LUA_REGISTRYINDEX); /* reference class session. */
|
||||
|
||||
/*
|
||||
*
|
||||
* Register class HTTP
|
||||
*
|
||||
*/
|
||||
|
||||
/* Create and fill the metatable. */
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* Create and fille the __index entry. */
|
||||
lua_pushstring(gL.T, "__index");
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* Register Lua functions. */
|
||||
hlua_class_function(gL.T, "req_get_headers",hlua_http_req_get_headers);
|
||||
hlua_class_function(gL.T, "req_del_header", hlua_http_req_del_hdr);
|
||||
hlua_class_function(gL.T, "req_rep_header", hlua_http_req_rep_hdr);
|
||||
hlua_class_function(gL.T, "req_rep_value", hlua_http_req_rep_val);
|
||||
hlua_class_function(gL.T, "req_add_header", hlua_http_req_add_hdr);
|
||||
hlua_class_function(gL.T, "req_set_header", hlua_http_req_set_hdr);
|
||||
hlua_class_function(gL.T, "req_set_method", hlua_http_req_set_meth);
|
||||
hlua_class_function(gL.T, "req_set_path", hlua_http_req_set_path);
|
||||
hlua_class_function(gL.T, "req_set_query", hlua_http_req_set_query);
|
||||
hlua_class_function(gL.T, "req_set_uri", hlua_http_req_set_uri);
|
||||
|
||||
hlua_class_function(gL.T, "res_get_headers",hlua_http_res_get_headers);
|
||||
hlua_class_function(gL.T, "res_del_header", hlua_http_res_del_hdr);
|
||||
hlua_class_function(gL.T, "res_rep_header", hlua_http_res_rep_hdr);
|
||||
hlua_class_function(gL.T, "res_rep_value", hlua_http_res_rep_val);
|
||||
hlua_class_function(gL.T, "res_add_header", hlua_http_res_add_hdr);
|
||||
hlua_class_function(gL.T, "res_set_header", hlua_http_res_set_hdr);
|
||||
|
||||
lua_settable(gL.T, -3);
|
||||
|
||||
/* Register previous table in the registry with reference and named entry. */
|
||||
lua_pushvalue(gL.T, -1); /* Copy the -1 entry and push it on the stack. */
|
||||
lua_setfield(gL.T, LUA_REGISTRYINDEX, CLASS_HTTP); /* register class session. */
|
||||
class_http_ref = luaL_ref(gL.T, LUA_REGISTRYINDEX); /* reference class session. */
|
||||
|
||||
/*
|
||||
*
|
||||
* Register class TXN
|
||||
@@ -4267,7 +4613,6 @@ void hlua_init(void)
|
||||
lua_newtable(gL.T);
|
||||
|
||||
/* Register Lua functions. */
|
||||
hlua_class_function(gL.T, "get_headers", hlua_session_get_headers);
|
||||
hlua_class_function(gL.T, "set_priv", hlua_set_priv);
|
||||
hlua_class_function(gL.T, "get_priv", hlua_get_priv);
|
||||
hlua_class_function(gL.T, "close", hlua_txn_close);
|
||||
|
||||
Reference in New Issue
Block a user