pluginats/connect_redis.lua (160 lines of code) (raw):

-- 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. ts.add_package_cpath('/opt/ats/lib/lua/5.1/?.so;/opt/ats/lib/lua/5.1/socket/?.so;/opt/ats/lib/lua/5.1/mime/?.so') ts.add_package_path('/opt/ats/share/lua/5.1/?.lua;/opt/ats/share/lua/5.1/socket/?.lua') local redis = require 'redis' -- connecting to unix domain socket local client = redis.connect('unix:///opt/ats/var/run/redis/redis.sock') local snippet_enabled = false function __init__(argtb) if (#argtb) > 0 then ts.debug("Parameter is given. Snippet is enabled.") snippet_enabled = true end end -- helper function to split a string function ipport_split(s, delimiter) result = {} if (s ~= nil and s ~= '') then for match in (s..delimiter):gmatch("(.-)"..delimiter) do table.insert(result, match) end end return result end function check_path_exact_match(req_scheme, req_host, req_path) local host_path = "E+"..req_scheme .. "://" .. req_host .. req_path ts.debug('checking host_path: '..host_path) client:select(1) -- go with hostpath table first return client:smembers(host_path) -- redis blocking call end function check_path_prefix_match(req_scheme, req_host, req_path) local host_path = "P+"..req_scheme .. "://" .. req_host .. req_path ts.debug('checking host_path: '..host_path) client:select(1) local svcs = client:smembers(host_path) -- redis blocking call if (svcs ~= nil and #svcs > 0) then return svcs end -- finding location of / in request path local t = {} -- table to store the indices local i = 0 while true do i = string.find(req_path, "%/", i+1) -- find 'next' dir if i == nil then break end table.insert(t, i) end for index = #t, 1, -1 do local pathindex = t[index] local subpath = string.sub (req_path, 1, pathindex) host_path = "P+"..req_scheme .. "://" .. req_host .. subpath ts.debug('checking host_path: '..host_path) client:select(1) svcs =client:smembers(host_path) -- redis blocking call if (svcs ~= nil and #svcs > 0) then return svcs end if pathindex > 1 then subpath = string.sub (req_path, 1, pathindex - 1) host_path = "P+"..req_scheme .. "://" .. req_host .. subpath ts.debug('checking host_path: '..host_path) client:select(1) svcs = client:smembers(host_path) -- redis blocking call if (svcs ~= nil and #svcs > 0) then return svcs end end end return nil end function get_wildcard_domain(req_host) local pos = string.find( req_host, '%.' ) if pos == nil then return nil end return "*" .. string.sub (req_host, pos) end --------------------------------------------- ----------------- DO_REMAP ------------------ --------------------------------------------- function do_global_read_request() ts.debug("In do_global_read_request()==========") local response = client:ping() -- if cannot connect to redis client, terminate early if not response then ts.debug("In 'not response: '", response) return 0 end -- We only care about host, path, and port# local req_scheme = ts.client_request.get_url_scheme() or 'http' local req_host = ts.client_request.get_url_host() or '' local req_path = ts.client_request.get_uri() or '' local req_port = ts.client_request.get_url_port() or '' local wildcard_req_host = get_wildcard_domain(req_host) ts.debug("-----Request-----") ts.debug("req_scheme: "..req_scheme) ts.debug("req_host: " .. req_host) ts.debug("req_port: " .. req_port) ts.debug("req_path: " .. req_path) ts.debug("wildcard_req_host: " .. (wildcard_req_host or 'invalid domain name')) ts.debug("-----------------") -- check for path exact match local svcs = check_path_exact_match(req_scheme, req_host, req_path) if (svcs == nil or #svcs == 0) then -- check for path prefix match svcs = check_path_prefix_match(req_scheme, req_host, req_path) end if (svcs == nil or #svcs == 0) and wildcard_req_host ~= nil then -- check for path exact match with wildcard domain name in prefix svcs = check_path_exact_match(req_scheme, wildcard_req_host, req_path) end if (svcs == nil or #svcs == 0) and wildcard_req_host ~= nil then -- check for path prefix match with wildcard domain name in prefix svcs = check_path_prefix_match(req_scheme, wildcard_req_host, req_path) end if (svcs == nil or #svcs == 0) then -- check for path exact match with wildcard domain name svcs = check_path_exact_match(req_scheme, '*', req_path) end if (svcs == nil or #svcs == 0) then -- check for path prefix match with wildcard domain name svcs = check_path_prefix_match(req_scheme, '*', req_path) end if (svcs == nil or #svcs == 0) then ts.error("Redis Lookup Failure: svcs == nil for hostpath") return 0 end for _, svc in ipairs(svcs) do if svc == nil then ts.error("Redis Lookup Failure: svc == nil for hostpath") return 0 end if string.sub(svc, 1, 1) ~= "$" then ts.debug("routing") client:select(0) -- go with svc table second local ipport = client:srandmember(svc) -- redis blocking call -- svc not in redis DB if ipport == nil then ts.error("Redis Lookup Failure: ipport == nil for svc") return 0 end -- find protocol, ip , port info local values = ipport_split(ipport, '#'); if #values ~= 3 then ts.error("Redis Lookup Failure: wrong format - "..ipport) return 0 end ts.http.skip_remapping_set(1) ts.client_request.set_url_scheme(values[3]) ts.client_request.set_uri(req_path) ts.client_request.set_url_host(values[1]) ts.client_request.set_url_port(values[2]) end end if snippet_enabled == true then for _, svc in ipairs(svcs) do if svc == nil then ts.error("Redis Lookup Failure: svc == nil for hostpath") return 0 end if string.sub(svc, 1, 1) == "$" then ts.debug("snippet") client:select(1) local snippets = client:smembers(svc) if snippets == nil then ts.error("Redis Lookup Failure: snippets == nil for hostpath") return 0 end local snippet = snippets[1] if snippet == nil then ts.error("Redis Lookup Failure: snippet == nil for hostpath") return 0 end local f = loadstring(snippet) f() end end end end