Initial code import
[msb/apigateway.git] / openresty-ext / src / assembly / resources / openresty / nginx / luaext / rewrite / customrewrite.lua
diff --git a/openresty-ext/src/assembly/resources/openresty/nginx/luaext/rewrite/customrewrite.lua b/openresty-ext/src/assembly/resources/openresty/nginx/luaext/rewrite/customrewrite.lua
new file mode 100644 (file)
index 0000000..564a52a
--- /dev/null
@@ -0,0 +1,208 @@
+--[[\r
+\r
+    Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)\r
+\r
+    Licensed under the Apache License, Version 2.0 (the "License");\r
+    you may not use this file except in compliance with the License.\r
+    You may obtain a copy of the License at\r
+\r
+            http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+    Unless required by applicable law or agreed to in writing, software\r
+    distributed under the License is distributed on an "AS IS" BASIS,\r
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+    See the License for the specific language governing permissions and\r
+    limitations under the License.\r
+\r
+--]]\r
+\r
+local msbConf   =  require('conf.msbinit')\r
+local svcConf   =  require('conf.svcconf')\r
+local dbclient  =  require('dao.db_access')\r
+local tbl_util  =  require('lib.utils.table_util')\r
+local svc_util  =  require('lib.utils.svc_util')\r
+local log_util  =  require('lib.utils.log_util')\r
+\r
+local tbl_concat = table.concat\r
+local tbl_isempty = tbl_util.isempty\r
+local svc_isactive = svc_util.isactive\r
+local svc_setauthheader = svc_util.setauthheader\r
+local svc_isautodiscover = svc_util.isautodiscover\r
+local str_sub = string.sub\r
+local str_len = string.len\r
+local str_low = string.lower\r
+local ngx_var = ngx.var\r
+local ngx_ctx = ngx.ctx\r
+local log = log_util.log\r
+\r
+local defaultport = msbConf.systemConf.defaultport\r
+local defaultprefix = msbConf.systemConf.defaultprefix\r
+local enablerefercheck = msbConf.systemConf.enablerefercheck\r
+local useconsultemplate = msbConf.systemConf.useconsultemplate\r
+local urlfieldMap = svcConf.urlfieldMap\r
+\r
+local donotfound = function() \r
+       ngx.status = ngx.HTTP_NOT_FOUND\r
+       ngx.say("service info not found!")\r
+       return ngx.exit(ngx.status)\r
+end\r
+\r
+---------------------------------------------------------------\r
+--preCheck:\r
+--     determine whether it is websocket request \r
+--     and do internal redirect\r
+---------------------------------------------------------------\r
+local http_upgrade = ngx_var.http_upgrade\r
+if(ngx_var.websocket_internal_redirect == "on") and http_upgrade and str_low(http_upgrade)== "websocket" then\r
+       ngx.log(ngx.ERR, "Websocket request and redirect to @customwebsocket")\r
+       return ngx.exec("@customwebsocket");\r
+end\r
+\r
+---------------------------------------------------------------\r
+--step0:Preparation\r
+--      svcnames:service names registered under this port\r
+---------------------------------------------------------------\r
+local sys_prefix = ""\r
+local server_port = ngx_var.server_port\r
+if(server_port == defaultport) then\r
+       sys_prefix = defaultprefix\r
+else\r
+       sys_prefix = server_port\r
+end\r
+\r
+local custom_svc_keypattern = tbl_concat({sys_prefix,"custom","*"},":")\r
+\r
+local get_svcinfokey_custom = function(svcname) \r
+       return tbl_concat({sys_prefix,"custom",svcname,"info"},":")\r
+end\r
+\r
+local get_svcserverpattern_custom = function(svcname) \r
+       return tbl_concat({sys_prefix,"custom",svcname,"lb:server*"},":")\r
+end\r
+\r
+local svcnames,err = dbclient.load_customsvcnames(custom_svc_keypattern)\r
+if not svcnames then \r
+       donotfound()\r
+end\r
+\r
+---------------------------------------------------------------\r
+--step1:run the match process(check whether the request \r
+--      match the name in the svcnames one by one) \r
+--      and return the matched serice info\r
+---------------------------------------------------------------\r
+local req_res  = ngx_var.uri\r
+local svc_type = ngx_var.svc_type\r
+local matchedsvcname\r
+local svcinfo\r
+--add by wangyg:20160418 special handler for refer\r
+local matched_usingrefer = false\r
+--end of add by wangyg:20160418 special handler for refer\r
+for _, svcname in ipairs(svcnames) do\r
+       if (svcname == "/") then\r
+               local svc_info_key = get_svcinfokey_custom(svcname)\r
+               local svc_info,err = dbclient.load_serviceinfo(svc_info_key)\r
+               if svc_info and svc_isactive(svc_info)then\r
+                       matchedsvcname = svcname\r
+                       svcinfo = svc_info\r
+                       break\r
+               end\r
+       end\r
+       local from, to, err = ngx.re.find(req_res, "^"..svcname.."(/(.*))?$", "jo")\r
+       --check whether svcname is the prefix of the req uri\r
+       if from then\r
+               local svc_info_key = get_svcinfokey_custom(svcname)\r
+               local svc_info,err = dbclient.load_serviceinfo(svc_info_key)\r
+               if svc_info and svc_isactive(svc_info) then \r
+                       matchedsvcname = svcname\r
+                       svcinfo = svc_info\r
+                       break\r
+               end\r
+       else\r
+               --do nothing\r
+       end\r
+end\r
+---------------------------------------------------------------\r
+--step1.1:additional process,test against the refer \r
+--        similar to step1\r
+---------------------------------------------------------------\r
+--add by wangyg:20160418 special handler for refer\r
+if not matchedsvcname and enablerefercheck then \r
+       local refer =  ngx_var.http_referer\r
+       if(refer and refer~="") then\r
+               for _, svcname in ipairs(svcnames) do\r
+                       local urlreg ="^(https://|http://|)(([1-9]|([1-9]\\d)|(1\\d\\d)|(2([0-4]\\d|5[0-5])))\\.)(([0-9]|([1-9]\\d)|(1\\d\\d)|(2([0-4]\\d|5[0-5])))\\.){2}([1-9]|([1-9]\\d)|(1\\d\\d)|(2([0-4]\\d|5[0-5])))(:\\d{1,5})?"..svcname.."(/(.*))?$";\r
+                       local from, to, err = ngx.re.find(refer, urlreg, "jo")\r
+                       ----check whether svcname is the prefix of the req refer\r
+                       if from then\r
+                               local svc_info_key = get_svcinfokey_custom(svcname)\r
+                               local svc_info,err = dbclient.load_serviceinfo(svc_info_key)\r
+                               if svc_info and svc_isactive(svc_info) then \r
+                                       matchedsvcname = svcname\r
+                                       svcinfo = svc_info\r
+                                       matched_usingrefer = true\r
+                                       break\r
+                               end\r
+                       end\r
+               end\r
+       end\r
+end\r
+--end of add by wangyg:20160418 special handler for refer\r
+\r
+if not matchedsvcname or tbl_isempty(svcinfo) then \r
+       donotfound()\r
+end\r
+\r
+local svc_url = svcinfo[urlfieldMap[svc_type]]\r
+if not svc_url then \r
+       donotfound()\r
+end\r
+\r
+---------------------------------------------------------------\r
+--step2:rewrite the request uri using the svcinfo\r
+---------------------------------------------------------------\r
+local rewrited_uri =""\r
+if (matchedsvcname == "/") then\r
+       --special handling: if "/" matched, contact directly\r
+       rewrited_uri = svc_url..req_res\r
+else\r
+       --rewrited_uri = ngx.re.sub(req_res, "^"..matchedsvcname.."(.*)", svc_url.."$1", "o")\r
+       local newuri,n,err = ngx.re.sub(req_res, "^"..matchedsvcname.."(/.*)?", svc_url.."$1", "o")\r
+       --add by wangyg:20160418 special handler for refer\r
+       if(n==0 and matched_usingrefer) then newuri = svc_url..req_res end --special handling if matched using refer\r
+       --end of add by wangyg:20160418 special handler for refer\r
+       rewrited_uri = newuri\r
+end\r
+if (rewrited_uri == "") then rewrited_uri = "/" end --avoid throws internal error when it is empty\r
+ngx.req.set_uri(rewrited_uri)\r
+\r
+--set the matched service info,used in the proxy_redirect directive \r
+ngx_var.svc_name = matchedsvcname\r
+ngx_var.svc_url =  svc_url\r
+\r
+--log the route info\r
+log("matchedservice",matchedsvcname)\r
+if(matched_usingrefer) then log("matched_usingrefer",true) end \r
+log("rewrited_uri",rewrited_uri)\r
+\r
+---------------------------------------------------------------\r
+--step2.1:if this service is inter-system,add custom http header\r
+---------------------------------------------------------------\r
+svc_setauthheader(svcinfo)\r
+\r
+---------------------------------------------------------------\r
+--step3:process the proxy upstream part\r
+-- con1-using consul template:set the upstream name\r
+-- con2-using msb balancer:query the backserver list and store in the ctx\r
+---------------------------------------------------------------\r
+if useconsultemplate and svc_isautodiscover(svcinfo) then\r
+       --FIX ME:if svcname contains "/", the upstream name may be illegal\r
+       ngx_var.backend = ngx.re.sub(matchedsvcname, "^/(.*)", "$1", "o")\r
+else\r
+       local svc_server_keypattern = get_svcserverpattern_custom(matchedsvcname)\r
+       local backservers,err = dbclient.load_backservers(svc_server_keypattern)\r
+       if tbl_isempty(backservers) then\r
+               donotfound()\r
+       end\r
+       ngx_ctx.backservers = backservers\r
+       ngx_ctx.svcserverpattern = svc_server_keypattern\r
+end
\ No newline at end of file