.. _ts-lua-plugin: ts-lua Plugin ************* .. 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. This module embeds Lua, via the standard Lua 5.1 interpreter, into Apache Traffic Server. With this module, we can implement ATS plugin by writing lua script instead of c code. Lua code executed using this module can be 100% non-blocking because the powerful Lua coroutines had been integrated in to ATS event model. Synopsis ======== **test_hdr.lua** :: function send_response() ts.client_response.header['Rhost'] = ts.ctx['rhost'] return 0 end function do_remap() local req_host = ts.client_request.header.Host ts.ctx['rhost'] = string.reverse(req_host) ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) return 0 end **sethost.lua** :: local HOSTNAME = '' function __init__(argtb) if (#argtb) < 1 then print(argtb[0], 'hostname parameter required!!') return -1 end HOSTNAME = argtb[1] end function do_remap() ts.client_request.header['Host'] = HOSTNAME return 0 end Installation ============ This plugin is only built if the configure option :: --enable-experimental-plugins is given at build time. Configuration ============= This module acts as remap plugin of Traffic Server, so we should realize 'do_remap' function in each lua script. We can write this in remap.config: :: map http://a.tbcdn.cn/ http://inner.tbcdn.cn/ @plugin=/XXX/tslua.so @pparam=/XXX/test_hdr.lua Sometimes we want to receive parameters and process them in the script, we should realize '__init__' function in the lua script, and we can write this in remap.config: :: map http://a.x.cn/ http://b.x.cn/ @plugin=/X/tslua.so @pparam=/X/sethost.lua @pparam=a.st.cn This module can also act as a global plugin of Traffic Server. In this case we should provide one of these functions in each lua script: - **'do_global_txn_start'** - **'do_global_txn_close'** - **'do_global_os_dns'** - **'do_global_pre_remap'** - **'do_global_post_remap'** - **'do_global_read_request'** - **'do_global_send_request'** - **'do_global_read_response'** - **'do_global_send_response'** - **'do_global_cache_lookup_complete'** - **'do_global_read_cache'** - **'do_global_select_alt'** We can write this in plugin.config: :: tslua.so /etc/trafficserver/script/test_global_hdr.lua TS API for Lua ============== Introduction ------------ The API is exposed to Lua in the form of one standard packages ``ts``. This package is in the default global scope and is always available within lua script. This package can be introduced into Lua like this: :: ts.say('Hello World') ts.sleep(10) `TOP <#ts-lua-plugin>`_ ts.now ------ **syntax:** *val = ts.now()* **context:** global **description:** This function returns the time since the Epoch (00:00:00 UTC, January 1, 1970), measured in seconds. Here is an example: :: local nt = ts.now() -- 1395221053 `TOP <#ts-lua-plugin>`_ ts.debug -------- **syntax:** *ts.debug(MESSAGE)* **context:** global **description**: Log the MESSAGE to traffic.out if debug is enabled. Here is an example: :: ts.debug('I am in do_remap now.') The debug tag is **ts_lua** and we should write this in records.config: ``CONFIG proxy.config.diags.debug.tags STRING ts_lua`` `TOP <#ts-lua-plugin>`_ Remap status constants ---------------------- **context:** do_remap :: TS_LUA_REMAP_NO_REMAP (0) TS_LUA_REMAP_DID_REMAP (1) TS_LUA_REMAP_NO_REMAP_STOP (2) TS_LUA_REMAP_DID_REMAP_STOP (3) TS_LUA_REMAP_ERROR (-1) These constants are usually used as return value of do_remap function. `TOP <#ts-lua-plugin>`_ ts.hook ------- **syntax:** *ts.hook(HOOK_POINT, FUNCTION)* **context:** global or do_remap or do_global_* or later **description**: Hooks are points in http transaction processing where we can step in and do some work. FUNCTION will be called when the http transaction steps in to HOOK_POINT. Here is an example :: function send_response() s.client_response.header['SHE'] = 'belief' end function do_remap() ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) end Then the client will get the response like this: :: HTTP/1.1 200 OK Content-Type: text/html Server: ATS/3.2.0 SHE: belief Connection: Keep-Alive ... You can create global hook as well :: function do_some_work() ts.debug('do_some_work') return 0 end ts.hook(TS_LUA_HOOK_READ_REQUEST_HDR, do_some_work) Or you can do it this way ts.hook(TS_LUA_HOOK_READ_REQUEST_HDR, function() ts.debug('do_some_work') return 0 end ) Also the return value of the function will control how the transaction will be re-enabled. Return value of 0 will cause the transaction to be re-enabled normally (TS_EVENT_HTTP_CONTINUE). Return value of 1 will be using TS_EVENT_HTTP_ERROR instead. `TOP <#ts-lua-plugin>`_ Hook point constants -------------------- **context:** do_remap or later :: TS_LUA_HOOK_OS_DNS TS_LUA_HOOK_PRE_REMAP TS_LUA_HOOK_READ_CACHE_HDR TS_LUA_HOOK_SELECT_ALT TS_LUA_HOOK_TXN_CLOSE TS_LUA_HOOK_POST_REMAP TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE TS_LUA_HOOK_READ_REQUEST_HDR TS_LUA_HOOK_SEND_REQUEST_HDR TS_LUA_HOOK_READ_RESPONSE_HDR TS_LUA_HOOK_SEND_RESPONSE_HDR TS_LUA_REQUEST_TRANSFORM TS_LUA_RESPONSE_TRANSFORM These constants are usually used in ts.hook method call. `TOP <#ts-lua-plugin>`_ ts.ctx ------ **syntax:** *ts.ctx[KEY] = VALUE* **syntax:** *VALUE = ts.ctx[KEY]* **context:** do_remap or do_global_* or later **description:** This table can be used to store per-request Lua context data and has a life time identical to the current request. Here is an example: :: function send_response() ts.client_response.header['F-Header'] = ts.ctx['hdr'] return 0 end function do_remap() ts.ctx['hdr'] = 'foo' ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) return 0 end Then the client will get the response like this: :: HTTP/1.1 200 OK Content-Type: text/html Server: ATS/3.2.0 F-Header: foo Connection: Keep-Alive ... `TOP <#ts-lua-plugin>`_ ts.client_request.get_method ---------------------------- **syntax:** *ts.client_request.get_method()* **context:** do_remap or do_global_* or later **description:** This function can be used to retrieve the current client request's method name. String like "GET" or "POST" is returned. `TOP <#ts-lua-plugin>`_ ts.client_request.set_method ---------------------------- **syntax:** *ts.client_request.set_method()* **context:** do_remap or do_global_* **description:** This function can be used to override the current client request's method with METHOD_NAME. ts.client_request.get_version ----------------------------- **syntax:** *ver = ts.client_request.get_version()* **context:** do_remap or do_global_* or later **description:** Return the http version string of the client request. Current possible values are 1.0, 1.1, and 0.9. `TOP <#ts-lua-plugin>`_ ts.client_request.set_version ----------------------------- **syntax:** *ts.client_request.set_version(VERSION_STR)* **context:** do_remap or do_global_* or later **description:** Set the http version of the client request with the VERSION_STR :: ts.client_request.set_version('1.0') `TOP <#ts-lua-plugin>`_ ts.client_request.get_uri ------------------------- **syntax:** *ts.client_request.get_uri()* **context:** do_remap or later **description:** This function can be used to retrieve the client request's path. Here is an example: :: function do_remap() local uri = ts.client_request.get_uri() print(uri) end Then ``GET /st?a=1`` will yield the output: ``/st`` `TOP <#ts-lua-plugin>`_ ts.client_request.set_uri ------------------------- **syntax:** *ts.client_request.set_uri(PATH)* **context:** do_remap or do_global_* **description:** This function can be used to override the client request's path. The PATH argument must be a Lua string and starts with ``/`` `TOP <#ts-lua-plugin>`_ ts.client_request.get_uri_args ------------------------------ **syntax:** *ts.client_request.get_uri_args()* **context:** do_remap or do_global_* or later **description:** This function can be used to retrieve the client request's query string. Here is an example: :: function do_remap() local query = ts.client_request.get_uri_args() print(query) end Then ``GET /st?a=1&b=2`` will yield the output: ``a=1&b=2`` `TOP <#ts-lua-plugin>`_ ts.client_request.set_uri_args ------------------------------ **syntax:** *ts.client_request.set_uri_args(QUERY_STRING)* **context:** do_remap or do_global_* **description:** This function can be used to override the client request's query string. :: ts.client_request.set_uri_args('n=6&p=7') `TOP <#ts-lua-plugin>`_ ts.client_request.get_url ------------------------- **syntax:** *ts.client_request.get_url()* **context:** do_remap or do_global_* or later **description:** This function can be used to retrieve the whole client request's url. Here is an example: :: function do_remap() local url = ts.client_request.get_url() print(url) end Then ``GET /st?a=1&b=2 HTTP/1.1\r\nHost: a.tbcdn.cn\r\n...`` will yield the output: ``http://a.tbcdn.cn/st?a=1&b=2`` `TOP <#ts-lua-plugin>`_ ts.client_request.header.HEADER ------------------------------- **syntax:** *ts.client_request.header.HEADER = VALUE* **syntax:** *ts.client_request.header[HEADER] = VALUE* **syntax:** *VALUE = ts.client_request.header.HEADER* **context:** do_remap or do_global_* or later **description:** Set, add to, clear or get the current client request's HEADER. Here is an example: :: function do_remap() local ua = ts.client_request.header['User-Agent'] print(ua) ts.client_request.header['Host'] = 'a.tbcdn.cn' end Then ``GET /st HTTP/1.1\r\nHost: b.tb.cn\r\nUser-Agent: Mozilla/5.0\r\n...`` will yield the output: ``Mozilla/5.0`` `TOP <#ts-lua-plugin>`_ ts.client_request.get_headers ----------------------------- **syntax:** *ts.client_request.get_headers()* **context:** do_remap or do_global_* or later **description:** Returns a Lua table holding all the headers for the current client request. Here is an example: :: function do_remap() hdrs = ts.client_request.get_headers() for k, v in pairs(hdrs) do print(k..': '..v) end end Then ``GET /st HTTP/1.1\r\nHost: b.tb.cn\r\nUser-Aget: Mozilla/5.0\r\nAccept: */*`` will yield the output :: Host: b.tb.cn User-Agent: Mozilla/5.0 Accept: */* `TOP <#ts-lua-plugin>`_ ts.client_request.client_addr.get_addr -------------------------------------- **syntax:** *ts.client_request.client_addr.get_addr()* **context:** do_remap or do_global_* or later **description**: This function can be used to get socket address of the client. The ts.client_request.client_addr.get_addr function returns three values, ip is a string, port and family is number. Here is an example: :: function do_remap() ip, port, family = ts.client_request.client_addr.get_addr() print(ip) -- 192.168.231.17 print(port) -- 17786 print(family) -- 2(AF_INET) return 0 end `TOP <#ts-lua-plugin>`_ ts.client_request.get_url_host ------------------------------ **syntax:** *host = ts.client_request.get_url_host()* **context:** do_remap or do_global_* or later **description:** Return the ``host`` field of the request url. Here is an example: :: function do_remap() local url_host = ts.client_request.get_url_host() print(url_host) end Then ``GET /liuyurou.txt HTTP/1.1\r\nHost: 192.168.231.129:8080\r\n...`` will yield the output: ``192.168.231.129`` `TOP <#ts-lua-plugin>`_ ts.client_request.set_url_host ------------------------------ **syntax:** *ts.client_request.set_url_host(str)* **context:** do_remap or do_global_* **description:** Set ``host`` field of the request url with ``str``. This function is used to change the address of the origin server, and we should return TS_LUA_REMAP_DID_REMAP(_STOP) in do_remap. Here is an example: :: function do_remap() ts.client_request.set_url_host('192.168.231.130') ts.client_request.set_url_port(80) ts.client_request.set_url_scheme('http') return TS_LUA_REMAP_DID_REMAP end remap.config like this: :: map http://192.168.231.129:8080/ http://192.168.231.129:9999/ Then server request will connect to ``192.168.231.130:80`` `TOP <#ts-lua-plugin>`_ ts.client_request.get_url_port ------------------------------ **syntax:** *port = ts.client_request.get_url_port()* **context:** do_remap or do_global_* or later **description:** Returns the ``port`` field of the request url as a Lua number. Here is an example: :: function do_remap() local url_port = ts.client_request.get_url_port() print(url_port) end Then Then ``GET /liuyurou.txt HTTP/1.1\r\nHost: 192.168.231.129:8080\r\n...`` will yield the output: ``8080`` `TOP <#ts-lua-plugin>`_ ts.client_request.set_url_port ------------------------------ **syntax:** *ts.client_request.set_url_port(NUMBER)* **context:** do_remap or do_global_* **description:** Set ``port`` field of the request url with ``NUMBER``. This function is used to change the address of the origin server, and we should return TS_LUA_REMAP_DID_REMAP(_STOP) in do_remap. `TOP <#ts-lua-plugin>`_ ts.client_request.get_url_scheme -------------------------------- **syntax:** *scheme = ts.client_request.get_url_scheme()* **context:** do_remap or do_global_* or later **description:** Return the ``scheme`` field of the request url. Here is an example: :: function do_remap() local url_scheme = ts.client_request.get_url_scheme() print(url_scheme) end Then ``GET /liuyurou.txt HTTP/1.1\r\nHost: 192.168.231.129:8080\r\n...`` will yield the output: ``http`` `TOP <#ts-lua-plugin>`_ ts.client_request.set_url_scheme -------------------------------- **syntax:** *ts.client_request.set_url_scheme(str)* **context:** do_remap or do_global_* **description:** Set ``scheme`` field of the request url with ``str``. This function is used to change the scheme of the server request, and we should return TS_LUA_REMAP_DID_REMAP(_STOP) in do_remap. `TOP <#ts-lua-plugin>`_ ts.http.set_cache_url --------------------- **syntax:** *ts.http.set_cache_url(KEY_URL)* **context:** do_remap or do_global_* **description:** This function can be used to modify the cache key for the client request. Here is an example: :: function do_remap() ts.http.set_cache_url('http://a.tbcdn.cn/foo') return 0 end `TOP <#ts-lua-plugin>`_ ts.http.set_resp ---------------- **syntax:** *ts.http.set_resp(CODE, BODY)* **context:** do_remap or do_global_* **description:** This function can be used to set response for the client with the CODE status and BODY string. Here is an example: :: function do_remap() ts.http.set_resp(403, "Document access failed :)\n") return 0 end We will get the response like this: :: HTTP/1.1 403 Forbidden Date: Thu, 20 Mar 2014 06:12:43 GMT Connection: close Server: ATS/5.0.0 Cache-Control: no-store Content-Type: text/html Content-Language: en Content-Length: 27 Document access failed :) `TOP <#ts-lua-plugin>`_ ts.http.get_cache_lookup_status ------------------------------- **syntax:** *ts.http.get_cache_lookup_status()* **context:** function @ TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE hook point **description:** This function can be used to get cache lookup status. Here is an example: :: function cache_lookup() local cache_status = ts.http.get_cache_lookup_status() if cache_status == TS_LUA_CACHE_LOOKUP_HIT_FRESH then print('hit') else print('not hit') end end function do_remap() ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) return 0 end `TOP <#ts-lua-plugin>`_ Http cache lookup status constants ---------------------------------- **context:** global :: TS_LUA_CACHE_LOOKUP_MISS (0) TS_LUA_CACHE_LOOKUP_HIT_STALE (1) TS_LUA_CACHE_LOOKUP_HIT_FRESH (2) TS_LUA_CACHE_LOOKUP_SKIPPED (3) `TOP <#ts-lua-plugin>`_ ts.cached_response.get_status ----------------------------- **syntax:** *status = ts.cached_response.get_status()* **context:** function @ TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE hook point or later **description:** This function can be used to retrieve the status code of the cached response. A Lua number will be returned. Here is an example: :: function cache_lookup() local cache_status = ts.http.get_cache_lookup_status() if cache_status == TS_LUA_CACHE_LOOKUP_HIT_FRESH then code = ts.cached_response.get_status() print(code) -- 200 end end function do_remap() ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) return 0 end `TOP <#ts-lua-plugin>`_ ts.cached_response.get_version ------------------------------ **syntax:** *ver = ts.cached_response.get_version()* **context:** function @ TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE hook point or later **description:** Return the http version string of the cached response. Current possible values are 1.0, 1.1, and 0.9. `TOP <#ts-lua-plugin>`_ ts.cached_response.header.HEADER -------------------------------- **syntax:** *VALUE = ts.cached_response.header.HEADER* **syntax:** *VALUE = ts.cached_response.header[HEADER]* **context:** function @ TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE hook point or later **description:** get the current cached response's HEADER. Here is an example: :: function cache_lookup() local status = ts.http.get_cache_lookup_status() if status == TS_LUA_CACHE_LOOKUP_HIT_FRESH then local ct = ts.cached_response.header['Content-Type'] print(ct) -- text/plain end end function do_remap() ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) return 0 end `TOP <#ts-lua-plugin>`_ ts.cached_response.get_headers ------------------------------ **syntax:** *ts.cached_response.get_headers()* **context:** function @ TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE hook point or later **description:** Returns a Lua table holding all the headers for the current cached response. Here is an example: :: function cache_lookup() local status = ts.http.get_cache_lookup_status() if status == TS_LUA_CACHE_LOOKUP_HIT_FRESH then hdrs = ts.cached_response.get_headers() for k, v in pairs(hdrs) do print(k..': '..v) end end end function do_remap() ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) return 0 end We will get the output: :: Connection: keep-alive Content-Type: text/plain Date: Thu, 20 Mar 2014 06:12:20 GMT Cache-Control: max-age=864000 Last-Modified: Sun, 19 May 2013 13:22:01 GMT Accept-Ranges: bytes Content-Length: 15 Server: ATS/5.0.0 `TOP <#ts-lua-plugin>`_ ts.server_request.get_uri ------------------------- **syntax:** *ts.server_request.get_uri()* **context:** function @ TS_LUA_HOOK_SEND_REQUEST_HDR hook point or later **description:** This function can be used to retrieve the server request's path. Here is an example: :: function send_request() local uri = ts.server_request.get_uri() print(uri) end function do_remap() ts.hook(TS_LUA_HOOK_SEND_REQUEST_HDR, send_request) return 0 end Then ``GET /am.txt?a=1`` will yield the output: ``/am.txt`` `TOP <#ts-lua-plugin>`_ ts.server_request.set_uri ------------------------- **syntax:** *ts.server_request.set_uri(PATH)* **context:** function @ TS_LUA_HOOK_SEND_REQUEST_HDR hook point **description:** This function can be used to override the server request's path. The PATH argument must be a Lua string and starts with ``/`` `TOP <#ts-lua-plugin>`_ ts.server_request.get_uri_args ------------------------------ **syntax:** *ts.server_request.get_uri_args()* **context:** function @ TS_LUA_HOOK_SEND_REQUEST_HDR hook point or later **description:** This function can be used to retrieve the server request's query string. Here is an example: :: function send_request() local query = ts.server_request.get_uri_args() print(query) end function do_remap() ts.hook(TS_LUA_HOOK_SEND_REQUEST_HDR, send_request) return 0 end Then ``GET /st?a=1&b=2`` will yield the output: ``a=1&b=2`` `TOP <#ts-lua-plugin>`_ ts.server_request.set_uri_args ------------------------------ **syntax:** *ts.server_request.set_uri_args(QUERY_STRING)* **context:** function @ TS_LUA_HOOK_SEND_REQUEST_HDR hook point **description:** This function can be used to override the server request's query string. :: ts.server_request.set_uri_args('n=6&p=7') `TOP <#ts-lua-plugin>`_ ts.server_request.header.HEADER ------------------------------- **syntax:** *ts.server_request.header.HEADER = VALUE* **syntax:** *ts.server_request.header[HEADER] = VALUE* **syntax:** *VALUE = ts.server_request.header.HEADER* **context:** function @ TS_LUA_HOOK_SEND_REQUEST_HDR hook point or later **description:** Set, add to, clear or get the current server request's HEADER. Here is an example: :: function send_request() local ua = ts.server_request.header['User-Agent'] print(ua) ts.server_request.header['Accept-Encoding'] = 'gzip' end function do_remap() ts.hook(TS_LUA_HOOK_SEND_REQUEST_HDR, send_request) return 0 end Then ``GET /st HTTP/1.1\r\nHost: b.tb.cn\r\nUser-Agent: Mozilla/5.0\r\n...`` will yield the output: ``Mozilla/5.0`` `TOP <#ts-lua-plugin>`_ ts.server_request.get_headers ----------------------------- **syntax:** *ts.server_request.get_headers()* **context:** function @ TS_LUA_HOOK_SEND_REQUEST_HDR hook point or later **description:** Returns a Lua table holding all the headers for the current server request. Here is an example: :: function send_request() hdrs = ts.cached_response.get_headers() for k, v in pairs(hdrs) do print(k..': '..v) end end function do_remap() ts.hook(TS_LUA_HOOK_SEND_REQUEST_HDR, send_request) return 0 end We will get the output: :: Host: b.tb.cn User-Agent: curl/7.19.7 Accept: */* `TOP <#ts-lua-plugin>`_ ts.server_response.get_status ----------------------------- **syntax:** *status = ts.server_response.get_status()* **context:** function @ TS_LUA_HOOK_READ_RESPONSE_HDR hook point or later **description:** This function can be used to retrieve the status code of the origin server's response. A Lua number will be returned. Here is an example: :: function read_response() local code = ts.server_response.get_status() print(code) -- 200 end function do_remap() ts.hook(TS_LUA_HOOK_READ_RESPONSE_HDR, read_response) return 0 end `TOP <#ts-lua-plugin>`_' ts.server_response.set_status ----------------------------- **syntax:** *ts.server_response.set_status(NUMBER)* **context:** function @ TS_LUA_HOOK_READ_RESPONSE_HDR hook point **description:** This function can be used to set the status code of the origin server's response. Here is an example: :: function read_response() ts.server_response.set_status(404) end function do_remap() ts.hook(TS_LUA_HOOK_READ_RESPONSE_HDR, read_response) return 0 end `TOP <#ts-lua-plugin>`_' ts.server_response.get_version ------------------------------ **syntax:** *ver = ts.server_response.get_version()* **context:** function @ TS_LUA_HOOK_READ_RESPONSE_HDR hook point or later. **description:** Return the http version string of the server response. Current possible values are 1.0, 1.1, and 0.9. `TOP <#ts-lua-plugin>`_ ts.server_response.set_version ------------------------------ **syntax:** *ts.server_response.set_version(VERSION_STR)* **context:** function @ TS_LUA_HOOK_READ_RESPONSE_HDR hook point **description:** Set the http version of the server response with the VERSION_STR :: ts.server_response.set_version('1.0') `TOP <#ts-lua-plugin>`_ ts.server_response.header.HEADER -------------------------------- **syntax:** *ts.server_response.header.HEADER = VALUE* **syntax:** *ts.server_response.header[HEADER] = VALUE* **syntax:** *VALUE = ts.server_response.header.HEADER* **context:** function @ TS_LUA_HOOK_READ_RESPONSE_HDR hook point or later. **description:** Set, add to, clear or get the current server response's HEADER. Here is an example: :: function read_response() local ct = ts.server_response.header['Content-Type'] print(ct) ts.server_response.header['Cache-Control'] = 'max-age=14400' end function do_remap() ts.hook(TS_LUA_HOOK_READ_RESPONSE_HDR, read_response) return 0 end We will get the output: ``text/html`` `TOP <#ts-lua-plugin>`_' ts.server_response.get_headers ------------------------------ **syntax:** *ts.server_response.get_headers()* **context:** function @ TS_LUA_HOOK_READ_RESPONSE_HDR hook point or later **description:** Returns a Lua table holding all the headers for the current server response. Here is an example: :: function read_response() hdrs = ts.server_response.get_headers() for k, v in pairs(hdrs) do print(k..': '..v) end end function do_remap() ts.hook(TS_LUA_HOOK_READ_RESPONSE_HDR, read_response) return 0 end We will get the output: :: Server: nginx/1.5.9 Date: Tue, 18 Mar 2014 10:12:25 GMT Content-Type: text/html Content-Length: 555 Last-Modified: Mon, 19 Aug 2013 14:25:55 GMT Connection: keep-alive ETag: "52122af3-22b" Cache-Control: max-age=14400 Accept-Ranges: bytes `TOP <#ts-lua-plugin>`_ ts.client_response.get_status ----------------------------- **syntax:** *status = ts.client_response.get_status()* **context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point **description:** This function can be used to retrieve the status code of the response to the client. A Lua number will be returned. Here is an example: :: function send_response() local code = ts.client_response.get_status() print(code) -- 200 end function do_remap() ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) return 0 end `TOP <#ts-lua-plugin>`_ ts.client_response.set_status ----------------------------- **syntax:** *ts.client_response.set_status(NUMBER)* **context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point **description:** This function can be used to set the status code of the response to the client. Here is an example: :: function send_response() ts.client_response.set_status(404) end function do_remap() ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) return 0 end `TOP <#ts-lua-plugin>`_ ts.client_response.get_version ------------------------------ **syntax:** *ver = ts.client_response.get_version()* **context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point. **description:** Return the http version string of the response to the client. Current possible values are 1.0, 1.1, and 0.9. `TOP <#ts-lua-plugin>`_ ts.client_response.set_version ------------------------------ **syntax:** *ts.client_response.set_version(VERSION_STR)* **context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point **description:** Set the http version of the response to the client with the VERSION_STR :: ts.client_response.set_version('1.0') `TOP <#ts-lua-plugin>`_ ts.client_response.header.HEADER -------------------------------- **syntax:** *ts.client_response.header.HEADER = VALUE* **syntax:** *ts.client_response.header[HEADER] = VALUE* **syntax:** *VALUE = ts.client_response.header.HEADER* **context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point. **description:** Set, add to, clear or get the current client response's HEADER. Here is an example: :: function send_response() local ct = ts.client_response.header['Content-Type'] print(ct) ts.client_response.header['Cache-Control'] = 'max-age=3600' end function do_remap() ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) return 0 end We will get the output: ``text/html`` `TOP <#ts-lua-plugin>`_ ts.client_response.get_headers ------------------------------ **syntax:** *ts.client_response.get_headers()* **context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point. **description:** Returns a Lua table holding all the headers for the current client response. Here is an example: :: function send_response() hdrs = ts.client_response.get_headers() for k, v in pairs(hdrs) do print(k..': '..v) end end function do_remap() ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) return 0 end We will get the output: :: Server: ATS/5.0.0 Date: Tue, 18 Mar 2014 10:12:25 GMT Content-Type: text/html Transfer-Encoding: chunked Last-Modified: Mon, 19 Aug 2013 14:25:55 GMT Connection: keep-alive Cache-Control: max-age=14400 Age: 2641 Accept-Ranges: bytes `TOP <#ts-lua-plugin>`_ ts.client_response.set_error_resp --------------------------------- **syntax:** *ts.client_response.set_error_resp(CODE, BODY)* **context:** function @ TS_LUA_HOOK_SEND_RESPONSE_HDR hook point. **description:** This function can be used to set the error response to the client. With this function we can jump to send error response to the client if exception exists, meanwhile we should return `-1` from the function where exception raises. Here is an example: :: function send_response() ts.client_response.set_error_resp(404, 'bad luck :(\n') end function cache_lookup() return -1 end function do_remap() ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) return 0 end We will get the response like this: :: HTTP/1.1 404 Not Found Date: Tue, 18 Mar 2014 11:16:00 GMT Connection: keep-alive Server: ATS/5.0.0 Content-Length: 12 bad luck :( `TOP <#ts-lua-plugin>`_ ts.http.resp_cache_transformed ------------------------------ **syntax:** *ts.http.resp_cache_transformed(BOOL)* **context:** do_remap or do_global_* or later **description**: This function can be used to tell trafficserver whether to cache the transformed data. Here is an example: :: function upper_transform(data, eos) if eos == 1 then return string.upper(data)..'S.H.E.\n', eos else return string.upper(data), eos end end function do_remap() ts.hook(TS_LUA_RESPONSE_TRANSFORM, upper_transform) ts.http.resp_cache_transformed(0) return 0 end This function is usually called after we hook TS_LUA_RESPONSE_TRANSFORM. `TOP <#ts-lua-plugin>`_ ts.http.resp_cache_untransformed -------------------------------- **syntax:** *ts.http.resp_cache_untransformed(BOOL)* **context:** do_remap or do_global_* or later **description**: This function can be used to tell trafficserver whether to cache the untransformed data. Here is an example: :: function upper_transform(data, eos) if eos == 1 then return string.upper(data)..'S.H.E.\n', eos else return string.upper(data), eos end end function do_remap() ts.hook(TS_LUA_RESPONSE_TRANSFORM, upper_transform) ts.http.resp_cache_untransformed(1) return 0 end This function is usually called after we hook TS_LUA_RESPONSE_TRANSFORM. `TOP <#ts-lua-plugin>`_ ts.http.skip_remapping_set ------------------------- **syntax:** *ts.http.skip_remapping_set(BOOL)* **context:** do_global_read_request **description**: This function can be used to tell trafficserver to skip doing remapping Here is an example: :: function do_global_read_request() ts.http.skip_remapping_set(1); ts.client_request.header['Host'] = 'www.yahoo.com' return 0 end This function is usually called in do_global_read_request function ts.http.is_internal_request --------------------------- **syntax:** *ts.http.is_internal_request()* ** context:** do_remap or do_global_* or later ** description**: This function can be used to tell is a request is internal or not Here is an example: :: function do_global_read_request() local internal = ts.http.is_internal_request() ts.debug(internal) return 0 end ts.add_package_path ------------------- **syntax:** *ts.add_package_path(lua-style-path-str)* **context:** init stage of the lua script **description:** Adds the Lua module search path used by scripts. The path string is in standard Lua path form. Here is an example: :: ts.add_package_path('/home/a/test/lua/pac/?.lua') local nt = require("nt") function do_remap() print(nt.t9(7979)) return 0 end `TOP <#ts-lua-plugin>`_ ts.add_package_cpath -------------------- **syntax:** *ts.add_package_cpath(lua-style-cpath-str)* **context:** init stage of the lua script **description:** Adds the Lua C-module search path used by scripts. The cpath string is in standard Lua cpath form. Here is an example: :: ts.add_package_cpath('/home/a/test/c/module/?.so') local ma = require("ma") function do_remap() print(ma.ft()) return 0 end `TOP <#ts-lua-plugin>`_ ts.md5 ------ **syntax:** *digest = ts.md5(str)* **context:** global **description:** Returns the hexadecimal representation of the MD5 digest of the ``str`` argument. Here is an example: :: function do_remap() uri = ts.client_request.get_uri() print(uri) -- /foo print(ts.md5(uri)) -- 1effb2475fcfba4f9e8b8a1dbc8f3caf end `TOP <#ts-lua-plugin>`_ ts.md5_bin ---------- **syntax:** *digest = ts.md5_bin(str)* **context:** global **description:** Returns the binary form of the MD5 digest of the ``str`` argument. Here is an example: :: function do_remap() uri = ts.client_request.get_uri() bin = ts.md5_bin(uri) end `TOP <#ts-lua-plugin>`_ ts.sha1 ------- **syntax:** *digest = ts.sha1(str)* **context:** global **description:** Returns the hexadecimal representation of the SHA-1 digest of the ``str`` argument. Here is an example: :: function do_remap() uri = ts.client_request.get_uri() print(uri) -- /foo print(ts.sha1(uri)) -- 6dbd548cc03e44b8b44b6e68e56255ce4273ae49 end `TOP <#ts-lua-plugin>`_ ts.sha1_bin ----------- **syntax:** *digest = ts.sha1_bin(str)* **context:** global **description:** Returns the binary form of the SHA-1 digest of the ``str`` argument. Here is an example: :: function do_remap() uri = ts.client_request.get_uri() bin = ts.sha1_bin(uri) end `TOP <#ts-lua-plugin>`_ ts.intercept ------------ **syntax:** *ts.intercept(FUNCTION)* **context:** do_remap or do_global_* **description:** Intercepts the client request and processes it in FUNCTION. We should construct the response for the client request, and the request will not be processed by other modules, like hostdb, cache, origin server... Here is an example: :: require 'os' function send_data() local nt = os.time()..' Zheng.\n' local resp = 'HTTP/1.0 200 OK\r\n' .. 'Server: ATS/3.2.0\r\n' .. 'Content-Type: text/plain\r\n' .. 'Content-Length: ' .. string.format('%d', string.len(nt)) .. '\r\n' .. 'Last-Modified: ' .. os.date("%a, %d %b %Y %H:%M:%S GMT", os.time()) .. '\r\n' .. 'Connection: keep-alive\r\n' .. 'Cache-Control: max-age=7200\r\n' .. 'Accept-Ranges: bytes\r\n\r\n' .. nt ts.say(resp) end function do_remap() ts.http.intercept(send_data) return 0 end Then we will get the response like this: :: HTTP/1.1 200 OK Server: ATS/5.0.0 Content-Type: text/plain Content-Length: 18 Last-Modified: Tue, 18 Mar 2014 08:23:12 GMT Cache-Control: max-age=7200 Accept-Ranges: bytes Date: Tue, 18 Mar 2014 12:23:12 GMT Age: 0 Connection: keep-alive 1395145392 Zheng. `TOP <#ts-lua-plugin>`_ ts.say ------ **syntax:** *ts.say(data)* **context:** *intercept or server_intercept* **description:** Write response to ATS within intercept or server_intercept. `TOP <#ts-lua-plugin>`_ ts.flush -------- **syntax:** *ts.flush()* **context:** *intercept or server_intercept* **description:** Flushes the output to ATS within intercept or server_intercept. In synchronous mode, the function will not return until all output data has been written into the system send buffer. Note that using the Lua coroutine mechanism means that this function does not block the ATS event loop even in the synchronous mode. Here is an example: :: require 'os' function send_data() ss = 'wo ai yu ye hua\n' local resp = 'HTTP/1.0 200 OK\r\n' .. 'Server: ATS/3.2.0\r\n' .. 'Content-Type: text/plain\r\n' .. 'Content-Length: ' .. string.format('%d', 5*string.len(ss)) .. '\r\n' .. 'Last-Modified: ' .. os.date("%a, %d %b %Y %H:%M:%S GMT", os.time()) .. '\r\n' .. 'Connection: keep-alive\r\n' .. 'Cache-Control: max-age=7200\r\n' .. 'Accept-Ranges: bytes\r\n\r\n' ts.say(resp) for i=1, 5 do ts.say(ss) ts.flush() end end function do_remap() ts.http.intercept(send_data) return 0 end We will get the response like this: :: HTTP/1.1 200 OK Server: ATS/5.0.0 Content-Type: text/plain Content-Length: 80 Last-Modified: Tue, 18 Mar 2014 08:38:29 GMT Cache-Control: max-age=7200 Accept-Ranges: bytes Date: Tue, 18 Mar 2014 12:38:29 GMT Age: 0 Connection: keep-alive wo ai yu ye hua wo ai yu ye hua wo ai yu ye hua wo ai yu ye hua wo ai yu ye hua `TOP <#ts-lua-plugin>`_ ts.sleep -------- **syntax:** *ts.sleep(sec)* **context:** *intercept or server_intercept* **description:** Sleeps for the specified seconds without blocking. Behind the scene, this method makes use of the ATS event model. Here is an example: :: require 'os' function send_data() local nt = os.time()..' Zheng.\n' local resp = 'HTTP/1.0 200 OK\r\n' .. 'Server: ATS/3.2.0\r\n' .. 'Content-Type: text/plain\r\n' .. 'Content-Length: ' .. string.format('%d', string.len(nt)) .. '\r\n\r\n' .. nt ts.sleep(3) ts.say(resp) end function do_remap() ts.http.intercept(send_data) return 0 end `TOP <#ts-lua-plugin>`_ ts.server_intercept ------------------- **syntax:** *ts.server_intercept(FUNCTION)* **context:** do_remap or do_global_* **description:** Intercepts the server request and acts as the origin server. We should construct the response for the server request, so the request will be processed within FUNCTION in case of miss for the cache lookup. Here is an example: :: require 'os' function send_data() local nt = os.time()..' Zheng.\n' local resp = 'HTTP/1.0 200 OK\r\n' .. 'Server: ATS/3.2.0\r\n' .. 'Content-Type: text/plain\r\n' .. 'Content-Length: ' .. string.format('%d', string.len(nt)) .. '\r\n' .. 'Last-Modified: ' .. os.date("%a, %d %b %Y %H:%M:%S GMT", os.time()) .. '\r\n' .. 'Connection: keep-alive\r\n' .. 'Cache-Control: max-age=7200\r\n' .. 'Accept-Ranges: bytes\r\n\r\n' .. nt ts.say(resp) end function do_remap() ts.http.server_intercept(send_data) return 0 end Then we will get the response like this: :: HTTP/1.1 200 OK Server: ATS/5.0.0 Content-Type: text/plain Content-Length: 18 Last-Modified: Tue, 18 Mar 2014 08:23:12 GMT Cache-Control: max-age=7200 Accept-Ranges: bytes Date: Tue, 18 Mar 2014 12:23:12 GMT Age: 1890 Connection: keep-alive 1395145392 Zheng. `TOP <#ts-lua-plugin>`_ ts.http.config_int_get ---------------------- **syntax:** *val = ts.http.config_int_get(CONFIG)* **context:** do_remap or do_global_* or later. **description:** Configuration option which has a int value can be retrieved with this function. :: val = ts.http.config_int_get(TS_LUA_CONFIG_HTTP_CACHE_HTTP) `TOP <#ts-lua-plugin>`_ ts.http.config_int_set ---------------------- **syntax:** *ts.http.config_int_set(CONFIG, NUMBER)* **context:** do_remap or do_global_* or later. **description:** This function can be used to overwrite the configuration options. Here is an example: :: function do_remap() ts.http.config_int_set(TS_LUA_CONFIG_HTTP_CACHE_HTTP, 0) -- bypass the cache processor return 0 end `TOP <#ts-lua-plugin>`_ ts.http.config_float_get ------------------------ **syntax:** *val = ts.http.config_float_get(CONFIG)* **context:** do_remap or do_global_* or later. **description:** Configuration option which has a float value can be retrieved with this function. `TOP <#ts-lua-plugin>`_ ts.http.config_float_set ------------------------ **syntax:** *ts.http.config_float_set(CONFIG, NUMBER)* **context:** do_remap or do_global_* or later. **description:** This function can be used to overwrite the configuration options. `TOP <#ts-lua-plugin>`_ ts.http.config_string_get ------------------------- **syntax:** *val = ts.http.config_string_get(CONFIG)* **context:** do_remap or do_global_* or later. **description:** Configuration option which has a string value can be retrieved with this function. `TOP <#ts-lua-plugin>`_ ts.http.config_string_set ------------------------- **syntax:** *ts.http.config_string_set(CONFIG, NUMBER)* **context:** do_remap or do_global_* or later. **description:** This function can be used to overwrite the configuration options. `TOP <#ts-lua-plugin>`_ Http config constants --------------------- **context:** do_remap or do_global_* or later :: TS_LUA_CONFIG_URL_REMAP_PRISTINE_HOST_HDR TS_LUA_CONFIG_HTTP_CHUNKING_ENABLED TS_LUA_CONFIG_HTTP_NEGATIVE_CACHING_ENABLED TS_LUA_CONFIG_HTTP_NEGATIVE_CACHING_LIFETIME TS_LUA_CONFIG_HTTP_CACHE_WHEN_TO_REVALIDATE TS_LUA_CONFIG_HTTP_KEEP_ALIVE_ENABLED_IN TS_LUA_CONFIG_HTTP_KEEP_ALIVE_ENABLED_OUT TS_LUA_CONFIG_HTTP_KEEP_ALIVE_POST_OUT TS_LUA_CONFIG_HTTP_SHARE_SERVER_SESSIONS TS_LUA_CONFIG_NET_SOCK_RECV_BUFFER_SIZE_OUT TS_LUA_CONFIG_NET_SOCK_SEND_BUFFER_SIZE_OUT TS_LUA_CONFIG_NET_SOCK_OPTION_FLAG_OUT TS_LUA_CONFIG_HTTP_FORWARD_PROXY_AUTH_TO_PARENT TS_LUA_CONFIG_HTTP_ANONYMIZE_REMOVE_FROM TS_LUA_CONFIG_HTTP_ANONYMIZE_REMOVE_REFERER TS_LUA_CONFIG_HTTP_ANONYMIZE_REMOVE_USER_AGENT TS_LUA_CONFIG_HTTP_ANONYMIZE_REMOVE_COOKIE TS_LUA_CONFIG_HTTP_ANONYMIZE_REMOVE_CLIENT_IP TS_LUA_CONFIG_HTTP_ANONYMIZE_INSERT_CLIENT_IP TS_LUA_CONFIG_HTTP_RESPONSE_SERVER_ENABLED TS_LUA_CONFIG_HTTP_INSERT_SQUID_X_FORWARDED_FOR TS_LUA_CONFIG_HTTP_SERVER_TCP_INIT_CWND TS_LUA_CONFIG_HTTP_SEND_HTTP11_REQUESTS TS_LUA_CONFIG_HTTP_CACHE_HTTP TS_LUA_CONFIG_HTTP_CACHE_CLUSTER_CACHE_LOCAL TS_LUA_CONFIG_HTTP_CACHE_IGNORE_CLIENT_NO_CACHE TS_LUA_CONFIG_HTTP_CACHE_IGNORE_CLIENT_CC_MAX_AGE TS_LUA_CONFIG_HTTP_CACHE_IMS_ON_CLIENT_NO_CACHE TS_LUA_CONFIG_HTTP_CACHE_IGNORE_SERVER_NO_CACHE TS_LUA_CONFIG_HTTP_CACHE_CACHE_RESPONSES_TO_COOKIES TS_LUA_CONFIG_HTTP_CACHE_IGNORE_AUTHENTICATION TS_LUA_CONFIG_HTTP_CACHE_CACHE_URLS_THAT_LOOK_DYNAMIC TS_LUA_CONFIG_HTTP_CACHE_REQUIRED_HEADERS TS_LUA_CONFIG_HTTP_INSERT_REQUEST_VIA_STR TS_LUA_CONFIG_HTTP_INSERT_RESPONSE_VIA_STR TS_LUA_CONFIG_HTTP_CACHE_HEURISTIC_MIN_LIFETIME TS_LUA_CONFIG_HTTP_CACHE_HEURISTIC_MAX_LIFETIME TS_LUA_CONFIG_HTTP_CACHE_GUARANTEED_MIN_LIFETIME TS_LUA_CONFIG_HTTP_CACHE_GUARANTEED_MAX_LIFETIME TS_LUA_CONFIG_HTTP_CACHE_MAX_STALE_AGE TS_LUA_CONFIG_HTTP_KEEP_ALIVE_NO_ACTIVITY_TIMEOUT_IN TS_LUA_CONFIG_HTTP_KEEP_ALIVE_NO_ACTIVITY_TIMEOUT_OUT TS_LUA_CONFIG_HTTP_TRANSACTION_NO_ACTIVITY_TIMEOUT_IN TS_LUA_CONFIG_HTTP_TRANSACTION_NO_ACTIVITY_TIMEOUT_OUT TS_LUA_CONFIG_HTTP_TRANSACTION_ACTIVE_TIMEOUT_OUT TS_LUA_CONFIG_HTTP_ORIGIN_MAX_CONNECTIONS TS_LUA_CONFIG_HTTP_CONNECT_ATTEMPTS_MAX_RETRIES TS_LUA_CONFIG_HTTP_CONNECT_ATTEMPTS_MAX_RETRIES_DEAD_SERVER TS_LUA_CONFIG_HTTP_CONNECT_ATTEMPTS_RR_RETRIES TS_LUA_CONFIG_HTTP_CONNECT_ATTEMPTS_TIMEOUT TS_LUA_CONFIG_HTTP_POST_CONNECT_ATTEMPTS_TIMEOUT TS_LUA_CONFIG_HTTP_DOWN_SERVER_CACHE_TIME TS_LUA_CONFIG_HTTP_DOWN_SERVER_ABORT_THRESHOLD TS_LUA_CONFIG_HTTP_CACHE_FUZZ_TIME TS_LUA_CONFIG_HTTP_CACHE_FUZZ_MIN_TIME TS_LUA_CONFIG_HTTP_DOC_IN_CACHE_SKIP_DNS TS_LUA_CONFIG_HTTP_RESPONSE_SERVER_STR TS_LUA_CONFIG_HTTP_CACHE_HEURISTIC_LM_FACTOR TS_LUA_CONFIG_HTTP_CACHE_FUZZ_PROBABILITY TS_LUA_CONFIG_NET_SOCK_PACKET_MARK_OUT TS_LUA_CONFIG_NET_SOCK_PACKET_TOS_OUT `TOP <#ts-lua-plugin>`_ ts.http.cntl_get ---------------- **syntax:** *val = ts.http.cntl_get(CNTL_TYPE)* **context:** do_remap or do_global_* or later. **description:** This function can be used to retireve the value of control channel. :: val = ts.http.cntl_get(TS_LUA_HTTP_CNTL_GET_LOGGING_MODE) `TOP <#ts-lua-plugin>`_ ts.http.cntl_set ---------------- **syntax:** *ts.http.cntl_set(CNTL_TYPE, BOOL)* **context:** do_remap or do_global_* or later. **description:** This function can be used to set the value of control channel. Here is an example: :: function do_remap() ts.http.cntl_set(TS_LUA_HTTP_CNTL_SET_LOGGING_MODE, 0) -- do not log the request return 0 end `TOP <#ts-lua-plugin>`_ Http control channel constants ------------------------------ **context:** do_remap or do_global_* or later :: TS_LUA_HTTP_CNTL_GET_LOGGING_MODE TS_LUA_HTTP_CNTL_SET_LOGGING_MODE TS_LUA_HTTP_CNTL_GET_INTERCEPT_RETRY_MODE TS_LUA_HTTP_CNTL_SET_INTERCEPT_RETRY_MODE `TOP <#ts-lua-plugin>`_ ts.mgmt.get_counter ------------------- **syntax:** *val = ts.mgmt.get_counter(RECORD_NAME)* **context:** do_remap or do_global_* or later. **description:** This function can be used to retrieve the record value which has a counter type. :: n = ts.mgmt.get_counter('proxy.process.http.incoming_requests') `TOP <#ts-lua-plugin>`_ ts.mgmt.get_int --------------- **syntax:** *val = ts.mgmt.get_int(RECORD_NAME)* **context:** do_remap or do_global_* or later. **description:** This function can be used to retrieve the record value which has a int type. `TOP <#ts-lua-plugin>`_ ts.mgmt.get_float ----------------- **syntax:** *val = ts.mgmt.get_float(RECORD_NAME)* **context:** do_remap or do_global_* or later. **description:** This function can be used to retrieve the record value which has a float type. `TOP <#ts-lua-plugin>`_ ts.mgmt.get_string ------------------ **syntax:** *val = ts.mgmt.get_string(RECORD_NAME)* **context:** do_remap or do_global_* or later. **description:** This function can be used to retrieve the record value which has a string type. :: name = ts.mgmt.get_string('proxy.config.product_name') `TOP <#ts-lua-plugin>`_ Todo ==== * ts.fetch * ts.cache_xxx * `support lua-5.2 `_ Currently when we use ts_lua as a global plugin, each global hook is using a separate lua state for the same transaction. This can be wasteful. Also the state cannot be reused for the same transaction across the global hooks. The alternative will be to use a TXN_START hook to create a lua state first and then add each global hook in the lua script as transaction hook instead. But this will have problem down the road when we need to have multiple plugins to work together in some proper orderings. In the future, we should consider different approach, such as creating and maintaining the lua state in the ATS core. `TOP <#ts-lua-plugin>`_ More docs ========= * https://github.com/portl4t/ts-lua `TOP <#ts-lua-plugin>`_