Files
2026-07-13 12:32:21 +08:00

134 lines
3.5 KiB
Lua

-- Copyright (c) Kong Inc. 2020
local deco = require "kong.plugins.grpc-gateway.deco"
local kong_meta = require "kong.meta"
local ngx = ngx
local kong = kong
local ngx_arg = ngx.arg
local kong_request_get_path = kong.request.get_path
local kong_request_get_method = kong.request.get_method
local kong_request_get_raw_body = kong.request.get_raw_body
local kong_response_exit = kong.response.exit
local kong_response_set_header = kong.response.set_header
local kong_service_request_set_header = kong.service.request.set_header
local kong_service_request_set_method = kong.service.request.set_method
local kong_service_request_set_raw_body = kong.service.request.set_raw_body
local grpc_gateway = {
PRIORITY = 998,
VERSION = kong_meta.version,
}
local CORS_HEADERS = {
["Content-Type"] = "application/json",
["Access-Control-Allow-Origin"] = "*",
["Access-Control-Allow-Methods"] = "GET,POST,PATCH,DELETE",
["Access-Control-Allow-Headers"] = "content-type", -- TODO: more headers?
}
function grpc_gateway:access(conf)
kong_response_set_header("Access-Control-Allow-Origin", "*")
if kong_request_get_method() == "OPTIONS" then
return kong_response_exit(200, "OK", CORS_HEADERS)
end
local dec, err = deco.new(kong_request_get_method():lower(),
kong_request_get_path(), conf.proto)
if not dec then
kong.log.err(err)
return kong_response_exit(400, err)
end
kong.ctx.plugin.dec = dec
kong_service_request_set_header("Content-Type", "application/grpc")
kong_service_request_set_header("TE", "trailers")
local body, err = dec:upstream(kong_request_get_raw_body())
if err then
kong.log.err(err)
return kong_response_exit(400, err)
end
kong_service_request_set_raw_body(body)
ngx.req.set_uri(dec.rewrite_path)
-- clear any query args
ngx.req.set_uri_args("")
kong_service_request_set_method("POST")
end
-- https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
local grpc_status_map = {
[0] = 200, -- OK
[1] = 499, -- CANCELLED
[2] = 500, -- UNKNOWN
[3] = 400, -- INVALID_ARGUMENT
[4] = 504, -- DEADLINE_EXCEEDED
[5] = 404, -- NOT_FOUND
[6] = 409, -- ALREADY_EXISTS
[7] = 403, -- PERMISSION_DENIED
[16] = 401, -- UNAUTHENTICATED
[8] = 429, -- RESOURCE_EXHAUSTED
[9] = 400, -- FAILED_PRECONDITION
[10] = 409, -- ABORTED
[11] = 400, -- OUT_OF_RANGE
[12] = 500, -- UNIMPLEMENTED
[13] = 500, -- INTERNAL
[14] = 503, -- UNAVAILABLE
[15] = 500, -- DATA_LOSS
}
function grpc_gateway:header_filter(conf)
if kong_request_get_method() == "OPTIONS" then
return
end
local dec = kong.ctx.plugin.dec
if dec then
kong_response_set_header("Content-Type", "application/json")
end
local grpc_status = tonumber(ngx.header['grpc-status'])
if grpc_status then
local http_status = grpc_status_map[grpc_status]
if not http_status then
kong.log.warn("Unable to map grpc-status ", ngx.header['grpc-status'], " to HTTP status code")
http_status = 500
end
ngx.status = http_status
end
end
function grpc_gateway:body_filter(conf)
local dec = kong.ctx.plugin.dec
if not dec then
return
end
local ret = dec:downstream(ngx_arg[1])
if not ret or #ret == 0 then
if ngx_arg[2] then
-- it's eof and we still cannot decode, fall through
ret = dec:get_raw_downstream_body()
else
-- clear output if we cannot decode, it could be body is not complete yet
ret = nil
end
end
ngx_arg[1] = ret
end
return grpc_gateway