You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2022/05/10 02:10:19 UTC
[apisix] branch master updated: feat(ext-plugin): support hook response body (#6968)
This is an automated email from the ASF dual-hosted git repository.
spacewander 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 c32caf3b1 feat(ext-plugin): support hook response body (#6968)
c32caf3b1 is described below
commit c32caf3b113c95ee086792c1de78e2a0533690ec
Author: soulbird <zh...@outlook.com>
AuthorDate: Tue May 10 10:10:14 2022 +0800
feat(ext-plugin): support hook response body (#6968)
---
apisix/constants.lua | 1 +
apisix/plugins/ext-plugin-post-resp.lua | 172 +++++++++++++
apisix/plugins/ext-plugin/init.lua | 108 +++++++-
conf/config-default.yaml | 1 +
rockspec/apisix-master-0.rockspec | 2 +-
t/admin/plugins.t | 1 +
t/lib/ext-plugin.lua | 111 ++++++++
t/plugin/ext-plugin/response.t | 431 ++++++++++++++++++++++++++++++++
t/plugin/ext-plugin/sanity.t | 19 +-
9 files changed, 842 insertions(+), 4 deletions(-)
diff --git a/apisix/constants.lua b/apisix/constants.lua
index f49e81d1c..cf04e890c 100644
--- a/apisix/constants.lua
+++ b/apisix/constants.lua
@@ -19,6 +19,7 @@ return {
RPC_PREPARE_CONF = 1,
RPC_HTTP_REQ_CALL = 2,
RPC_EXTRA_INFO = 3,
+ RPC_HTTP_RESP_CALL = 4,
HTTP_ETCD_DIRECTORY = {
["/upstreams"] = true,
["/plugins"] = true,
diff --git a/apisix/plugins/ext-plugin-post-resp.lua b/apisix/plugins/ext-plugin-post-resp.lua
new file mode 100644
index 000000000..e6156804c
--- /dev/null
+++ b/apisix/plugins/ext-plugin-post-resp.lua
@@ -0,0 +1,172 @@
+--
+-- 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 core = require("apisix.core")
+local ext = require("apisix.plugins.ext-plugin.init")
+local constants = require("apisix.constants")
+local http = require("resty.http")
+
+local ngx = ngx
+local ngx_print = ngx.print
+local ngx_flush = ngx.flush
+local string = string
+local str_sub = string.sub
+
+
+local name = "ext-plugin-post-resp"
+local _M = {
+ version = 0.1,
+ priority = -4000,
+ name = name,
+ schema = ext.schema,
+}
+
+
+local function include_req_headers(ctx)
+ -- TODO: handle proxy_set_header
+ return core.request.headers(ctx)
+end
+
+
+local function close(http_obj)
+ -- TODO: keepalive
+ local ok, err = http_obj:close()
+ if not ok then
+ core.log.error("close http object failed: ", err)
+ end
+end
+
+
+local function get_response(ctx, http_obj)
+ local ok, err = http_obj:connect({
+ scheme = ctx.upstream_scheme,
+ host = ctx.picked_server.host,
+ port = ctx.picked_server.port,
+ })
+
+ if not ok then
+ return nil, err
+ end
+ -- TODO: set timeout
+ local uri, args
+ if ctx.var.upstream_uri == "" then
+ -- use original uri instead of rewritten one
+ uri = ctx.var.uri
+ else
+ uri = ctx.var.upstream_uri
+
+ -- the rewritten one may contain new args
+ local index = core.string.find(uri, "?")
+ if index then
+ local raw_uri = uri
+ uri = str_sub(raw_uri, 1, index - 1)
+ args = str_sub(raw_uri, index + 1)
+ end
+ end
+ local params = {
+ path = uri,
+ query = args or ctx.var.args,
+ headers = include_req_headers(ctx),
+ method = core.request.get_method(),
+ }
+
+ local body, err = core.request.get_body()
+ if err then
+ return nil, err
+ end
+
+ if body then
+ params["body"] = body
+ end
+
+ local res, err = http_obj:request(params)
+ if not res then
+ return nil, err
+ end
+
+ return res, err
+end
+
+
+local function send_response(res, code)
+ ngx.status = code or res.status
+
+ local reader = res.body_reader
+ repeat
+ local chunk, ok, read_err, print_err, flush_err
+ -- TODO: HEAD or 304
+ chunk, read_err = reader()
+ if read_err then
+ return "read response failed: ".. (read_err or "")
+ end
+
+ if chunk then
+ ok, print_err = ngx_print(chunk)
+ if not ok then
+ return "output response failed: ".. (print_err or "")
+ end
+ ok, flush_err = ngx_flush(true)
+ if not ok then
+ core.log.warn("flush response failed: ", flush_err)
+ end
+ end
+ until not chunk
+
+ return nil
+end
+
+
+
+function _M.check_schema(conf)
+ return core.schema.check(_M.schema, conf)
+end
+
+
+function _M.before_proxy(conf, ctx)
+ local http_obj = http.new()
+ local res, err = get_response(ctx, http_obj)
+ if not res or err then
+ core.log.error("failed to request: ", err or "")
+ close(http_obj)
+ return 502
+ end
+ ctx.runner_ext_response = res
+
+ core.log.info("response info, status: ", res.status)
+ core.log.info("response info, headers: ", core.json.delay_encode(res.headers))
+
+ local code, body = ext.communicate(conf, ctx, name, constants.RPC_HTTP_RESP_CALL)
+ if body then
+ close(http_obj)
+ -- if the body is changed, the code will be set.
+ return code, body
+ end
+ core.log.info("ext-plugin will send response")
+
+ -- send origin response, status maybe changed.
+ err = send_response(res, code)
+ close(http_obj)
+
+ if err then
+ core.log.error(err)
+ return not ngx.headers_sent and 502 or nil
+ end
+
+ core.log.info("ext-plugin send response succefully")
+end
+
+
+return _M
diff --git a/apisix/plugins/ext-plugin/init.lua b/apisix/plugins/ext-plugin/init.lua
index c37b4ab83..b575ba45f 100644
--- a/apisix/plugins/ext-plugin/init.lua
+++ b/apisix/plugins/ext-plugin/init.lua
@@ -24,6 +24,8 @@ local http_req_call_resp = require("A6.HTTPReqCall.Resp")
local http_req_call_action = require("A6.HTTPReqCall.Action")
local http_req_call_stop = require("A6.HTTPReqCall.Stop")
local http_req_call_rewrite = require("A6.HTTPReqCall.Rewrite")
+local http_resp_call_req = require("A6.HTTPRespCall.Req")
+local http_resp_call_resp = require("A6.HTTPRespCall.Resp")
local extra_info = require("A6.ExtraInfo.Info")
local extra_info_req = require("A6.ExtraInfo.Req")
local extra_info_var = require("A6.ExtraInfo.Var")
@@ -680,6 +682,107 @@ local rpc_handlers = {
return true
end,
+ nil, -- ignore RPC_EXTRA_INFO, already processed during RPC_HTTP_REQ_CALL interaction
+ function (conf, ctx, sock, entry)
+ local lrucache_id = core.lrucache.plugin_ctx_id(ctx, entry)
+ local token, err = core.lrucache.plugin_ctx(lrucache, ctx, entry, rpc_call,
+ constants.RPC_PREPARE_CONF, conf, ctx,
+ lrucache_id)
+ if not token then
+ return nil, err
+ end
+
+ builder:Clear()
+ local var = ctx.var
+
+ local res = ctx.runner_ext_response
+ local textEntries = {}
+ local hdrs = res.headers
+ for key, val in pairs(hdrs) do
+ local ty = type(val)
+ if ty == "table" then
+ for _, v in ipairs(val) do
+ core.table.insert(textEntries, build_headers(var, builder, key, v))
+ end
+ else
+ core.table.insert(textEntries, build_headers(var, builder, key, val))
+ end
+ end
+ local len = #textEntries
+ http_resp_call_req.StartHeadersVector(builder, len)
+ for i = len, 1, -1 do
+ builder:PrependUOffsetTRelative(textEntries[i])
+ end
+ local hdrs_vec = builder:EndVector(len)
+
+ local id = generate_id()
+ local status = res.status
+
+ http_resp_call_req.Start(builder)
+ http_resp_call_req.AddId(builder, id)
+ http_resp_call_req.AddStatus(builder, status)
+ http_resp_call_req.AddConfToken(builder, token)
+ http_resp_call_req.AddHeaders(builder, hdrs_vec)
+
+ local req = http_resp_call_req.End(builder)
+ builder:Finish(req)
+
+ local ok, err = send(sock, constants.RPC_HTTP_RESP_CALL, builder:Output())
+ if not ok then
+ return nil, "failed to send RPC_HTTP_RESP_CALL: " .. err
+ end
+
+ local ty, resp = receive(sock)
+ if ty == nil then
+ return nil, "failed to receive RPC_HTTP_RESP_CALL: " .. resp
+ end
+
+ if ty ~= constants.RPC_HTTP_RESP_CALL then
+ return nil, "failed to receive RPC_HTTP_RESP_CALL: unexpected type " .. ty
+ end
+
+ local buf = flatbuffers.binaryArray.New(resp)
+ local call_resp = http_resp_call_resp.GetRootAsResp(buf, 0)
+ local len = call_resp:HeadersLength()
+ if len > 0 then
+ local resp_headers = {}
+ for i = 1, len do
+ local entry = call_resp:Headers(i)
+ local name = str_lower(entry:Name())
+ if not exclude_resp_header[name] then
+ if resp_headers[name] == nil then
+ core.response.set_header(name, entry:Value())
+ resp_headers[name] = true
+ else
+ core.response.add_header(name, entry:Value())
+ end
+ end
+ end
+ else
+ -- Filter out origin headeres
+ for k, v in pairs(res.headers) do
+ if not exclude_resp_header[str_lower(k)] then
+ core.response.set_header(k, v)
+ end
+ end
+ end
+
+ local body
+ local len = call_resp:BodyLength()
+ if len > 0 then
+ -- TODO: support empty body
+ body = call_resp:BodyAsString()
+ end
+ local code = call_resp:Status()
+ core.log.info("recv resp, code: ", code, " body: ", body, " len: ", len)
+
+ if code == 0 then
+ -- runner changes body only, we should set code.
+ code = body and res.status or nil
+ end
+
+ return true, nil, code, body
+ end
}
@@ -719,12 +822,13 @@ local function recreate_lrucache()
end
-function _M.communicate(conf, ctx, plugin_name)
+function _M.communicate(conf, ctx, plugin_name, rpc_cmd)
local ok, err, code, body
local tries = 0
+ local ty = rpc_cmd and rpc_cmd or constants.RPC_HTTP_REQ_CALL
while tries < 3 do
tries = tries + 1
- ok, err, code, body = rpc_call(constants.RPC_HTTP_REQ_CALL, conf, ctx, plugin_name)
+ ok, err, code, body = rpc_call(ty, conf, ctx, plugin_name)
if ok then
if code then
return code, body
diff --git a/conf/config-default.yaml b/conf/config-default.yaml
index 0888743dd..ae3f151a7 100644
--- a/conf/config-default.yaml
+++ b/conf/config-default.yaml
@@ -402,6 +402,7 @@ plugins: # plugin list (sorted by priority)
- openwhisk # priority: -1901
- serverless-post-function # priority: -2000
- ext-plugin-post-req # priority: -3000
+ - ext-plugin-post-resp # priority: -4000
stream_plugins: # sorted by priority
- ip-restriction # priority: 3000
diff --git a/rockspec/apisix-master-0.rockspec b/rockspec/apisix-master-0.rockspec
index e75c13e13..af447f1bd 100644
--- a/rockspec/apisix-master-0.rockspec
+++ b/rockspec/apisix-master-0.rockspec
@@ -67,7 +67,7 @@ dependencies = {
"luasec = 0.9-1",
"lua-resty-consul = 0.3-2",
"penlight = 1.9.2-1",
- "ext-plugin-proto = 0.4.0",
+ "ext-plugin-proto = 0.5.0",
"casbin = 1.26.0",
"api7-snowflake = 2.0-1",
"inspect == 3.1.1",
diff --git a/t/admin/plugins.t b/t/admin/plugins.t
index 2557da750..a639d3af7 100644
--- a/t/admin/plugins.t
+++ b/t/admin/plugins.t
@@ -127,6 +127,7 @@ azure-functions
openwhisk
serverless-post-function
ext-plugin-post-req
+ext-plugin-post-resp
diff --git a/t/lib/ext-plugin.lua b/t/lib/ext-plugin.lua
index c74464eaa..33bb32b15 100644
--- a/t/lib/ext-plugin.lua
+++ b/t/lib/ext-plugin.lua
@@ -29,6 +29,8 @@ local http_req_call_resp = require("A6.HTTPReqCall.Resp")
local http_req_call_action = require("A6.HTTPReqCall.Action")
local http_req_call_stop = require("A6.HTTPReqCall.Stop")
local http_req_call_rewrite = require("A6.HTTPReqCall.Rewrite")
+local http_resp_call_req = require("A6.HTTPRespCall.Req")
+local http_resp_call_resp = require("A6.HTTPRespCall.Resp")
local extra_info = require("A6.ExtraInfo.Info")
local extra_info_req = require("A6.ExtraInfo.Req")
local extra_info_var = require("A6.ExtraInfo.Var")
@@ -440,6 +442,115 @@ function _M.go(case)
local req = http_req_call_resp.End(builder)
builder:Finish(req)
data = builder:Output()
+
+ elseif ty == constants.RPC_HTTP_RESP_CALL then
+ local buf = flatbuffers.binaryArray.New(data)
+ local call_req = http_resp_call_req.GetRootAsReq(buf, 0)
+ if case.check_input then
+ assert(call_req:Id() == 0)
+ assert(call_req:ConfToken() == 233)
+ assert(call_req:Status() == 200)
+ local len = call_req:HeadersLength()
+
+ local headers = {}
+ for i = 1, len do
+ local entry = call_req:Headers(i)
+ local r = headers[entry:Name()]
+ if r then
+ headers[entry:Name()] = {r, entry:Value()}
+ else
+ headers[entry:Name()] = entry:Value() or true
+ end
+ end
+ assert(json.encode(headers), '{"Connection":"close","Content-Length":"12",' ..
+ '"Content-Type":"text/plain","Server":"openresty"}')
+ http_resp_call_resp.Start(builder)
+
+ elseif case.modify_body then
+ local len = 3
+ http_resp_call_resp.StartBodyVector(builder, len)
+ builder:PrependByte(string.byte("t"))
+ builder:PrependByte(string.byte("a"))
+ builder:PrependByte(string.byte("c"))
+ local b = builder:EndVector(len)
+
+
+ http_resp_call_resp.Start(builder)
+ http_resp_call_resp.AddBody(builder, b)
+
+ elseif case.modify_header then
+ local len = call_req:HeadersLength()
+
+ local headers = {}
+ for i = 1, len do
+ local entry = call_req:Headers(i)
+ local r = headers[entry:Name()]
+ if r then
+ headers[entry:Name()] = {r, entry:Value()}
+ else
+ headers[entry:Name()] = entry:Value() or true
+ end
+ end
+
+ if case.same_header then
+ headers["x-same"] = {"one", "two"}
+ else
+ local runner = headers["x-runner"]
+ if runner and runner == "Go-runner" then
+ headers["x-runner"] = "Test-Runner"
+ end
+ end
+
+ local i = 1
+ local textEntries = {}
+ for k, v in pairs(headers) do
+ local name = builder:CreateString(k)
+ if type(v) == "table" then
+ for j = 1, #v do
+ local value = builder:CreateString(v[j])
+ text_entry.Start(builder)
+ text_entry.AddName(builder, name)
+ text_entry.AddValue(builder, value)
+ local c = text_entry.End(builder)
+ textEntries[i] = c
+ i = i + 1
+ end
+ else
+ local value = builder:CreateString(v)
+ text_entry.Start(builder)
+ text_entry.AddName(builder, name)
+ text_entry.AddValue(builder, value)
+ local c = text_entry.End(builder)
+ textEntries[i] = c
+ i = i + 1
+ end
+ end
+
+ len = #textEntries
+ http_resp_call_resp.StartHeadersVector(builder, len)
+ for i = len, 1, -1 do
+ builder:PrependUOffsetTRelative(textEntries[i])
+ end
+ local vec = builder:EndVector(len)
+
+ http_resp_call_resp.Start(builder)
+ http_resp_call_resp.AddHeaders(builder, vec)
+
+ elseif case.modify_status then
+ local status = call_req:Status()
+ if status == 200 then
+ status = 304
+ end
+ http_resp_call_resp.Start(builder)
+ http_resp_call_resp.AddStatus(builder, status)
+
+ else
+ http_resp_call_resp.Start(builder)
+ end
+
+ local resp = http_resp_call_resp.End(builder)
+ builder:Finish(resp)
+ data = builder:Output()
end
local ok, err = ext.send(sock, ty, data)
diff --git a/t/plugin/ext-plugin/response.t b/t/plugin/ext-plugin/response.t
new file mode 100644
index 000000000..2500e5db0
--- /dev/null
+++ b/t/plugin/ext-plugin/response.t
@@ -0,0 +1,431 @@
+#
+# 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.
+#
+use t::APISIX 'no_plan';
+
+repeat_each(1);
+no_long_string();
+no_root_location();
+no_shuffle();
+
+add_block_preprocessor(sub {
+ my ($block) = @_;
+
+ $block->set_value("stream_conf_enable", 1);
+
+ if (!defined $block->extra_stream_config) {
+ my $stream_config = <<_EOC_;
+ server {
+ listen unix:\$TEST_NGINX_HTML_DIR/nginx.sock;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({})
+ }
+ }
+
+_EOC_
+ $block->set_value("extra_stream_config", $stream_config);
+ }
+
+ my $unix_socket_path = $ENV{"TEST_NGINX_HTML_DIR"} . "/nginx.sock";
+ my $cmd = $block->ext_plugin_cmd // "['sleep', '5s']";
+ my $extra_yaml_config = <<_EOC_;
+ext-plugin:
+ path_for_test: $unix_socket_path
+ cmd: $cmd
+_EOC_
+
+ $block->set_value("extra_yaml_config", $extra_yaml_config);
+
+ if (!$block->request) {
+ $block->set_value("request", "GET /t");
+ }
+
+ if (!$block->error_log) {
+ $block->set_value("no_error_log", "[error]\n[alert]");
+ }
+});
+
+run_tests;
+
+__DATA__
+
+=== TEST 1: add route
+--- config
+ location /t {
+ content_by_lua_block {
+ local json = require("toolkit.json")
+ local t = require("lib.test_admin")
+
+ local code, message, res = t.test('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/*",
+ "plugins": {
+ "ext-plugin-post-resp": {
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(message)
+ return
+ end
+
+ ngx.say(message)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 2: check input
+--- request
+GET /hello
+--- extra_stream_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({check_input = true})
+ }
+ }
+--- error_code: 200
+--- response_body
+hello world
+
+
+
+=== TEST 3: modify body
+--- request
+GET /hello
+--- extra_stream_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({modify_body = true})
+ }
+ }
+--- error_code: 200
+--- response_body chomp
+cat
+
+
+
+=== TEST 4: modify header
+--- request
+GET /hello
+--- extra_stream_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({modify_header = true})
+ }
+ }
+--- more_headers
+resp-X-Runner: Go-runner
+--- error_code: 200
+--- response_headers
+X-Runner: Test-Runner
+--- response_body
+hello world
+
+
+
+=== TEST 5: modify same response headers
+--- request
+GET /hello
+--- extra_stream_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({modify_header = true, same_header = true})
+ }
+ }
+--- error_code: 200
+--- response_headers
+X-Same: one, two
+--- response_body
+hello world
+
+
+
+=== TEST 6: modify status
+--- request
+GET /hello
+--- extra_stream_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({modify_status = true})
+ }
+ }
+--- error_code: 304
+
+
+
+=== TEST 7: default allow_degradation
+--- config
+ location /t {
+ content_by_lua_block {
+ local json = require("toolkit.json")
+ local t = require("lib.test_admin")
+
+ local code, message, res = t.test('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/hello",
+ "plugins": {
+ "ext-plugin-post-resp": {
+ "conf": [
+ {"name":"foo", "value":"bar"}
+ ]
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(message)
+ return
+ end
+
+ ngx.say(message)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 8: ext-plugin-resp wrong, req reject
+--- request
+GET /hello
+--- extra_stream_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock1;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({})
+ }
+ }
+--- error_code: 503
+--- error_log eval
+qr/failed to connect to the unix socket/
+
+
+
+=== TEST 9: open allow_degradation
+--- config
+ location /t {
+ content_by_lua_block {
+ local json = require("toolkit.json")
+ local t = require("lib.test_admin")
+
+ local code, message, res = t.test('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/hello",
+ "plugins": {
+ "ext-plugin-post-req": {
+ "conf": [
+ {"name":"foo", "value":"bar"}
+ ],
+ "allow_degradation": true
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(message)
+ return
+ end
+
+ ngx.say(message)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 10: ext-plugin-resp wrong, req access
+--- request
+GET /hello
+--- extra_stream_config
+ server {
+ listen unix:$TEST_NGINX_HTML_DIR/nginx.sock1;
+
+ content_by_lua_block {
+ local ext = require("lib.ext-plugin")
+ ext.go({})
+ }
+ }
+--- response_body
+hello world
+--- error_log eval
+qr/Plugin Runner.*allow degradation/
+
+
+
+=== TEST 11: add route: wrong upstream
+--- config
+ location /t {
+ content_by_lua_block {
+ local json = require("toolkit.json")
+ local t = require("lib.test_admin")
+
+ local code, message, res = t.test('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/*",
+ "plugins": {
+ "ext-plugin-post-resp": {
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:3980": 1
+ },
+ "type": "roundrobin"
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(message)
+ return
+ end
+
+ ngx.say(message)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 12: request upstream failed
+--- request
+GET /hello
+--- error_code: 502
+--- error_log eval
+qr/failed to request/
+
+
+
+=== TEST 13: add route
+--- config
+ location /t {
+ content_by_lua_block {
+ local json = require("toolkit.json")
+ local t = require("lib.test_admin")
+
+ local code, message, res = t.test('/apisix/admin/routes/1',
+ ngx.HTTP_PUT,
+ [[{
+ "uri": "/*",
+ "plugins": {
+ "ext-plugin-post-resp": {
+ }
+ },
+ "upstream": {
+ "nodes": {
+ "127.0.0.1:1980": 1
+ },
+ "type": "roundrobin"
+ }
+ }]]
+ )
+
+ if code >= 300 then
+ ngx.status = code
+ ngx.say(message)
+ return
+ end
+
+ ngx.say(message)
+ }
+ }
+--- response_body
+passed
+
+
+
+=== TEST 14: body_reader error
+--- request
+GET /hello1
+--- more_headers
+resp-Content-Length: 14
+--- error_code: 502
+--- error_log eval
+qr/read response failed/
+
+
+
+=== TEST 15: response chunked
+--- request
+GET /hello_chunked
+--- error_code: 200
+--- response_body
+hello world
+
+
+
+=== TEST 16: check upstream uri with args
+--- request
+GET /plugin_proxy_rewrite_args?aaa=bbb&ccc=ddd
+--- error_code: 200
+--- response_body
+uri: /plugin_proxy_rewrite_args
+aaa: bbb
+ccc: ddd
diff --git a/t/plugin/ext-plugin/sanity.t b/t/plugin/ext-plugin/sanity.t
index a665f1cf8..707c9db1d 100644
--- a/t/plugin/ext-plugin/sanity.t
+++ b/t/plugin/ext-plugin/sanity.t
@@ -82,7 +82,8 @@ __DATA__
"uri": "/hello",
"plugins": {
"ext-plugin-pre-req": {"a":"b"},
- "ext-plugin-post-req": {"c":"d"}
+ "ext-plugin-post-req": {"c":"d"},
+ "ext-plugin-post-resp": {"e":"f"}
},
"upstream": {
"nodes": {
@@ -136,6 +137,14 @@ sending rpc type: 2 data length:
receiving rpc type: 2 data length:
sending rpc type: 2 data length:
receiving rpc type: 2 data length:
+sending rpc type: 1 data length:
+receiving rpc type: 1 data length:
+sending rpc type: 1 data length:
+receiving rpc type: 1 data length:
+sending rpc type: 4 data length:
+receiving rpc type: 4 data length:
+sending rpc type: 4 data length:
+receiving rpc type: 4 data length:
@@ -268,6 +277,14 @@ sending rpc type: 1 data length:
receiving rpc type: 1 data length:
sending rpc type: 1 data length:
receiving rpc type: 1 data length:
+sending rpc type: 1 data length:
+receiving rpc type: 1 data length:
+sending rpc type: 1 data length:
+receiving rpc type: 1 data length:
+sending rpc type: 1 data length:
+receiving rpc type: 1 data length:
+sending rpc type: 1 data length:
+receiving rpc type: 1 data length:
--- error_log
flush conf token lrucache
flush conf token in shared dict