]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: lua: create and register HTTP class
authorThierry FOURNIER <tfournier@haproxy.com>
Mon, 16 Mar 2015 13:17:08 +0000 (14:17 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 18 Mar 2015 10:34:06 +0000 (11:34 +0100)
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

doc/lua-api/index.rst
include/types/hlua.h
src/hlua.c

index 545ee375074aad87b43786a73a95e8b0442a0307..d9cf262136e9007158ef62a6e2b39f8f3a8385a6 100644 (file)
@@ -425,6 +425,179 @@ Channel class
   :param class_channel channel: The manipulated channel.
   :param integer int: The amount of data which will be forwarded.
 
+
+HTTP class
+==========
+
+.. js:class:: HTTP
+
+   This class contain all the HTTP manipulation functions.
+
+.. js:function:: http.req_get_header(http)
+
+  Returns an array containing all the request headers.
+
+  :param class_http http: The related http object.
+  :returns: array of headers.
+  :see: http.res_get_header()
+
+.. js:function:: http.res_get_header(http)
+
+  Returns an array containing all the response headers.
+
+  :param class_http http: The related http object.
+  :returns: array of headers.
+  :see: http.req_get_header()
+
+.. js:function:: http.req_add_header(http, name, value)
+
+  Appends an HTTP header field in the request whose name is
+  specified in "name" and whose value is defined in "value".
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string value: The header value.
+  :see: http.res_add_header()
+
+.. js:function:: http.res_add_header(http, name, value)
+
+  appends an HTTP header field in the response whose name is
+  specified in "name" and whose value is defined in "value".
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string value: The header value.
+  :see: http.req_add_header()
+
+.. js:function:: http.req_del_header(http, name)
+
+  Removes all HTTP header fields in the request whose name is
+  specified in "name".
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :see: http.res_del_header()
+
+.. js:function:: http.res_del_header(http, name)
+
+  Removes all HTTP header fields in the response whose name is
+  specified in "name".
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :see: http.req_del_header()
+
+.. js:function:: http.req_set_header(http, name, value)
+
+  This variable replace all occurence of all header "name", by only
+  one containing the "value".
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string value: The header value.
+  :see: http.res_set_header()
+
+  This function does the same work as the folowwing code:
+
+.. code-block:: lua
+
+   function fcn(txn)
+      txn.http:req_del_header("header")
+      txn.http:req_add_header("header", "value")
+   end
+..
+
+.. js:function:: http.res_set_header(http, name, value)
+
+  This variable replace all occurence of all header "name", by only
+  one containing the "value".
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string value: The header value.
+  :see: http.req_set_header()
+
+.. js:function:: http.req_replace_header(http, name, regex, replace)
+
+  Matches the regular expression in all occurrences of header field "name"
+  according to "regex", and replaces them with the "replace" argument. The
+  replacement value can contain back references like \1, \2, ... This
+  function works with the request.
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string regex: The match regular expression.
+  :param string replace: The replacement value.
+  :see: http.res_replace_header()
+
+.. js:function:: http.res_replace_header(http, name, regex, string)
+
+  Matches the regular expression in all occurrences of header field "name"
+  according to "regex", and replaces them with the "replace" argument. The
+  replacement value can contain back references like \1, \2, ... This
+  function works with the request.
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string regex: The match regular expression.
+  :param string replace: The replacement value.
+  :see: http.req_replace_header()
+
+.. js:function:: http.req_replace_value(http, name, regex, replace)
+
+  Works like "http.req_replace_header()" except that it matches the regex
+  against every comma-delimited value of the header field "name" instead of the
+  entire header.
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string regex: The match regular expression.
+  :param string replace: The replacement value.
+  :see: http.req_replace_header()
+  :see: http.res_replace_value()
+
+.. js:function:: http.res_replace_value(http, name, regex, replace)
+
+  Works like "http.res_replace_header()" except that it matches the regex
+  against every comma-delimited value of the header field "name" instead of the
+  entire header.
+
+  :param class_http http: The related http object.
+  :param string name: The header name.
+  :param string regex: The match regular expression.
+  :param string replace: The replacement value.
+  :see: http.res_replace_header()
+  :see: http.req_replace_value()
+
+.. js:function:: http.req_set_method(http, method)
+
+  Rewrites the request method with the parameter "method".
+
+  :param class_http http: The related http object.
+  :param string method: The new method.
+
+.. js:function:: http.req_set_path(http, path)
+
+  Rewrites the request path with the "path" parameter.
+
+  :param class_http http: The related http object.
+  :param string path: The new path.
+
+.. js:function:: http.req_set_query(http, query)
+
+  Rewrites the request's query string which appears after the first question
+  mark ("?") with the parameter "query".
+
+  :param class_http http: The related http object.
+  :param string query: The new query.
+
+.. js:function:: http.req.set_uri(http, uri)
+
+  Rewrites the request URI with the parameter "uri".
+
+  :param class_http http: The related http object.
+  :param string uri: The new uri.
+
 TXN class
 =========
 
@@ -466,6 +639,11 @@ TXN class
 
   This attribute contains a channel class object for the response buffer.
 
+.. js:attribute:: txn.http
+
+  This attribute contains an HTTP class object. It is avalaible only if the
+  proxy has the "mode http" enabled.
+
 .. js:function:: txn.get_priv(txn)
 
   Return Lua data stored in the current transaction (with the `txn.set_priv()`)
@@ -497,61 +675,11 @@ TXN class
 
   :param class_txn txn: The class txn object containing the data.
 
-.. js:function:: txn.http.redirect(txn, location)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.add_header(txn, name, value)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.set_method(txn, string)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.set_path(txn, string)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.set_query(txn, string)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.set_uri(txn, string)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.set_header(txn, name, value)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.del_header(txn, name)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.replace_header(txn, name, regex, string)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.req.replace_value(txn, name, regex, string)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.res.set_header(txn, name, value)
-
-  Not yet avalaible.
-
-.. js:function:: txn.http.res.del_header(txn, name)
 
-  Not yet avalaible.
 
-.. js:function:: txn.http.res.replace_header(txn, name, regex, string)
 
-  Not yet avalaible.
 
-.. js:function:: txn.http.res.replace_value(txn, name, regex, string)
 
-  Not yet avalaible.
 
 .. js:function:: txn.set_loglevel(txn, loglevel)
 
index b59a3b7a39fd33feca7aa0659c44fe2a8aba80a0..8418771fb7116999638cb7558a55f3d0ddbddcb4 100644 (file)
@@ -15,6 +15,7 @@
 #define CLASS_CONVERTERS "Converters"
 #define CLASS_SOCKET   "Socket"
 #define CLASS_CHANNEL  "Channel"
+#define CLASS_HTTP     "HTTP"
 
 struct session;
 
index 65939eebbd2b61e5486ca6bb340f070618f4c4a1..b6f53a9dd9e179ae0c47391d77b2ac77cf1dc84c 100644 (file)
@@ -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);