Divide the MSB source codes into two repos
[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 dbclient  =  require('dao.db_access')\r
21 local tbl_util  =  require('lib.utils.table_util')\r
22 local svc_util  =  require('lib.utils.svc_util')\r
23 local log_util  =  require('lib.utils.log_util')\r
24 local error_handler  =  require('lib.utils.error_handler')\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_get_url = svc_util.get_url\r
30 local svc_get_backend_protocol = svc_util.get_backend_protocol\r
31 local svc_use_own_upstream = svc_util.use_own_upstream\r
32 local svc_get_key_prefix = svc_util.get_key_prefix\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 local error_svc_not_found = error_handler.svc_not_found\r
38 local error_upstream_not_found = error_handler.upstream_not_found\r
39 \r
40 local enablerefercheck = msbConf.systemConf.enablerefercheck\r
41 local useconsultemplate = msbConf.systemConf.useconsultemplate\r
42 \r
43 ---------------------------------------------------------------\r
44 --preCheck:\r
45 --     determine whether it is websocket request \r
46 --     and do internal redirect\r
47 ---------------------------------------------------------------\r
48 if ngx.var.uri == "/" then\r
49         local m, err = ngx.re.match(ngx.var.host, "^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)$","o")\r
50         if m then\r
51                 return ngx.exec("@defaultpage")\r
52         end\r
53 end\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 req_res  = ngx_var.uri\r
66 local svc_type = ngx_var.svc_type\r
67 local key_prefix = svc_get_key_prefix()\r
68 \r
69 local custom_svc_keypattern = tbl_concat({key_prefix,"custom","*"},":")\r
70 \r
71 local get_svckey_custom = function(svcname)\r
72         return tbl_concat({key_prefix,"custom",svcname},":")\r
73 end\r
74 \r
75 local svcnames,err = dbclient.load_customsvcnames(custom_svc_keypattern)\r
76 if not svcnames then\r
77         error_svc_not_found("Failed to load the route table!","keypattern--"..custom_svc_keypattern)\r
78 end\r
79 \r
80 ---------------------------------------------------------------\r
81 --step1:run the match process(check whether the request \r
82 --      match the name in the svcnames one by one) \r
83 --      and return the matched serice info\r
84 ---------------------------------------------------------------\r
85 local matchedsvcname\r
86 local svcinfo\r
87 local svc_key = ""\r
88 --add by wangyg:20160418 special handler for refer\r
89 local matched_usingrefer = false\r
90 --end of add by wangyg:20160418 special handler for refer\r
91 for _, svcname in ipairs(svcnames) do\r
92         if (svcname == "/") then\r
93                 svc_key = get_svckey_custom(svcname)\r
94                 local svc_info,err = dbclient.load_serviceinfo(svc_key)\r
95                 if svc_info and svc_isactive(svc_info)then\r
96                         matchedsvcname = svcname\r
97                         svcinfo = svc_info\r
98                         break\r
99                 end\r
100         end\r
101         local from, to, err = ngx.re.find(req_res, "^"..svcname.."(/(.*))?$", "jo")\r
102         --check whether svcname is the prefix of the req uri\r
103         if from then\r
104                 svc_key = get_svckey_custom(svcname)\r
105                 local svc_info,err = dbclient.load_serviceinfo(svc_key)\r
106                 if svc_info and svc_isactive(svc_info) then \r
107                         matchedsvcname = svcname\r
108                         svcinfo = svc_info\r
109                         break\r
110                 end\r
111         else\r
112                 --do nothing\r
113         end\r
114 end\r
115 ---------------------------------------------------------------\r
116 --step1.1:additional process,test against the refer \r
117 --        similar to step1\r
118 ---------------------------------------------------------------\r
119 --add by wangyg:20160418 special handler for refer\r
120 if not matchedsvcname and enablerefercheck then \r
121         local refer =  ngx_var.http_referer\r
122         if(refer and refer~="") then\r
123                 for _, svcname in ipairs(svcnames) do\r
124                         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
125                         local from, to, err = ngx.re.find(refer, urlreg, "jo")\r
126                         ----check whether svcname is the prefix of the req refer\r
127                         if from then\r
128                                 svc_key = get_svckey_custom(svcname)\r
129                                 local svc_info,err = dbclient.load_serviceinfo(svc_key)\r
130                                 if svc_info and svc_isactive(svc_info) then \r
131                                         matchedsvcname = svcname\r
132                                         svcinfo = svc_info\r
133                                         matched_usingrefer = true\r
134                                         break\r
135                                 end\r
136                         end\r
137                 end\r
138         end\r
139 end\r
140 --end of add by wangyg:20160418 special handler for refer\r
141 \r
142 if not matchedsvcname or tbl_isempty(svcinfo) then\r
143         error_svc_not_found("No route found for this request!","custom not match")\r
144 end\r
145 \r
146 local svc_url = svc_get_url(svcinfo,svc_type)\r
147 \r
148 ---------------------------------------------------------------\r
149 --step2:rewrite the request uri using the svcinfo\r
150 ---------------------------------------------------------------\r
151 local rewrited_uri =""\r
152 if (matchedsvcname == "/") then\r
153         --special handling: if "/" matched, contact directly\r
154         rewrited_uri = svc_url..req_res\r
155 else\r
156         --rewrited_uri = ngx.re.sub(req_res, "^"..matchedsvcname.."(.*)", svc_url.."$1", "o")\r
157         local newuri,n,err = ngx.re.sub(req_res, "^"..matchedsvcname.."(/.*)?", svc_url.."$1", "o")\r
158         --add by wangyg:20160418 special handler for refer\r
159         if(n==0 and matched_usingrefer) then newuri = svc_url..req_res end --special handling if matched using refer\r
160         --end of add by wangyg:20160418 special handler for refer\r
161         rewrited_uri = newuri\r
162 end\r
163 --if (rewrited_uri == "") then rewrited_uri = "/" end --avoid throws internal error when it is empty\r
164 if (rewrited_uri == "") then return ngx.redirect(ngx.var.uri.."/") end \r
165 ngx.req.set_uri(rewrited_uri)\r
166 \r
167 --set the matched service info,used in the proxy_redirect directive \r
168 ngx_var.svc_name = matchedsvcname\r
169 ngx_var.svc_url =  svc_url\r
170 \r
171 --log the route info\r
172 log("matched",matchedsvcname)\r
173 if(matched_usingrefer) then log("matched_usingrefer",true) end \r
174 --log("rewrited_uri",rewrited_uri)\r
175 \r
176 ---------------------------------------------------------------\r
177 --step2.1:store the svcinfo in the context, plugins may use it\r
178 ---------------------------------------------------------------\r
179 ngx_ctx.svcinfo = svcinfo\r
180 \r
181 ---------------------------------------------------------------\r
182 --step3:process the proxy upstream part\r
183 -- con1-using consul template:set the upstream name\r
184 -- con2-using msb balancer:query the backserver list and store in the ctx\r
185 ---------------------------------------------------------------\r
186 --set the http_protocol used by proxy_pass directive\r
187 ngx_var.http_protocol = svc_get_backend_protocol(svcinfo)\r
188 \r
189 if svc_use_own_upstream(svcinfo) then\r
190         local consul_servicename = svcinfo.spec["consulServiceName"]\r
191         if not consul_servicename or consul_servicename == "" then\r
192                 error_upstream_not_found()\r
193         end\r
194         ngx_var.backend = consul_servicename\r
195         ngx.ctx.use_ownupstream = true\r
196 else\r
197         local backservers = svcinfo.spec.nodes\r
198         if tbl_isempty(backservers) then\r
199                 error_svc_not_found("No active backend server found!","key--"..svc_key)\r
200         end\r
201         ngx_ctx.backservers = backservers\r
202         ngx_ctx.svc_key = svc_key\r
203 end