| -- |
| -- 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 json = require("toolkit.json") |
| local ext = require("apisix.plugins.ext-plugin.init") |
| local constants = require("apisix.constants") |
| local flatbuffers = require("flatbuffers") |
| 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) |
| if not ty then |
| ngx.log(ngx.ERR, data) |
| return |
| end |
| ngx.log(ngx.WARN, "receive rpc call successfully") |
| |
| if ty == constants.RPC_PREPARE_CONF then |
| if case.inject_error then |
| ty = constants.RPC_ERROR |
| err_resp.Start(builder) |
| err_resp.AddCode(builder, err_code.BAD_REQUEST) |
| local req = prepare_conf_req.End(builder) |
| builder:Finish(req) |
| data = builder:Output() |
| |
| else |
| local buf = flatbuffers.binaryArray.New(data) |
| local pc = prepare_conf_req.GetRootAsReq(buf, 0) |
| |
| if case.with_conf then |
| local conf = pc:Conf(1) |
| assert(conf:Name(), "foo") |
| assert(conf:Value(), "bar") |
| local conf = pc:Conf(2) |
| assert(conf:Name(), "cat") |
| assert(conf:Value(), "dog") |
| else |
| assert(pc:ConfLength() == 0) |
| end |
| |
| prepare_conf_resp.Start(builder) |
| prepare_conf_resp.AddConfToken(builder, 233) |
| local req = prepare_conf_req.End(builder) |
| builder:Finish(req) |
| data = builder:Output() |
| 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) |
| return |
| end |
| ngx.log(ngx.WARN, "send rpc call response successfully") |
| end |
| |
| |
| function _M.header_too_short() |
| local sock = ngx.req.socket() |
| local ty, data = ext.receive(sock) |
| if not ty then |
| ngx.log(ngx.ERR, data) |
| return |
| end |
| ngx.log(ngx.WARN, "receive rpc call successfully") |
| |
| local ok, err = sock:send({string.char(2), string.char(1)}) |
| if not ok then |
| ngx.log(ngx.ERR, err) |
| return |
| end |
| end |
| |
| |
| function _M.data_too_short() |
| local sock = ngx.req.socket() |
| local ty, data = ext.receive(sock) |
| if not ty then |
| ngx.log(ngx.ERR, data) |
| return |
| end |
| ngx.log(ngx.WARN, "receive rpc call successfully") |
| |
| local ok, err = sock:send({string.char(2), string.char(1), string.rep(string.char(0), 3)}) |
| if not ok then |
| ngx.log(ngx.ERR, err) |
| return |
| end |
| end |
| |
| |
| return _M |