Initial code import
[msb/apigateway.git] / openresty-ext / src / assembly / resources / openresty / nginx / luaext / rewrite / customrewrite.lua
1 --[[\r
2 \r
3     Copyright (C) 2016 ZTE, Inc. and others. All rights reserved. (ZTE)\r
4 \r
5     Licensed under the Apache License, Version 2.0 (the "License");\r
6     you may not use this file except in compliance with the License.\r
7     You may obtain a copy of the License at\r
8 \r
9             http://www.apache.org/licenses/LICENSE-2.0\r
10 \r
11     Unless required by applicable law or agreed to in writing, software\r
12     distributed under the License is distributed on an "AS IS" BASIS,\r
13     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
14     See the License for the specific language governing permissions and\r
15     limitations under the License.\r
16 \r
17 --]]\r
18 \r
19 local msbConf   =  require('conf.msbinit')\r
20 local svcConf   =  require('conf.svcconf')\r
21 local dbclient  =  require('dao.db_access')\r
22 local tbl_util  =  require('lib.utils.table_util')\r
23 local svc_util  =  require('lib.utils.svc_util')\r
24 local log_util  =  require('lib.utils.log_util')\r
25 \r
26 local tbl_concat = table.concat\r
27 local tbl_isempty = tbl_util.isempty\r
28 local svc_isactive = svc_util.isactive\r
29 local svc_setauthheader = svc_util.setauthheader\r
30 local svc_isautodiscover = svc_util.isautodiscover\r
31 local str_sub = string.sub\r
32 local str_len = string.len\r
33 local str_low = string.lower\r
34 local ngx_var = ngx.var\r
35 local ngx_ctx = ngx.ctx\r
36 local log = log_util.log\r
37 \r
38 local defaultport = msbConf.systemConf.defaultport\r
39 local defaultprefix = msbConf.systemConf.defaultprefix\r
40 local enablerefercheck = msbConf.systemConf.enablerefercheck\r
41 local useconsultemplate = msbConf.systemConf.useconsultemplate\r
42 local urlfieldMap = svcConf.urlfieldMap\r
43 \r
44 local donotfound = function() \r
45         ngx.status = ngx.HTTP_NOT_FOUND\r
46         ngx.say("service info not found!")\r
47         return ngx.exit(ngx.status)\r
48 end\r
49 \r
50 ---------------------------------------------------------------\r
51 --preCheck:\r
52 --     determine whether it is websocket request \r
53 --     and do internal redirect\r
54 ---------------------------------------------------------------\r
55 local http_upgrade = ngx_var.http_upgrade\r
56 if(ngx_var.websocket_internal_redirect == "on") and http_upgrade and str_low(http_upgrade)== "websocket" then\r
57         ngx.log(ngx.ERR, "Websocket request and redirect to @customwebsocket")\r
58         return ngx.exec("@customwebsocket");\r
59 end\r
60 \r
61 ---------------------------------------------------------------\r
62 --step0:Preparation\r
63 --      svcnames:service names registered under this port\r
64 ---------------------------------------------------------------\r
65 local sys_prefix = ""\r
66 local server_port = ngx_var.server_port\r
67 if(server_port == defaultport) then\r
68         sys_prefix = defaultprefix\r
69 else\r
70         sys_prefix = server_port\r
71 end\r
72 \r
73 local custom_svc_keypattern = tbl_concat({sys_prefix,"custom","*"},":")\r
74 \r
75 local get_svcinfokey_custom = function(svcname) \r
76         return tbl_concat({sys_prefix,"custom",svcname,"info"},":")\r
77 end\r
78 \r
79 local get_svcserverpattern_custom = function(svcname) \r
80         return tbl_concat({sys_prefix,"custom",svcname,"lb:server*"},":")\r
81 end\r
82 \r
83 local svcnames,err = dbclient.load_customsvcnames(custom_svc_keypattern)\r
84 if not svcnames then \r
85         donotfound()\r
86 end\r
87 \r
88 ---------------------------------------------------------------\r
89 --step1:run the match process(check whether the request \r
90 --      match the name in the svcnames one by one) \r
91 --      and return the matched serice info\r
92 ---------------------------------------------------------------\r
93 local req_res  = ngx_var.uri\r
94 local svc_type = ngx_var.svc_type\r
95 local matchedsvcname\r
96 local svcinfo\r
97 --add by wangyg:20160418 special handler for refer\r
98 local matched_usingrefer = false\r
99 --end of add by wangyg:20160418 special handler for refer\r
100 for _, svcname in ipairs(svcnames) do\r
101         if (svcname == "/") then\r
102                 local svc_info_key = get_svcinfokey_custom(svcname)\r
103                 local svc_info,err = dbclient.load_serviceinfo(svc_info_key)\r
104                 if svc_info and svc_isactive(svc_info)then\r
105                         matchedsvcname = svcname\r
106                         svcinfo = svc_info\r
107                         break\r
108                 end\r
109         end\r
110         local from, to, err = ngx.re.find(req_res, "^"..svcname.."(/(.*))?$", "jo")\r
111         --check whether svcname is the prefix of the req uri\r
112         if from then\r
113                 local svc_info_key = get_svcinfokey_custom(svcname)\r
114                 local svc_info,err = dbclient.load_serviceinfo(svc_info_key)\r
115                 if svc_info and svc_isactive(svc_info) then \r
116                         matchedsvcname = svcname\r
117                         svcinfo = svc_info\r
118                         break\r
119                 end\r
120         else\r
121                 --do nothing\r
122         end\r
123 end\r
124 ---------------------------------------------------------------\r
125 --step1.1:additional process,test against the refer \r
126 --        similar to step1\r
127 ---------------------------------------------------------------\r
128 --add by wangyg:20160418 special handler for refer\r
129 if not matchedsvcname and enablerefercheck then \r
130         local refer =  ngx_var.http_referer\r
131         if(refer and refer~="") then\r
132                 for _, svcname in ipairs(svcnames) do\r
133                         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
134                         local from, to, err = ngx.re.find(refer, urlreg, "jo")\r
135                         ----check whether svcname is the prefix of the req refer\r
136                         if from then\r
137                                 local svc_info_key = get_svcinfokey_custom(svcname)\r
138                                 local svc_info,err = dbclient.load_serviceinfo(svc_info_key)\r
139                                 if svc_info and svc_isactive(svc_info) then \r
140                                         matchedsvcname = svcname\r
141                                         svcinfo = svc_info\r
142                                         matched_usingrefer = true\r
143                                         break\r
144                                 end\r
145                         end\r
146                 end\r
147         end\r
148 end\r
149 --end of add by wangyg:20160418 special handler for refer\r
150 \r
151 if not matchedsvcname or tbl_isempty(svcinfo) then \r
152         donotfound()\r
153 end\r
154 \r
155 local svc_url = svcinfo[urlfieldMap[svc_type]]\r
156 if not svc_url then \r
157         donotfound()\r
158 end\r
159 \r
160 ---------------------------------------------------------------\r
161 --step2:rewrite the request uri using the svcinfo\r
162 ---------------------------------------------------------------\r
163 local rewrited_uri =""\r
164 if (matchedsvcname == "/") then\r
165         --special handling: if "/" matched, contact directly\r
166         rewrited_uri = svc_url..req_res\r
167 else\r
168         --rewrited_uri = ngx.re.sub(req_res, "^"..matchedsvcname.."(.*)", svc_url.."$1", "o")\r
169         local newuri,n,err = ngx.re.sub(req_res, "^"..matchedsvcname.."(/.*)?", svc_url.."$1", "o")\r
170         --add by wangyg:20160418 special handler for refer\r
171         if(n==0 and matched_usingrefer) then newuri = svc_url..req_res end --special handling if matched using refer\r
172         --end of add by wangyg:20160418 special handler for refer\r
173         rewrited_uri = newuri\r
174 end\r
175 if (rewrited_uri == "") then rewrited_uri = "/" end --avoid throws internal error when it is empty\r
176 ngx.req.set_uri(rewrited_uri)\r
177 \r
178 --set the matched service info,used in the proxy_redirect directive \r
179 ngx_var.svc_name = matchedsvcname\r
180 ngx_var.svc_url =  svc_url\r
181 \r
182 --log the route info\r
183 log("matchedservice",matchedsvcname)\r
184 if(matched_usingrefer) then log("matched_usingrefer",true) end \r
185 log("rewrited_uri",rewrited_uri)\r
186 \r
187 ---------------------------------------------------------------\r
188 --step2.1:if this service is inter-system,add custom http header\r
189 ---------------------------------------------------------------\r
190 svc_setauthheader(svcinfo)\r
191 \r
192 ---------------------------------------------------------------\r
193 --step3:process the proxy upstream part\r
194 -- con1-using consul template:set the upstream name\r
195 -- con2-using msb balancer:query the backserver list and store in the ctx\r
196 ---------------------------------------------------------------\r
197 if useconsultemplate and svc_isautodiscover(svcinfo) then\r
198         --FIX ME:if svcname contains "/", the upstream name may be illegal\r
199         ngx_var.backend = ngx.re.sub(matchedsvcname, "^/(.*)", "$1", "o")\r
200 else\r
201         local svc_server_keypattern = get_svcserverpattern_custom(matchedsvcname)\r
202         local backservers,err = dbclient.load_backservers(svc_server_keypattern)\r
203         if tbl_isempty(backservers) then\r
204                 donotfound()\r
205         end\r
206         ngx_ctx.backservers = backservers\r
207         ngx_ctx.svcserverpattern = svc_server_keypattern\r
208 end