Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: supported to match route by host + uri. #325

Merged
merged 3 commits into from
Jul 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions conf/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 17 additions & 2 deletions lua/apisix.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
46 changes: 38 additions & 8 deletions lua/apisix/http/route.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand All @@ -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

Expand Down
197 changes: 197 additions & 0 deletions t/node/match-host-uri.t
Original file line number Diff line number Diff line change
@@ -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]