fix(proto): avoid sharing state (#6199)

This commit is contained in:
罗泽轩 2022-01-26 09:16:43 +08:00 committed by GitHub
parent b57f52302c
commit 14f0889bad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 133 additions and 20 deletions

View File

@ -16,6 +16,7 @@
--
local core = require("apisix.core")
local config_util = require("apisix.core.config_util")
local pb = require("pb")
local protoc = require("protoc")
local pcall = pcall
local ipairs = ipairs
@ -29,6 +30,10 @@ local lrucache_proto = core.lrucache.new({
local proto_fake_file = "filename for loaded"
local function compile_proto(content)
-- clear pb state
pb.state(nil)
protoc.reload()
local _p = protoc.new()
-- the loaded proto won't appears in _p.loaded without a file name after lua-protobuf=0.3.2,
-- which means _p.loaded after _p:load(content) is always empty, so we can pass a fake file
@ -44,7 +49,23 @@ local function compile_proto(content)
return nil, "failed to load proto content"
end
return _p.loaded
local compiled = _p.loaded
-- fetch pb state
compiled.pb_state = pb.state(nil)
local index = {}
for _, s in ipairs(compiled[proto_fake_file].service or {}) do
local method_index = {}
for _, m in ipairs(s.method) do
method_index[m.name] = m
end
index[compiled[proto_fake_file].package .. '.' .. s.name] = method_index
end
compiled[proto_fake_file].index = index
return compiled
end
@ -71,24 +92,7 @@ local function create_proto_obj(proto_id)
return nil, "failed to find proto by id: " .. proto_id
end
local compiled, err = compile_proto(content)
if not compiled then
return nil, err
end
local index = {}
for _, s in ipairs(compiled[proto_fake_file].service or {}) do
local method_index = {}
for _, m in ipairs(s.method) do
method_index[m.name] = m
end
index[compiled[proto_fake_file].package .. '.' .. s.name] = method_index
end
compiled[proto_fake_file].index = index
return compiled
return compile_proto(content)
end

View File

@ -37,7 +37,14 @@ function _M.find_method(protos, service, method)
return nil
end
return loaded.index[service][method]
local res = loaded.index[service][method]
if not res then
return nil
end
-- restore pb state
pb.state(protos.pb_state)
return res
end

View File

@ -128,3 +128,105 @@ POST /grpctest
Content-Type: application/json
--- response_body chomp
{"message":"Hello world, name: Joe"}
=== TEST 4: set rule to check if each proto is separate
--- config
location /t {
content_by_lua_block {
local t = require("lib.test_admin").test
local etcd = require("apisix.core.etcd")
local code, body = t('/apisix/admin/proto/2',
ngx.HTTP_PUT,
[[{
"content" : "syntax = \"proto3\";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// same message, different fields. use to pollute the type info
message HelloRequest {
string name = 1;
string person = 2;
}
message HelloReply {
string message = 1;
}"
}]]
)
if code >= 300 then
ngx.status = code
ngx.say(body)
return
end
local code, body = t('/apisix/admin/routes/2',
ngx.HTTP_PUT,
[[{
"uri": "/fail",
"plugins": {
"grpc-transcode": {
"proto_id": "2",
"service": "helloworld.Greeter",
"method": "SayHello"
}
},
"upstream": {
"scheme": "grpc",
"type": "roundrobin",
"nodes": {
"127.0.0.1:50051": 1
}
}
}]]
)
if code >= 300 then
ngx.status = code
end
ngx.say(body)
}
}
--- response_body
passed
=== TEST 5: hit route
--- config
location /t {
content_by_lua_block {
local http = require "resty.http"
local uri = "http://127.0.0.1:" .. ngx.var.server_port
local body = [[{"name":"world","person":{"name":"John"}}]]
local opt = {method = "POST", body = body, headers = {["Content-Type"] = "application/json"}}
local function access(path)
local httpc = http.new()
local res, err = httpc:request_uri(uri .. path, opt)
if not res then
ngx.say(err)
return
end
if res.status > 300 then
ngx.say(res.status)
else
ngx.say(res.body)
end
end
access("/fail")
access("/grpctest")
access("/fail")
access("/grpctest")
}
}
--- response_body
400
{"message":"Hello world, name: John"}
400
{"message":"Hello world, name: John"}
--- error_log
failed to encode request data to protobuf