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/01/26 01:16:46 UTC

[apisix] branch master updated: fix(proto): avoid sharing state (#6199)

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 14f0889  fix(proto): avoid sharing state (#6199)
14f0889 is described below

commit 14f0889badc808d8f2fb4a11ca4b4d0d3f026cf4
Author: 罗泽轩 <sp...@gmail.com>
AuthorDate: Wed Jan 26 09:16:43 2022 +0800

    fix(proto): avoid sharing state (#6199)
---
 apisix/plugins/grpc-transcode/proto.lua |  42 +++++++------
 apisix/plugins/grpc-transcode/util.lua  |   9 ++-
 t/plugin/grpc-transcode2.t              | 102 ++++++++++++++++++++++++++++++++
 3 files changed, 133 insertions(+), 20 deletions(-)

diff --git a/apisix/plugins/grpc-transcode/proto.lua b/apisix/plugins/grpc-transcode/proto.lua
index 33d84eb..de19be2 100644
--- a/apisix/plugins/grpc-transcode/proto.lua
+++ b/apisix/plugins/grpc-transcode/proto.lua
@@ -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
 
 
diff --git a/apisix/plugins/grpc-transcode/util.lua b/apisix/plugins/grpc-transcode/util.lua
index 8fbe962..18c9f78 100644
--- a/apisix/plugins/grpc-transcode/util.lua
+++ b/apisix/plugins/grpc-transcode/util.lua
@@ -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
 
 
diff --git a/t/plugin/grpc-transcode2.t b/t/plugin/grpc-transcode2.t
index 0e7fd2b..7a48077 100644
--- a/t/plugin/grpc-transcode2.t
+++ b/t/plugin/grpc-transcode2.t
@@ -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