| -- 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 |
| |