| -- |
| -- 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. |
| -- |
| local require = require |
| local router = require("apisix.utils.router") |
| local radixtree = require("resty.radixtree") |
| local builtin_v1_routes = require("apisix.control.v1") |
| local plugin_mod = require("apisix.plugin") |
| local core = require("apisix.core") |
| |
| local str_sub = string.sub |
| local ipairs = ipairs |
| local pairs = pairs |
| local type = type |
| local ngx = ngx |
| local get_method = ngx.req.get_method |
| |
| |
| local _M = {} |
| |
| |
| local function format_dismod_uri(mod_name, uri) |
| if core.string.has_prefix(uri, "/v1/") then |
| return uri |
| end |
| |
| local tmp = {"/v1/discovery/", mod_name} |
| if not core.string.has_prefix(uri, "/") then |
| core.table.insert(tmp, "/") |
| end |
| core.table.insert(tmp, uri) |
| |
| return core.table.concat(tmp, "") |
| end |
| |
| -- we do not hardcode the discovery module's control api uri |
| local function format_dismod_control_api_uris(mod_name, api_route) |
| if not api_route or #api_route == 0 then |
| return api_route |
| end |
| |
| local clone_route = core.table.clone(api_route) |
| for _, v in ipairs(clone_route) do |
| local uris = v.uris |
| local target_uris = core.table.new(#uris, 0) |
| for _, uri in ipairs(uris) do |
| local target_uri = format_dismod_uri(mod_name, uri) |
| core.table.insert(target_uris, target_uri) |
| end |
| v.uris = target_uris |
| end |
| |
| return clone_route |
| end |
| |
| |
| local fetch_control_api_router |
| do |
| local function register_api_routes(routes, api_routes) |
| for _, route in ipairs(api_routes) do |
| core.table.insert(routes, { |
| methods = route.methods, |
| -- note that it is 'uris' for control API, which is an array of strings |
| paths = route.uris, |
| handler = function (api_ctx) |
| local code, body = route.handler(api_ctx) |
| if code or body then |
| if type(body) == "table" and ngx.header["Content-Type"] == nil then |
| core.response.set_header("Content-Type", "application/json") |
| end |
| |
| core.response.exit(code, body) |
| end |
| end |
| }) |
| end |
| end |
| |
| local routes = {} |
| local v1_routes = {} |
| local function empty_func() end |
| |
| function fetch_control_api_router() |
| core.table.clear(routes) |
| |
| for _, plugin in ipairs(plugin_mod.plugins) do |
| local api_fun = plugin.control_api |
| if api_fun then |
| local api_route = api_fun() |
| register_api_routes(routes, api_route) |
| end |
| end |
| |
| local discovery_type = require("apisix.core.config_local").local_conf().discovery |
| if discovery_type then |
| local discovery = require("apisix.discovery.init").discovery |
| local dump_apis = {} |
| for key, _ in pairs(discovery_type) do |
| local dis_mod = discovery[key] |
| -- if discovery module has control_api method, support it |
| local api_fun = dis_mod.control_api |
| if api_fun then |
| local api_route = api_fun() |
| local format_route = format_dismod_control_api_uris(key, api_route) |
| register_api_routes(routes, format_route) |
| end |
| |
| local dump_data = dis_mod.dump_data |
| if dump_data then |
| local target_uri = format_dismod_uri(key, "/dump") |
| local item = { |
| methods = {"GET"}, |
| uris = {target_uri}, |
| handler = function() |
| return 200, dump_data() |
| end |
| } |
| core.table.insert(dump_apis, item) |
| end |
| end |
| |
| if #dump_apis > 0 then |
| core.log.notice("dump_apis: ", core.json.encode(dump_apis, true)) |
| register_api_routes(routes, dump_apis) |
| end |
| end |
| |
| core.table.clear(v1_routes) |
| register_api_routes(v1_routes, builtin_v1_routes) |
| |
| local v1_router, err = router.new(v1_routes) |
| if not v1_router then |
| return nil, err |
| end |
| |
| core.table.insert(routes, { |
| paths = {"/v1/*"}, |
| filter_fun = function(vars, opts, ...) |
| local uri = str_sub(vars.uri, #"/v1" + 1) |
| return v1_router:dispatch(uri, opts, ...) |
| end, |
| handler = empty_func, |
| }) |
| |
| local with_parameter = false |
| local conf = core.config.local_conf() |
| if conf.apisix.enable_control and conf.apisix.control then |
| if conf.apisix.control.router == "radixtree_uri_with_parameter" then |
| with_parameter = true |
| end |
| end |
| |
| if with_parameter then |
| return radixtree.new(routes) |
| else |
| return router.new(routes) |
| end |
| end |
| |
| end -- do |
| |
| |
| do |
| local match_opts = {} |
| local cached_version |
| local router |
| |
| function _M.match(uri) |
| if cached_version ~= plugin_mod.load_times then |
| local err |
| router, err = fetch_control_api_router() |
| if router == nil then |
| core.log.error("failed to fetch valid api router: ", err) |
| return false |
| end |
| |
| cached_version = plugin_mod.load_times |
| end |
| |
| core.table.clear(match_opts) |
| match_opts.method = get_method() |
| |
| return router:dispatch(uri, match_opts) |
| end |
| |
| end -- do |
| |
| |
| return _M |