This is an automated email from the ASF dual-hosted git repository.
monkeydluffy 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 0bea3dbf6 fix(grpc-web): missing trailers issue (#10851)
0bea3dbf6 is described below
commit 0bea3dbf6b1b868ba35acdb2fd0205f2a352479d
Author: Shehar Yaar <[email protected]>
AuthorDate: Fri Jan 26 13:54:34 2024 +0530
fix(grpc-web): missing trailers issue (#10851)
---
apisix/plugins/grpc-web.lua | 49 +++++++++++++++++++++++++++++++++++++++++++-
t/plugin/grpc-web.t | 37 +++++++++++++++++++++++++++++++--
t/plugin/grpc-web/client.js | 6 ++++++
t/plugin/grpc-web/req.bin | Bin 0 -> 14 bytes
4 files changed, 89 insertions(+), 3 deletions(-)
diff --git a/apisix/plugins/grpc-web.lua b/apisix/plugins/grpc-web.lua
index 18465063b..5771604e7 100644
--- a/apisix/plugins/grpc-web.lua
+++ b/apisix/plugins/grpc-web.lua
@@ -21,6 +21,8 @@ local req_set_uri = ngx.req.set_uri
local req_set_body_data = ngx.req.set_body_data
local decode_base64 = ngx.decode_base64
local encode_base64 = ngx.encode_base64
+local bit = require("bit")
+local string = string
local ALLOW_METHOD_OPTIONS = "OPTIONS"
@@ -87,7 +89,7 @@ function _M.access(conf, ctx)
-- set grpc path
if not (ctx.curr_req_matched and ctx.curr_req_matched[":ext"]) then
core.log.error("routing configuration error, grpc-web plugin only
supports ",
- "`prefix matching` pattern routing")
+ "`prefix matching` pattern routing")
return 400
end
@@ -130,6 +132,7 @@ function _M.header_filter(conf, ctx)
core.response.set_header("Access-Control-Allow-Origin",
DEFAULT_CORS_ALLOW_ORIGIN)
end
core.response.set_header("Content-Type", ctx.grpc_web_mime)
+ core.response.set_header("Access-Control-Expose-Headers",
"grpc-message,grpc-status")
end
function _M.body_filter(conf, ctx)
@@ -147,6 +150,50 @@ function _M.body_filter(conf, ctx)
chunk = encode_base64(chunk)
ngx_arg[1] = chunk
end
+
+ --[[
+ upstream_trailer_* available since NGINX version 1.13.10 :
+
https://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_trailer_
+
+ grpc-web trailer format reference:
+ envoyproxy/envoy/source/extensions/filters/http/grpc_web/grpc_web_filter.cc
+
+ Format for grpc-web trailer
+ 1 byte: 0x80
+ 4 bytes: length of the trailer
+ n bytes: trailer
+
+ --]]
+ local status = ctx.var.upstream_trailer_grpc_status
+ local message = ctx.var.upstream_trailer_grpc_message
+ if status ~= "" and status ~= nil then
+ local status_str = "grpc-status:" .. status
+ local status_msg = "grpc-message:" .. ( message or "")
+ local grpc_web_trailer = status_str .. "\r\n" .. status_msg .. "\r\n"
+ local len = #grpc_web_trailer
+
+ -- 1 byte: 0x80
+ local trailer_buf = string.char(0x80)
+ -- 4 bytes: length of the trailer
+ trailer_buf = trailer_buf .. string.char(
+ bit.band(bit.rshift(len, 24), 0xff),
+ bit.band(bit.rshift(len, 16), 0xff),
+ bit.band(bit.rshift(len, 8), 0xff),
+ bit.band(len, 0xff)
+ )
+ -- n bytes: trailer
+ trailer_buf = trailer_buf .. grpc_web_trailer
+
+ if ctx.grpc_web_encoding == CONTENT_ENCODING_BINARY then
+ ngx_arg[1] = ngx_arg[1] .. trailer_buf
+ else
+ ngx_arg[1] = ngx_arg[1] .. encode_base64(trailer_buf)
+ end
+
+ -- clear trailer
+ ctx.var.upstream_trailer_grpc_status = nil
+ ctx.var.upstream_trailer_grpc_message = nil
+ end
end
return _M
diff --git a/t/plugin/grpc-web.t b/t/plugin/grpc-web.t
index 7340add60..7069a8c2c 100644
--- a/t/plugin/grpc-web.t
+++ b/t/plugin/grpc-web.t
@@ -68,25 +68,33 @@ passed
-=== TEST 2: Proxy unary request using APISIX gRPC-Web plugin
+=== TEST 2: Proxy unary request using APISIX with trailers gRPC-Web plugin
--- exec
node ./t/plugin/grpc-web/client.js BIN UNARY
node ./t/plugin/grpc-web/client.js TEXT UNARY
--- response_body
+Status: { code: 0, details: '', metadata: {} }
+Status: { code: 0, details: '', metadata: {} }
{"name":"hello","path":"/hello"}
+Status: { code: 0, details: '', metadata: {} }
+Status: { code: 0, details: '', metadata: {} }
{"name":"hello","path":"/hello"}
-=== TEST 3: Proxy server-side streaming request using APISIX gRPC-Web plugin
+=== TEST 3: Proxy server-side streaming request using APISIX with trailers
gRPC-Web plugin
--- exec
node ./t/plugin/grpc-web/client.js BIN STREAM
node ./t/plugin/grpc-web/client.js TEXT STREAM
--- response_body
{"name":"hello","path":"/hello"}
{"name":"world","path":"/world"}
+Status: { code: 0, details: '', metadata: {} }
+Status: { code: 0, details: '', metadata: {} }
{"name":"hello","path":"/hello"}
{"name":"world","path":"/world"}
+Status: { code: 0, details: '', metadata: {} }
+Status: { code: 0, details: '', metadata: {} }
@@ -227,3 +235,28 @@ Content-Type: application/grpc-web
--- response_headers
Access-Control-Allow-Origin: http://test.com
Content-Type: application/grpc-web
+
+
+
+=== TEST 11: check for Access-Control-Expose-Headers header in response
+--- request
+POST /grpc/web/a6.RouteService/GetRoute
+{}
+--- more_headers
+Origin: http://test.com
+Content-Type: application/grpc-web
+--- response_headers
+Access-Control-Allow-Origin: http://test.com
+Access-Control-Expose-Headers: grpc-message,grpc-status
+Content-Type: application/grpc-web
+
+
+
+=== TEST 12: verify trailers in response
+--- exec
+curl -iv --location 'http://127.0.0.1:1984/grpc/web/a6.RouteService/GetRoute' \
+--header 'Content-Type: application/grpc-web+proto' \
+--header 'X-Grpc-Web: 1' \
+--data-binary '@./t/plugin/grpc-web/req.bin'
+--- response_body eval
+qr/grpc-status:0\x0d\x0agrpc-message:/
diff --git a/t/plugin/grpc-web/client.js b/t/plugin/grpc-web/client.js
index 3f10a80bc..9ec044124 100644
--- a/t/plugin/grpc-web/client.js
+++ b/t/plugin/grpc-web/client.js
@@ -49,6 +49,8 @@ class gRPCWebClient {
return
}
console.log(JSON.stringify(response.toObject()));
+ }).on("status", function (status) {
+ console.log("Status:", status);
});
}
@@ -62,6 +64,10 @@ class gRPCWebClient {
stream.on('end', function(end) {
stream.cancel();
});
+
+ stream.on("status", function (status) {
+ console.log("Status:", status);
+ });
}
}
diff --git a/t/plugin/grpc-web/req.bin b/t/plugin/grpc-web/req.bin
new file mode 100644
index 000000000..908c829c6
Binary files /dev/null and b/t/plugin/grpc-web/req.bin differ