| Name |
| ====== |
| |
| ts-lua - Embed the Power of Lua into TrafficServer. |
| |
| Status |
| ====== |
| This module is being tested under our production environment. |
| |
| Version |
| ====== |
| ts-lua has not been released yet. |
| |
| 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 |
| |
| if req_host == nil then |
| return 0 |
| end |
| |
| ts.ctx['rhost'] = string.reverse(req_host) |
| |
| ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) |
| |
| return 0 |
| end |
| |
| |
| |
| **test_transform.lua** |
| |
| 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 send_response() |
| ts.client_response.header['SHE'] = ts.ctx['tb']['she'] |
| return 0 |
| end |
| |
| |
| function do_remap() |
| local req_host = ts.client_request.header.Host |
| |
| if req_host == nil then |
| return 0 |
| end |
| |
| ts.ctx['tb'] = {} |
| ts.ctx['tb']['she'] = 'wo ai yu ye hua' |
| |
| ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) |
| ts.hook(TS_LUA_RESPONSE_TRANSFORM, upper_transform) |
| |
| ts.http.resp_cache_transformed(0) |
| ts.http.resp_cache_untransformed(1) |
| return 0 |
| end |
| |
| |
| |
| **test_cache_lookup.lua** |
| |
| function send_response() |
| ts.client_response.header['Rhost'] = ts.ctx['rhost'] |
| ts.client_response.header['CStatus'] = ts.ctx['cstatus'] |
| end |
| |
| |
| function cache_lookup() |
| local cache_status = ts.http.get_cache_lookup_status() |
| ts.ctx['cstatus'] = cache_status |
| end |
| |
| |
| function do_remap() |
| local req_host = ts.client_request.header.Host |
| |
| if req_host == nil then |
| return 0 |
| end |
| |
| ts.ctx['rhost'] = string.reverse(req_host) |
| |
| ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) |
| ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup) |
| |
| return 0 |
| end |
| |
| |
| |
| **test_ret_403.lua** |
| |
| function send_response() |
| ts.client_response.header['Now'] = ts.now() |
| return 0 |
| end |
| |
| |
| function do_remap() |
| |
| local uri = ts.client_request.get_uri() |
| |
| pos, len = string.find(uri, '/css/') |
| if pos ~= nil then |
| ts.http.set_resp(403, "Document access failed :)\n") |
| return 0 |
| end |
| |
| ts.hook(TS_LUA_HOOK_SEND_RESPONSE_HDR, send_response) |
| |
| return 0 |
| end |
| |
| |
| |
| **sethost.lua** |
| |
| HOSTNAME = '' |
| |
| function __init__(argtb) |
| |
| if (#argtb) < 1 then |
| print(argtb[0], 'hostname parameter required!!') |
| return -1 |
| end |
| |
| HOSTNAME = argtb[1] |
| end |
| |
| function do_remap() |
| local req_host = ts.client_request.header.Host |
| |
| if req_host == nil then |
| return 0 |
| end |
| |
| ts.client_request.header['Host'] = HOSTNAME |
| |
| return 0 |
| end |
| |
| |
| **test_intercept.lua** |
| |
| require 'os' |
| |
| function send_data() |
| local nt = os.time()..' Zheng.\n' |
| local resp = 'HTTP/1.1 200 OK\r\n' .. |
| 'Server: ATS/3.2.0\r\n' .. |
| 'Content-Type: text/plain\r\n' .. |
| 'Content-Length: ' .. 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.sleep(1) |
| return resp |
| end |
| |
| function do_remap() |
| ts.http.intercept(send_data) |
| return 0 |
| end |
| |
| |
| **test_server_intercept.lua** |
| |
| require 'os' |
| |
| function send_data() |
| local nt = os.time()..'\n' |
| local resp = 'HTTP/1.1 200 OK\r\n' .. |
| 'Server: ATS/3.2.0\r\n' .. |
| 'Content-Type: text/plain\r\n' .. |
| 'Content-Length: ' .. 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=30\r\n' .. |
| 'Accept-Ranges: bytes\r\n\r\n' .. |
| nt |
| return resp |
| end |
| |
| function do_remap() |
| ts.http.server_intercept(send_data) |
| return 0 |
| end |
| |
| |
| Description |
| ====== |
| This module embeds Lua, via the standard Lua 5.1 interpreter, into Apache Traffic Server. 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=/usr/lib64/trafficserver/plugins/libtslua.so @pparam=/etc/trafficserver/script/test_hdr.lua |
| |
| Sometimes we want to receive parameters and process them in the script, we should realize **'\__init__'** function in the lua script(sethost.lua is a reference), and we can write this in remap.config: |
| |
| map http://a.tbcdn.cn/ http://inner.tbcdn.cn/ @plugin=/usr/lib64/trafficserver/plugins/libtslua.so @pparam=/etc/trafficserver/script/sethost.lua @pparam=img03.tbcdn.cn |
| |
| |
| |
| 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. |
| |
| |
| |
| 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: |
| |
| function send_response() |
| ts.client_response.header['Now'] = ts.now() |
| return 0 |
| end |
| |
| |
| ts.debug |
| ------ |
| **syntax**: *ts.debug(MESSAGE)* |
| |
| **context**: global |
| |
| **description**: Log the MESSAGE to traffic.out if debug is enabled. |
| |
| Here is an example: |
| |
| function do_remap() |
| ts.debug('I am in do_remap now.') |
| return 0 |
| end |
| |
| The debug tag is ts_lua and we should write this in records.config: |
| |
| CONFIG proxy.config.diags.debug.tags STRING ts_lua |
| |
| |
| ts.hook |
| ------ |
| **syntax**: *ts.hook(HOOK_POINT, FUNCTION)* |
| |
| **context**: do_remap 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 |
| |
| Hook point constants |
| ------ |
| **context**: do_remap or later |
| |
| TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE |
| 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. |
| |
| |
| ts.ctx |
| ------ |
| **syntax**: *ts.ctx[KEY]* |
| |
| **context**: do_remap 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['RR'] = 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 |
| |
| |
| 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 send_response() |
| ts.client_response.header['CStatus'] = ts.ctx['cstatus'] |
| end |
| |
| function cache_lookup() |
| local cache_status = ts.http.get_cache_lookup_status() |
| if cache_status == TS_LUA_CACHE_LOOKUP_HIT_FRESH: |
| ts.ctx['cstatus'] = 'hit' |
| else |
| ts.ctx['cstatus'] = 'not hit' |
| end |
| 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 |
| |
| |
| 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) |
| |
| |
| ts.http.set_cache_url |
| ------ |
| **syntax**: *ts.http.set_cache_url(KEY_URL)* |
| |
| **context**: do_remap |
| |
| **description**: This function can be used to modify the cache key for the request. |
| |
| Here is an example: |
| |
| function do_remap() |
| ts.http.set_cache_url('http://127.0.0.1:8080/abc/') |
| return 0 |
| end |
| |
| |
| ts.http.resp_cache_transformed |
| ------ |
| **syntax**: *ts.http.resp_cache_transformed(BOOL)* |
| |
| **context**: do_remap 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) |
| ts.http.resp_cache_untransformed(1) |
| return 0 |
| end |
| |
| This function is usually called after we hook TS_LUA_RESPONSE_TRANSFORM. |
| |
| |
| ts.http.resp_cache_untransformed |
| ------ |
| **syntax**: *ts.http.resp_cache_untransformed(BOOL)* |
| |
| **context**: do_remap 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_transformed(0) |
| ts.http.resp_cache_untransformed(1) |
| return 0 |
| end |
| |
| This function is usually called after we hook TS_LUA_RESPONSE_TRANSFORM. |
| |
| |
| ts.client_request.client_addr.get_addr |
| ------ |
| **syntax**: *ts.client_request.client_addr.get_addr()* |
| |
| **context**: do_remap or later |
| |
| **description**: This function can be used to get socket address of the client. |
| |
| Here is an example: |
| |
| function do_remap |
| ip, port, family = ts.client_request.client_addr.get_addr() |
| return 0 |
| end |
| |
| The ts.client_request.client_addr.get_addr function returns three values, ip is a string, port and family is number. |
| |
| |
| ts.client_request.get_method |
| ------ |
| **syntax**: *ts.client_request.get_method()* |
| |
| **context**: do_remap or later |
| |
| **description**: This function can be used to retrieve the current request's request method name. String like "GET" or |
| "POST" is returned. |
| |
| |
| ts.client_request.set_method |
| ------ |
| **syntax**: *ts.client_request.set_method(METHOD_NAME)* |
| |
| **context**: do_remap |
| |
| **description**: This function can be used to override the current request's request method with METHOD_NAME. |
| |
| |
| ts.client_request.get_url |
| ------ |
| **syntax**: *ts.client_request.get_url()* |
| |
| **context**: do_remap or later |
| |
| **description**: This function can be used to retrieve the whole request's url. |
| |
| |
| 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 request's path. |
| |
| |
| ts.client_request.set_uri |
| ------ |
| **syntax**: *ts.client_request.set_uri(PATH)* |
| |
| **context**: do_remap |
| |
| **description**: This function can be used to override the request's path. |
| |
| |
| ts.client_request.get_uri_args |
| ------ |
| **syntax**: *ts.client_request.get_uri_args()* |
| |
| **context**: do_remap or later |
| |
| **description**: This function can be used to retrieve the request's query string. |
| |
| |
| ts.client_request.set_uri_args |
| ------ |
| **syntax**: *ts.client_request.set_uri_args(QUERY_STRING)* |
| |
| **context**: do_remap |
| |
| **description**: This function can be used to override the request's query string. |
| |
| |
| 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 later |
| |
| **description**: Set, add to, clear or get the current request's HEADER. |
| |
| Here is an example: |
| |
| function do_remap() |
| local req_host = ts.client_request.header.Host |
| ts.client_request.header['Host'] = 'a.tbcdn.cn' |
| end |
| |
| |
| TODO |
| ======= |
| Short Term |
| ------ |
| * non-blocking I/O operation |
| * ts.fetch |
| |
| Long Term |
| ------ |
| * ts.regex |
| |