pax_global_header00006660000000000000000000000064114571410160014512gustar00rootroot0000000000000052 comment=23a045550090e4f5c96886f545c76d15392c6ca1 timn-lua-xmlrpc-77956f4/000077500000000000000000000000001145714101600150405ustar00rootroot00000000000000timn-lua-xmlrpc-77956f4/.gitignore000066400000000000000000000000031145714101600170210ustar00rootroot00000000000000*~ timn-lua-xmlrpc-77956f4/Makefile000077500000000000000000000002461145714101600165050ustar00rootroot00000000000000 LUA_DIR= /usr/local/share/lua/5.1 LUAS= src/init.lua src/http.lua src/server.lua build clean: install: mkdir -p $(LUA_DIR)/xmlrpc cp $(LUAS) $(LUA_DIR)/xmlrpc timn-lua-xmlrpc-77956f4/README000077500000000000000000000024241145714101600157250ustar00rootroot00000000000000Lua-XML-RPC is a Lua package to access and provide XML-RPC services Synopsis ======== This package provides code to access XML-RPC [1] services over HTTP. It also provides code to provide these services, e.g. by using Xavante [2]. The project website is at http://github.com/timn/lua-xmlrpc. [1]: http://www.xmlrpc.com/ [2]: http://keplerproject.github.com/xavante/ Dependencies ============ This library depends on the following packages. The given version numbers are known working versions. Earlier versions might work, but in that case we cannot accept bug reports. - LuaExpat http://www.keplerproject.org/luaexpat/ 2.0.1 - LuaSocket http://luasocket.luaforge.net/ 2.0.2 Files in this package ===================== README -- This file Makefile -- Makefile for Unix systems src/ init.lua -- Main module source file http.lua -- Extension library over HTTP server.lua -- Server implementation over CGILua tests/ apitest.lua -- Overall API test script httptest.lua -- Automatic tests over HTTP doc/us/ index.html -- Home page license.html -- Copyright & License luaxmlrpc.png -- LuaXMLRPC Logo manual.html -- Reference manual examples.html -- Examples timn-lua-xmlrpc-77956f4/doc/000077500000000000000000000000001145714101600156055ustar00rootroot00000000000000timn-lua-xmlrpc-77956f4/doc/examples.html000077500000000000000000000143661145714101600203260ustar00rootroot00000000000000 Lua XML-RPC: XML-RPC interface to the Lua programming language
Lua XML-RPC
XML-RPC interface to the Lua programming language

Examples

Client example

Below is a small sample code displaying the use of the library in a client application.

	    require "xmlrpc.http"

	    local ok, res = xmlrpc.http.call (
	    "http://www.oreillynet.com/meerkat/xml-rpc/server.php", 
	    "system.listMethods")
	    print (ok)
	    for i, v in pairs(res) do print ('\t', i, v) end
	  

Type conversion example

The next example shows how to force the conversion of types from Lua to XML-RPC.

	    require "xmlrpc"

	    double_array_type = xmlrpc.newArray ("double")
	    double_array = xmlrpc.newTypedValue ( { 1.1, 2, 3, 4 }, double_array_type)

	    double_array_array_type = xmlrpc.newArray (double_array_type)
	    double_array_array = xmlrpc.newTypedValue (
	    {
	    { 11, 12, 13, },
	    { 21, 22, 23, },
	    { 31, 32, 33, },
	    }, double_array_array_type)
	  

The table double_array_array will be:

	    <array>
	    <data>
	    <value>
	    <array>
            <data>
            <value><double>11</double></value>
            <value><double>12</double></value>
            <value><double>13</double></value>
            </data>
	    </array>
	    </value>
	    <value>
	    <array>
            <data>
            <value><double>21</double></value>
            <value><double>22</double></value>
            <value><double>23</double></value>
            </data>
	    </array>
	    </value>
	    <value>
	    <array>
            <data>
            <value><double>31</double></value>
            <value><double>32</double></value>
            <value><double>33</double></value>
            </data>
	    </array>
	    </value>
	    </data>
	    </array>
	  

Server example

Follows a small example of a server based on Xavante WSAPI. You can call the service for example with the xmlrpc tool from XML-RPC C (xmlrpc http://localhost:12345 hello_world) or by using examples/client.lua in the source tarball.

require("xavante")
require("xavante.httpd")
require("wsapi.xavante")
require("wsapi.request")
require("xmlrpc")

--- XML-RPC WSAPI handler
-- @param wsapi_env WSAPI environment
function wsapi_handler(wsapi_env)
   local headers = { ["Content-type"] = "text/xml" }
   local req = wsapi.request.new(wsapi_env)
   local method, arg_table = xmlrpc.srvDecode(req.POST.post_data)
   local func = xmlrpc.dispatch(method)
   local result = { pcall(func, unpack(arg_table or {})) }
   local ok = result[1]
   if not ok then
      result = { code = 3, message = result[2] }
   else
      table.remove(result, 1)
      if table.getn(result) == 1 then
         result = result[1]
      end
   end

   local r = xmlrpc.srvEncode(result, not ok)
   headers["Content-length"] = tostring(#r)

   local function xmlrpc_reply(wsapienv)
      coroutine.yield(r)
   end

   return 200, headers, coroutine.wrap(xmlrpc_reply)
end

-- XML-RPC exported functions
xmlrpc_exports = {}

--- Get simple string.
-- @return simple string
function xmlrpc_exports.hello_world()
   return "Hello World"
end

local rules = {{ match = ".", with = wsapi.xavante.makeHandler(wsapi_handler) }}
local config = { server = {host = "*", port = 12345}, defaultHost = { rules = rules} }

xmlrpc.srvMethods(xmlrpc_exports)
xavante.HTTP(config)

xavante.run()

Note that the package post and the function respond should be provided by the cgi launcher.

Valid XHTML 1.0!

timn-lua-xmlrpc-77956f4/doc/index.html000077500000000000000000000107521145714101600176120ustar00rootroot00000000000000 Lua XML-RPC: XML-RPC interface to the Lua programming language
Lua XML-RPC
XML-RPC interface to the Lua programming language

Overview

Lua XML-RPC is a library to make remote procedure calls using XML-RPC. It also offers facilities to develop server-side software.

Lua XML-RPC provides a simple API and an abstraction layer over XML, thus avoiding the complexity of having to deal with strings that represent data structures.

Lua XML-RPC is free software and uses the same license as Lua 5.1.

Status

Current version is 1.2. It was developed for Lua 5.1 based on LuaExpat.

Download

Lua XML-RPC can be downloaded in source code from Github.

History

Version 1.2 [18/oct/2010] (timn)
Lua 5.1 compatibility, converted from CVS to git, patches to improve handling or errorneous data
Version 1.0 [23/jan/2006]
Version 1.0 Beta [2/dec/2004]
Version 1.0 Alpha [10/dec/2003]

Lua XML-RPC Version 1.2 follows the package model for Lua 5.1 (see section Installation for more details).

Credits

Lua XML-RPC was designed by Roberto Ierusalimschy, André Carregal and Tomás Guisasola as part of the Kepler Project which holds its copyright. It was initially implemented by Tomás Guisasola. Tim Niemueller is the current maintainer.

Lua XML-RPC initial development was sponsored by Fábrica Digital and FINEP.

Contact

For more information please contact us. Comments are welcome!

Valid XHTML 1.0!

timn-lua-xmlrpc-77956f4/doc/license.html000077500000000000000000000110301145714101600201130ustar00rootroot00000000000000 Lua XML-RPC: XML-RPC interface to the Lua programming language
Lua XML-RPC
XML-RPC interface to the Lua programming language

License

Lua XML-RPC is free software: it can be used for both academic and commercial purposes at absolutely no cost. There are no royalties or GNU-like "copyleft" restrictions. Lua XML-RPC qualifies as Open Source software. Its licenses are compatible with GPL. Lua XML-RPC is not in the public domain and the Kepler Project hold its copyright. The legal details are below.

The spirit of the license is that you are free to use Lua XML-RPC for any purpose at no cost without having to ask us. The only requirement is that if you do use Lua XML-RPC, then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation.

The Lua XML-RPC library is designed and implemented by Roberto Ierusalimschy, André Carregal and Tomás Guisasola. Tim Niemueller is the current maintainer. The implementation is not derived from licensed software.


Copyright © 2003-2010 Kepler Project.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Valid XHTML 1.0!

timn-lua-xmlrpc-77956f4/doc/luaxmlrpc.png000077500000000000000000000202251145714101600203260ustar00rootroot00000000000000PNG  IHDRL\ IDATxy\׾gY !,5(ܨP)u)֥Ros_o{m}}^VXiׂX۪7/l+kX@֙y"6B/9s͜w~u\]wC.8 "[1P B *j``_*h3@R:ub!"!\]vSvtƍ Bɤheffx<9~xiӦ 822r;wh4WS @DPdffdJeNNεk6n@kkkkkM #==}߾}&\/X|7k֬zp"ah}TjXXX}}ߺ:oo񹹻gff2qZ:::8N```GG GD&H$ÿ"4瀀WU\#0dChTTԈe'z=Fo6]QQ![[[ ;::"""Ba[[[UUUBBd)nݺEl6DOp3 Jܹb))#'■PhHT}W)OI %VRNBLT&''ĘMpܹ"L&;p>VΜ9lZܹs555x<@ h4zjennnXjU,^|QlS#$'RILb|iʄb2|><..L&3>K HK, ` m^m~dD|q[[G6>}K TjhnMv-ZmV9CRO>:(//rVH&l6áhXZrc={vhh1wRTl_MMb//ٳgXe; aaat:(10 WVVƎ0>}:,z;@r]T* wo۶t7ovma#r, ~O{zz?a111躧#} rJ4V{r&;ON@bb":;; S"҂Ǵ StRÿ2l||| 'ϏzA L&;ydAAA[[[jj'MG*=+#>55IL;Y &&&VWW?s'??_* ŋ!*++޺usR]-rVVUUfrHΨs ɍ/~P(tzrrrmmoܸdɒ[OV3Og簳6Fsر^.x9={vyyy|| rss?9k֬{yyؽ] HoC٣GxTҫz(믿޲eM++ -_}u…V^,3m._.1|}o7x|x%D`XXի1V8Bh(7n<͍h%J'|\\OuvYN a BYnH ޺u+T*Fss##feMk?sʧF\>movG} Jye2Ynn.J3J0ݫ2KYY]Α'8IIf )<8:;ظ l: >>˰dnذA&}w&W(4v>)׶>/Zt,+\n `BGgͶ>`|>J1n:B1w\gt {L:TZ-4ɭ"w_c22NڔCx Iw---A^'@ A!/[Jv8hk[rrVP(Yhǥocjdž=Mi{}g3g\` z o(իt5j# 94^?߼;KK;,݈Á+WF.B}Kcc]0njKݓׄ@<D`+ w//w:pFgcX*U S ֬ fbԸ/Htȑ 6|rgn&6- ^*21̢HţW|YzJZڣ ^x!- z=sT K^4tPTZSS#=)###Vn dB>E),\wk>nژ/<觛76n< AXSR㛍*ѣRq=PhvϞܞ6/dӓHp<WRh0,Z%Tz???6]0 lٲݾ}b``bH֭[\E^͌tII hpFG|B!PH$"d2bqNNΙ3gm+7mɅ Rcc}cٿ1E`˖^-Z$ǜy.DfP>755t.qFKS AΉD hXL̛9ۉDCiF[aylvLLL[]\.WTVUU6CSTVj;u᧟`Nc7_  /7V_RPP+W&CիyKY M WVuaA.3}7ۢ AGoUlA,COOO#sfOy) dzzz~EPxpZZ0u^^j{MnuUFF.F+ڊ^}*c,5LU !)I).?&?:L t:GCCC $F<c0 c F&IR+:8fxXx>V}) BmA c=Q7$P ަ#|LF3]-& G0eq3h4EHv데T=TKM!'#eh(1::䓛pW`ppaV{f4A\F#p #JvܪAu,WTFםD|>"8!YCàYde%|R78d͟8~_mEN=X02`s4lD/8_60H$"btT7ٲXnϙ3 cX7Z-2Kݳg_ջv~>*Ø윜JCN"{o껣QTt_ Eyyyw0PL# 0Z_[ P_?}[=tXmfOV+G+5e ̭cT* DMC&͆Ey2`Dd$TL@EEwE%L,@4`^(~zPOl=!6tA^^^fcg4/@E7[HJ Ȉ%-ꊍÁsN:qv9N( ""|`Gww9sLC5W|}}KbN^$'.@~ۅjReìd__^^f `y_R/_|ߘ ([ZZZG܊wuuq\1 &0Ϩ(N}Y9{~~u˗یvlIҿٳ6dmm-QQfr ˖cq`\ p  &{WTX؈16KI 7/ǣp8Hqvυ -h4G lB~aNKK6bF֡Sf(BUH٧L&[nY ;wU; ᇋ\\bi}Lk6̟?Ν^,\ۉ;'\x8NLLLII ;z\.5//)QpcsvRL( VP*GVbmۆD^nI?9b ,)j_~iz:%\M:_䓔 o gfaL|toߒ'Yw22r /ڵk>p83f̰~0jh4"8 x:```W_5Z9q4---ݻwL2%`:޺Ni Lua XML-RPC: XML-RPC interface to the Lua programming language
Lua XML-RPC
XML-RPC interface to the Lua programming language

Introduction

Lua XML-RPC is a Lua library that can be used to build XML-RPC clients and servers. It enables a Lua program to:

  • Encode and decode XML-RPC messages without handling XML code
  • Transform Lua data structures into XML-RPC data types and vice-versa

Lua XML-RPC provides a simple API and an abstraction layer over XML avoiding manipulation of string representation of data structures.

Lua XML-RPC is based on LuaExpat and on Lua 5.1. The abstraction layer over HTTP depends on LuaSocket 2.0.2.

Installation

Lua XML-RPC is composed by three Lua files:

init.lua
Main source file providing the API
http.lua
API to call XML-RPC via HTTP
server.lua
Server side API

These files should be copied to a directory named xmlrpc created in your LUA_PATH.

Lua XML-RPC follows the package model for Lua 5.1, therefore it should be "installed". Refer to Compat-5.1 configuration section about how to install the module.

Data types

XML-RPC elements are usually represented by the simplest correspondent Lua object. When the correspondance is not obvious, a Lua table is used with a field specifying the element.

From XML-RPC to Lua

When converting from XML-RPC element to a Lua data item or table, a table with a field tag is used. The child elements are stored at numbered indexes and white space is ignored.

XML-RPC data type(s) Lua object
double
int
i4
number
string string
boolean boolean
struct
arrray
table
other elements
{
		tag = "element name",
		[1] = <first child>,
		[2] = <second child>,
		[3] = ...,
		}

From Lua to XML-RPC

A conversion from a Lua data item or table to an XML-RPC element can be made automatically or explicitly. The automatic conversion rules are:

Lua object XML-RPC data type
number int or double
string string
boolean boolean
{ key = val }
		<struct>
		<member>
		<name>key</name>
		<value>val</value>
		</member>
		</struct>
	      
val is converted according to the same rules.

Ifn case of a table that has numeric keys, the resulting struct will have the string representation of these numbers as keys (e.g. "1" instead of 1). The library tries to convert integral numbers to integer types, otherwise converting them to floating point numbers.

Library functions

The xmlrpc.lua file implements the functions that encode and decode XML-RPC messages and transform data types between the Lua and XML-RPC. The functions are:

clEncode (method_name [, params]) => method_call
Build a XML-RPC document containing a methodCall element. It receives a string with the method's name and an optional list of parameters. The result is a string containing the XML-RPC document.
clDecode (method_response) => ok, results
Disassemble the server response into a Lua object. It receives a string containing the XML-RPC document representing the methodResponse element. The result is a boolean indicating wether the call was successful or not followed by the resulting objects (typically a methodResponse has only one value so only one Lua object will be returned). In case of error the false value is followed by the XMLRPC faultString and the faultCode. This values are extracted from the fault element.
srvDecode (method_call) => method_name, list_params
Disassemble the client request into a method's name and a table with the list of parameters. It receives a string containing the XML-RPC document representing the methodCall element. The result is a string with the name of the method to be called and a Lua table with the arguments to the call.
srvEncode (object, is_fault) => method_response
Build a XML-RPC document containing a methodResponse element. It receives a Lua object (a number, a string, a table, a "created typed value" etc.) with the return value of the call. The result is a string containing the XML-RPC document. Note that XML-RPC defines that a response only returns one value so a Lua function that returns more than one value has to pack them into a table to guarantee that all of them will be returned. The second parameter (is_fault) can be used to force a fault element to be generated instead of a params. In this case, the Lua object must be a table with the members faultCode and faultString.
srvMethods (tab_or_func)
Register the methods on the server. The parameter can be a table or a dispatching function. If a table is given it can have one level of objects with the corresponding methods. If a function is given, it will replace the dispatcher.
dispatch (method_name) => function
Returns a Lua function that implements the method call. Note that the object is encapsulated into that function so that the call will be turned into a real method call.

Client side

The http.lua file implements a simple stand-alone client based on LuaSocket 2.0.2. The following function is provided:

call (url, method [, params])
Execute the call to method at location url with the given params (if any). The method and params parameters will be just passed to clEncode function. The result is the same as clDecode function: a boolean indicating whether the call was successful or not, followed by the response value (if successful) or by the faultString and the faultCode (if the call fails).

Server side

The distribution also offers a simple XML-RPC server implemented over a CGI launcher. This launcher just have to offer a way to decode POST data and to send data back to the client.

The tests directory contains a file named cgi.lua, which implements an example of a simple XML-RPC server using the package post (which parses incoming POST data from the http server). An appropriate environment for writing Lua functions is implemented; a new assert function generates a XML-RPC fault in case of a false condition; a respond function creates the correct header for the responses. The main goal of cgi.lua is to give a starting point for other implementations.

References

Related documentation can be found at: http://www.xmlrpc.com.

timn-lua-xmlrpc-77956f4/examples/000077500000000000000000000000001145714101600166565ustar00rootroot00000000000000timn-lua-xmlrpc-77956f4/examples/client.lua000066400000000000000000000003251145714101600206370ustar00rootroot00000000000000require("xmlrpc.http") local ok, res = xmlrpc.http.call("http://localhost:12345", "hello_world") assert(ok, string.format("XML-RPC call failed on client: %s", tostring(res))) print("Result: " .. tostring(res)) timn-lua-xmlrpc-77956f4/examples/server_xavante.lua000066400000000000000000000024431145714101600224200ustar00rootroot00000000000000require("xavante") require("xavante.httpd") require("wsapi.xavante") require("wsapi.request") require("xmlrpc") --- XML-RPC WSAPI handler -- @param wsapi_env WSAPI environment function wsapi_handler(wsapi_env) local headers = { ["Content-type"] = "text/xml" } local req = wsapi.request.new(wsapi_env) local method, arg_table = xmlrpc.srvDecode(req.POST.post_data) local func = xmlrpc.dispatch(method) local result = { pcall(func, unpack(arg_table or {})) } local ok = result[1] if not ok then result = { code = 3, message = result[2] } else table.remove(result, 1) if table.getn(result) == 1 then result = result[1] end end local r = xmlrpc.srvEncode(result, not ok) headers["Content-length"] = tostring(#r) local function xmlrpc_reply(wsapienv) coroutine.yield(r) end return 200, headers, coroutine.wrap(xmlrpc_reply) end -- XML-RPC exported functions xmlrpc_exports = {} --- Get simple string. -- @return simple string function xmlrpc_exports.hello_world() return "Hello World" end local rules = {{ match = ".", with = wsapi.xavante.makeHandler(wsapi_handler) }} local config = { server = {host = "*", port = 12345}, defaultHost = { rules = rules} } xmlrpc.srvMethods(xmlrpc_exports) xavante.HTTP(config) xavante.start() timn-lua-xmlrpc-77956f4/src/000077500000000000000000000000001145714101600156275ustar00rootroot00000000000000timn-lua-xmlrpc-77956f4/src/http.lua000077500000000000000000000027121145714101600173160ustar00rootroot00000000000000--------------------------------------------------------------------- -- XML-RPC over HTTP. -- See Copyright Notice in license.html --------------------------------------------------------------------- local error, tonumber, tostring, unpack = error, tonumber, tostring, unpack local ltn12 = require"ltn12" local request = require"socket.http".request local string = require"string" local table = require"table" local xmlrpc = require"xmlrpc" module("xmlrpc.http") --------------------------------------------------------------------- -- Call a remote method. -- @param url String with the location of the 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 (url, method, ...) local request_sink, tbody = ltn12.sink.table() local request_body = xmlrpc.clEncode(method, ...) local err, code, headers, status = request { url = url, method = "POST", source = ltn12.source.string (request_body), sink = request_sink, headers = { ["User-agent"] = xmlrpc._PKGNAME .. " " .. xmlrpc._VERSION, ["Content-type"] = "text/xml", ["content-length"] = tostring (string.len (request_body)), }, } local body = table.concat (tbody) if tonumber (code) == 200 then return xmlrpc.clDecode (body) else error (tostring (err or code).."\n\n"..tostring(body)) end end timn-lua-xmlrpc-77956f4/src/init.lua000077500000000000000000000466671145714101600173230ustar00rootroot00000000000000--------------------------------------------------------------------- -- XML-RPC implementation for Lua. -- See Copyright Notice in license.html --------------------------------------------------------------------- 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 = lxp.lom.parse module (...) _COPYRIGHT = "Copyright (C) 2003-2010 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 = 1 _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 == "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, 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 nor a 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 = "%d", number = "%d", string = "%s", array = "\n%s\n", double = "%s", int = "%s", struct = "%s", member = "%s%s", value = "%s", param = "%s", params = [[ %s ]], fault = [[ %s ]], methodCall = [[ %s %s ]], methodResponse = [[ %s ]], } 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 --------------------------------------------------------------------- -- 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" 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 timn-lua-xmlrpc-77956f4/src/server.lua000077500000000000000000000051541145714101600176500ustar00rootroot00000000000000--------------------------------------------------------------------- -- XML-RPC server -- See Copyright Notice in license.html --------------------------------------------------------------------- local assert, pcall, setmetatable, type, unpack = assert, pcall, setmetatable, type, unpack local cgilua = require"cgilua" local os = require"os" local string = require"string" local table = require"table" local xmlrpc = require"xmlrpc" module("xmlrpc.server") --------------------------------------------------------------------- local function respond (resp) cgilua.header ("Date", os.date()) cgilua.header ("Server", "Me") cgilua.header ("Content-length", string.len (resp)) cgilua.header ("Connection", "close") cgilua.contentheader ("text", "xml") cgilua.put (resp) end --------------------------------------------------------------------- function assert (cond, msg) if not cond then respond (xmlrpc.srvEncode ( { code = 2, message = msg, }, true )) --os.exit() -- !!!!!!!!!!! end end cgilua.seterroroutput (function (msg) respond (xmlrpc.srvEncode ({ code = 2, message = msg, }, true)) end) --------------------------------------------------------------------- local function decodedata (doc) local method, arg_table = xmlrpc.srvDecode (doc) assert (type(method) == "string", "Invalid `method': string expected") local t = type(arg_table) assert (t == "table" or t == "nil", "Invalid table of arguments: not a table nor nil") local func = xmlrpc.dispatch (method) assert (type(func) == "function", "Unavailable method") return func, (arg_table or {}) end --------------------------------------------------------------------- local function callfunc (func, arg_table) local result = { pcall (func, unpack (arg_table)) } local ok = result[1] if not ok then result = { code = 3, message = result[2], } else table.remove (result, 1) if #result == 1 then result = result[1] end end return ok, result end --------------------------------------------------------------------- function xmlrpc.server:new() local o = { methods = { } } setmetatable (o, self) self.__index = self return o end --------------------------------------------------------------------- function xmlrpc.server:register(name, service) assert (type(name) == "string", "Invalid `name': string expected") self.methods[name] = service end --------------------------------------------------------------------- function xmlrpc.server:handle() xmlrpc.srvMethods (self.methods) local func, arg_table = decodedata (cgi[1]) local ok, result = callfunc (func, arg_table) local r = xmlrpc.srvEncode (result, not ok) respond (r) end timn-lua-xmlrpc-77956f4/tests/000077500000000000000000000000001145714101600162025ustar00rootroot00000000000000timn-lua-xmlrpc-77956f4/tests/apitest.lua000077500000000000000000000230671145714101600203710ustar00rootroot00000000000000#!/usr/local/bin/lua50 --------------------------------------------------------------------- -- XML-RPC Overall API test script -- See Copyright Notice in license.html --------------------------------------------------------------------- require "xmlrpc" function table._print (tab, indent, spacing) spacing = spacing or "" indent = indent or "\t" io.write ("{\n") for nome, val in pairs (tab) do io.write (spacing..indent) local t = type(nome) if t == "string" then io.write (string.format ("[%q] = ", tostring (nome))) elseif t == "number" or t == "boolean" then io.write (string.format ("[%s] = ", tostring (nome))) else io.write (t) end t = type(val) if t == "string" or t == "number" then io.write (string.format ("%q", val)) elseif t == "table" then table.print (val, indent, spacing..indent) else io.write (t) end io.write (",\n") end io.write (spacing.."}") end function table._tostring (tab, indent, spacing) local s = {} spacing = spacing or "" indent = indent or "\t" table.insert (s, "{\n") for nome, val in pairs (tab) do table.insert (s, spacing..indent) local t = type(nome) if t == "string" then table.insert (s, string.format ("[%q] = ", tostring (nome))) elseif t == "number" or t == "boolean" then table.insert (s, string.format ("[%s] = ", tostring (nome))) else table.insert (s, t) end t = type(val) if t == "string" or t == "number" then table.insert (s, string.format ("%q", val)) elseif t == "table" then table.insert (s, table._tostring (val, indent, spacing..indent)) else table.insert (s, t) end table.insert (s, ",\n") end table.insert (s, spacing.."}") return table.concat (s) end function table.print (tab, indent, spacing) io.write (table._tostring (tab, indent, spacing)) end function table.equal2 (t1, t2) if type(t1) ~= "table" or type(t2) ~= "table" then return false end for key, v1 in t1 do local v2 = rawget (t2, key) if type(v1) == "table" and type(v2) == "table" then if not table.equal (v1, v2) then return false end elseif v1 ~= v2 then return false end end return true end function table.equal (t1, t2) if type(t1) ~= "table" or type(t2) ~= "table" then return false end local s1 = table._tostring (t1) local s2 = table._tostring (t2) s1 = string.gsub (s1, "%s*", "") s2 = string.gsub (s2, "%s*", "") --if s1 ~= s2 then --print(s1, "!!!!", s2) --end return s1 == s2, s1.."!!!"..s2 end function remove_type (tab) if type(tab) ~= "table" then return tab elseif tab["*type"] then return tab["*value"] end for i,v in pairs (tab) do if type(v) == "table" then tab[i] = remove_type (v) end end return tab end function call_test (xml_call, method, ...) local xc = string.gsub (xml_call, "(%p)", "%%%1") --xc = string.gsub (xc, "\r?\n%s*", "%%s*") xc = string.gsub (xc, "%s*", "") arg.n = nil -- client enconding test local meth_call = xmlrpc.clEncode (method, unpack (arg)) meth_call = string.gsub (meth_call, "%s*", "") local s = string.gsub (meth_call, xc, "") s = string.gsub (s, "%s*", "") assert (s == "", s.."\n!!!\n"..xc) -- server decoding test local meth_call, param = xmlrpc.srvDecode (xml_call) assert (meth_call == method, meth_call) arg = remove_type (arg) assert (table.equal (arg, param)) end function response_test (xml_resp, lua_obj) -- client decoding test local ok, obj = xmlrpc.clDecode (xml_resp) -- server encoding test xml_resp = string.gsub (xml_resp, "(%p)", "%%%1") xml_resp = string.gsub (xml_resp, "\r?\n%s*", "%%s*") local meth_resp = xmlrpc.srvEncode (lua_obj) if type (obj) == "table" then lua_obj = remove_type (lua_obj) assert (table.equal (obj, lua_obj)) else assert (obj == lua_obj) end local s = string.gsub (meth_resp, xml_resp, "") s = string.gsub (s, "%s*", "") assert (s == "", s) end function fault_test (xml_resp, message, code) -- client decoding test local ok, str, n = xmlrpc.clDecode (xml_resp) assert (str == message) assert (n == code) -- server encoding test xml_resp = string.gsub (xml_resp, "(%p)", "%%%1") xml_resp = string.gsub (xml_resp, "\r?\n%s*", "%%s*") local meth_resp = xmlrpc.srvEncode ({ message = message, code = code }, true) local s = string.gsub (meth_resp, xml_resp, "") s = string.gsub (s, "%s*", "") assert (s == "", s) end --------------------------------------------------------------------- -- call tests. --------------------------------------------------------------------- call_test ([[ examples.getStateName 41 ]], "examples.getStateName", 41) local double_139 = xmlrpc.newTypedValue (139, "double") call_test ([[ examples.getSomething lowerBound 18.2 upperBound 139 ]], "examples.getSomething", { lowerBound = 18.2, upperBound = double_139 }) local double_array = xmlrpc.newArray ("double") call_test ([[ test 1 2 3 4 ]], "test", xmlrpc.newTypedValue ({ 1, 2, 3, 4, }, double_array) ) local double_array_array = xmlrpc.newArray (double_array) call_test ([[ test 1 2 3 4 11 12 13 14 21 22 23 24 ]], "test", xmlrpc.newTypedValue ( { { 1, 2, 3, 4, }, { 11, 12, 13, 14, }, { 21, 22, 23, 24, }, }, double_array_array ) ) call_test ([[ insertTable people name Fulano email fulano@nowhere.world name Beltrano email beltrano@nowhere.world name Cicrano email cicrano@nowhere.world ]], "insertTable", "people", xmlrpc.newTypedValue ( { { name = "Fulano", email = "fulano@nowhere.world", }, { name = "Beltrano", email = "beltrano@nowhere.world", }, { name = "Cicrano", email = "cicrano@nowhere.world", }, }, xmlrpc.newArray ("struct") ) ) --------------------------------------------------------------------- -- response tests. --------------------------------------------------------------------- response_test ([[ South Dakota ]], "South Dakota") response_test ([[ lowerBound 18.2 upperBound 139 ]], { lowerBound = 18.2, upperBound = double_139 }) fault_test ([[ faultCode 1 faultString error string ]], "error string", 1) print("Ok!") timn-lua-xmlrpc-77956f4/tests/httptest.lua000077500000000000000000000055061145714101600205750ustar00rootroot00000000000000--------------------------------------------------------------------- -- XML-RPC Automatic Tests -- See Copyright Notice in license.html ----------------------------------------------------------------------- require"xmlrpc.http" local function init_launcher(launcher) if launcher == 'cgilua' then require"cgilua" cgilua.htmlheader() io.write = function(str) cgilua.put(string.gsub(str, '\n','
')) end --io.write end --if end local function dumpt(t) for k,v in pairs(t) do io.write('\nk='..tostring(k)..'\tv='..tostring(v)) if type(v) == 'table' then dumpt(v) end end --for end local function test(url, rtype, rvalue, method, args) local status, res io.write('\nURL='..url..'\nMETHOD='..method..'\nPARAMETERS=') io.write(unpack(args or {'void'})) if args then status, xmlstatus, res = pcall( xmlrpc.http.call,url, method, unpack(args)) else status, xmlstatus, res = pcall( xmlrpc.http.call,url, method) end --if if not status then io.write('\nFAILURE! '..xmlstatus) else if not xmlstatus and rtype ~= 'failure' then io.write('\nFAILURE! '..res) else io.write('\nreturn type expected= '..rtype) if type(res) == rtype or (not xmlstatus and rtype == 'failure') then io.write(' (OK)') else io.write(' (FAILURE) returning a '..type(res)) end --if if rvalue then io.write('\nvalue expected='..tostring(rvalue)) if type(res) == 'table' then dumpt(res) elseif tostring(rvalue) == tostring(res) then io.write(' (OK)') else io.write(' (FAILURE) value returned='..tostring(res)) end --if end --if end --if end --if io.write('\n') end function syndic8() test( "http://www.syndic8.com/xmlrpc.php", "string", nil, "syndic8.GetFeedCount" ) end local server = 'http://localhost:80/server.lua' function calc() test( server, 'number', '25', 'calc.add', {10,15} ) test( server, 'string', '0.1v', 'calc.getVersion' ) test( server, 'boolean', 'true', 'calc.isprime', {7} ) test( server, 'boolean', 'false', 'calc.isprime', {80} ) test( server, 'table', {{1,0},{0,1}}, 'calc.MID' ) test( server, 'failure', 'Unavailable method', 'calc' ) test( server, 'failure', 'Unavailable method', 'calc.MID2' ) test( server, 'failure', 'Unavailable method', 'foo', {2} ) test( server, 'failure', 'Unavailable method', 'foo.foo2.foo3', {3,4,5} ) -- test( 'http://localhost:82/calc.xmlrpc', 'number', '25', 'calc.add', {10,15} ) end local launcher = { 'lua', 'cgilua', } local tests = { [1] = { name='SYNDIC8', func=syndic8 }, [2] = { name='CALCULATOR', func=calc }, } init_launcher(launcher[1]) io.write( [[ LuaXMLRPC - Automatic Tests 0.1v ]] ) for k,v in pairs( tests ) do io.write( "\n\nT"..k.." - "..v.name.."\n" ) v.func() end --for