Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add http-dubbo plugin #10703

Merged
merged 40 commits into from
Feb 1, 2024
Merged
Changes from 4 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ae3a219
add http-dubbo plugin
ShenFeng312 Dec 25, 2023
f3e4a03
Merge branch 'master' of github.com:ShenFeng312/apisix
ShenFeng312 Dec 25, 2023
1445d09
fix params append
ShenFeng312 Dec 25, 2023
d129cf3
add License
ShenFeng312 Dec 25, 2023
202a523
add http-dubbo test cases and fix cr
ShenFeng312 Jan 10, 2024
e694b7a
add License
ShenFeng312 Jan 10, 2024
3d41ca5
polish
ShenFeng312 Jan 10, 2024
31ae727
fix ci
ShenFeng312 Jan 11, 2024
e8ff79e
fix ci
ShenFeng312 Jan 11, 2024
443495a
fix ci
ShenFeng312 Jan 15, 2024
b8f5ec4
Merge branch 'master' into master
ShenFeng312 Jan 15, 2024
b69dcc7
Merge branch 'master' of github.com:ShenFeng312/apisix
ShenFeng312 Jan 15, 2024
34fdc5d
add License
ShenFeng312 Jan 15, 2024
4aa4d03
Update t/plugin/http-dubbo.t
ShenFeng312 Jan 19, 2024
37d8163
fix cr
ShenFeng312 Jan 19, 2024
662dc2b
Merge branch 'master' of github.com:ShenFeng312/apisix
ShenFeng312 Jan 19, 2024
abd9593
fix cr
ShenFeng312 Jan 19, 2024
92596b0
fix cr
ShenFeng312 Jan 19, 2024
8451fd8
add service_version
ShenFeng312 Jan 19, 2024
6862618
Merge branch 'apache:master' into master
ShenFeng312 Jan 23, 2024
6599c31
fix test
ShenFeng312 Jan 23, 2024
fa9ad21
Merge branch 'master' of github.com:ShenFeng312/apisix
ShenFeng312 Jan 23, 2024
132777a
fix test
ShenFeng312 Jan 23, 2024
81e9f00
fix test
ShenFeng312 Jan 23, 2024
5f1664c
add test
ShenFeng312 Jan 24, 2024
982380e
fix test
ShenFeng312 Jan 24, 2024
5d68990
fix ci
ShenFeng312 Jan 24, 2024
2f1b54f
Merge branch 'apache:master' into master
ShenFeng312 Jan 24, 2024
33a47ee
fix ci
ShenFeng312 Jan 24, 2024
56a159f
fix ci
ShenFeng312 Jan 24, 2024
d08cdb1
Merge branch 'master' of github.com:ShenFeng312/apisix
ShenFeng312 Jan 24, 2024
ef24da9
fix test
ShenFeng312 Jan 24, 2024
9ba3458
fix test
ShenFeng312 Jan 24, 2024
3707b29
fix ci
ShenFeng312 Jan 24, 2024
b948642
fix ci
ShenFeng312 Jan 24, 2024
a8027ef
fix http-dubbo params len
ShenFeng312 Jan 24, 2024
43f4269
fix http-dubbo params
ShenFeng312 Jan 24, 2024
7084aa3
fix codestyle
ShenFeng312 Jan 26, 2024
45f319a
fix codestyle
ShenFeng312 Feb 1, 2024
64d65f7
Merge branch 'apache:master' into master
ShenFeng312 Feb 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 242 additions & 0 deletions apisix/plugins/http-dubbo.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
--
-- 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 require = require
local core = require("apisix.core")
local pairs = pairs
local str_format = string.format
local rshift = bit.rshift
local band = bit.band
local char = string.char
local tostring = tostring
local ngx = ngx
local type = type
local plugin_name = "http-dubbo"

local schema = {
type = "object",
properties = {
service_name = {
type = "string",
minLength = 1,
},
service_version = {
type = "string",
pattern = [[^\d+\.\d+\.\d+]],
},
method = {
type = "string",
minLength = 1,
},
params_type_desc = {
type = "string",
minLength = 1,
},
serialization_header_key = {
type = "string"
},
serialized = {
type = "boolean",
default = false
}
},
required = { "service_name", "method", "params_type_desc" },
}

local _M = {
version = 0.1,
priority = 0,
ShenFeng312 marked this conversation as resolved.
Show resolved Hide resolved
name = plugin_name,
schema = schema,
}

function _M.check_schema(conf)
return core.schema.check(schema, conf)
end

local function str_int32(int)
ShenFeng312 marked this conversation as resolved.
Show resolved Hide resolved
return char(band(rshift(int, 24), 0xff),
band(rshift(int, 16), 0xff),
band(rshift(int, 8), 0xff),
band(int, 0xff))
end

local function parse_dubbo_header(header)
for i = 1, 16 do
local currentByte = header:byte(i)
if not currentByte then
return nil
end
end

local magic_number = str_format("%04x", header:byte(1) * 256 + header:byte(2))
local message_flag = header:byte(3)
local status = header:byte(4)
local request_id = 0
for i = 5, 12 do
request_id = request_id * 256 + header:byte(i)
end

local byte13Val = header:byte(13) * 256 * 256 * 256
local byte14Val = header:byte(14) * 256 * 256
local data_length = byte13Val + byte14Val + header:byte(15) * 256 + header:byte(16)

local is_request = bit.band(bit.rshift(message_flag, 7), 0x01) == 1 and 1 or 0
local is_two_way = bit.band(bit.rshift(message_flag, 6), 0x01) == 1 and 1 or 0
local is_event = bit.band(bit.rshift(message_flag, 5), 0x01) == 1 and 1 or 0

return {
magic_number = magic_number,
message_flag = message_flag,
is_request = is_request,
is_two_way = is_two_way,
is_event = is_event,
status = status,
request_id = request_id,
data_length = data_length
}
end

local function string_to_json_string(str)
local result = "\""
for i = 1, #str do
local byte = core.string.sub(str, i, i)
if byte == "\\" then
result = result .. "\\\\"
elseif byte == "\n" then
result = result .. "\\n"
elseif byte == "\t" then
result = result .. "\\t"
elseif byte == "\r" then
result = result .. "\\r"
elseif byte == "\b" then
result = result .. "\\b"
elseif byte == "\f" then
result = result .. "\\f"
elseif byte == "\"" then
result = result .. "\\\""
else
result = result .. byte
end
end
return result .. "\""
end

local function get_dubbo_request(conf, ctx)
-- use dubbo and fastjson
local first_byte4 = "\xda\xbb\xc6\x00"

local requestId = "\x00\x00\x00\x00\x00\x00\x00\x01"
local version = "\"2.0.2\"\n"
local service = "\"" .. conf.service_name .. "\"" .. "\n"

local service_version
if not conf.service_version then
service_version = "0.0.0"
ShenFeng312 marked this conversation as resolved.
Show resolved Hide resolved
else
service_version = conf.service_version
end
service_version = "\"" .. service_version .. "\"" .. "\n"
local method_name = "\"" .. conf.method .. "\"" .. "\n"

local params_desc = "\"" .. conf.params_type_desc .. "\"" .. "\n"
local params = ""
local serialized = conf.serialized
if conf.serialization_header_key then
local serialization_header = core.request.header(ctx, conf.serialization_header_key)
serialized = serialization_header == "true"
end
if serialized then
params = core.request.get_body()
local end_of_params = core.string.sub(params, -1)
if not end_of_params == "\n" then
params = params .. "\n"
end
else
local body_data = core.request.get_body()
if body_data then
local lua_object = core.json.decode(body_data);
for k, v in pairs(lua_object) do
local pt = type(v)
if pt == "nil" then
params = params .. "null" .. "\n"
elseif pt == "string" then
params = params .. string_to_json_string(v) .. "\n"
elseif pt == "number" then
params = params .. tostring(v) .. "\n"
else
params = params .. core.json.encode(v) .. "\n"
end
end
else
ngx.say("Failed to get request body data.")
return
end
end
local attachments = "{}\n"

local payload = #version + #service + #service_version + #method_name + #params_desc + #params + #attachments
return {
first_byte4,
requestId,
str_int32(payload),
version,
service,
service_version,
method_name,
params_desc,
params,
attachments
}
end

function _M.before_proxy(conf, ctx)
local sock = ngx.socket.tcp()
sock:settimeouts(6000, 6000, 6000) -- one second timeout
ShenFeng312 marked this conversation as resolved.
Show resolved Hide resolved
local ok, err = sock:connect(ctx.picked_server.host, ctx.picked_server.port)
if not ok then
ngx.say("failed to connect to upstream ", err)
ShenFeng312 marked this conversation as resolved.
Show resolved Hide resolved
return
end
local request = get_dubbo_request(conf, ctx)
local bytes, err = sock:send(request)
if bytes > 0 then
local header, err = sock:receiveany(16);
if header then
local header_info = parse_dubbo_header(header)
if header_info and header_info.status == 20 then
local readline = sock:receiveuntil("\n")
local body_status, err, partial = readline()

if body_status then
local response_status = core.string.sub(body_status, 1, 1)
if response_status == "2" or response_status == "5" then
return 200
elseif response_status == "1" or response_status == "4" then
local body, err, partial = readline()
return 200, body
end
end
end
end
end
sock:close()
ShenFeng312 marked this conversation as resolved.
Show resolved Hide resolved
return 500

end

return _M
ShenFeng312 marked this conversation as resolved.
Show resolved Hide resolved
Loading