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