diff --git a/conf/config.yaml b/conf/config.yaml index 9864584a2dc4..db2cbfcc696a 100644 --- a/conf/config.yaml +++ b/conf/config.yaml @@ -10,6 +10,9 @@ apisix: - 127.0.0.1 - 'unix:' # port_admin: 9180 # use a separate port + route_idx: 'uri' # how to create the route index: + # `uri`: only use `uri` for routing + # `host + uri`: use `host + uri` for routing etcd: host: "http://127.0.0.1:2379" # etcd address diff --git a/lua/apisix.lua b/lua/apisix.lua index 67c8fcaef79e..98804f3e854d 100644 --- a/lua/apisix.lua +++ b/lua/apisix.lua @@ -8,10 +8,12 @@ local service_fetch = require("apisix.http.service").get local ssl_match = require("apisix.http.ssl").match local admin_init = require("apisix.admin.init") local get_var = require("resty.ngxvar").fetch +local local_conf = core.config.local_conf local ngx = ngx local get_method = ngx.req.get_method local ngx_exit = ngx.exit local ngx_ERROR = ngx.ERROR +local str_reverse = string.reverse local math = math local match_opts = {} local error = error @@ -153,9 +155,22 @@ function _M.http_access_phase() core.ctx.set_vars_meta(api_ctx) core.table.clear(match_opts) match_opts.method = api_ctx.var.method - match_opts.host = api_ctx.var.host - local ok = router():dispatch2(nil, api_ctx.var.uri, match_opts, api_ctx) + local ok + + if local_conf().apisix + and local_conf().apisix.route_idx == "host+uri" then + local host = api_ctx.var.host + host = host and str_reverse(host) or "[^/]+" + host = host .. api_ctx.var.uri + ok = router():dispatch2(nil, host, match_opts, api_ctx) + core.log.info("match string: ", host) + + else + match_opts.host = api_ctx.var.host + ok = router():dispatch2(nil, api_ctx.var.uri, match_opts, api_ctx) + end + if not ok then core.log.info("not find any matched route") return core.response.exit(404) diff --git a/lua/apisix/http/route.lua b/lua/apisix/http/route.lua index 588aff465784..f7357cc78744 100644 --- a/lua/apisix/http/route.lua +++ b/lua/apisix/http/route.lua @@ -7,6 +7,7 @@ local plugin = require("apisix.plugin") local ipairs = ipairs local type = type local error = error +local str_reverse = string.reverse local routes @@ -33,18 +34,47 @@ local function create_r3_router(routes) end end + local local_conf = core.config.local_conf() + local route_idx = local_conf and local_conf.apisix and + local_conf.apisix.route_idx + for _, route in ipairs(routes) do if type(route) == "table" then idx = idx + 1 - route_items[idx] = { - path = route.value.uri, - method = route.value.methods, - host = route.value.host, - handler = function (params, api_ctx) - api_ctx.matched_params = params - api_ctx.matched_route = route + if route_idx == "host+uri" then + local host = route.value.host + if not host then + host = [=[{domain:[^/]+}]=] + + else + host = str_reverse(host) + if host:sub(#host) == "*" then + host = host:sub(1, #host - 1) .. "{prefix:.*}" + end end - } + + core.log.info("route rule: ", host .. route.value.uri) + route_items[idx] = { + path = host .. route.value.uri, + method = route.value.methods, + handler = function (params, api_ctx) + api_ctx.matched_params = params + api_ctx.matched_route = route + end + } + + else + route_items[idx] = { + path = route.value.uri, + method = route.value.methods, + host = route.value.host, + handler = function (params, api_ctx) + api_ctx.matched_params = params + api_ctx.matched_route = route + end + } + end + end end diff --git a/t/node/match-host-uri.t b/t/node/match-host-uri.t new file mode 100644 index 000000000000..8a4f15f5ce9f --- /dev/null +++ b/t/node/match-host-uri.t @@ -0,0 +1,197 @@ +use t::APISix 'no_plan'; + +repeat_each(1); +log_level('info'); +worker_connections(1024); +no_root_location(); +no_shuffle(); + +sub read_file($) { + my $infile = shift; + open my $in, $infile + or die "cannot open $infile for reading: $!"; + my $cert = do { local $/; <$in> }; + close $in; + $cert; +} + +our $yaml_config = read_file("conf/config.yaml"); +$yaml_config =~ s/node_listen: 9080/node_listen: 1984/; +$yaml_config =~ s/enable_heartbeat: true/enable_heartbeat: false/; +$yaml_config =~ s/route_idx: 'uri'/route_idx: 'host+uri'/; + +run_tests(); + +__DATA__ + +=== TEST 1: set route(id: 1) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "methods": ["GET"], + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "host": "foo.com", + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- yaml_config eval: $::yaml_config +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 2: /not_found +--- request +GET /not_found +--- yaml_config eval: $::yaml_config +--- error_code: 404 +--- response_body eval +qr/404 Not Found/ +--- no_error_log +[error] + + + +=== TEST 3: /not_found +--- request +GET /hello +--- yaml_config eval: $::yaml_config +--- error_code: 404 +--- response_body eval +qr/404 Not Found/ +--- no_error_log +[error] + + + +=== TEST 4: /not_found +--- request +GET /hello +--- yaml_config eval: $::yaml_config +--- more_headers +Host: not_found.com +--- error_code: 404 +--- response_body eval +qr/404 Not Found/ +--- no_error_log +[error] + + + +=== TEST 5: hit routes +--- request +GET /hello +--- yaml_config eval: $::yaml_config +--- more_headers +Host: foo.com +--- response_body +hello world +--- no_error_log +[error] + + + +=== TEST 6: hit routes +--- request +GET /hello +--- yaml_config eval: $::yaml_config +--- more_headers +Host: foo.com +--- response_body +hello world +--- error_log +moc.oof/hello + + + +=== TEST 7: set route(id: 1) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/routes/1', + ngx.HTTP_PUT, + [[{ + "methods": ["GET"], + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin" + }, + "uri": "/hello" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- yaml_config eval: $::yaml_config +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 8: /not_found +--- request +GET /hello2 +--- yaml_config eval: $::yaml_config +--- more_headers +Host: not_found.com +--- error_code: 404 +--- response_body eval +qr/404 Not Found/ +--- no_error_log +[error] + + + +=== TEST 9: hit routes +--- request +GET /hello +--- yaml_config eval: $::yaml_config +--- more_headers +Host: foo.com +--- response_body +hello world +--- no_error_log +[error] +--- LAST + + + +=== TEST 10: hit routes +--- request +GET /hello +--- yaml_config eval: $::yaml_config +--- response_body +hello world +--- no_error_log +[error]