blob: 29d4262380b77a961a60fd58aa1667c26b0fb81f [file] [log] [blame]
-- 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
function cache_lookup()
local cache = ts.http.get_cache_lookup_url()
if (cache == nil or #cache == 0) then
ts.debug("Cache lookup is empty")
else
ts.debug("Cache lookup using the get cache lookup url " .. cache)
end
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 ''
-- Checking the http version
local ver = ts.client_request.get_version()
ts.debug("Requested http version is: " .. ver)
if (ver == "1.1" and req_scheme == "http") then
ts.client_request.set_url_host(req_host)
ts.debug("Host for http version 1.1 is: " .. req_host)
end
-- ts.client_request.set_url_host(req_host)
-- Extracting original url
local url = ts.client_request.get_pristine_url()
ts.debug("Pristine url is: " .. url)
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("-----------------")
ts.hook(TS_LUA_HOOK_CACHE_LOOKUP_COMPLETE, cache_lookup)
-- 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
-- Setting up cache key
ts.debug("setting up the cache url key using the set_cache_url " .. url)
ts.http.set_cache_url(url)
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
ts.debug("Snippet in the Connect Redis lua file " .. snippet)
local f = loadstring(snippet)
f()
end
end
end
end