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 ffed438 feat(ext-plugin): implement the http-req-call protocol (#4183) ffed438 is described below commit ffed4383f14dd9de4118511ec4e6edff53965e03 Author: 罗泽轩 <spacewander...@gmail.com> AuthorDate: Thu May 6 10:07:56 2021 +0800 feat(ext-plugin): implement the http-req-call protocol (#4183) --- apisix/core/request.lua | 28 ++ apisix/plugins/ext-plugin/init.lua | 283 +++++++++++++++++++- rockspec/apisix-master-0.rockspec | 2 +- t/lib/ext-plugin.lua | 214 +++++++++++++++ t/lib/server.lua | 6 +- t/plugin/ext-plugin/http-req-call.t | 517 ++++++++++++++++++++++++++++++++++++ 6 files changed, 1038 insertions(+), 12 deletions(-) diff --git a/apisix/core/request.lua b/apisix/core/request.lua index f359460..e43a647 100644 --- a/apisix/core/request.lua +++ b/apisix/core/request.lua @@ -29,6 +29,8 @@ local io_open = io.open local req_read_body = ngx.req.read_body local req_get_body_data = ngx.req.get_body_data local req_get_body_file = ngx.req.get_body_file +local req_get_uri_args = ngx.req.get_uri_args +local req_set_uri_args = ngx.req.set_uri_args local _M = {} @@ -122,6 +124,32 @@ function _M.get_remote_client_port(ctx) end +function _M.get_uri_args(ctx) + if not ctx then + ctx = ngx.ctx.api_ctx + end + + if not ctx.req_uri_args then + -- use 0 to avoid truncated result and keep the behavior as the + -- same as other platforms + local args = req_get_uri_args(0) + ctx.req_uri_args = args + end + + return ctx.req_uri_args +end + + +function _M.set_uri_args(ctx, args) + if not ctx then + ctx = ngx.ctx.api_ctx + end + + ctx.req_uri_args = nil + return req_set_uri_args(args) +end + + local function get_file(file_name) local f, err = io_open(file_name, 'r') if not f then diff --git a/apisix/plugins/ext-plugin/init.lua b/apisix/plugins/ext-plugin/init.lua index 9dde610..f37ab81 100644 --- a/apisix/plugins/ext-plugin/init.lua +++ b/apisix/plugins/ext-plugin/init.lua @@ -16,8 +16,14 @@ -- local is_http = ngx.config.subsystem == "http" local flatbuffers = require("flatbuffers") +local a6_method = require("A6.Method") local prepare_conf_req = require("A6.PrepareConf.Req") local prepare_conf_resp = require("A6.PrepareConf.Resp") +local http_req_call_req = require("A6.HTTPReqCall.Req") +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 text_entry = require("A6.TextEntry") local err_resp = require("A6.Err.Resp") local err_code = require("A6.Err.Code") @@ -35,16 +41,23 @@ local band = bit.band local lshift = bit.lshift local rshift = bit.rshift local ffi = require("ffi") +local ffi_new = ffi.new local ffi_str = ffi.string local socket_tcp = ngx.socket.tcp -local str_byte = string.byte -local str_format = string.format +local worker_id = ngx.worker.id local ngx_timer_at = ngx.timer.at local exiting = ngx.worker.exiting +local str_byte = string.byte +local str_format = string.format +local str_lower = string.lower +local str_sub = string.sub local error = error -local events_list +local ipairs = ipairs +local pairs = pairs +local type = type +local events_list local lrucache = core.lrucache.new({ type = "plugin", ttl = helper.get_conf_token_cache_time(), @@ -171,6 +184,80 @@ end _M.receive = receive +local generate_id +do + local count = 0 + local MAX_COUNT = lshift(1, 22) + + function generate_id() + local wid = worker_id() + local id = lshift(wid, 22) + count + count = count + 1 + if count == MAX_COUNT then + count = 0 + end + return id + end +end + + +local encode_a6_method +do + local map = { + GET = a6_method.GET, + HEAD = a6_method.HEAD, + POST = a6_method.POST, + PUT = a6_method.PUT, + DELETE = a6_method.DELETE, + MKCOL = a6_method.MKCOL, + COPY = a6_method.COPY, + MOVE = a6_method.MOVE, + OPTIONS = a6_method.OPTIONS, + PROPFIND = a6_method.PROPFIND, + PROPPATCH = a6_method.PROPPATCH, + LOCK = a6_method.LOCK, + UNLOCK = a6_method.UNLOCK, + PATCH = a6_method.PATCH, + TRACE = a6_method.TRACE, + } + + function encode_a6_method(name) + return map[name] + end +end + + +local function build_args(builder, key, val) + local name = builder:CreateString(key) + local value + if val ~= true then + value = builder:CreateString(val) + end + + text_entry.Start(builder) + text_entry.AddName(builder, name) + if val ~= true then + text_entry.AddValue(builder, value) + end + return text_entry.End(builder) +end + + +local function build_headers(var, builder, key, val) + if key == "host" then + val = var.upstream_host + end + + local name = builder:CreateString(key) + local value = builder:CreateString(val) + + text_entry.Start(builder) + text_entry.AddName(builder, name) + text_entry.AddValue(builder, value) + return text_entry.End(builder) +end + + local rpc_call local rpc_handlers = { nil, @@ -232,8 +319,90 @@ local rpc_handlers = { return nil, err end - local req = "hello" - local ok, err = send(sock, constants.RPC_HTTP_REQ_CALL, req) + builder:Clear() + local var = ctx.var + + local uri + if var.upstream_uri == "" then + -- use original uri instead of rewritten one + uri = var.uri + else + uri = 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) + core.request.set_uri_args(ctx, str_sub(raw_uri, index + 1)) + end + end + + local path = builder:CreateString(uri) + + local bin_addr = var.binary_remote_addr + local len = #bin_addr + http_req_call_req.StartSrcIpVector(builder, len) + for i = len, 1, -1 do + builder:PrependByte(str_byte(bin_addr, i)) + end + local src_ip = builder:EndVector(len) + + local args = core.request.get_uri_args(ctx) + local textEntries = {} + for key, val in pairs(args) do + local ty = type(val) + if ty == "table" then + for _, v in ipairs(val) do + core.table.insert(textEntries, build_args(builder, key, v)) + end + else + core.table.insert(textEntries, build_args(builder, key, val)) + end + end + local len = #textEntries + http_req_call_req.StartArgsVector(builder, len) + for i = len, 1, -1 do + builder:PrependUOffsetTRelative(textEntries[i]) + end + local args_vec = builder:EndVector(len) + + local hdrs = core.request.headers(ctx) + core.table.clear(textEntries) + 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_req_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 method = var.method + + http_req_call_req.Start(builder) + http_req_call_req.AddId(builder, id) + http_req_call_req.AddConfToken(builder, token) + http_req_call_req.AddSrcIp(builder, src_ip) + http_req_call_req.AddPath(builder, path) + http_req_call_req.AddArgs(builder, args_vec) + http_req_call_req.AddHeaders(builder, hdrs_vec) + http_req_call_req.AddMethod(builder, encode_a6_method(method)) + -- TODO: handle extraInfo + + local req = http_req_call_req.End(builder) + builder:Finish(req) + + local ok, err = send(sock, constants.RPC_HTTP_REQ_CALL, builder:Output()) if not ok then return nil, "failed to send RPC_HTTP_REQ_CALL: " .. err end @@ -247,7 +416,95 @@ local rpc_handlers = { return nil, "failed to receive RPC_HTTP_REQ_CALL: unexpected type " .. ty end - core.log.warn(resp) + local buf = flatbuffers.binaryArray.New(resp) + local call_resp = http_req_call_resp.GetRootAsResp(buf, 0) + local action_type = call_resp:ActionType() + + if action_type == http_req_call_action.Stop then + local action = call_resp:Action() + local stop = http_req_call_stop.New() + stop:Init(action.bytes, action.pos) + + local len = stop:HeadersLength() + if len > 0 then + for i = 1, len do + local entry = stop:Headers(i) + core.response.set_header(entry:Name(), entry:Value()) + end + end + + local body + local len = stop:BodyLength() + if len > 0 then + -- TODO: support empty body + body = ffi_new("unsigned char[?]", len) + for i = 1, len do + body[i - 1] = stop:Body(i) + end + body = ffi_str(body, len) + end + return true, nil, stop:Status(), body + end + + if action_type == http_req_call_action.Rewrite then + ctx.request_rewritten = constants.REWRITTEN_BY_EXT_PLUGIN + + local action = call_resp:Action() + local rewrite = http_req_call_rewrite.New() + rewrite:Init(action.bytes, action.pos) + + local path = rewrite:Path() + if path then + path = core.utils.uri_safe_encode(path) + var.upstream_uri = path + end + + local len = rewrite:HeadersLength() + if len > 0 then + for i = 1, len do + local entry = rewrite:Headers(i) + local name = entry:Name() + core.request.set_header(ctx, name, entry:Value()) + + if str_lower(name) == "host" then + var.upstream_host = entry:Value() + end + end + end + + local len = rewrite:ArgsLength() + if len > 0 then + local changed = {} + for i = 1, len do + local entry = rewrite:Args(i) + local name = entry:Name() + local value = entry:Value() + if value == nil then + args[name] = nil + + else + if changed[name] then + if type(args[name]) == "table" then + core.table.insert(args[name], value) + else + args[name] = {args[name], entry:Value()} + end + else + args[name] = entry:Value() + end + + changed[name] = true + end + end + + core.request.set_uri_args(ctx, args) + + if path then + var.upstream_uri = path .. '?' .. var.args + end + end + end + return true end, } @@ -263,8 +520,8 @@ rpc_call = function (ty, conf, ctx) return nil, "failed to connect to the unix socket " .. path .. ": " .. err end - local ok, err = rpc_handlers[ty + 1](conf, ctx, sock) - if not ok then + local res, err, code, body = rpc_handlers[ty + 1](conf, ctx, sock) + if not res then sock:close() return nil, err end @@ -273,16 +530,22 @@ rpc_call = function (ty, conf, ctx) if not ok then core.log.info("failed to setkeepalive: ", err) end - return true + + return res, nil, code, body end function _M.communicate(conf, ctx) - local ok, err = rpc_call(constants.RPC_HTTP_REQ_CALL, conf, ctx) + local ok, err, code, body = rpc_call(constants.RPC_HTTP_REQ_CALL, conf, ctx) if not ok then core.log.error(err) return 503 end + + if code then + return code, body + end + return end diff --git a/rockspec/apisix-master-0.rockspec b/rockspec/apisix-master-0.rockspec index 8c536e3..bc1082f 100644 --- a/rockspec/apisix-master-0.rockspec +++ b/rockspec/apisix-master-0.rockspec @@ -66,7 +66,7 @@ dependencies = { "luasec = 0.9-1", "lua-resty-consul = 0.3-2", "penlight = 1.9.2-1", - "ext-plugin-proto = 0.1.0", + "ext-plugin-proto = 0.1.1", } build = { diff --git a/t/lib/ext-plugin.lua b/t/lib/ext-plugin.lua index be7f6e5..5ef8eb9 100644 --- a/t/lib/ext-plugin.lua +++ b/t/lib/ext-plugin.lua @@ -14,6 +14,7 @@ -- See the License for the specific language governing permissions and -- limitations under the License. -- +local json = require("toolkit.json") local ext = require("apisix.plugins.ext-plugin.init") local constants = require("apisix.constants") local flatbuffers = require("flatbuffers") @@ -21,12 +22,26 @@ local err_code = require("A6.Err.Code") local err_resp = require("A6.Err.Resp") local prepare_conf_req = require("A6.PrepareConf.Req") local prepare_conf_resp = require("A6.PrepareConf.Resp") +local a6_method = require("A6.Method") +local text_entry = require("A6.TextEntry") +local http_req_call_req = require("A6.HTTPReqCall.Req") +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 _M = {} local builder = flatbuffers.Builder(0) +local function build_action(action, ty) + http_req_call_resp.Start(builder) + http_req_call_resp.AddActionType(builder, ty) + http_req_call_resp.AddAction(builder, action) +end + + function _M.go(case) local sock = ngx.req.socket() local ty, data = ext.receive(sock) @@ -68,6 +83,205 @@ function _M.go(case) end end + if ty == constants.RPC_HTTP_REQ_CALL then + local buf = flatbuffers.binaryArray.New(data) + local call_req = http_req_call_req.GetRootAsReq(buf, 0) + if case.check_input then + assert(call_req:Id() == 0) + assert(call_req:ConfToken() == 233) + assert(call_req:SrcIpLength() == 4) + assert(call_req:SrcIp(1) == 127) + assert(call_req:SrcIp(2) == 0) + assert(call_req:SrcIp(3) == 0) + assert(call_req:SrcIp(4) == 1) + assert(call_req:Method() == a6_method.PUT) + assert(call_req:Path() == "/hello") + + assert(call_req:ArgsLength() == 4) + local res = {} + for i = 1, call_req:ArgsLength() do + local entry = call_req:Args(i) + local r = res[entry:Name()] + if r then + res[entry:Name()] = {r, entry:Value()} + else + res[entry:Name()] = entry:Value() or true + end + end + assert(json.encode(res) == '{\"xx\":[\"y\",\"z\"],\"y\":\"\",\"z\":true}') + + assert(call_req:HeadersLength() == 5) + local res = {} + for i = 1, call_req:HeadersLength() do + local entry = call_req:Headers(i) + local r = res[entry:Name()] + if r then + res[entry:Name()] = {r, entry:Value()} + else + res[entry:Name()] = entry:Value() or true + end + end + assert(json.encode(res) == '{\"connection\":\"close\",\"host\":\"localhost\",' .. + '\"x-req\":[\"foo\",\"bar\"],\"x-resp\":\"cat\"}') + elseif case.check_input_ipv6 then + assert(call_req:SrcIpLength() == 16) + for i = 1, 15 do + assert(call_req:SrcIp(i) == 0) + end + assert(call_req:SrcIp(16) == 1) + elseif case.check_input_rewrite_host then + for i = 1, call_req:HeadersLength() do + local entry = call_req:Headers(i) + if entry:Name() == "host" then + assert(entry:Value() == "test.com") + end + end + elseif case.check_input_rewrite_path then + assert(call_req:Path() == "/xxx") + elseif case.check_input_rewrite_args then + assert(call_req:Path() == "/xxx") + assert(call_req:ArgsLength() == 1) + local entry = call_req:Args(1) + assert(entry:Name() == "x") + assert(entry:Value() == "z") + else + assert(call_req:Method() == a6_method.GET) + end + + if case.stop == true then + local len = 3 + http_req_call_stop.StartBodyVector(builder, len) + builder:PrependByte(string.byte("t")) + builder:PrependByte(string.byte("a")) + builder:PrependByte(string.byte("c")) + local b = builder:EndVector(len) + + local hdrs = { + {"X-Resp", "foo"}, + {"X-Req", "bar"}, + } + local len = #hdrs + local textEntries = {} + for i = 1, len do + local name = builder:CreateString(hdrs[i][1]) + local value = builder:CreateString(hdrs[i][2]) + text_entry.Start(builder) + text_entry.AddName(builder, name) + text_entry.AddValue(builder, value) + local c = text_entry.End(builder) + textEntries[i] = c + end + http_req_call_stop.StartHeadersVector(builder, len) + for i = len, 1, -1 do + builder:PrependUOffsetTRelative(textEntries[i]) + end + local vec = builder:EndVector(len) + + http_req_call_stop.Start(builder) + http_req_call_stop.AddStatus(builder, 405) + http_req_call_stop.AddBody(builder, b) + http_req_call_stop.AddHeaders(builder, vec) + local action = http_req_call_stop.End(builder) + build_action(action, http_req_call_action.Stop) + + elseif case.rewrite == true or case.rewrite_host == true then + local hdrs + if case.rewrite_host then + hdrs = {{"host", "127.0.0.1"}} + else + hdrs = { + {"X-Delete", nil}, + {"X-Change", "bar"}, + {"X-Add", "bar"}, + } + end + + local len = #hdrs + local textEntries = {} + for i = 1, len do + local name = builder:CreateString(hdrs[i][1]) + local value + if hdrs[i][2] then + value = builder:CreateString(hdrs[i][2]) + end + text_entry.Start(builder) + text_entry.AddName(builder, name) + if value then + text_entry.AddValue(builder, value) + end + local c = text_entry.End(builder) + textEntries[i] = c + end + http_req_call_rewrite.StartHeadersVector(builder, len) + for i = len, 1, -1 do + builder:PrependUOffsetTRelative(textEntries[i]) + end + local vec = builder:EndVector(len) + + local path = builder:CreateString("/uri") + + http_req_call_rewrite.Start(builder) + http_req_call_rewrite.AddPath(builder, path) + http_req_call_rewrite.AddHeaders(builder, vec) + local action = http_req_call_rewrite.End(builder) + build_action(action, http_req_call_action.Rewrite) + + elseif case.rewrite_args == true or case.rewrite_args_only == true then + local path = builder:CreateString("/plugin_proxy_rewrite_args") + + local args = { + {"a", "foo"}, + {"d", nil}, + {"c", "bar"}, + {"a", "bar"}, + } + + local len = #args + local textEntries = {} + for i = 1, len do + local name = builder:CreateString(args[i][1]) + local value + if args[i][2] then + value = builder:CreateString(args[i][2]) + end + text_entry.Start(builder) + text_entry.AddName(builder, name) + if value then + text_entry.AddValue(builder, value) + end + local c = text_entry.End(builder) + textEntries[i] = c + end + http_req_call_rewrite.StartHeadersVector(builder, len) + for i = len, 1, -1 do + builder:PrependUOffsetTRelative(textEntries[i]) + end + local vec = builder:EndVector(len) + + http_req_call_rewrite.Start(builder) + if not case.rewrite_args_only then + http_req_call_rewrite.AddPath(builder, path) + end + http_req_call_rewrite.AddArgs(builder, vec) + local action = http_req_call_rewrite.End(builder) + build_action(action, http_req_call_action.Rewrite) + + elseif case.rewrite_bad_path == true then + local path = builder:CreateString("/plugin_proxy_rewrite_args?a=2") + http_req_call_rewrite.Start(builder) + http_req_call_rewrite.AddPath(builder, path) + local action = http_req_call_rewrite.End(builder) + build_action(action, http_req_call_action.Rewrite) + + else + http_req_call_resp.Start(builder) + end + + local req = http_req_call_resp.End(builder) + builder:Finish(req) + data = builder:Output() + end + local ok, err = ext.send(sock, ty, data) if not ok then ngx.log(ngx.ERR, err) diff --git a/t/lib/server.lua b/t/lib/server.lua index f8323ee..5a1b454 100644 --- a/t/lib/server.lua +++ b/t/lib/server.lua @@ -94,7 +94,11 @@ function _M.plugin_proxy_rewrite_args() table.sort(keys) for _, key in ipairs(keys) do - ngx.say(key, ": ", args[key]) + if type(args[key]) == "table" then + ngx.say(key, ": ", table.concat(args[key], ',')) + else + ngx.say(key, ": ", args[key]) + end end end diff --git a/t/plugin/ext-plugin/http-req-call.t b/t/plugin/ext-plugin/http-req-call.t new file mode 100644 index 0000000..76d56b4 --- /dev/null +++ b/t/plugin/ext-plugin/http-req-call.t @@ -0,0 +1,517 @@ +# +# 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(); +log_level("info"); + +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 $extra_yaml_config = <<_EOC_; +ext-plugin: + path_for_test: $unix_socket_path +_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": "/hello", + "plugins": { + "ext-plugin-pre-req": { + } + }, + "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: stop +--- request +GET /hello +--- response_body chomp +cat +--- extra_stream_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + content_by_lua_block { + local ext = require("lib.ext-plugin") + ext.go({stop = true}) + } + } +--- error_code: 405 +--- response_headers +X-Resp: foo +X-Req: bar + + + +=== TEST 3: check input +--- request +PUT /hello?xx=y&xx=z&&y=&&z +--- more_headers +X-Req: foo +X-Req: bar +X-Resp: cat +--- 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}) + } + } + + + +=== TEST 4: check input (ipv6) +--- config +location /t { + content_by_lua_block { + local t = require("lib.test_admin").test_ipv6 + t('/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_ipv6 = true}) + } + } +--- listen_ipv6 + + + +=== TEST 5: rewrite +--- request +GET /hello +--- more_headers +X-Change: foo +X-Delete: foo +--- extra_stream_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + content_by_lua_block { + local ext = require("lib.ext-plugin") + ext.go({rewrite = true}) + } + } +--- response_body +uri: /uri +host: localhost +x-add: bar +x-change: bar +x-real-ip: 127.0.0.1 + + + +=== TEST 6: rewrite host +--- 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({rewrite_host = true}) + } + } +--- response_body +uri: /uri +host: 127.0.0.1 +x-real-ip: 127.0.0.1 + + + +=== TEST 7: rewrite args +--- request +GET /hello?c=foo&d=bar +--- extra_stream_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + content_by_lua_block { + local ext = require("lib.ext-plugin") + ext.go({rewrite_args = true}) + } + } +--- response_body +uri: /plugin_proxy_rewrite_args +a: foo,bar +c: bar + + + +=== TEST 8: proxy-rewrite + rewrite host +--- 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": { + "proxy-rewrite": { + "host": "test.com" + }, + "ext-plugin-post-req": { + } + }, + "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 9: hit +--- 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({rewrite_host = true, check_input_rewrite_host = true}) + } + } +--- response_body +uri: /uri +host: 127.0.0.1 +x-real-ip: 127.0.0.1 + + + +=== TEST 10: proxy-rewrite + rewrite path +--- 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": { + "proxy-rewrite": { + "uri": "/xxx" + }, + "ext-plugin-post-req": { + } + }, + "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 11: hit +--- 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({rewrite_host = true, check_input_rewrite_path = true}) + } + } +--- response_body +uri: /uri +host: 127.0.0.1 +x-real-ip: 127.0.0.1 + + + +=== TEST 12: proxy-rewrite + rewrite path with args +--- 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": { + "proxy-rewrite": { + "uri": "/xxx?x=z" + }, + "ext-plugin-post-req": { + } + }, + "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 13: hit +--- 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({rewrite_args = true, check_input_rewrite_args = true}) + } + } +--- response_body +uri: /plugin_proxy_rewrite_args +a: foo,bar +c: bar +x: z + + + +=== TEST 14: rewrite args only +--- 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": "/plugin_proxy_rewrite_args", + "plugins": { + "ext-plugin-post-req": { + } + }, + "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 15: hit +--- request +GET /plugin_proxy_rewrite_args +--- extra_stream_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; + + content_by_lua_block { + local ext = require("lib.ext-plugin") + ext.go({rewrite_args_only = true}) + } + } +--- response_body +uri: /plugin_proxy_rewrite_args +a: foo,bar +c: bar + + + +=== TEST 16: rewrite, bad path +--- 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": { + } + }, + "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 17: hit +--- 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({rewrite_bad_path = true}) + } + } +--- access_log +GET /plugin_proxy_rewrite_args%3Fa=2 +--- error_code: 404