You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2021/01/27 23:01:03 UTC

[trafficserver] 03/04: Simple and miscellaneous fixes/additions for lua plugin

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

zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 51a61251ad75aef13c9ba8d8249fe68c007624ab
Author: Kit Chan <ki...@apache.org>
AuthorDate: Sat Jan 4 15:38:16 2020 -0800

    Simple and miscellaneous fixes/additions for lua plugin
    
    (cherry picked from commit 7236e78f7f53acae3fd6f71ce9cd12f99f7b5b9c)
---
 doc/admin-guide/plugins/lua.en.rst   | 77 +++++++++++++++++++++++++++++++++++-
 plugins/lua/Makefile.inc             |  1 +
 plugins/lua/ts_lua.c                 | 16 ++++++--
 plugins/lua/ts_lua_client_request.c  |  2 +-
 plugins/lua/ts_lua_client_response.c |  2 +-
 plugins/lua/ts_lua_fetch.c           |  4 +-
 plugins/lua/ts_lua_http.c            | 41 +++++++++++++++----
 plugins/lua/ts_lua_http_config.c     |  2 +-
 plugins/lua/ts_lua_http_intercept.c  | 15 +++----
 plugins/lua/ts_lua_http_txn_info.c   | 76 +++++++++++++++++++++++++++++++++++
 plugins/lua/ts_lua_http_txn_info.h   | 23 +++++++++++
 plugins/lua/ts_lua_log.c             |  4 +-
 plugins/lua/ts_lua_misc.c            | 40 +++++++++++++++++--
 plugins/lua/ts_lua_package.c         |  4 +-
 plugins/lua/ts_lua_server_request.c  |  2 +-
 plugins/lua/ts_lua_server_response.c |  2 +-
 plugins/lua/ts_lua_transform.c       |  9 +++--
 plugins/lua/ts_lua_util.c            | 11 +++++-
 18 files changed, 292 insertions(+), 39 deletions(-)

diff --git a/doc/admin-guide/plugins/lua.en.rst b/doc/admin-guide/plugins/lua.en.rst
index de48ec3..d160e2a 100644
--- a/doc/admin-guide/plugins/lua.en.rst
+++ b/doc/admin-guide/plugins/lua.en.rst
@@ -267,6 +267,38 @@ Here is an example:
 
 :ref:`TOP <admin-plugins-ts-lua>`
 
+ts.fatal
+--------
+**syntax:** *ts.fatal(MESSAGE)*
+
+**context:** global
+
+**description**: Log the MESSAGE to error.log and shutdown Traffic Server
+
+Here is an example:
+
+::
+
+       ts.fatal('This is an fatal message')
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
+ts.emergency
+------------
+**syntax:** *ts.emergency(MESSAGE)*
+
+**context:** global
+
+**description**: Log the MESSAGE to error.log and shutdown Traffic Server
+
+Here is an example:
+
+::
+
+       ts.emergency('This is an emergency message')
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 TS Basic Internal Information
 -----------------------------
 **syntax:** *ts.get_install_dir()*
@@ -1147,6 +1179,16 @@ ts.http.set_cache_lookup_url
 
 :ref:`TOP <admin-plugins-ts-lua>`
 
+ts.http.redo_cache_lookup
+-------------------------
+**syntax:** *ts.http.redo_cache_lookup()*
+
+**context:** do_global_cache_lookup_complete
+
+**description:** This function can be used to redo cache lookup with a different url.
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 ts.http.get_parent_proxy
 ------------------------
 **syntax:** *ts.http.get_parent_proxy()*
@@ -2605,6 +2647,9 @@ Here is an example:
         return 0
     end
 
+The above example also shows the use of eos passed as a parameter to transform function. It indicates the end of the
+data stream to the transform function. 
+
 :ref:`TOP <admin-plugins-ts-lua>`
 
 ts.http.resp_transform.get_upstream_watermark_bytes
@@ -3981,7 +4026,7 @@ of seconds since the beginning of the transaction.
 :ref:`TOP <admin-plugins-ts-lua>`
 
 Milestone constants
-------------------------------
+-------------------
 **context:** do_remap/do_os_response or do_global_* or later
 
 ::
@@ -4014,6 +4059,36 @@ Milestone constants
 
 :ref:`TOP <admin-plugins-ts-lua>`
 
+ts.http.txn_info_get
+--------------------
+**syntax:** *val = ts.http.txn_info_get(TXN_INFO_TYPE)*
+
+**context:** do_global_cache_lookup_complete
+
+**description:** This function can be used to retrieve the various cache related info about a transaction.
+
+::
+
+    val = ts.http.txn_info_get(TS_LUA_TXN_INFO_CACHE_HIT_RAM)
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
+Txn Info constants
+------------------
+**context:** do_global_cache_lookup_complete
+
+::
+
+    TS_LUA_TXN_INFO_CACHE_HIT_RAM
+    TS_LUA_TXN_INFO_CACHE_COMPRESSED_IN_RAM
+    TS_LUA_TXN_INFO_CACHE_HIT_RWW
+    TS_LUA_TXN_INFO_CACHE_OPEN_READ_TRIES
+    TS_LUA_TXN_INFO_CACHE_OPEN_WRITE_TRIES
+    TS_LUA_TXN_INFo_CACHE_VOLUME
+
+
+:ref:`TOP <admin-plugins-ts-lua>`
+
 ts.mgmt.get_counter
 -------------------
 **syntax:** *val = ts.mgmt.get_counter(RECORD_NAME)*
diff --git a/plugins/lua/Makefile.inc b/plugins/lua/Makefile.inc
index adcdde5..d68faa8 100644
--- a/plugins/lua/Makefile.inc
+++ b/plugins/lua/Makefile.inc
@@ -37,6 +37,7 @@ lua_tslua_la_SOURCES = \
   lua/ts_lua_remap.c \
   lua/ts_lua_http_cntl.c \
   lua/ts_lua_http_milestone.c \
+  lua/ts_lua_http_txn_info.c \
   lua/ts_lua_http_config.c \
   lua/ts_lua_mgmt.c \
   lua/ts_lua_package.c \
diff --git a/plugins/lua/ts_lua.c b/plugins/lua/ts_lua.c
index 1451c56..0e7468f 100644
--- a/plugins/lua/ts_lua.c
+++ b/plugins/lua/ts_lua.c
@@ -511,7 +511,7 @@ ts_lua_remap_plugin_init(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri)
 
   ts_lua_set_cont_info(L, NULL);
   if (lua_pcall(L, 0, 1, 0) != 0) {
-    TSError("[ts_lua] lua_pcall failed: %s", lua_tostring(L, -1));
+    TSError("[ts_lua][%s] lua_pcall failed: %s", __FUNCTION__, lua_tostring(L, -1));
     ret = TSREMAP_NO_REMAP;
 
   } else {
@@ -636,6 +636,7 @@ globalHookHandler(TSCont contp, TSEvent event ATS_UNUSED, void *edata)
     // to allow API(s) to fetch the pointers again when it re-enters the hook
     if (http_ctx->client_response_hdrp != NULL) {
       TSHandleMLocRelease(http_ctx->client_response_bufp, TS_NULL_MLOC, http_ctx->client_response_hdrp);
+      http_ctx->client_response_bufp = NULL;
       http_ctx->client_response_hdrp = NULL;
     }
     lua_getglobal(l, TS_LUA_FUNCTION_G_SEND_RESPONSE);
@@ -688,12 +689,21 @@ globalHookHandler(TSCont contp, TSEvent event ATS_UNUSED, void *edata)
   ts_lua_set_cont_info(l, NULL);
 
   if (lua_pcall(l, 0, 1, 0) != 0) {
-    TSError("[ts_lua] lua_pcall failed: %s", lua_tostring(l, -1));
+    TSError("[ts_lua][%s] lua_pcall failed: %s", __FUNCTION__, lua_tostring(l, -1));
   }
 
   ret = lua_tointeger(l, -1);
   lua_pop(l, 1);
 
+  // client response can be changed within a transaction
+  // (e.g. due to the follow redirect feature). So, clearing the pointers
+  // to allow API(s) to fetch the pointers again when it re-enters the hook
+  if (http_ctx->client_response_hdrp != NULL) {
+    TSHandleMLocRelease(http_ctx->client_response_bufp, TS_NULL_MLOC, http_ctx->client_response_hdrp);
+    http_ctx->client_response_bufp = NULL;
+    http_ctx->client_response_hdrp = NULL;
+  }
+
   if (http_ctx->has_hook) {
     // add a hook to release resources for context
     TSDebug(TS_LUA_DEBUG_TAG, "[%s] has txn hook -> adding txn close hook handler to release resources", __FUNCTION__);
@@ -724,7 +734,7 @@ TSPluginInit(int argc, const char *argv[])
   info.support_email = "dev@trafficserver.apache.org";
 
   if (TSPluginRegister(&info) != TS_SUCCESS) {
-    TSError("[ts_lua] Plugin registration failed");
+    TSError("[ts_lua][%s] Plugin registration failed", __FUNCTION__);
   }
 
   if (NULL == ts_lua_g_main_ctx_array) {
diff --git a/plugins/lua/ts_lua_client_request.c b/plugins/lua/ts_lua_client_request.c
index a78b5b9..2d1d509 100644
--- a/plugins/lua/ts_lua_client_request.c
+++ b/plugins/lua/ts_lua_client_request.c
@@ -900,7 +900,7 @@ ts_lua_client_request_set_version(lua_State *L)
 {
   const char *version;
   size_t len;
-  int major, minor;
+  unsigned int major, minor;
 
   ts_lua_http_ctx *http_ctx;
 
diff --git a/plugins/lua/ts_lua_client_response.c b/plugins/lua/ts_lua_client_response.c
index 224e5e4..8ecbf44 100644
--- a/plugins/lua/ts_lua_client_response.c
+++ b/plugins/lua/ts_lua_client_response.c
@@ -358,7 +358,7 @@ ts_lua_client_response_set_version(lua_State *L)
 {
   const char *version;
   size_t len;
-  int major, minor;
+  unsigned int major, minor;
 
   ts_lua_http_ctx *http_ctx;
 
diff --git a/plugins/lua/ts_lua_fetch.c b/plugins/lua/ts_lua_fetch.c
index 88042f0..88c7660 100644
--- a/plugins/lua/ts_lua_fetch.c
+++ b/plugins/lua/ts_lua_fetch.c
@@ -256,9 +256,9 @@ ts_lua_fetch_one_item(lua_State *L, const char *url, size_t url_len, ts_lua_fetc
       addr = luaL_checklstring(L, -1, &addr_len);
 
       if (TS_ERROR == TSIpStringToAddr(addr, addr_len, &clientaddr)) {
-        TSError("[%s] Client ip parse failed! Using default.", TS_LUA_DEBUG_TAG);
+        TSError("[ts_lua][%s] Client ip parse failed! Using default.", TS_LUA_DEBUG_TAG);
         if (TS_ERROR == TSIpStringToAddr(TS_LUA_FETCH_CLIENT_ADDRPORT, TS_LUA_FETCH_CLIENT_ADDRPORT_LEN, &clientaddr)) {
-          TSError("[%s] Default client ip parse failed!", TS_LUA_DEBUG_TAG);
+          TSError("[ts_lua][%s] Default client ip parse failed!", TS_LUA_DEBUG_TAG);
           return 0;
         }
       }
diff --git a/plugins/lua/ts_lua_http.c b/plugins/lua/ts_lua_http.c
index b10fefb..9ea883c 100644
--- a/plugins/lua/ts_lua_http.c
+++ b/plugins/lua/ts_lua_http.c
@@ -21,6 +21,7 @@
 #include "ts_lua_http_config.h"
 #include "ts_lua_http_cntl.h"
 #include "ts_lua_http_milestone.h"
+#include "ts_lua_http_txn_info.h"
 
 typedef enum {
   TS_LUA_CACHE_LOOKUP_MISS,
@@ -71,6 +72,7 @@ static int ts_lua_http_set_cache_lookup_status(lua_State *L);
 static int ts_lua_http_set_cache_url(lua_State *L);
 static int ts_lua_http_get_cache_lookup_url(lua_State *L);
 static int ts_lua_http_set_cache_lookup_url(lua_State *L);
+static int ts_lua_http_redo_cache_lookup(lua_State *L);
 static int ts_lua_http_get_parent_proxy(lua_State *L);
 static int ts_lua_http_set_parent_proxy(lua_State *L);
 static int ts_lua_http_get_parent_selection_url(lua_State *L);
@@ -121,6 +123,7 @@ ts_lua_inject_http_api(lua_State *L)
   ts_lua_inject_http_config_api(L);
   ts_lua_inject_http_cntl_api(L);
   ts_lua_inject_http_milestone_api(L);
+  ts_lua_inject_txn_info_api(L);
   ts_lua_inject_http_misc_api(L);
 
   lua_setfield(L, -2, "http");
@@ -157,6 +160,9 @@ ts_lua_inject_http_cache_api(lua_State *L)
   lua_pushcfunction(L, ts_lua_http_set_cache_lookup_url);
   lua_setfield(L, -2, "set_cache_lookup_url");
 
+  lua_pushcfunction(L, ts_lua_http_redo_cache_lookup);
+  lua_setfield(L, -2, "redo_cache_lookup");
+
   lua_pushcfunction(L, ts_lua_http_get_parent_proxy);
   lua_setfield(L, -2, "get_parent_proxy");
 
@@ -424,7 +430,28 @@ ts_lua_http_set_cache_lookup_url(lua_State *L)
         TSHttpTxnCacheLookupUrlSet(http_ctx->txnp, http_ctx->client_request_bufp, new_url_loc) == TS_SUCCESS) {
       TSDebug(TS_LUA_DEBUG_TAG, "Set cache lookup URL");
     } else {
-      TSError("[ts_lua] Failed to set cache lookup URL");
+      TSError("[ts_lua][%s] Failed to set cache lookup URL", __FUNCTION__);
+    }
+  }
+
+  return 0;
+}
+
+static int
+ts_lua_http_redo_cache_lookup(lua_State *L)
+{
+  const char *url;
+  size_t url_len;
+
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  url = luaL_checklstring(L, 1, &url_len);
+
+  if (url && url_len) {
+    if (TSHttpTxnRedoCacheLookup(http_ctx->txnp, url, url_len) != TS_SUCCESS) {
+      TSError("[ts_lua][%s] Failed to redo cache lookup", __FUNCTION__);
     }
   }
 
@@ -536,7 +563,7 @@ ts_lua_http_set_parent_selection_url(lua_State *L)
         TSHttpTxnParentSelectionUrlSet(http_ctx->txnp, http_ctx->client_request_bufp, new_url_loc) == TS_SUCCESS) {
       TSDebug(TS_LUA_DEBUG_TAG, "Set parent selection URL");
     } else {
-      TSError("[ts_lua] Failed to set parent selection URL");
+      TSError("[ts_lua][%s] Failed to set parent selection URL", __FUNCTION__);
     }
   }
 
@@ -557,7 +584,7 @@ ts_lua_http_set_cache_url(lua_State *L)
 
   if (url && url_len) {
     if (TSCacheUrlSet(http_ctx->txnp, url, url_len) != TS_SUCCESS) {
-      TSError("[ts_lua] Failed to set cache url");
+      TSError("[ts_lua][%s] Failed to set cache url", __FUNCTION__);
     }
   }
 
@@ -883,7 +910,7 @@ ts_lua_http_resp_transform_get_upstream_bytes(lua_State *L)
 
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
-    TSError("[ts_lua] missing transform_ctx");
+    TSError("[ts_lua][%s] missing transform_ctx", __FUNCTION__);
     return 0;
   }
 
@@ -899,7 +926,7 @@ ts_lua_http_resp_transform_get_upstream_watermark_bytes(lua_State *L)
 
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
-    TSError("[ts_lua] missing transform_ctx");
+    TSError("[ts_lua][%s] missing transform_ctx", __FUNCTION__);
     return 0;
   }
 
@@ -916,7 +943,7 @@ ts_lua_http_resp_transform_set_upstream_watermark_bytes(lua_State *L)
 
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
-    TSError("[ts_lua] missing transform_ctx");
+    TSError("[ts_lua][%s] missing transform_ctx", __FUNCTION__);
     return 0;
   }
 
@@ -935,7 +962,7 @@ ts_lua_http_resp_transform_set_downstream_bytes(lua_State *L)
 
   transform_ctx = ts_lua_get_http_transform_ctx(L);
   if (transform_ctx == NULL) {
-    TSError("[ts_lua] missing transform_ctx");
+    TSError("[ts_lua][%s] missing transform_ctx", __FUNCTION__);
     return 0;
   }
 
diff --git a/plugins/lua/ts_lua_http_config.c b/plugins/lua/ts_lua_http_config.c
index d9738be..72146aa 100644
--- a/plugins/lua/ts_lua_http_config.c
+++ b/plugins/lua/ts_lua_http_config.c
@@ -506,7 +506,7 @@ ts_lua_http_timeout_set(lua_State *L)
     break;
 
   default:
-    TSError("[ts_lua] Unsupported timeout config option for lua plugin");
+    TSError("[ts_lua][%s] Unsupported timeout config option for lua plugin", __FUNCTION__);
     break;
   }
 
diff --git a/plugins/lua/ts_lua_http_intercept.c b/plugins/lua/ts_lua_http_intercept.c
index d794231..d03bd0c 100644
--- a/plugins/lua/ts_lua_http_intercept.c
+++ b/plugins/lua/ts_lua_http_intercept.c
@@ -73,13 +73,13 @@ ts_lua_http_intercept(lua_State *L)
   n = lua_gettop(L);
 
   if (n < 1) {
-    TSError("[ts_lua] ts.http.intercept need at least one param");
+    TSError("[ts_lua][%s] ts.http.intercept need at least one param", __FUNCTION__);
     return 0;
   }
 
   type = lua_type(L, 1);
   if (type != LUA_TFUNCTION) {
-    TSError("[ts_lua] ts.http.intercept should use function as param, but there is %s", lua_typename(L, type));
+    TSError("[ts_lua][%s] ts.http.intercept should use function as param, but there is %s", __FUNCTION__, lua_typename(L, type));
     return 0;
   }
 
@@ -106,13 +106,14 @@ ts_lua_http_server_intercept(lua_State *L)
   n = lua_gettop(L);
 
   if (n < 1) {
-    TSError("[ts_lua] ts.http.server_intercept need at least one param");
+    TSError("[ts_lua][%s] ts.http.server_intercept need at least one param", __FUNCTION__);
     return 0;
   }
 
   type = lua_type(L, 1);
   if (type != LUA_TFUNCTION) {
-    TSError("[ts_lua] ts.http.server_intercept should use function as param, but there is %s", lua_typename(L, type));
+    TSError("[ts_lua][%s] ts.http.server_intercept should use function as param, but there is %s", __FUNCTION__,
+            lua_typename(L, type));
     return 0;
   }
 
@@ -274,7 +275,7 @@ ts_lua_http_intercept_run_coroutine(ts_lua_http_intercept_ctx *ictx, int n)
     break;
 
   default: // error
-    TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1));
+    TSError("[ts_lua][%s] lua_resume failed: %s", __FUNCTION__, lua_tostring(L, -1));
     lua_pop(L, 1);
     return -1;
   }
@@ -357,7 +358,7 @@ ts_lua_say(lua_State *L)
 
   ictx = ts_lua_get_http_intercept_ctx(L);
   if (ictx == NULL) {
-    TSError("[ts_lua] missing ictx");
+    TSError("[ts_lua][%s] missing ictx", __FUNCTION__);
     return 0;
   }
 
@@ -379,7 +380,7 @@ ts_lua_flush(lua_State *L)
 
   ictx = ts_lua_get_http_intercept_ctx(L);
   if (ictx == NULL) {
-    TSError("[ts_lua] missing ictx");
+    TSError("[ts_lua][%s] missing ictx", __FUNCTION__);
     return 0;
   }
 
diff --git a/plugins/lua/ts_lua_http_txn_info.c b/plugins/lua/ts_lua_http_txn_info.c
new file mode 100644
index 0000000..3f8bd80
--- /dev/null
+++ b/plugins/lua/ts_lua_http_txn_info.c
@@ -0,0 +1,76 @@
+/*
+  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.
+*/
+
+#include "ts_lua_util.h"
+
+typedef enum {
+  TS_LUA_TXN_INFO_CACHE_HIT_RAM           = TS_TXN_INFO_CACHE_HIT_RAM,
+  TS_LUA_TXN_INFO_CACHE_COMPRESSED_IN_RAM = TS_TXN_INFO_CACHE_COMPRESSED_IN_RAM,
+  TS_LUA_TXN_INFO_CACHE_HIT_RWW           = TS_TXN_INFO_CACHE_HIT_RWW,
+  TS_LUA_TXN_INFO_CACHE_OPEN_READ_TRIES   = TS_TXN_INFO_CACHE_OPEN_READ_TRIES,
+  TS_LUA_TXN_INFO_CACHE_OPEN_WRITE_TRIES  = TS_TXN_INFO_CACHE_OPEN_WRITE_TRIES,
+  TS_LUA_TXN_INFO_CACHE_VOLUME            = TS_TXN_INFO_CACHE_VOLUME
+} TSLuaTxnInfoType;
+
+ts_lua_var_item ts_lua_txn_info_type_vars[] = {
+  TS_LUA_MAKE_VAR_ITEM(TS_LUA_TXN_INFO_CACHE_HIT_RAM),          TS_LUA_MAKE_VAR_ITEM(TS_LUA_TXN_INFO_CACHE_COMPRESSED_IN_RAM),
+  TS_LUA_MAKE_VAR_ITEM(TS_LUA_TXN_INFO_CACHE_HIT_RWW),          TS_LUA_MAKE_VAR_ITEM(TS_LUA_TXN_INFO_CACHE_OPEN_READ_TRIES),
+  TS_LUA_MAKE_VAR_ITEM(TS_LUA_TXN_INFO_CACHE_OPEN_WRITE_TRIES), TS_LUA_MAKE_VAR_ITEM(TS_LUA_TXN_INFO_CACHE_VOLUME)};
+
+static void ts_lua_inject_txn_info_variables(lua_State *L);
+
+static int ts_lua_txn_info_get(lua_State *L);
+
+void
+ts_lua_inject_txn_info_api(lua_State *L)
+{
+  ts_lua_inject_txn_info_variables(L);
+
+  lua_pushcfunction(L, ts_lua_txn_info_get);
+  lua_setfield(L, -2, "txn_info_get");
+}
+
+static void
+ts_lua_inject_txn_info_variables(lua_State *L)
+{
+  size_t i;
+
+  for (i = 0; i < sizeof(ts_lua_txn_info_type_vars) / sizeof(ts_lua_var_item); i++) {
+    lua_pushinteger(L, ts_lua_txn_info_type_vars[i].nvar);
+    lua_setglobal(L, ts_lua_txn_info_type_vars[i].svar);
+  }
+}
+
+static int
+ts_lua_txn_info_get(lua_State *L)
+{
+  TSHttpTxnInfoKey type;
+  TSMgmtInt value;
+  ts_lua_http_ctx *http_ctx;
+
+  GET_HTTP_CONTEXT(http_ctx, L);
+
+  type = luaL_checkinteger(L, 1);
+
+  if (TS_SUCCESS == TSHttpTxnInfoIntGet(http_ctx->txnp, type, &value)) {
+    lua_pushnumber(L, value);
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/plugins/lua/ts_lua_http_txn_info.h b/plugins/lua/ts_lua_http_txn_info.h
new file mode 100644
index 0000000..3d8ed13
--- /dev/null
+++ b/plugins/lua/ts_lua_http_txn_info.h
@@ -0,0 +1,23 @@
+/*
+  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.
+*/
+
+#pragma once
+
+#include "ts_lua_common.h"
+
+void ts_lua_inject_txn_info_api(lua_State *L);
diff --git a/plugins/lua/ts_lua_log.c b/plugins/lua/ts_lua_log.c
index 72a48d2..f2db53a 100644
--- a/plugins/lua/ts_lua_log.c
+++ b/plugins/lua/ts_lua_log.c
@@ -58,7 +58,7 @@ ts_lua_log_object_creat(lua_State *L)
   log_name = luaL_checklstring(L, -2, &name_len);
 
   if (lua_isnil(L, 3)) {
-    TSError("[ts_lua] No log name!!");
+    TSError("[ts_lua][%s] No log name!!", __FUNCTION__);
     return -1;
   } else {
     log_mode = luaL_checknumber(L, 3);
@@ -67,7 +67,7 @@ ts_lua_log_object_creat(lua_State *L)
   error = TSTextLogObjectCreate(log_name, log_mode, &log);
 
   if (!log || error == TS_ERROR) {
-    TSError("[ts_lua] Unable to create log <%s>", log_name);
+    TSError("[ts_lua][%s] Unable to create log <%s>", __FUNCTION__, log_name);
     return -1;
   }
   return 0;
diff --git a/plugins/lua/ts_lua_misc.c b/plugins/lua/ts_lua_misc.c
index 30e362a..057ef07 100644
--- a/plugins/lua/ts_lua_misc.c
+++ b/plugins/lua/ts_lua_misc.c
@@ -24,6 +24,8 @@ static int ts_lua_get_process_id(lua_State *L);
 static int ts_lua_get_now_time(lua_State *L);
 static int ts_lua_debug(lua_State *L);
 static int ts_lua_error(lua_State *L);
+static int ts_lua_emergency(lua_State *L);
+static int ts_lua_fatal(lua_State *L);
 static int ts_lua_sleep(lua_State *L);
 static int ts_lua_host_lookup(lua_State *L);
 static int ts_lua_schedule(lua_State *L);
@@ -64,6 +66,14 @@ ts_lua_inject_misc_api(lua_State *L)
   lua_pushcfunction(L, ts_lua_error);
   lua_setfield(L, -2, "error");
 
+  /* ts.emergency(...) */
+  lua_pushcfunction(L, ts_lua_emergency);
+  lua_setfield(L, -2, "emergency");
+
+  /* ts.fatal(...) */
+  lua_pushcfunction(L, ts_lua_fatal);
+  lua_setfield(L, -2, "fatal");
+
   /* ts.sleep(...) */
   lua_pushcfunction(L, ts_lua_sleep);
   lua_setfield(L, -2, "sleep");
@@ -164,6 +174,28 @@ ts_lua_error(lua_State *L)
 }
 
 static int
+ts_lua_emergency(lua_State *L)
+{
+  const char *msg;
+  size_t len = 0;
+
+  msg = luaL_checklstring(L, 1, &len);
+  TSEmergency("%.*s", (int)len, msg);
+  return 0;
+}
+
+static int
+ts_lua_fatal(lua_State *L)
+{
+  const char *msg;
+  size_t len = 0;
+
+  msg = luaL_checklstring(L, 1, &len);
+  TSFatal("%.*s", (int)len, msg);
+  return 0;
+}
+
+static int
 ts_lua_schedule(lua_State *L)
 {
   int sec;
@@ -197,7 +229,7 @@ ts_lua_schedule(lua_State *L)
   n = lua_gettop(L);
 
   if (n < 3) {
-    TSError("[ts_lua] ts.schedule need at least three parameters");
+    TSError("[ts_lua][%s] ts.schedule need at least three parameters", __FUNCTION__);
     return 0;
   }
 
@@ -256,7 +288,7 @@ ts_lua_schedule_handler(TSCont contp, TSEvent ev, void *edata)
   }
 
   if (ret != 0) {
-    TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1));
+    TSError("[ts_lua][%s] lua_resume failed: %s", __FUNCTION__, lua_tostring(L, -1));
   }
 
   lua_pop(L, lua_gettop(L));
@@ -342,7 +374,7 @@ ts_lua_host_lookup(lua_State *L)
   }
 
   if (lua_gettop(L) != 1) {
-    TSError("[ts_lua] ts.host_lookup need at least one parameter");
+    TSError("[ts_lua][%s] ts.host_lookup need at least one parameter", __FUNCTION__);
     return 0;
   }
 
@@ -376,7 +408,7 @@ ts_lua_host_lookup_handler(TSCont contp, TSEvent event, void *edata)
   ts_lua_host_lookup_cleanup(ai);
 
   if (event != TS_EVENT_HOST_LOOKUP) {
-    TSError("[ts_lua] ts.host_lookup receives unknown event");
+    TSError("[ts_lua][%s] ts.host_lookup receives unknown event", __FUNCTION__);
     lua_pushnil(L);
   } else if (!edata) {
     lua_pushnil(L);
diff --git a/plugins/lua/ts_lua_package.c b/plugins/lua/ts_lua_package.c
index 6b97832..33ff3f1 100644
--- a/plugins/lua/ts_lua_package.c
+++ b/plugins/lua/ts_lua_package.c
@@ -182,7 +182,7 @@ ts_lua_add_package_path_items(lua_State *L, ts_lua_package_path *pp, int n)
 
   for (i = 0; i < n; i++) {
     if (new_path_len + pp[i].len + 1 >= sizeof(new_path)) {
-      TSError("[ts_lua] Extended package.path is too long");
+      TSError("[ts_lua][%s] Extended package.path is too long", __FUNCTION__);
       return -1;
     }
 
@@ -328,7 +328,7 @@ ts_lua_add_package_cpath_items(lua_State *L, ts_lua_package_path *pp, int n)
 
   for (i = 0; i < n; i++) {
     if (new_path_len + pp[i].len + 1 >= sizeof(new_path)) {
-      TSError("[ts_lua] Extended package.cpath is too long");
+      TSError("[ts_lua][%s] Extended package.cpath is too long", __FUNCTION__);
       return -1;
     }
 
diff --git a/plugins/lua/ts_lua_server_request.c b/plugins/lua/ts_lua_server_request.c
index 6b5cf85..eb986c2 100644
--- a/plugins/lua/ts_lua_server_request.c
+++ b/plugins/lua/ts_lua_server_request.c
@@ -699,7 +699,7 @@ ts_lua_server_request_set_version(lua_State *L)
 {
   const char *version;
   size_t len;
-  int major, minor;
+  unsigned int major, minor;
 
   ts_lua_http_ctx *http_ctx;
 
diff --git a/plugins/lua/ts_lua_server_response.c b/plugins/lua/ts_lua_server_response.c
index f2c78d4..d99935b 100644
--- a/plugins/lua/ts_lua_server_response.c
+++ b/plugins/lua/ts_lua_server_response.c
@@ -344,7 +344,7 @@ ts_lua_server_response_set_version(lua_State *L)
 {
   const char *version;
   size_t len;
-  int major, minor;
+  unsigned int major, minor;
 
   ts_lua_http_ctx *http_ctx;
 
diff --git a/plugins/lua/ts_lua_transform.c b/plugins/lua/ts_lua_transform.c
index 57da47d..5e8d75b 100644
--- a/plugins/lua/ts_lua_transform.c
+++ b/plugins/lua/ts_lua_transform.c
@@ -137,9 +137,10 @@ ts_lua_transform_handler(TSCont contp, ts_lua_http_transform_ctx *transform_ctx,
       eos = 0;
     }
   } else {
-    input_avail = 0;
-    toread      = 0;
-    eos         = 1;
+    input_avail   = 0;
+    upstream_done = 0;
+    toread        = 0;
+    eos           = 1;
   }
 
   if (input_avail > 0) {
@@ -224,7 +225,7 @@ ts_lua_transform_handler(TSCont contp, ts_lua_http_transform_ctx *transform_ctx,
       break;
 
     default: // coroutine failed
-      TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1));
+      TSError("[ts_lua][%s] lua_resume failed: %s", __FUNCTION__, lua_tostring(L, -1));
       ret     = 1;
       res     = NULL;
       res_len = 0;
diff --git a/plugins/lua/ts_lua_util.c b/plugins/lua/ts_lua_util.c
index 76d86fd..abb4bc2 100644
--- a/plugins/lua/ts_lua_util.c
+++ b/plugins/lua/ts_lua_util.c
@@ -929,6 +929,7 @@ ts_lua_http_cont_handler(TSCont contp, TSEvent ev, void *edata)
     // to allow API(s) to fetch the pointers again when it re-enters the hook
     if (http_ctx->client_response_hdrp != NULL) {
       TSHandleMLocRelease(http_ctx->client_response_bufp, TS_NULL_MLOC, http_ctx->client_response_hdrp);
+      http_ctx->client_response_bufp = NULL;
       http_ctx->client_response_hdrp = NULL;
     }
 
@@ -938,6 +939,12 @@ ts_lua_http_cont_handler(TSCont contp, TSEvent ev, void *edata)
       ret = lua_resume(L, 0);
     }
 
+    if (http_ctx->client_response_hdrp != NULL) {
+      TSHandleMLocRelease(http_ctx->client_response_bufp, TS_NULL_MLOC, http_ctx->client_response_hdrp);
+      http_ctx->client_response_bufp = NULL;
+      http_ctx->client_response_hdrp = NULL;
+    }
+
     break;
 
   case TS_EVENT_HTTP_READ_REQUEST_HDR:
@@ -989,7 +996,7 @@ ts_lua_http_cont_handler(TSCont contp, TSEvent ev, void *edata)
     lua_getglobal(L, TS_LUA_FUNCTION_TXN_CLOSE);
     if (lua_type(L, -1) == LUA_TFUNCTION) {
       if (lua_pcall(L, 0, 1, 0)) {
-        TSError("[ts_lua] lua_pcall failed: %s", lua_tostring(L, -1));
+        TSError("[ts_lua][%s] lua_pcall failed: %s", __FUNCTION__, lua_tostring(L, -1));
       }
     }
 
@@ -1018,7 +1025,7 @@ ts_lua_http_cont_handler(TSCont contp, TSEvent ev, void *edata)
     break;
 
   default: // coroutine failed
-    TSError("[ts_lua] lua_resume failed: %s", lua_tostring(L, -1));
+    TSError("[ts_lua][%s] lua_resume failed: %s", __FUNCTION__, lua_tostring(L, -1));
     rc = -1;
     lua_pop(L, 1);
     break;