You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by me...@apache.org on 2020/08/30 14:43:36 UTC

[apisix] branch master updated: feat: support different modes to pass host to upstream (#2132)

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 <33...@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 <me...@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]