mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 01:55:13 +08:00
🌴 Sync 2026-03-05 23:51:42
This commit is contained in:
1 parent
97c049ed0a
commit
0acff03804
14253 files changed
+3893239
No files matched your search
@@ -0,0 +1,608 @@
|
||||
-- Copyright 2003-2010 Kepler Project
|
||||
-- XML-RPC implementation for Lua.
|
||||
|
||||
local lxp = require "lxp"
|
||||
local lom = require "lxp.lom"
|
||||
|
||||
local assert, error, ipairs, pairs, select, type, tonumber, unpack = assert, error, ipairs, pairs, select, type, tonumber, unpack
|
||||
local format, gsub, strfind, strsub = string.format, string.gsub, string.find, string.sub
|
||||
local concat, tinsert = table.concat, table.insert
|
||||
local ceil = math.ceil
|
||||
local parse = lom.parse
|
||||
|
||||
module (...)
|
||||
|
||||
_COPYRIGHT = "Copyright (C) 2003-2014 Kepler Project"
|
||||
_DESCRIPTION = "LuaXMLRPC is a library to make remote procedure calls using XML-RPC"
|
||||
_PKGNAME = "LuaXMLRPC"
|
||||
_VERSION_MAJOR = 1
|
||||
_VERSION_MINOR = 2
|
||||
_VERSION_MICRO = 2
|
||||
_VERSION = _VERSION_MAJOR .. "." .. _VERSION_MINOR .. "." .. _VERSION_MICRO
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- XML-RPC Parser
|
||||
---------------------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function trim (s)
|
||||
return (type(s) == "string" and gsub (s, "^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function is_space (s)
|
||||
return type(s) == "string" and trim(s) == ""
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Get next non-space element from tab starting from index i.
|
||||
-- @param tab Table.
|
||||
-- @param i Numeric index.
|
||||
-- @return Object and its position on table; nil and an invalid index
|
||||
-- when there is no more elements.
|
||||
---------------------------------------------------------------------
|
||||
function next_nonspace (tab, i)
|
||||
if not i then i = 1 end
|
||||
while is_space (tab[i]) do i = i+1 end
|
||||
return tab[i], i
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Get next element of tab with the given tag starting from index i.
|
||||
-- @param tab Table.
|
||||
-- @param tag String with the name of the tag.
|
||||
-- @param i Numeric index.
|
||||
-- @return Object and its position on table; nil and an invalid index
|
||||
-- when there is no more elements.
|
||||
---------------------------------------------------------------------
|
||||
local function next_tag (tab, tag, i)
|
||||
if not i then i = 1 end
|
||||
while tab[i] do
|
||||
if type (tab[i]) == "table" and tab[i].tag == tag then
|
||||
return tab[i], i
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
return nil, i
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function x2number (tab)
|
||||
if tab.tag == "int" or tab.tag == "i4" or tab.tag == "i8" or tab.tag == "double" then
|
||||
return tonumber (next_nonspace (tab, 1), 10)
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function x2boolean (tab)
|
||||
if tab.tag == "boolean" then
|
||||
local v = next_nonspace (tab, 1)
|
||||
return v == true or v == "true" or tonumber (v) == 1 or false
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function x2string (tab)
|
||||
return tab.tag == "string" and (tab[1] or "")
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function x2date (tab)
|
||||
return tab.tag == "dateTime.iso8601" and next_nonspace (tab, 1)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function x2base64 (tab)
|
||||
return tab.tag == "base64" and next_nonspace (tab, 1)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function x2name (tab)
|
||||
return tab.tag == "name" and next_nonspace (tab, 1)
|
||||
end
|
||||
|
||||
local x2value
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a member object in its name and value parts.
|
||||
-- @param tab Table with a DOM representation.
|
||||
-- @return String (name) and Object (value).
|
||||
-- @see x2name, x2value.
|
||||
---------------------------------------------------------------------
|
||||
local function x2member (tab)
|
||||
return
|
||||
x2name (next_tag(tab,"name")),
|
||||
x2value (next_tag(tab,"value"))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a struct object into a Lua table.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Table with "name = value" pairs.
|
||||
---------------------------------------------------------------------
|
||||
local function x2struct (tab)
|
||||
if tab.tag == "struct" then
|
||||
local res = {}
|
||||
for i = 1, #tab do
|
||||
if not is_space (tab[i]) then
|
||||
local name, val = x2member (tab[i])
|
||||
res[name] = val
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble an array object into a Lua table.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Table.
|
||||
---------------------------------------------------------------------
|
||||
local function x2array (tab)
|
||||
if tab.tag == "array" then
|
||||
local d = next_tag (tab, "data")
|
||||
local res = {}
|
||||
for i = 1, #d do
|
||||
if not is_space (d[i]) then
|
||||
tinsert (res, x2value (d[i]))
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local xmlrpc_types = {
|
||||
int = x2number,
|
||||
i4 = x2number,
|
||||
i8 = x2number,
|
||||
boolean = x2boolean,
|
||||
string = x2string,
|
||||
double = x2number,
|
||||
["dateTime.iso8601"] = x2date,
|
||||
base64 = x2base64,
|
||||
struct = x2struct,
|
||||
array = x2array,
|
||||
}
|
||||
|
||||
local x2param, x2fault
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a methodResponse into a Lua object.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Boolean (indicating wether the response was successful)
|
||||
-- and (a Lua object representing the return values OR the fault
|
||||
-- string and the fault code).
|
||||
---------------------------------------------------------------------
|
||||
local function x2methodResponse (tab)
|
||||
assert (type(tab) == "table", "Not a table")
|
||||
assert (tab.tag == "methodResponse",
|
||||
"Not a `methodResponse' tag: "..tab.tag)
|
||||
local t = next_nonspace (tab, 1)
|
||||
if t.tag == "params" then
|
||||
return true, unpack (x2param (t))
|
||||
elseif t.tag == "fault" then
|
||||
local f = x2fault (t)
|
||||
return false, f.faultString, f.faultCode
|
||||
else
|
||||
error ("Couldn't find a <params> nor a <fault> element")
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a value element into a Lua object.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Object.
|
||||
---------------------------------------------------------------------
|
||||
x2value = function (tab)
|
||||
local t = tab.tag
|
||||
assert (t == "value", "Not a `value' tag: "..t)
|
||||
local n = next_nonspace (tab)
|
||||
if type(n) == "string" or type(n) == "number" then
|
||||
return n
|
||||
elseif type (n) == "table" then
|
||||
local t = n.tag
|
||||
local get = xmlrpc_types[t]
|
||||
if not get then error ("Invalid <"..t.."> element") end
|
||||
return get (next_nonspace (tab))
|
||||
elseif type(n) == "nil" then
|
||||
-- the next best thing is to assume it's an empty string
|
||||
return ""
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a fault element into a Lua object.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Object.
|
||||
---------------------------------------------------------------------
|
||||
x2fault = function (tab)
|
||||
assert (tab.tag == "fault", "Not a `fault' tag: "..tab.tag)
|
||||
return x2value (next_nonspace (tab))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a param element into a Lua object.
|
||||
-- Ignore white spaces between elements.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Object.
|
||||
---------------------------------------------------------------------
|
||||
x2param = function (tab)
|
||||
assert (tab.tag == "params", "Not a `params' tag")
|
||||
local res = {}
|
||||
local p, i = next_nonspace (tab, 1)
|
||||
while p do
|
||||
if p.tag == "param" then
|
||||
tinsert (res, x2value (next_tag (p, "value")))
|
||||
end
|
||||
p, i = next_nonspace (tab, i+1)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a methodName element into a Lua object.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Object.
|
||||
---------------------------------------------------------------------
|
||||
local function x2methodName (tab)
|
||||
assert (tab.tag == "methodName", "Not a `methodName' tag: "..tab.tag)
|
||||
return (next_nonspace (tab, 1))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a methodCall element into its name and a list of parameters.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Object.
|
||||
---------------------------------------------------------------------
|
||||
local function x2methodCall (tab)
|
||||
assert (tab.tag == "methodCall", "Not a `methodCall' tag: "..tab.tag)
|
||||
return
|
||||
x2methodName (next_tag (tab,"methodName")),
|
||||
x2param (next_tag (tab,"params"))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- End of XML-RPC Parser
|
||||
---------------------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Convert a Lua Object into an XML-RPC string.
|
||||
---------------------------------------------------------------------
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local formats = {
|
||||
boolean = "<boolean>%d</boolean>",
|
||||
number = "<double>%d</double>",
|
||||
string = "<string>%s</string>",
|
||||
base64 = "<base64>%s</base64>",
|
||||
|
||||
array = "<array><data>\n%s\n</data></array>",
|
||||
double = "<double>%s</double>",
|
||||
int = "<int>%s</int>",
|
||||
struct = "<struct>%s</struct>",
|
||||
|
||||
member = "<member><name>%s</name>%s</member>",
|
||||
value = "<value>%s</value>",
|
||||
|
||||
param = "<param>%s</param>",
|
||||
|
||||
params = [[
|
||||
<params>
|
||||
%s
|
||||
</params>]],
|
||||
|
||||
fault = [[
|
||||
<fault>
|
||||
%s
|
||||
</fault>]],
|
||||
|
||||
methodCall = [[
|
||||
<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>%s</methodName>
|
||||
%s
|
||||
</methodCall>
|
||||
]],
|
||||
|
||||
methodResponse = [[
|
||||
<?xml version="1.0"?>
|
||||
<methodResponse>
|
||||
%s
|
||||
</methodResponse>]],
|
||||
}
|
||||
formats.table = formats.struct
|
||||
|
||||
local toxml = {}
|
||||
toxml.double = function (v,t) return format (formats.double, v) end
|
||||
toxml.int = function (v,t) return format (formats.int, v) end
|
||||
toxml.string = function (v,t) return format (formats.string, v) end
|
||||
toxml.base64 = function (v,t) return format (formats.base64, v) end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Build a XML-RPC representation of a boolean.
|
||||
-- @param v Object.
|
||||
-- @return String.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.boolean (v)
|
||||
local n = (v and 1) or 0
|
||||
return format (formats.boolean, n)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Build a XML-RPC representation of a number.
|
||||
-- @param v Object.
|
||||
-- @param t Object representing the XML-RPC type of the value.
|
||||
-- @return String.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.number (v, t)
|
||||
local tt = (type(t) == "table") and t["*type"]
|
||||
if tt == "int" or tt == "i4" or tt == "i8" then
|
||||
return toxml.int (v, t)
|
||||
elseif tt == "double" then
|
||||
return toxml.double (v, t)
|
||||
elseif v == ceil(v) then
|
||||
return toxml.int (v, t)
|
||||
else
|
||||
return toxml.double (v, t)
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param typ Object representing a type.
|
||||
-- @return Function that generate an XML element of the given type.
|
||||
-- The object could be a string (as usual in Lua) or a table with
|
||||
-- a field named "type" that should be a string with the XML-RPC
|
||||
-- type name.
|
||||
---------------------------------------------------------------------
|
||||
local function format_func (typ)
|
||||
if type (typ) == "table" then
|
||||
return toxml[typ.type]
|
||||
else
|
||||
return toxml[typ]
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param val Object representing an array of values.
|
||||
-- @param typ Object representing the type of the value.
|
||||
-- @return String representing the equivalent XML-RPC value.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.array (val, typ)
|
||||
local ret = {}
|
||||
local et = typ.elemtype
|
||||
local f = format_func (et)
|
||||
for i,v in ipairs (val) do
|
||||
if et and et ~= "array" then
|
||||
tinsert (ret, format (formats.value, f (v, et)))
|
||||
else
|
||||
local ct,cv = type_val(v)
|
||||
local cf = format_func(ct)
|
||||
tinsert (ret, format (formats.value, cf(cv, ct)))
|
||||
end
|
||||
|
||||
end
|
||||
return format (formats.array, concat (ret, '\n'))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
---------------------------------------------------------------------
|
||||
function toxml.struct (val, typ)
|
||||
local ret = {}
|
||||
if type (typ) == "table" then
|
||||
for n,t in pairs (typ.elemtype) do
|
||||
local f = format_func (t)
|
||||
tinsert (ret, format (formats.member, n, f (val[n], t)))
|
||||
end
|
||||
else
|
||||
for i, v in pairs (val) do
|
||||
tinsert (ret, toxml.member (i, v))
|
||||
end
|
||||
end
|
||||
return format (formats.struct, concat (ret))
|
||||
end
|
||||
|
||||
toxml.table = toxml.struct
|
||||
|
||||
---------------------------------------------------------------------
|
||||
---------------------------------------------------------------------
|
||||
function toxml.member (n, v)
|
||||
return format (formats.member, n, toxml.value (v))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Get type and value of object.
|
||||
---------------------------------------------------------------------
|
||||
function type_val (obj)
|
||||
local t = type (obj)
|
||||
local v = obj
|
||||
if t == "table" then
|
||||
t = obj["*type"] or "table"
|
||||
v = obj["*value"] or obj
|
||||
end
|
||||
return t, v
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Convert a Lua object to a XML-RPC object (plain string).
|
||||
---------------------------------------------------------------------
|
||||
function toxml.value (obj)
|
||||
local to, val = type_val (obj)
|
||||
if type(to) == "table" then
|
||||
return format (formats.value, toxml[to.type] (val, to))
|
||||
else
|
||||
-- primitive (not structured) types.
|
||||
--return format (formats[to], val)
|
||||
return format (formats.value, toxml[to] (val, to))
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param ... List of parameters.
|
||||
-- @return String representing the `params' XML-RPC element.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.params (...)
|
||||
local params_list = {}
|
||||
for i = 1, select ("#", ...) do
|
||||
params_list[i] = format (formats.param, toxml.value (select (i, ...)))
|
||||
end
|
||||
return format (formats.params, concat (params_list, '\n '))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param method String with method's name.
|
||||
-- @param ... List of parameters.
|
||||
-- @return String representing the `methodCall' XML-RPC element.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.methodCall (method, ...)
|
||||
local idx = strfind (method, "[^A-Za-z_.:/0-9]")
|
||||
if idx then
|
||||
error (format ("Invalid character `%s'", strsub (method, idx, idx)))
|
||||
end
|
||||
return format (formats.methodCall, method, toxml.params (...))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param err String with error message.
|
||||
-- @return String representing the `fault' XML-RPC element.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.fault (err)
|
||||
local code
|
||||
local message = err
|
||||
if type (err) == "table" then
|
||||
code = err.code
|
||||
message = err.message
|
||||
end
|
||||
return format (formats.fault, toxml.value {
|
||||
faultCode = { ["*type"] = "int", ["*value"] = code or err.faultCode or 1 },
|
||||
faultString = message or err.faultString or "fatal error",
|
||||
})
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param ok Boolean indicating if the response was correct or a
|
||||
-- fault one.
|
||||
-- @param params Object containing the response contents.
|
||||
-- @return String representing the `methodResponse' XML-RPC element.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.methodResponse (ok, params)
|
||||
local resp
|
||||
if ok then
|
||||
resp = toxml.params (params)
|
||||
else
|
||||
resp = toxml.fault (params)
|
||||
end
|
||||
return format (formats.methodResponse, resp)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- End of converter from Lua to XML-RPC.
|
||||
---------------------------------------------------------------------
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Create a representation of an array with the given element type.
|
||||
---------------------------------------------------------------------
|
||||
function newArray (elemtype)
|
||||
return { type = "array", elemtype = elemtype, }
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Create a representation of a structure with the given members.
|
||||
---------------------------------------------------------------------
|
||||
function newStruct (members)
|
||||
return { type = "struct", elemtype = members, }
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Create a representation of a value according to a type.
|
||||
-- @param val Any Lua value.
|
||||
-- @param typ A XML-RPC type.
|
||||
---------------------------------------------------------------------
|
||||
function newTypedValue (val, typ)
|
||||
return { ["*type"] = typ, ["*value"] = val }
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Create the XML-RPC string used to call a method.
|
||||
-- @param method String with method name.
|
||||
-- @param ... Parameters to the call.
|
||||
-- @return String with the XML string/document.
|
||||
---------------------------------------------------------------------
|
||||
function clEncode (method, ...)
|
||||
return toxml.methodCall (method, ...)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Convert the method response document to a Lua table.
|
||||
-- @param meth_resp String with XML document.
|
||||
-- @return Boolean indicating whether the call was successful or not;
|
||||
-- and a Lua object with the converted response element.
|
||||
---------------------------------------------------------------------
|
||||
function clDecode (meth_resp)
|
||||
local d = parse (meth_resp)
|
||||
if type(d) ~= "table" then
|
||||
error ("Not an XML document: "..meth_resp)
|
||||
end
|
||||
return x2methodResponse (d)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Convert the method call (client request) document to a name and
|
||||
-- a list of parameters.
|
||||
-- @param request String with XML document.
|
||||
-- @return String with method's name AND the table of arguments.
|
||||
---------------------------------------------------------------------
|
||||
function srvDecode (request)
|
||||
local d = parse (request)
|
||||
if type(d) ~= "table" then
|
||||
error ("Not an XML document: "..request)
|
||||
end
|
||||
return x2methodCall (d)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Convert a table into an XML-RPC methodReponse element.
|
||||
-- @param obj Lua object.
|
||||
-- @param is_fault Boolean indicating wether the result should be
|
||||
-- a `fault' element (default = false).
|
||||
-- @return String with XML-RPC response.
|
||||
---------------------------------------------------------------------
|
||||
function srvEncode (obj, is_fault)
|
||||
local ok = not (is_fault or false)
|
||||
return toxml.methodResponse (ok, obj)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Register the methods.
|
||||
-- @param tab_or_func Table or mapping function.
|
||||
-- If a table is given, it can have one level of objects and then the
|
||||
-- methods;
|
||||
-- if a function is given, it will be used as the dispatcher.
|
||||
-- The given function should return a Lua function that implements.
|
||||
---------------------------------------------------------------------
|
||||
dispatch = error
|
||||
function srvMethods (tab_or_func)
|
||||
local t = type (tab_or_func)
|
||||
if t == "function" then
|
||||
dispatch = tab_or_func
|
||||
elseif t == "table" then
|
||||
dispatch = function (name)
|
||||
local ok, _, obj, method = strfind (name, "^([^.]+)%.(.+)$")
|
||||
if not ok then
|
||||
return tab_or_func[name]
|
||||
else
|
||||
if tab_or_func[obj] and tab_or_func[obj][method] then
|
||||
return function (...)
|
||||
return tab_or_func[obj][method] (obj, ...)
|
||||
end
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
error ("Argument is neither a table nor a function")
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,76 @@
|
||||
-- Copyright 2003-2010 Kepler Project
|
||||
-- Copyright 2014-2018 Sandor Balazsi <sandor.balazsi@gmail.com>
|
||||
-- XML-RPC over SCGI.
|
||||
|
||||
local error, tonumber, tostring, unpack = error, tonumber, tostring, unpack
|
||||
|
||||
local socket= require"socket"
|
||||
local string= require"string"
|
||||
local xmlrpc= require"xmlrpc"
|
||||
|
||||
module("xmlrpc.scgi")
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Call a remote method.
|
||||
-- @param addr String with the address of the SCGI server.
|
||||
-- @param port The port of the SCGI server.
|
||||
-- @param method String with the name of the method to be called.
|
||||
-- @return Table with the response(could be a `fault' or a `params'
|
||||
-- XML-RPC element).
|
||||
---------------------------------------------------------------------
|
||||
function call(addr, port, method, ...)
|
||||
local request_body = xmlrpc.clEncode(method, ...)
|
||||
local sock = socket.connect(addr, port)
|
||||
if sock == nil then
|
||||
return false, "socket connect failed"
|
||||
end
|
||||
sock:send(netstring(request_body))
|
||||
local err, code, headers, body = receive(sock)
|
||||
|
||||
if tonumber(code) == 200 then
|
||||
return xmlrpc.clDecode(body)
|
||||
else
|
||||
error(tostring(err or code))
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Encode message as netstring
|
||||
-- @param request_body String with the message
|
||||
-- @return String with the encoded message
|
||||
---------------------------------------------------------------------
|
||||
function netstring(request_body)
|
||||
local null = "\0"
|
||||
local content_length = "CONTENT_LENGTH" .. null .. string.len(request_body) .. null
|
||||
local scgi_enable = "SCGI" .. null .. "1" .. null
|
||||
local request_method = "REQUEST_METHOD" .. null .. "POST" .. null
|
||||
local server_protocol = "SERVER_PROTOCOL" .. null .. "HTTP/1.1" .. null
|
||||
local header = content_length .. scgi_enable .. request_method .. server_protocol
|
||||
return string.len(header) .. ":" .. header .. "," .. request_body
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Receive and parse socket response
|
||||
-- @param sock Socket instance
|
||||
-- @return Headers, body and error codes
|
||||
---------------------------------------------------------------------
|
||||
function receive(sock)
|
||||
local line, body, err
|
||||
local headers = {}
|
||||
|
||||
line, err = sock:receive()
|
||||
if err then return err, "500" end
|
||||
while line ~= "" do
|
||||
local name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
|
||||
if not(name and value) then return "malformed reponse header: " .. line, "500" end
|
||||
headers[string.lower(name)] = value
|
||||
|
||||
line, err = sock:receive()
|
||||
if err then return err, "500" end
|
||||
end
|
||||
|
||||
body = sock:receive(headers["content-length"])
|
||||
local code = socket.skip(2, string.find(headers["status"], "^(%d%d%d)"))
|
||||
return err, code, headers, body
|
||||
end
|
||||
|
||||
Reference in new issue
Block a user