This is an automated email from the ASF dual-hosted git repository.

kichan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new e1900ef  Add support for header_table for lua plugin (#8261)
e1900ef is described below

commit e1900ef05bef22ccda939e6a585777c7e8e47560
Author: Kit Chan <[email protected]>
AuthorDate: Sat Aug 28 11:36:56 2021 -0700

    Add support for header_table for lua plugin (#8261)
    
    * Add support for header_table for lua plugin
    
    * Update gold test
    
    * fix test
    
    * fix test
---
 doc/admin-guide/plugins/lua.en.rst                 | 69 ++++++++++++++++++
 plugins/lua/ts_lua_cached_response.c               | 75 ++++++++++++++++++++
 plugins/lua/ts_lua_client_request.c                | 73 +++++++++++++++++++
 plugins/lua/ts_lua_client_response.c               | 81 ++++++++++++++++++++++
 plugins/lua/ts_lua_server_request.c                | 80 +++++++++++++++++++++
 plugins/lua/ts_lua_server_response.c               | 76 ++++++++++++++++++++
 tests/gold_tests/pluginTest/lua/header_table.lua   | 26 +++++++
 .../pluginTest/lua/lua_header_table.test.py        | 43 ++++++++++++
 8 files changed, 523 insertions(+)

diff --git a/doc/admin-guide/plugins/lua.en.rst 
b/doc/admin-guide/plugins/lua.en.rst
index 9065323..28eef1b 100644
--- a/doc/admin-guide/plugins/lua.en.rst
+++ b/doc/admin-guide/plugins/lua.en.rst
@@ -905,6 +905,16 @@ Then ``GET /st HTTP/1.1\r\nHost: b.tb.cn\r\nUser-Agent: 
Mozilla/5.0\r\n...`` wil
 
 :ref:`TOP <admin-plugins-ts-lua>`
 
+ts.client_request.header_table
+------------------------------
+**syntax:** *VALUE = ts.client_request.header_table[HEADER]*
+
+**context:** do_remap/do_os_response or do_global_* or later
+
+**description:** get the current client request's HEADER as a table.
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 ts.client_request.get_headers
 -----------------------------
 **syntax:** *ts.client_request.get_headers()*
@@ -1516,6 +1526,16 @@ Here is an example:
 
 :ref:`TOP <admin-plugins-ts-lua>`
 
+ts.cached_response.header_table
+-------------------------------
+**syntax:** *VALUE = ts.cached_response.header_table[HEADER]*
+
+**context:** function @ TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE hook point or later
+
+**description:** get the current cached response's HEADER as a table.
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 ts.cached_response.get_headers
 ------------------------------
 **syntax:** *ts.cached_response.get_headers()*
@@ -1724,6 +1744,16 @@ Then ``GET /st HTTP/1.1\r\nHost: b.tb.cn\r\nUser-Agent: 
Mozilla/5.0\r\n...`` wil
 
 :ref:`TOP <admin-plugins-ts-lua>`
 
+ts.server_request.header_table
+------------------------------
+**syntax:** *VALUE = ts.server_request.header_table[HEADER]*
+
+**context:** function @ TS_LUA_HOOK_SEND_REQUEST_HDR hook point or later
+
+**description:** get the current server request's HEADER as a table.
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 ts.server_request.get_headers
 -----------------------------
 **syntax:** *ts.server_request.get_headers()*
@@ -2399,6 +2429,16 @@ We will get the output:
 
 :ref:`TOP <admin-plugins-ts-lua>`'
 
+ts.server_response.header_table
+-------------------------------
+**syntax:** *VALUE = ts.server_response.header_table[HEADER]*
+
+**context:** function @ TS_LUA_HOOK_READ_RESPONSE_HDR hook point or later.
+
+**description:** get the current server response's HEADER as a table.
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 ts.server_response.get_headers
 ------------------------------
 **syntax:** *ts.server_response.get_headers()*
@@ -2550,6 +2590,35 @@ We will get the output:
 
 :ref:`TOP <admin-plugins-ts-lua>`
 
+ts.client_response.header_table
+-------------------------------
+**syntax:** *VALUE = ts.client_response.header_table[HEADER]*
+
+**context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point.
+
+**description:** get the current client response's HEADER as a table.
+
+Here is an example:
+
+::
+
+    function send_response()
+        local hdrs = ts.client_response.header_table['Set-Cookie'] or {}
+        for k, v in pairs(hdrs) do
+            ts.debug(k..': '..v)
+        end
+    end
+
+    function do_remap()
+        ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response)
+        return 0
+    end
+
+If there are multiple 'Set-Cookie' response header, they will be printed as 
debug message.
+
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 ts.client_response.get_headers
 ------------------------------
 **syntax:** *ts.client_response.get_headers()*
diff --git a/plugins/lua/ts_lua_cached_response.c 
b/plugins/lua/ts_lua_cached_response.c
index 0fa5e17..bbfa95d 100644
--- a/plugins/lua/ts_lua_cached_response.c
+++ b/plugins/lua/ts_lua_cached_response.c
@@ -35,10 +35,13 @@
 
 static void ts_lua_inject_cached_response_misc_api(lua_State *L);
 static void ts_lua_inject_cached_response_header_api(lua_State *L);
+static void ts_lua_inject_cached_response_header_table_api(lua_State *L);
 static void ts_lua_inject_cached_response_headers_api(lua_State *L);
 
 static int ts_lua_cached_response_header_get(lua_State *L);
 static int ts_lua_cached_response_header_set(lua_State *L);
+static int ts_lua_cached_response_header_table_get(lua_State *L);
+static int ts_lua_cached_response_header_table_set(lua_State *L);
 static int ts_lua_cached_response_get_headers(lua_State *L);
 
 static int ts_lua_cached_response_get_status(lua_State *L);
@@ -50,6 +53,7 @@ ts_lua_inject_cached_response_api(lua_State *L)
   lua_newtable(L);
 
   ts_lua_inject_cached_response_header_api(L);
+  ts_lua_inject_cached_response_header_table_api(L);
   ts_lua_inject_cached_response_headers_api(L);
   ts_lua_inject_cached_response_misc_api(L);
 
@@ -76,6 +80,23 @@ ts_lua_inject_cached_response_header_api(lua_State *L)
 }
 
 static void
+ts_lua_inject_cached_response_header_table_api(lua_State *L)
+{
+  lua_newtable(L); /* .header */
+
+  lua_createtable(L, 0, 2); /* metatable for .header */
+
+  lua_pushcfunction(L, ts_lua_cached_response_header_table_get);
+  lua_setfield(L, -2, "__index");
+  lua_pushcfunction(L, ts_lua_cached_response_header_table_set);
+  lua_setfield(L, -2, "__newindex");
+
+  lua_setmetatable(L, -2);
+
+  lua_setfield(L, -2, "header_table");
+}
+
+static void
 ts_lua_inject_cached_response_headers_api(lua_State *L)
 {
   lua_pushcfunction(L, ts_lua_cached_response_get_headers);
@@ -189,6 +210,60 @@ ts_lua_cached_response_header_set(lua_State *L ATS_UNUSED)
 }
 
 static int
+ts_lua_cached_response_header_table_get(lua_State *L)
+{
+  const char *key;
+  const char *val;
+  int val_len;
+  size_t key_len;
+  int count;
+
+  TSMLoc field_loc, next_field_loc;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  /*  we skip the first argument that is the table */
+  key = luaL_checklstring(L, 2, &key_len);
+
+  TS_LUA_CHECK_CACHED_RESPONSE_HDR(http_ctx);
+
+  if (key && key_len) {
+    field_loc = TSMimeHdrFieldFind(http_ctx->cached_response_bufp, 
http_ctx->cached_response_hdrp, key, key_len);
+
+    if (field_loc != TS_NULL_MLOC) {
+      lua_newtable(L);
+      count = 0;
+      while (field_loc != TS_NULL_MLOC) {
+        val = TSMimeHdrFieldValueStringGet(http_ctx->cached_response_bufp, 
http_ctx->cached_response_hdrp, field_loc, -1, &val_len);
+        next_field_loc = TSMimeHdrFieldNextDup(http_ctx->cached_response_bufp, 
http_ctx->cached_response_hdrp, field_loc);
+        count++;
+
+        lua_pushlstring(L, val, val_len);
+        lua_rawseti(L, -2, count);
+
+        TSHandleMLocRelease(http_ctx->cached_response_bufp, 
http_ctx->cached_response_hdrp, field_loc);
+        field_loc = next_field_loc;
+      }
+
+    } else {
+      lua_pushnil(L);
+    }
+
+  } else {
+    lua_pushnil(L);
+  }
+
+  return 1;
+}
+
+static int
+ts_lua_cached_response_header_table_set(lua_State *L)
+{
+  return 0;
+}
+
+static int
 ts_lua_cached_response_get_headers(lua_State *L)
 {
   const char *name;
diff --git a/plugins/lua/ts_lua_client_request.c 
b/plugins/lua/ts_lua_client_request.c
index 2d1d509..37ca12a 100644
--- a/plugins/lua/ts_lua_client_request.c
+++ b/plugins/lua/ts_lua_client_request.c
@@ -25,6 +25,8 @@ static void 
ts_lua_inject_client_request_server_addr_api(lua_State *L);
 
 static int ts_lua_client_request_header_get(lua_State *L);
 static int ts_lua_client_request_header_set(lua_State *L);
+static int ts_lua_client_request_header_table_get(lua_State *L);
+static int ts_lua_client_request_header_table_set(lua_State *L);
 static int ts_lua_client_request_get_headers(lua_State *L);
 static int ts_lua_client_request_get_url(lua_State *L);
 static int ts_lua_client_request_get_pristine_url(lua_State *L);
@@ -51,6 +53,7 @@ static int ts_lua_client_request_get_header_size(lua_State 
*L);
 
 static void ts_lua_inject_client_request_socket_api(lua_State *L);
 static void ts_lua_inject_client_request_header_api(lua_State *L);
+static void ts_lua_inject_client_request_header_table_api(lua_State *L);
 static void ts_lua_inject_client_request_headers_api(lua_State *L);
 static void ts_lua_inject_client_request_url_api(lua_State *L);
 static void ts_lua_inject_client_request_uri_api(lua_State *L);
@@ -82,6 +85,7 @@ ts_lua_inject_client_request_api(lua_State *L)
 
   ts_lua_inject_client_request_socket_api(L);
   ts_lua_inject_client_request_header_api(L);
+  ts_lua_inject_client_request_header_table_api(L);
   ts_lua_inject_client_request_headers_api(L);
   ts_lua_inject_client_request_url_api(L);
   ts_lua_inject_client_request_uri_api(L);
@@ -263,6 +267,75 @@ ts_lua_client_request_header_set(lua_State *L)
 }
 
 static void
+ts_lua_inject_client_request_header_table_api(lua_State *L)
+{
+  lua_newtable(L); /* .header */
+
+  lua_createtable(L, 0, 2); /* metatable for .header */
+
+  lua_pushcfunction(L, ts_lua_client_request_header_table_get);
+  lua_setfield(L, -2, "__index");
+  lua_pushcfunction(L, ts_lua_client_request_header_table_set);
+  lua_setfield(L, -2, "__newindex");
+
+  lua_setmetatable(L, -2);
+
+  lua_setfield(L, -2, "header_table");
+}
+
+static int
+ts_lua_client_request_header_table_get(lua_State *L)
+{
+  const char *key;
+  const char *val;
+  int val_len;
+  size_t key_len;
+  int count;
+
+  TSMLoc field_loc, next_field_loc;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  /*  we skip the first argument that is the table */
+  key = luaL_checklstring(L, 2, &key_len);
+
+  if (key && key_len) {
+    field_loc = TSMimeHdrFieldFind(http_ctx->client_request_bufp, 
http_ctx->client_request_hdrp, key, key_len);
+
+    if (field_loc != TS_NULL_MLOC) {
+      lua_newtable(L);
+      count = 0;
+      while (field_loc != TS_NULL_MLOC) {
+        val = TSMimeHdrFieldValueStringGet(http_ctx->client_request_bufp, 
http_ctx->client_request_hdrp, field_loc, -1, &val_len);
+        next_field_loc = TSMimeHdrFieldNextDup(http_ctx->client_request_bufp, 
http_ctx->client_request_hdrp, field_loc);
+        count++;
+
+        lua_pushlstring(L, val, val_len);
+        lua_rawseti(L, -2, count);
+
+        TSHandleMLocRelease(http_ctx->client_request_bufp, 
http_ctx->client_request_hdrp, field_loc);
+        field_loc = next_field_loc;
+      }
+
+    } else {
+      lua_pushnil(L);
+    }
+
+  } else {
+    lua_pushnil(L);
+  }
+
+  return 1;
+}
+
+static int
+ts_lua_client_request_header_table_set(lua_State *L)
+{
+  return 0;
+}
+
+static void
 ts_lua_inject_client_request_headers_api(lua_State *L)
 {
   lua_pushcfunction(L, ts_lua_client_request_get_headers);
diff --git a/plugins/lua/ts_lua_client_response.c 
b/plugins/lua/ts_lua_client_response.c
index 8ecbf44..f7e3a35 100644
--- a/plugins/lua/ts_lua_client_response.c
+++ b/plugins/lua/ts_lua_client_response.c
@@ -31,6 +31,9 @@
 static int ts_lua_client_response_header_get(lua_State *L);
 static int ts_lua_client_response_header_set(lua_State *L);
 
+static int ts_lua_client_response_header_table_get(lua_State *L);
+static int ts_lua_client_response_header_table_set(lua_State *L);
+
 static int ts_lua_client_response_get_headers(lua_State *L);
 
 static int ts_lua_client_response_get_status(lua_State *L);
@@ -42,6 +45,7 @@ static int ts_lua_client_response_get_version(lua_State *L);
 static int ts_lua_client_response_set_version(lua_State *L);
 
 static void ts_lua_inject_client_response_header_api(lua_State *L);
+static void ts_lua_inject_client_response_header_table_api(lua_State *L);
 static void ts_lua_inject_client_response_headers_api(lua_State *L);
 static void ts_lua_inject_client_response_misc_api(lua_State *L);
 
@@ -51,6 +55,7 @@ ts_lua_inject_client_response_api(lua_State *L)
   lua_newtable(L);
 
   ts_lua_inject_client_response_header_api(L);
+  ts_lua_inject_client_response_header_table_api(L);
   ts_lua_inject_client_response_headers_api(L);
   ts_lua_inject_client_response_misc_api(L);
 
@@ -202,6 +207,82 @@ ts_lua_client_response_header_set(lua_State *L)
 }
 
 static void
+ts_lua_inject_client_response_header_table_api(lua_State *L)
+{
+  lua_newtable(L); /* .header */
+
+  lua_createtable(L, 0, 2); /* metatable for .header */
+
+  lua_pushcfunction(L, ts_lua_client_response_header_table_get);
+  lua_setfield(L, -2, "__index");
+  lua_pushcfunction(L, ts_lua_client_response_header_table_set);
+  lua_setfield(L, -2, "__newindex");
+
+  lua_setmetatable(L, -2);
+
+  lua_setfield(L, -2, "header_table");
+}
+
+static int
+ts_lua_client_response_header_table_get(lua_State *L)
+{
+  const char *key;
+  const char *val;
+  int val_len;
+  size_t key_len;
+  int count;
+
+  TSMLoc field_loc, next_field_loc;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  /*  we skip the first argument that is the table */
+  key = luaL_checklstring(L, 2, &key_len);
+
+  if (!http_ctx->client_response_hdrp) {
+    if (TSHttpTxnClientRespGet(http_ctx->txnp, 
&http_ctx->client_response_bufp, &http_ctx->client_response_hdrp) != 
TS_SUCCESS) {
+      lua_pushnil(L);
+      return 1;
+    }
+  }
+
+  if (key && key_len) {
+    field_loc = TSMimeHdrFieldFind(http_ctx->client_response_bufp, 
http_ctx->client_response_hdrp, key, key_len);
+
+    if (field_loc != TS_NULL_MLOC) {
+      lua_newtable(L);
+      count = 0;
+      while (field_loc != TS_NULL_MLOC) {
+        val = TSMimeHdrFieldValueStringGet(http_ctx->client_response_bufp, 
http_ctx->client_response_hdrp, field_loc, -1, &val_len);
+        next_field_loc = TSMimeHdrFieldNextDup(http_ctx->client_response_bufp, 
http_ctx->client_response_hdrp, field_loc);
+        count++;
+
+        lua_pushlstring(L, val, val_len);
+        lua_rawseti(L, -2, count);
+
+        TSHandleMLocRelease(http_ctx->client_response_bufp, 
http_ctx->client_response_hdrp, field_loc);
+        field_loc = next_field_loc;
+      }
+
+    } else {
+      lua_pushnil(L);
+    }
+
+  } else {
+    lua_pushnil(L);
+  }
+
+  return 1;
+}
+
+static int
+ts_lua_client_response_header_table_set(lua_State *L)
+{
+  return 0;
+}
+
+static void
 ts_lua_inject_client_response_headers_api(lua_State *L)
 {
   lua_pushcfunction(L, ts_lua_client_response_get_headers);
diff --git a/plugins/lua/ts_lua_server_request.c 
b/plugins/lua/ts_lua_server_request.c
index eb986c2..eef5205 100644
--- a/plugins/lua/ts_lua_server_request.c
+++ b/plugins/lua/ts_lua_server_request.c
@@ -44,6 +44,7 @@ static void 
ts_lua_inject_server_request_server_addr_api(lua_State *L);
 
 static void ts_lua_inject_server_request_socket_api(lua_State *L);
 static void ts_lua_inject_server_request_header_api(lua_State *L);
+static void ts_lua_inject_server_request_header_table_api(lua_State *L);
 static void ts_lua_inject_server_request_headers_api(lua_State *L);
 static void ts_lua_inject_server_request_get_header_size_api(lua_State *L);
 static void ts_lua_inject_server_request_get_body_size_api(lua_State *L);
@@ -55,6 +56,8 @@ static void ts_lua_inject_server_request_method_api(lua_State 
*L);
 
 static int ts_lua_server_request_header_get(lua_State *L);
 static int ts_lua_server_request_header_set(lua_State *L);
+static int ts_lua_server_request_header_table_get(lua_State *L);
+static int ts_lua_server_request_header_table_set(lua_State *L);
 static int ts_lua_server_request_get_headers(lua_State *L);
 static int ts_lua_server_request_get_header_size(lua_State *L);
 static int ts_lua_server_request_get_body_size(lua_State *L);
@@ -89,6 +92,7 @@ ts_lua_inject_server_request_api(lua_State *L)
 
   ts_lua_inject_server_request_socket_api(L);
   ts_lua_inject_server_request_header_api(L);
+  ts_lua_inject_server_request_header_table_api(L);
   ts_lua_inject_server_request_headers_api(L);
   ts_lua_inject_server_request_get_header_size_api(L);
   ts_lua_inject_server_request_get_body_size_api(L);
@@ -290,6 +294,82 @@ ts_lua_server_request_header_set(lua_State *L)
 }
 
 static void
+ts_lua_inject_server_request_header_table_api(lua_State *L)
+{
+  lua_newtable(L); /* .header */
+
+  lua_createtable(L, 0, 2); /* metatable for .header */
+
+  lua_pushcfunction(L, ts_lua_server_request_header_table_get);
+  lua_setfield(L, -2, "__index");
+  lua_pushcfunction(L, ts_lua_server_request_header_table_set);
+  lua_setfield(L, -2, "__newindex");
+
+  lua_setmetatable(L, -2);
+
+  lua_setfield(L, -2, "header_table");
+}
+
+static int
+ts_lua_server_request_header_table_get(lua_State *L)
+{
+  const char *key;
+  const char *val;
+  int val_len;
+  size_t key_len;
+  int count;
+
+  TSMLoc field_loc, next_field_loc;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  /*  we skip the first argument that is the table */
+  key = luaL_checklstring(L, 2, &key_len);
+
+  if (!http_ctx->server_request_hdrp) {
+    if (TSHttpTxnServerReqGet(http_ctx->txnp, &http_ctx->server_request_bufp, 
&http_ctx->server_request_hdrp) != TS_SUCCESS) {
+      lua_pushnil(L);
+      return 1;
+    }
+  }
+
+  if (key && key_len) {
+    field_loc = TSMimeHdrFieldFind(http_ctx->server_request_bufp, 
http_ctx->server_request_hdrp, key, key_len);
+
+    if (field_loc != TS_NULL_MLOC) {
+      lua_newtable(L);
+      count = 0;
+      while (field_loc != TS_NULL_MLOC) {
+        val = TSMimeHdrFieldValueStringGet(http_ctx->server_request_bufp, 
http_ctx->server_request_hdrp, field_loc, -1, &val_len);
+        next_field_loc = TSMimeHdrFieldNextDup(http_ctx->server_request_bufp, 
http_ctx->server_request_hdrp, field_loc);
+        count++;
+
+        lua_pushlstring(L, val, val_len);
+        lua_rawseti(L, -2, count);
+
+        TSHandleMLocRelease(http_ctx->server_request_bufp, 
http_ctx->server_request_hdrp, field_loc);
+        field_loc = next_field_loc;
+      }
+
+    } else {
+      lua_pushnil(L);
+    }
+
+  } else {
+    lua_pushnil(L);
+  }
+
+  return 1;
+}
+
+static int
+ts_lua_server_request_header_table_set(lua_State *L)
+{
+  return 0;
+}
+
+static void
 ts_lua_inject_server_request_headers_api(lua_State *L)
 {
   lua_pushcfunction(L, ts_lua_server_request_get_headers);
diff --git a/plugins/lua/ts_lua_server_response.c 
b/plugins/lua/ts_lua_server_response.c
index b14cc32..2beb344 100644
--- a/plugins/lua/ts_lua_server_response.c
+++ b/plugins/lua/ts_lua_server_response.c
@@ -29,12 +29,16 @@
   } while (0)
 
 static void ts_lua_inject_server_response_header_api(lua_State *L);
+static void ts_lua_inject_server_response_header_table_api(lua_State *L);
 static void ts_lua_inject_server_response_headers_api(lua_State *L);
 static void ts_lua_inject_server_response_misc_api(lua_State *L);
 
 static int ts_lua_server_response_header_get(lua_State *L);
 static int ts_lua_server_response_header_set(lua_State *L);
 
+static int ts_lua_server_response_header_table_get(lua_State *L);
+static int ts_lua_server_response_header_table_set(lua_State *L);
+
 static int ts_lua_server_response_get_headers(lua_State *L);
 
 static int ts_lua_server_response_get_status(lua_State *L);
@@ -52,6 +56,7 @@ ts_lua_inject_server_response_api(lua_State *L)
   lua_newtable(L);
 
   ts_lua_inject_server_response_header_api(L);
+  ts_lua_inject_server_response_header_table_api(L);
   ts_lua_inject_server_response_headers_api(L);
   ts_lua_inject_server_response_misc_api(L);
 
@@ -76,6 +81,23 @@ ts_lua_inject_server_response_header_api(lua_State *L)
 }
 
 static void
+ts_lua_inject_server_response_header_table_api(lua_State *L)
+{
+  lua_newtable(L); /* .header */
+
+  lua_createtable(L, 0, 2); /* metatable for .header */
+
+  lua_pushcfunction(L, ts_lua_server_response_header_table_get);
+  lua_setfield(L, -2, "__index");
+  lua_pushcfunction(L, ts_lua_server_response_header_table_set);
+  lua_setfield(L, -2, "__newindex");
+
+  lua_setmetatable(L, -2);
+
+  lua_setfield(L, -2, "header_table");
+}
+
+static void
 ts_lua_inject_server_response_headers_api(lua_State *L)
 {
   lua_pushcfunction(L, ts_lua_server_response_get_headers);
@@ -278,6 +300,60 @@ ts_lua_server_response_header_set(lua_State *L)
 }
 
 static int
+ts_lua_server_response_header_table_get(lua_State *L)
+{
+  const char *key;
+  const char *val;
+  int val_len;
+  size_t key_len;
+  int count;
+
+  TSMLoc field_loc, next_field_loc;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  /*  we skip the first argument that is the table */
+  key = luaL_checklstring(L, 2, &key_len);
+
+  TS_LUA_CHECK_SERVER_RESPONSE_HDR(http_ctx);
+
+  if (key && key_len) {
+    field_loc = TSMimeHdrFieldFind(http_ctx->server_response_bufp, 
http_ctx->server_response_hdrp, key, key_len);
+
+    if (field_loc != TS_NULL_MLOC) {
+      lua_newtable(L);
+      count = 0;
+      while (field_loc != TS_NULL_MLOC) {
+        val = TSMimeHdrFieldValueStringGet(http_ctx->server_response_bufp, 
http_ctx->server_response_hdrp, field_loc, -1, &val_len);
+        next_field_loc = TSMimeHdrFieldNextDup(http_ctx->server_response_bufp, 
http_ctx->server_response_hdrp, field_loc);
+        count++;
+
+        lua_pushlstring(L, val, val_len);
+        lua_rawseti(L, -2, count);
+
+        TSHandleMLocRelease(http_ctx->server_response_bufp, 
http_ctx->server_response_hdrp, field_loc);
+        field_loc = next_field_loc;
+      }
+
+    } else {
+      lua_pushnil(L);
+    }
+
+  } else {
+    lua_pushnil(L);
+  }
+
+  return 1;
+}
+
+static int
+ts_lua_server_response_header_table_set(lua_State *L)
+{
+  return 0;
+}
+
+static int
 ts_lua_server_response_get_status(lua_State *L)
 {
   int status;
diff --git a/tests/gold_tests/pluginTest/lua/header_table.lua 
b/tests/gold_tests/pluginTest/lua/header_table.lua
new file mode 100644
index 0000000..699ee2b
--- /dev/null
+++ b/tests/gold_tests/pluginTest/lua/header_table.lua
@@ -0,0 +1,26 @@
+--  Licensed to the Apache Software Foundation (ASF) under one
+--  or more contributor license agreements.  See the NOTICE file
+--  distributed with this work for additional information
+--  regarding copyright ownership.  The ASF licenses this file
+--  to you under the Apache License, Version 2.0 (the
+--  "License"); you may not use this file except in compliance
+--  with the License.  You may obtain a copy of the License at
+--
+--  http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+
+function do_remap()
+    local hdrs = ts.client_request.header_table['X-Test'] or {}
+    local h = ''
+    for k, v in pairs(hdrs) do
+        h = h..v
+    end
+    ts.http.set_resp(200, h)
+    hdrs = {}
+    return 0
+end
diff --git a/tests/gold_tests/pluginTest/lua/lua_header_table.test.py 
b/tests/gold_tests/pluginTest/lua/lua_header_table.test.py
new file mode 100644
index 0000000..7fdf775
--- /dev/null
+++ b/tests/gold_tests/pluginTest/lua/lua_header_table.test.py
@@ -0,0 +1,43 @@
+'''
+'''
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+Test.Summary = '''
+Test lua header table functionality
+'''
+
+Test.SkipUnless(
+    Condition.PluginExists('tslua.so'),
+)
+
+Test.ContinueOnFail = True
+# Define default ATS
+ts = Test.MakeATSProcess("ts")
+
+ts.Disk.remap_config.AddLine(
+    f"map / http://127.0.0.1 @plugin=tslua.so 
@pparam={Test.TestDirectory}/header_table.lua"
+)
+
+# Test - Check for header table
+tr = Test.AddTestRun("Lua Header Table")
+ps = tr.Processes.Default  # alias
+ps.StartBefore(Test.Processes.ts)
+ps.Command = f"curl -s -D /dev/stderr -H 'X-Test: test1' -H 'X-Test: test2' 
http://127.0.0.1:{ts.Variables.port}";
+ps.Env = ts.Env
+ps.ReturnCode = 0
+ps.Streams.stdout.Content = Testers.ContainsExpression("test1test2", "expected 
header table results")
+tr.StillRunningAfter = ts

Reply via email to