MEDIUM: lua/htx: Adapt functions of the HTTP to be compatible with HTX
So, LUA actions, converter and sample fetches are now available from HTX
proxies.
diff --git a/src/hlua.c b/src/hlua.c
index 810489f..1be6271 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -29,6 +29,7 @@
#include <common/hathreads.h>
#include <common/initcall.h>
#include <common/xref.h>
+#include <common/h1.h>
#include <types/cli.h>
#include <types/hlua.h>
@@ -45,6 +46,7 @@
#include <proto/hlua.h>
#include <proto/hlua_fcn.h>
#include <proto/http_fetch.h>
+#include <proto/http_htx.h>
#include <proto/http_rules.h>
#include <proto/map.h>
#include <proto/obj_type.h>
@@ -4662,16 +4664,6 @@
*/
__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;
- int type;
- const char *in;
- char *out;
- int len;
-
/* Create the table. */
lua_newtable(L);
@@ -4682,84 +4674,148 @@
if (unlikely(msg->msg_state < HTTP_MSG_BODY))
return 1;
- /* Build array of headers. */
- old_idx = 0;
- cur_next = ci_head(msg->chn) + hdr_idx_first_pos(&htxn->s->txn->hdr_idx);
+ if (IS_HTX_STRM(htxn->s)) {
+ /* HTX version */
+ struct htx *htx = htxbuf(&msg->chn->buf);
+ int32_t pos;
- while (1) {
- cur_idx = htxn->s->txn->hdr_idx.v[old_idx].next;
- if (!cur_idx)
- break;
- old_idx = cur_idx;
+ for (pos = htx_get_head(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;
- 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;
+ 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;
- /* 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.
- */
+ /* 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);
- /* 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' ))
+ 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;
+ int len;
+
+ /* Build array of headers. */
+ old_idx = 0;
+ cur_next = ci_head(msg->chn) + 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++;
- if (p >= cur_ptr+cur_hdr->len)
- continue;
- hv = p;
- hvl = cur_ptr+cur_hdr->len-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; in<hn+hnl; in++, out++)
- *out = tolower(*in);
- *out = '\0';
+ /* 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; in<hn+hnl; in++, out++)
+ *out = tolower(*in);
+ *out = '\0';
- /* 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, trash.area, hnl);
- lua_gettable(L, -2);
- type = lua_type(L, -1);
+ /* 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, trash.area, hnl);
+ lua_gettable(L, -2);
- switch (type) {
- case LUA_TNIL:
- /* Table not found, create it. */
- lua_pop(L, 1); /* remove the nil value. */
- lua_pushlstring(L, trash.area, hnl); /* push the header name as key. */
- lua_newtable(L); /* create and push empty table. */
- lua_pushlstring(L, hv, hvl); /* 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;
+ switch (lua_type(L, -1)) {
+ case LUA_TNIL:
+ /* Table not found, create it. */
+ lua_pop(L, 1); /* remove the nil value. */
+ lua_pushlstring(L, trash.area, hnl); /* push the header name as key. */
+ lua_newtable(L); /* create and push empty table. */
+ lua_pushlstring(L, hv, hvl); /* 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, hv, hvl); /* 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;
+ case LUA_TTABLE:
+ /* Entry found: push the value in the table. */
+ len = lua_rawlen(L, -1);
+ lua_pushlstring(L, hv, hvl); /* 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));
+ default:
+ /* Other cases are errors. */
+ hlua_pusherror(L, "internal error during the parsing of headers.");
+ WILL_LJMP(lua_error(L));
+ }
}
}
-
return 1;
}
@@ -4855,16 +4911,29 @@
{
size_t len;
const char *name = MAY_LJMP(luaL_checklstring(L, 2, &len));
- struct hdr_ctx ctx;
- struct http_txn *txn = htxn->s->txn;
/* Check if a valid response is parsed */
if (unlikely(msg->msg_state < HTTP_MSG_BODY))
return 0;
- 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);
+ 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);
+ }
return 0;
}
@@ -4903,24 +4972,33 @@
if (unlikely(msg->msg_state < HTTP_MSG_BODY))
return 0;
- /* Check length. */
- trash.data = value_len + name_len + 2;
- if (trash.data > trash.size)
- return 0;
+ if (IS_HTX_STRM(htxn->s)) {
+ /* HTX version */
+ struct htx *htx = htxbuf(&msg->chn->buf);
- /* 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_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;
- lua_pushboolean(L, http_header_add_tail2(msg, &htxn->s->txn->hdr_idx,
- trash.area, trash.data) != 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);
+ }
return 0;
}
@@ -5742,11 +5820,6 @@
if (!stream)
return 0;
- if (IS_HTX_STRM(stream)) {
- SEND_ERR(stream->be, "Lua converter '%s': Lua fetches cannot be used when the"
- " HTX internal representation is enabled.\n", fcn->name);
- return 0;
- }
/* In the execution wrappers linked with a stream, the
* Lua context can be not initialized. This behavior
* permits to save performances because a systematic
@@ -5879,12 +5952,6 @@
if (!stream)
return 0;
- if (IS_HTX_STRM(stream)) {
- SEND_ERR(stream->be, "Lua sample-fetch '%s': Lua fetches cannot be used when the"
- " HTX internal representation is enabled.\n", fcn->name);
- return 0;
- }
-
/* In the execution wrappers linked with a stream, the
* Lua context can be not initialized. This behavior
* permits to save performances because a systematic
@@ -6830,11 +6897,6 @@
struct hlua_function *fcn = rule->kw->private;
int i;
- if (px->options2 & PR_O2_USE_HTX) {
- memprintf(err, "Lua actions cannot be used when the HTX internal representation is enabled");
- return ACT_RET_PRS_ERR;
- }
-
/* Memory for the rule. */
rule->arg.hlua_rule = calloc(1, sizeof(*rule->arg.hlua_rule));
if (!rule->arg.hlua_rule) {
@@ -7508,33 +7570,6 @@
INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
-static int hlua_check_config()
-{
- struct proxy *px;
- struct acl *acl;
- struct acl_expr *expr;
- struct sample_fetch *fetch;
- int err = 0;
-
- for (px = proxies_list; px; px = px->next) {
- if (!(px->options2 & PR_O2_USE_HTX))
- continue;
-
- list_for_each_entry(acl, &px->acl, list) {
- list_for_each_entry(expr, &acl->expr, list) {
- fetch = expr->smp->fetch;
- if (fetch->process != hlua_sample_fetch_wrapper)
- continue;
-
- ha_alert("config: %s '%s': sample-fetch '%s' cannot be used used "
- "when the HTX internal representation is enabled.\n",
- proxy_type_str(px), px->id, fetch->kw);
- err++;
- }
- }
- }
- return err;
-}
/* This function can fail with an abort() due to an Lua critical error.
* We are in the initialisation process of HAProxy, this abort() is
@@ -8198,4 +8233,3 @@
}
INITCALL0(STG_REGISTER, hlua_register_build_options);
-REGISTER_CONFIG_POSTPARSER("hlua", hlua_check_config);