-
Notifications
You must be signed in to change notification settings - Fork 27
Transform
Transform is usually used to filter the HTTP reponse body to the client.
The HTTP response header will be influnced if we want to transform the response body.
If we want to set Content-Length in response header, we have to determine the total output bytes before the transform handler returns any data, we can return nil if we can not decide the total output bytes. If we have to return data from transform handler more than once, we should use ts.http.resp_transform.set_downstream_bytes to inform ats the total output bytes previously.
Sometimes we want to compute the output bytes based on the input bytes which can be retrieved by ts.http.resp_transform.get_upstream_bytes, however, this is not always true because we may get TS_LUA_INT64_MAX which indicates that we do not know how many bytes will be received from upstream at the beginning.
Here are some examples:
-
- We want to append
abcdefgat the end of the response body, we can insureContent-Lengthwill be set correctly unless the we got chunked response body from origin server.
- We want to append
function append_transform(data, eos)
if ts.ctx['cset'] == false then
local n = ts.http.resp_transform.get_upstream_bytes()
if n ~= TS_LUA_INT64_MAX then
ts.http.resp_transform.set_downstream_bytes(n+7)
end
ts.ctx['cset'] = true
end
if eos == 1 then
return string.upper(data)..'abcdefg', eos
else
return string.upper(data), eos
end
end
function do_remap()
ts.hook(TS_LUA_RESPONSE_TRANSFORM, append_transform)
ts.http.resp_cache_transformed(0)
ts.http.resp_cache_untransformed(1)
ts.ctx['cset'] = false
return 0
endFunction ts.http.resp_transform.get_upstream_bytes will return TS_LUA_INT64_MAX if we got chunked response body from origin server.
-
- We want to replace
abcdefwith1234567in the response body and setContent-Lengthcorrectly unless we got chunked response body from origin server.
- We want to replace
function do_replace(str)
local newstr = ''
local a, b, c = string.find(str, 'abcdef')
while a ~= nil
do
newstr = newstr .. string.sub(str, 1, a-1) .. '1234567'
str = string.sub(str, b+1)
a, b, c = string.find(str, 'abcdef')
end
newstr = newstr .. str
return newstr
end
function replace_transform(data, eos)
ts.ctx['reserved'] = ts.ctx['reserved'] .. data
if eos == 1 then
local repl = do_replace(ts.ctx['reserved'])
return repl, eos
else
return nil, eos
end
end
function do_remap()
ts.hook(TS_LUA_RESPONSE_TRANSFORM, replace_transform)
ts.http.resp_cache_transformed(0)
ts.http.resp_cache_untransformed(1)
ts.ctx['reserved'] = ''
return 0
endAs we can see, we will not return data from the transform handler unless there are no more input data from upstream, this will guarantee Content-Length will be set correctly unless we got chunked response body from origin server.
-
- We want to replace the response body with
abcdefg
- We want to replace the response body with
function rep_transform(data, eos)
return 'abcdefg', 1
end
function do_remap()
ts.hook(TS_LUA_RESPONSE_TRANSFORM, rep_transform)
ts.http.resp_cache_transformed(0)
ts.http.resp_cache_untransformed(1)
return 0
endThe transform handler will be called only once here and Content-Length will be set correctly unless we got chunked response body from origin server.
Fact, we may want to set Content-Length correctly in example 2 and 3 even the orgin server issues chunked response body, because we write down only once in the transform handler and the size of the body can be ensured. This can be done by applying this patch TS-3252