This is an automated email from the ASF dual-hosted git repository. membphis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push: new 502310b feat: support different modes to pass host to upstream (#2132) 502310b is described below commit 502310bef6c6b77410e17bf3b805437fe4c705f9 Author: nic-chen <33000667+nic-c...@users.noreply.github.com> AuthorDate: Sun Aug 30 22:43:28 2020 +0800 feat: support different modes to pass host to upstream (#2132) * test: using `httpbin.org` for test cases. * doc: add doc * remove golang apt repository and runtime in travis. * download proto file Co-authored-by: Yuansheng <membp...@gmail.com> --- .travis/linux_apisix_current_luarocks_runner.sh | 1 - .travis/linux_apisix_master_luarocks_runner.sh | 1 - .travis/linux_openresty_mtls_runner.sh | 1 - .travis/linux_openresty_runner.sh | 3 - .travis/linux_tengine_runner.sh | 3 - .travis/osx_openresty_runner.sh | 2 - apisix/admin/upstreams.lua | 13 +++ apisix/init.lua | 43 ++++++++ apisix/schema_def.lua | 7 ++ doc/admin-api.md | 3 + doc/architecture-design.md | 2 + doc/zh-cn/admin-api.md | 2 + doc/zh-cn/architecture-design.md | 2 + t/admin/routes.t | 33 ++++++ t/admin/upstream.t | 59 ++++++++++ t/node/merge-route.t | 3 +- t/node/route-domain.t | 90 +++++++++++++++ t/node/upstream.t | 141 ++++++++++++++++++++++++ 18 files changed, 396 insertions(+), 13 deletions(-) diff --git a/.travis/linux_apisix_current_luarocks_runner.sh b/.travis/linux_apisix_current_luarocks_runner.sh index 0264fc5..5a48932 100755 --- a/.travis/linux_apisix_current_luarocks_runner.sh +++ b/.travis/linux_apisix_current_luarocks_runner.sh @@ -27,7 +27,6 @@ do_install() { sudo apt-get -y update --fix-missing sudo apt-get -y install software-properties-common sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" - sudo add-apt-repository -y ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install openresty-debug lua5.1 liblua5.1-0-dev diff --git a/.travis/linux_apisix_master_luarocks_runner.sh b/.travis/linux_apisix_master_luarocks_runner.sh index 6b63f3a..a7b684c 100755 --- a/.travis/linux_apisix_master_luarocks_runner.sh +++ b/.travis/linux_apisix_master_luarocks_runner.sh @@ -28,7 +28,6 @@ do_install() { sudo apt-get -y update --fix-missing sudo apt-get -y install software-properties-common sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" - sudo add-apt-repository -y ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install openresty-debug lua5.1 liblua5.1-0-dev diff --git a/.travis/linux_openresty_mtls_runner.sh b/.travis/linux_openresty_mtls_runner.sh index d0a7ceb..876c868 100755 --- a/.travis/linux_openresty_mtls_runner.sh +++ b/.travis/linux_openresty_mtls_runner.sh @@ -44,7 +44,6 @@ do_install() { sudo apt-get -y update --fix-missing sudo apt-get -y install software-properties-common sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" - sudo add-apt-repository -y ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install openresty-debug lua5.1 liblua5.1-0-dev diff --git a/.travis/linux_openresty_runner.sh b/.travis/linux_openresty_runner.sh index 6cc48b4..42ff254 100755 --- a/.travis/linux_openresty_runner.sh +++ b/.travis/linux_openresty_runner.sh @@ -59,7 +59,6 @@ do_install() { sudo apt-get -y update --fix-missing sudo apt-get -y install software-properties-common sudo add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" - sudo add-apt-repository -y ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install openresty-debug lua5.1 liblua5.1-0-dev @@ -75,8 +74,6 @@ do_install() { sudo luarocks install luacheck > build.log 2>&1 || (cat build.log && exit 1) - export GO111MOUDULE=on - if [ ! -f "build-cache/apisix-master-0.rockspec" ]; then create_lua_deps diff --git a/.travis/linux_tengine_runner.sh b/.travis/linux_tengine_runner.sh index ec73c16..2404978 100755 --- a/.travis/linux_tengine_runner.sh +++ b/.travis/linux_tengine_runner.sh @@ -228,7 +228,6 @@ do_install() { sudo apt-get -y update --fix-missing sudo apt-get -y install software-properties-common - sudo add-apt-repository -y ppa:longsleep/golang-backports sudo apt-get update sudo apt-get install lua5.1 liblua5.1-0-dev @@ -244,8 +243,6 @@ do_install() { cd .. rm -rf luarocks-2.4.4 - export GO111MOUDULE=on - if [ ! -f "build-cache/apisix-master-0.rockspec" ]; then create_lua_deps diff --git a/.travis/osx_openresty_runner.sh b/.travis/osx_openresty_runner.sh index b31e9de..6070f02 100755 --- a/.travis/osx_openresty_runner.sh +++ b/.travis/osx_openresty_runner.sh @@ -28,12 +28,10 @@ before_install() { fi HOMEBREW_NO_AUTO_UPDATE=1 brew install perl cpanminus etcd luarocks openresty/brew/openresty-debug redis@3.2 - brew upgrade go sudo sed -i "" "s/requirepass/#requirepass/g" /usr/local/etc/redis.conf brew services start redis@3.2 - export GO111MOUDULE=on sudo cpanm --notest Test::Nginx >build.log 2>&1 || (cat build.log && exit 1) export_or_prefix luarocks install --lua-dir=${OPENRESTY_PREFIX}/luajit luacov-coveralls --local --tree=deps diff --git a/apisix/admin/upstreams.lua b/apisix/admin/upstreams.lua index b74f46e..8f03e89 100644 --- a/apisix/admin/upstreams.lua +++ b/apisix/admin/upstreams.lua @@ -54,6 +54,18 @@ local function check_upstream_conf(conf) return false, "invalid configuration: " .. err end + if conf.pass_host == "node" and conf.nodes and + core.table.nkeys(conf.nodes) ~= 1 + then + return false, "only support single node for `node` mode currently" + end + + if conf.pass_host == "rewrite" and + (conf.upstream_host == nil or conf.upstream_host == "") + then + return false, "`upstream_host` can't be empty when `pass_host` is `rewrite`" + end + if conf.type ~= "chash" then return true end @@ -77,6 +89,7 @@ local function check_upstream_conf(conf) return false, "invalid configuration: " .. err end end + return true end diff --git a/apisix/init.lua b/apisix/init.lua index 3a69534..6e20cfd 100644 --- a/apisix/init.lua +++ b/apisix/init.lua @@ -203,6 +203,7 @@ local function parse_domain_for_nodes(nodes) if ip then local new_node = core.table.clone(node) new_node.host = ip + new_node.domain = host core.table.insert(new_nodes, new_node) end @@ -297,6 +298,36 @@ local function return_direct(...) end +local function set_upstream_host(api_ctx) + local pass_host = api_ctx.pass_host or "pass" + if pass_host == "pass" then + return + end + + if pass_host == "rewrite" then + api_ctx.var.upstream_host = api_ctx.upstream_host + return + end + + -- only support single node for `node` mode currently + local host + local up_conf = api_ctx.upstream_conf + local nodes_count = up_conf.nodes and #up_conf.nodes or 0 + if nodes_count == 1 then + local node = up_conf.nodes[1] + if node.domain and #node.domain > 0 then + host = node.domain + else + host = node.host + end + end + + if host then + api_ctx.var.upstream_host = host + end +end + + function _M.http_access_phase() local ngx_ctx = ngx.ctx local api_ctx = ngx_ctx.api_ctx @@ -429,6 +460,11 @@ function _M.http_access_phase() if upstream.value.enable_websocket then enable_websocket = true end + + if upstream.value.pass_host then + api_ctx.pass_host = upstream.value.pass_host + api_ctx.upstream_host = upstream.value.upstream_host + end end else @@ -455,6 +491,11 @@ function _M.http_access_phase() if route.value.upstream and route.value.upstream.enable_websocket then enable_websocket = true end + + if route.value.upstream and route.value.upstream.pass_host then + api_ctx.pass_host = route.value.upstream.pass_host + api_ctx.upstream_host = route.value.upstream.upstream_host + end end if enable_websocket then @@ -490,6 +531,8 @@ function _M.http_access_phase() core.log.error("failed to parse upstream: ", err) core.response.exit(500) end + + set_upstream_host(api_ctx) end diff --git a/apisix/schema_def.lua b/apisix/schema_def.lua index a6656b2..52a7f42 100644 --- a/apisix/schema_def.lua +++ b/apisix/schema_def.lua @@ -332,6 +332,13 @@ local upstream_schema = { description = "enable websocket for request", type = "boolean" }, + pass_host = { + description = "mod of host passing", + type = "string", + enum = {"pass", "node", "rewrite"}, + default = "pass" + }, + upstream_host = host_def, name = {type = "string", maxLength = 50}, desc = {type = "string", maxLength = 256}, service_name = {type = "string", maxLength = 50}, diff --git a/doc/admin-api.md b/doc/admin-api.md index 3b8ac89..e197421 100644 --- a/doc/admin-api.md +++ b/doc/admin-api.md @@ -504,6 +504,9 @@ In addition to the basic complex equalization algorithm selection, APISIX's Upst |timeout|optional| Set the timeout for connection, sending and receiving messages. | |name |optional|Identifies upstream names| |desc |optional|upstream usage scenarios, and more.| +|pass_host |optional|`pass` pass the client request host, `node` not pass the client request host, using the upstream node host, `rewrite` rewrite host by the configured `upstream_host`.| +|upstream_host |optional|This option is only valid if the `pass_host` is `rewrite`.| + Config Example: diff --git a/doc/architecture-design.md b/doc/architecture-design.md index a8593b8..34a8af8 100644 --- a/doc/architecture-design.md +++ b/doc/architecture-design.md @@ -265,6 +265,8 @@ In addition to the basic complex equalization algorithm selection, APISIX's Upst |enable_websocket|optional| enable `websocket`(boolean), default `false`.| |timeout|optional| Set the timeout for connection, sending and receiving messages. | |desc |optional|Identifies route names, usage scenarios, and more.| +|pass_host |optional|`pass` pass the client request host, `node` not pass the client request host, using the upstream node host, `rewrite` rewrite host by the configured `upstream_host`.| +|upstream_host |optional|This option is only valid if the `pass_host` is `rewrite`.| Create an upstream object use case: diff --git a/doc/zh-cn/admin-api.md b/doc/zh-cn/admin-api.md index 529d102..0597ef9 100644 --- a/doc/zh-cn/admin-api.md +++ b/doc/zh-cn/admin-api.md @@ -518,6 +518,8 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上 |hash_on |可选 |辅助|该参数作为一致性 hash 的入参|| |name |可选 |辅助|标识上游服务名称、使用场景等。|| |desc |可选 |辅助|上游服务描述、使用场景等。|| +|pass_host |可选|枚举|`pass` 透传客户端请求的 host, `node` 不透传客户端请求的 host, 使用 upstream node 配置的 host, `rewrite` 使用 `upstream_host` 配置的值重写 host 。|| +|upstream_host |可选|辅助|只在 `pass_host` 配置为 `rewrite` 时有效。|| upstream 对象 json 配置内容: diff --git a/doc/zh-cn/architecture-design.md b/doc/zh-cn/architecture-design.md index 37ff449..0b5eabf 100644 --- a/doc/zh-cn/architecture-design.md +++ b/doc/zh-cn/architecture-design.md @@ -273,6 +273,8 @@ APISIX 的 Upstream 除了基本的复杂均衡算法选择外,还支持对上 |checks |可选|配置健康检查的参数,详细可参考[health-check](../health-check.md)| |retries |可选|使用底层的 Nginx 重试机制将请求传递给下一个上游,默认 APISIX 会启用重试机制,根据配置的后端节点个数设置重试次数,如果此参数显式被设置将会覆盖系统默认设置的重试次数。| |enable_websocket|可选| 是否启用 `websocket`(布尔值),默认不启用| +|pass_host |可选|`pass` 透传客户端请求的 host, `node` 不透传客户端请求的 host, 使用 upstream node 配置的 host, `rewrite` 使用 `upstream_host` 配置的值重写 host 。| +|upstream_host |可选|只在 `pass_host` 配置为 `rewrite` 时有效。| `hash_on` 比较复杂,这里专门说明下: diff --git a/t/admin/routes.t b/t/admin/routes.t index afa846a..9d98b25 100644 --- a/t/admin/routes.t +++ b/t/admin/routes.t @@ -2147,3 +2147,36 @@ GET /t {"error_msg":"invalid configuration: value wasn't supposed to match schema"} --- no_error_log [error] + + + +=== TEST 59: invalid route: multi nodes with `node` mode to pass host +--- 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", "GET"], + "upstream": { + "nodes": { + "httpbin.org:8080": 1, + "test.com:8080": 1 + }, + "type": "roundrobin", + "pass_host": "node" + }, + "uri": "/index.html" + }]] + ) + + ngx.status = code + ngx.print(body) + } + } +--- request +GET /t +--- error_code: 400 +--- no_error_log +[error] diff --git a/t/admin/upstream.t b/t/admin/upstream.t index 02cd5e0..3dc116d 100644 --- a/t/admin/upstream.t +++ b/t/admin/upstream.t @@ -1578,3 +1578,62 @@ GET /t {"error_msg":"invalid configuration: property \"retries\" validation failed: expected -1 to be greater than 0"} --- no_error_log [error] + + + +=== TEST 48: invalid route: multi nodes with `node` mode to pass host +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PUT, + [[{ + "nodes": { + "httpbin.org:8080": 1, + "test.com:8080": 1 + }, + "type": "roundrobin", + "pass_host": "node" + }]] + ) + + ngx.status = code + ngx.print(body) + } + } +--- request +GET /t +--- error_code: 400 +--- no_error_log +[error] + + + +=== TEST 49: invalid route: empty `upstream_host` when `pass_host` is `rewrite` +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PUT, + [[{ + "nodes": { + "httpbin.org:8080": 1, + "test.com:8080": 1 + }, + "type": "roundrobin", + "pass_host": "rewrite", + "upstream_host": "" + }]] + ) + + ngx.status = code + ngx.print(body) + } + } +--- request +GET /t +--- error_code: 400 +--- no_error_log +[error] diff --git a/t/node/merge-route.t b/t/node/merge-route.t index 772ab0d..988699a 100644 --- a/t/node/merge-route.t +++ b/t/node/merge-route.t @@ -280,8 +280,7 @@ passed "host": "httpbin.org", "plugins": { "proxy-rewrite": { - "scheme": "https" - + "scheme": "https" } }, "service_id": "1" diff --git a/t/node/route-domain.t b/t/node/route-domain.t index 05bc3d9..6fbd31d 100644 --- a/t/node/route-domain.t +++ b/t/node/route-domain.t @@ -80,3 +80,93 @@ hello world [error] --- error_log eval qr/dns resolver domain: baidu.com to \d+.\d+.\d+.\d+/ + + + +=== TEST 4: set route(id: 1, using `rewrite` mode to pass upstream host) +--- 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, + [[{ + "upstream": { + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin", + "pass_host": "rewrite", + "upstream_host": "httpbin.org" + }, + "uri": "/uri" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 5: hit route +--- request +GET /uri +--- response_body eval +qr/host: httpbin.org/ +--- no_error_log +[error] + + + +=== TEST 6: set route(id: 1, using `node` mode to pass upstream host) +--- 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, + [[{ + "upstream": { + "nodes": { + "httpbin.org:80": 1 + }, + "type": "roundrobin", + "desc": "new upstream", + "pass_host": "node" + }, + "uri": "/get" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 7: hit route +--- request +GET /get +--- response_body eval +qr/"Host": "httpbin.org"/ +--- no_error_log +[error] diff --git a/t/node/upstream.t b/t/node/upstream.t index f631971..ef88bbd 100644 --- a/t/node/upstream.t +++ b/t/node/upstream.t @@ -262,3 +262,144 @@ GET /t [delete] code: 404 --- no_error_log [error] + + + +=== TEST 11: set upstream(id: 1, using `node` mode to pass upstream host) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PUT, + [[{ + "nodes": { + "httpbin.org:80": 1 + }, + "type": "roundrobin", + "desc": "new upstream", + "pass_host": "node" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 12: set route(id: 1, using `node` mode to pass upstream host) +--- 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, + [[{ + "uri": "/get", + "upstream_id": "1" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 13: hit route +--- request +GET /get +--- response_body eval +qr/"Host": "httpbin.org"/ +--- no_error_log +[error] + + + +=== TEST 14: set upstream(id: 1, using `rewrite` mode to pass upstream host) +--- config + location /t { + content_by_lua_block { + local t = require("lib.test_admin").test + local code, body = t('/apisix/admin/upstreams/1', + ngx.HTTP_PUT, + [[{ + "nodes": { + "127.0.0.1:1980": 1 + }, + "type": "roundrobin", + "desc": "new upstream", + "pass_host": "rewrite", + "upstream_host": "httpbin.org" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 15: set route(id: 1, using `rewrite` mode to pass upstream host) +--- 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, + [[{ + "uri": "/uri", + "upstream_id": "1" + }]] + ) + + if code >= 300 then + ngx.status = code + end + ngx.say(body) + } + } +--- request +GET /t +--- response_body +passed +--- no_error_log +[error] + + + +=== TEST 16: hit route +--- request +GET /uri +--- response_body eval +qr/host: httpbin.org/ +--- no_error_log +[error]