Initial revision
This commit is contained in:
commit
9a829802f0
17
Makefile
Executable file
17
Makefile
Executable file
@ -0,0 +1,17 @@
|
||||
VERSION= 1.0a
|
||||
PKG= luaxmlrpc-$(VERSION)
|
||||
TAR_FILE= $(PKG).tar.gz
|
||||
ZIP_FILE= $(PKG).zip
|
||||
SRCS= README Makefile \
|
||||
xmlrpc.lua xrh.lua xrc.lua test.lua \
|
||||
index.html manual.html license.html lua.png
|
||||
|
||||
dist:
|
||||
mkdir $(PKG)
|
||||
cp $(SRCS) $(PKG)
|
||||
tar -czf $(TAR_FILE) $(PKG)
|
||||
zip -lq $(ZIP_FILE) $(PKG)
|
||||
rm -rf $(PKG)
|
||||
|
||||
clean:
|
||||
rm $(TAR_FILE) $(ZIP_FILE)
|
19
README
Executable file
19
README
Executable file
@ -0,0 +1,19 @@
|
||||
LuaXMLRPC is a library of functions to deal with XML-RPC.
|
||||
|
||||
This library depends on LuaExpat.
|
||||
The standalone server depends on LuaSocket for Lua 5.0 also.
|
||||
|
||||
Here goes a small description of the files in the distribution
|
||||
|
||||
index.html -- Home page
|
||||
license.html -- Copyright & License
|
||||
lua.png -- Lua Logo
|
||||
Makefile -- Makefile for Unix systems
|
||||
manual.html -- Reference manual
|
||||
README -- This file
|
||||
test.lua -- Overall API test script
|
||||
xmlrpc.lua -- Source file
|
||||
xrc.lua -- Extension server library over CGI
|
||||
xrh.lua -- Extension server library over HTTP
|
||||
|
||||
$Id$
|
126
doc/index.html
Executable file
126
doc/index.html
Executable file
@ -0,0 +1,126 @@
|
||||
<! See Copyright Notice in license.html>
|
||||
<html>
|
||||
<!$Id$>
|
||||
|
||||
<head>
|
||||
<style type="text/css">
|
||||
ul { list-style-type: disc };
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<hr>
|
||||
|
||||
<center>
|
||||
<table border=0 cellspacing=2 cellpadding=2>
|
||||
<tr><td align=center><a href="http://www.lua.org">
|
||||
<img border=0 alt="The Lua language" src="lua.png"></a>
|
||||
<tr><td align=center><big><b>LuaXMLRPC</b></big>
|
||||
<tr><td align=center valign=top>A Lua library for XML-RPC
|
||||
</table>
|
||||
</center>
|
||||
<p>
|
||||
|
||||
<center><small>
|
||||
<a href=#over>overview</a> ·
|
||||
<a href=#version>current version</a> ·
|
||||
<a href=#download>download</a> ·
|
||||
<a href=#new>what's new</a> ·
|
||||
<a href=#installation>installation</a> ·
|
||||
<a href="manual.html">manual</a> ·
|
||||
<a href=#hist>history</a>
|
||||
</small></center>
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>Contents</h2>
|
||||
<p>
|
||||
<ul>
|
||||
<li> <a href=#over>Overview</a>
|
||||
<li> <a href=#version>Current Version</a>
|
||||
<li> <a href=#download>Download</a>
|
||||
<li> <a href=#new>What's new</a>
|
||||
<li> <a href=#installation>Installation</a>
|
||||
<li> <a href="manual.html">User's manual</a>
|
||||
<ul>
|
||||
<li> <a href="manual.html#introduction">Introduction</a>
|
||||
<li> <a href="manual.html#examples">Examples</a>
|
||||
</ul>
|
||||
<li> <a href=#hist>History</a>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<a name=over>
|
||||
<h2>Overview</h2>
|
||||
<p>
|
||||
LuaXMLRPC is a library to make remote procedure calls over
|
||||
<a href="http://www.xmlrpc.com">XML-RPC</a>.
|
||||
|
||||
|
||||
<a name=version>
|
||||
<h2>Current version</h2>
|
||||
<p>
|
||||
Current version is 1.0 alpha.
|
||||
</p>
|
||||
|
||||
|
||||
<a name=download>
|
||||
<h2>Download</h2>
|
||||
|
||||
LuaXMLRPC can be downloaded in source code from the following links: <p>
|
||||
|
||||
<blockquote>
|
||||
<a href="http://poison.les.inf.puc-rio.br/luaxmlrpc/luaxmlrpc-1.0a.tar.gz">luaxmlrpc-1.0a.tar.gz</a><br>
|
||||
<a href="http://poison.les.inf.puc-rio.br/luaxmlrpc/luaxmlrpc-1.0a.zip">luaxmlrpc-1.0a.zip</a>
|
||||
</blockquote><p>
|
||||
|
||||
|
||||
<a name=new>
|
||||
<h2>What's new</h2>
|
||||
<p>
|
||||
<ul>
|
||||
<li>[?/?/2003] Version 1.0 alpha released
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<a name="installation"></a>
|
||||
<h2>Installation</h2>
|
||||
|
||||
<p>
|
||||
LuaXMLRPC is a Lua library so the installation is very simple.
|
||||
</p>
|
||||
|
||||
|
||||
<a name=hist>
|
||||
<h2>History</h2>
|
||||
|
||||
<p>
|
||||
LuaXMLRPC development was sponsored by
|
||||
<a href="http://www.fabricadigital.com.br">Fábrica Digital</a>
|
||||
and FINEP.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<center><small>
|
||||
<a href=#over>overview</a> ·
|
||||
<a href=#version>current version</a> ·
|
||||
<a href=#download>download</a> ·
|
||||
<a href=#new>what's new</a> ·
|
||||
<a href=#installation>installation</a> ·
|
||||
<a href="manual.html">manual</a> ·
|
||||
<a href=#hist>history</a>
|
||||
</small></center>
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
<small>
|
||||
Last modified on
|
||||
Tue Oct 28 15:28:41 BRST 2003
|
||||
</small>
|
||||
|
||||
</body>
|
||||
</html>
|
80
doc/license.html
Executable file
80
doc/license.html
Executable file
@ -0,0 +1,80 @@
|
||||
<! See Copyright Notice at the end of this file>
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>LuaXMLRPC: license</TITLE>
|
||||
</HEAD>
|
||||
<!$Id$>
|
||||
|
||||
<BODY BGCOLOR="#FFFFFF">
|
||||
|
||||
<HR>
|
||||
<H1>
|
||||
License
|
||||
</H1>
|
||||
|
||||
LuaXMLRPC
|
||||
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.
|
||||
LuaXMLRPC qualifies as
|
||||
<A HREF="http://www.opensource.org/docs/definition.html">Open Source</A>
|
||||
software.
|
||||
Its licenses are compatible with
|
||||
<A HREF="http://www.gnu.org/licenses/gpl.html">GPL</A>.
|
||||
LuaXMLRPC is not in the public domain and
|
||||
<a href="http://www.keplerproject.org">The Kepler Project</a>
|
||||
keep its copyright.
|
||||
The legal details are below.
|
||||
<P>
|
||||
|
||||
The spirit of the license is that
|
||||
you are free to use LuaXMLRPC for any purpose at no cost without having to ask us.
|
||||
The only requirement is that
|
||||
if you do use LuaXMLRPC,
|
||||
then you should give us credit by including the appropriate copyright notice
|
||||
somewhere in your product or its documentation.
|
||||
<P>
|
||||
|
||||
The LuaXMLRPC library is designed and implemented
|
||||
by
|
||||
Roberto Ierusalimschy,
|
||||
André Carregal and
|
||||
Tomás Guisasola.
|
||||
The implementation is not derived from licensed software.
|
||||
<P>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<HR>
|
||||
Copyright © 2003 The Kepler Project.
|
||||
<P>
|
||||
|
||||
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:
|
||||
<P>
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
<P>
|
||||
|
||||
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.
|
||||
<P>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<HR>
|
||||
<SMALL>
|
||||
Last update:
|
||||
Fri Nov 28 15:57:05 BRST 2003
|
||||
</SMALL>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
288
doc/manual.html
Executable file
288
doc/manual.html
Executable file
@ -0,0 +1,288 @@
|
||||
<! See Copyright Notice in license.html>
|
||||
<html>
|
||||
<!$Id$>
|
||||
|
||||
<head>
|
||||
<style type="text/css">
|
||||
ul { list-style-type: disc };
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#FFFFFF">
|
||||
|
||||
<hr>
|
||||
|
||||
<center>
|
||||
<table border=0 cellspacing=2 cellpadding=2>
|
||||
<tr><td align=center><a href="http://www.lua.org">
|
||||
<img border=0 alt="The Lua language" src="lua.png"></a>
|
||||
<tr><td align=center><big><b>LuaXMLRPC Reference Manual</b></big>
|
||||
<tr><td align=center valign=top>A Lua library for Remote Procedure Call over HTTP
|
||||
</table>
|
||||
</center>
|
||||
<p>
|
||||
|
||||
<center><small>
|
||||
<a href="index.html">home</a> ·
|
||||
<a href="#data_types">data types</a> ·
|
||||
<a href="#client">client</a> ·
|
||||
<a href="#server">server</a> ·
|
||||
<a href="#toxml">xml elements</a> ·
|
||||
<a href="#xmlrpc_parser">xml-rpc parser</a> ·
|
||||
<a href="#examples">example</a> ·
|
||||
<a href="#related_docs">related docs</a>
|
||||
</small></center>
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
|
||||
<a name="introduction"></a>
|
||||
<h2>Introduction</h2>
|
||||
|
||||
<p>
|
||||
LuaXMLRPC is a <a href="http://www.lua.org">Lua</a> library
|
||||
to manage <a href="http://www.xmlrpc.com">XML-RPC</a> clients and servers.
|
||||
It enables a Lua program to:
|
||||
<ul>
|
||||
<li> Make a remote procedure call to a XML-RPC server
|
||||
without having to deal with XML code
|
||||
<li> Register Lua functions/scripts ??????
|
||||
to respond to remote procedure calls
|
||||
<li> Transform Lua objects into XML-RPC data types and vice-versa
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
LuaXMLRPC provides simple API and an abstraction layer over XML
|
||||
avoiding manipulation of string representation of data structures.
|
||||
It also offers ways to express everything when needed.
|
||||
<p>
|
||||
The library is divided into four Lua files:
|
||||
<ul>
|
||||
<li> <b><code>xmlrpc.lua</code></b> basic support:
|
||||
build client requests and server responses;
|
||||
and disassemble client requests and server responses.
|
||||
<li> <b><code>toxml.lua</code></b> convert Lua objects to XML
|
||||
<li> <b><code>xrp.lua</code></b> parse XML-RPC objects to Lua
|
||||
</ul>
|
||||
<p>
|
||||
LuaXMLRPC is based on
|
||||
<a href="http://www.tecgraf.puc-rio.br/luasocket">LuaSocket</a>,
|
||||
<a href="http://poison.les.inf.puc-rio.br/luaexpat">LuaExpat</a>
|
||||
and on <a href="http://www.lua.org">Lua 5.0</a>.
|
||||
|
||||
|
||||
<a name="data_types"></a>
|
||||
<h2>Data types</h2>
|
||||
<p>
|
||||
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.
|
||||
|
||||
|
||||
<a name="xr2lua"</a>
|
||||
<h3>From XML-RPC to Lua</h3>
|
||||
<p>
|
||||
When converting from XML-RPC element to a Lua object,
|
||||
a table with a field <code>tag</code> is used.
|
||||
The child elements are stored at numbered indexes
|
||||
and white space is ignored.
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td>XML-RPC data type
|
||||
<td>Lua object
|
||||
</tr>
|
||||
<tr>
|
||||
<td>double<br>int<br>i4
|
||||
<td>number
|
||||
</tr>
|
||||
<tr>
|
||||
<td>string
|
||||
<td>string
|
||||
</tr>
|
||||
<tr>
|
||||
<td>boolean
|
||||
<td>boolean
|
||||
</tr>
|
||||
<tr>
|
||||
<td>struct<br>arrray
|
||||
<td>table
|
||||
</tr>
|
||||
<tr>
|
||||
<td>other elements
|
||||
<td><pre>{
|
||||
tag = "element name",
|
||||
[1] = <first child>,
|
||||
[2] = <second child>,
|
||||
[3] = ...,
|
||||
}</pre>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<a name="lua2xr"</a>
|
||||
<h3>From Lua to XML-RPC</h3>
|
||||
<p>
|
||||
A convertion from a Lua object to an XML-RPC can be made automatically
|
||||
or explicitly.
|
||||
The automatic conversion rules are:
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td>Lua object
|
||||
<td>XML-RPC data type
|
||||
</tr>
|
||||
<tr>
|
||||
<td>number
|
||||
<td>double
|
||||
</tr>
|
||||
<tr>
|
||||
<td>string
|
||||
<td>string
|
||||
</tr>
|
||||
<tr>
|
||||
<td>boolean
|
||||
<td>boolean
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>{ key = val }</code>
|
||||
<td><pre>
|
||||
<struct>
|
||||
<member>
|
||||
<name>key</name>
|
||||
<value><i>val</i></value>
|
||||
</member>
|
||||
</struct></pre>
|
||||
<small><i>val</i> is converted according to the same rules.</small>
|
||||
</tr>
|
||||
</table>
|
||||
In case of a table that has numeric keys,
|
||||
the resulting struct will have numbers as keys (but they will be
|
||||
treated as strings).
|
||||
|
||||
<p>
|
||||
Explicit conversions can be forced by the creation of <i>typed values</i>
|
||||
(see function <code><a href="#createtypedvalue">createTypedValue</a></code>).
|
||||
|
||||
|
||||
<a name="basic"></a>
|
||||
<h2>Basic support</h2>
|
||||
<p>
|
||||
<ul>
|
||||
<a name="client_encode"></a>
|
||||
<li> <b><code>client_encode (method_name, params*) => method_call</code></b> <br>
|
||||
Build a XML-RPC document containing a <code>methodCall</code> 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.
|
||||
|
||||
<a name="client_decode"></a>
|
||||
<li> <b><code>client_decode (method_response) => ok, list_results</code></b> <br>
|
||||
Disassemble the server response into a Lua object.
|
||||
It receives a string containing the XML-RPC document representing
|
||||
the <code>methodResponse</code> element.
|
||||
The result is a boolean indicating wether the call was successful or not
|
||||
and a Lua table containing the results of the call,
|
||||
equivalent to the <code>params</code> element.
|
||||
|
||||
<a name="server_decode"></a>
|
||||
<li> <b><code>server_decode (method_call) => method_name, list_params</code></b> <br>
|
||||
Disassemble the client request into a method's name and a Lua object.
|
||||
It receives a string containing the XML-RPC document representing
|
||||
the <code>methodCall</code> element.
|
||||
The result is a string with the name of the method to be called
|
||||
and a Lua table with all the arguments to be passed to it.
|
||||
|
||||
<a name="server_encode"></a>
|
||||
<li> <b><code>server_encode (object) => method_response</code></b> <br>
|
||||
Build a XML-RPC document containing a <code>methodResponse</code> element.
|
||||
It receives a Lua object (a number, a string, a table etc.) with the
|
||||
response of the call to be sent.
|
||||
The result is a string containing the XML-RPC document.
|
||||
|
||||
<a name="createtypedvalue"></a>
|
||||
<li> <b><code>createTypeValue (value, type)</code></b> <br>
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<a name="client"></a>
|
||||
<h2>Client side</h2>
|
||||
<p>
|
||||
The client side library offers the following functions:
|
||||
<ul>
|
||||
<a name="call"></a>
|
||||
<li> <b><code>call (url, method, params*)</code></b> <br>
|
||||
Execute the call to <code>method</code> at location <code>url</code>
|
||||
with the given <code>params</code> (if any).
|
||||
The result is a Lua object containing the response.
|
||||
It could be a <code><params></code> or a <code><fault></code>
|
||||
XML-RPC element.
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
<a name="server"></a>
|
||||
<h2>Server side</h2>
|
||||
<p>
|
||||
|
||||
|
||||
<a name="toxml"></a>
|
||||
<h2>Creating XML elements</h2>
|
||||
<p>
|
||||
|
||||
|
||||
<a name="xmlrpc_parser"></a>
|
||||
<h2>Parsing XML-RPC elements</h2>
|
||||
<p>
|
||||
|
||||
|
||||
<a name="examples"></a>
|
||||
<h2>Example</h2>
|
||||
|
||||
Below is a small sample code displaying the basic use of the library.
|
||||
|
||||
<blockquote>
|
||||
<pre>
|
||||
require "xmlrpc"
|
||||
|
||||
|
||||
</pre>
|
||||
</blockquote>
|
||||
|
||||
|
||||
<a name="related_docs"></a>
|
||||
<h2>Related documentation</h2>
|
||||
|
||||
Here is a list of related documentation:
|
||||
<ul>
|
||||
<li> <a href="http://www.xmlrpc.com">http://www.xmlrpc.com</a>
|
||||
</ul>
|
||||
|
||||
|
||||
<a name="contents"></a>
|
||||
<h2>Contents</h2>
|
||||
<p>
|
||||
<ul>
|
||||
<li> <a href="#introduction">Introduction</a>
|
||||
<li> <a href="#examples">Example</a>
|
||||
<li> <a href="#related_docs">Related documentation</a>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<center><small>
|
||||
<a href="index.html">home</a> ·
|
||||
<a href="#examples">example</a> ·
|
||||
<a href="#related_docs">related docs</a>
|
||||
</small></center>
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
<small>
|
||||
Last modified on
|
||||
Mon Sep 1 15:54:23 BRT 2003
|
||||
</small>
|
||||
|
||||
</body>
|
||||
</html>
|
589
src/xmlrpc.lua
Executable file
589
src/xmlrpc.lua
Executable file
@ -0,0 +1,589 @@
|
||||
---------------------------------------------------------------------
|
||||
-- XML-RPC implementation for Lua.
|
||||
-- See Copyright Notice in license.html
|
||||
-- $Id$
|
||||
---------------------------------------------------------------------
|
||||
|
||||
require "lxp"
|
||||
require "dom"
|
||||
|
||||
local assert, error, ipairs, pairs, type, tonumber, unpack = assert, error, ipairs, pairs, type, tonumber, unpack
|
||||
local format, gsub, strfind, strsub = string.format, string.gsub, string.find, string.sub
|
||||
local concat, getn, tinsert = table.concat, table.getn, table.insert
|
||||
local ceil = math.ceil
|
||||
local parse = dom.parse
|
||||
|
||||
local Public = {}
|
||||
setmetatable (Public, {__newindex == function (n)
|
||||
error ("undeclared variable "..n, 2)
|
||||
end})
|
||||
|
||||
xmlrpc = Public
|
||||
|
||||
setfenv (1, Public)
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- 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 false
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
local function x2string (tab)
|
||||
return tab.tag == "string" and tab[1]
|
||||
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, getn (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, getn (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
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a methodResponse into a Lua object.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Boolean (indicating wether the response was successful)
|
||||
-- and (a Lua table with 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, 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))
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Disassemble a fault element into a Lua object.
|
||||
-- @param tab Table with DOM representation.
|
||||
-- @return Object.
|
||||
---------------------------------------------------------------------
|
||||
local function x2fault (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>",
|
||||
|
||||
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
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- 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
|
||||
tinsert (ret, format (formats.value, f (v, et)))
|
||||
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.
|
||||
---------------------------------------------------------------------
|
||||
local 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 params_list Table with list of parameters.
|
||||
-- @return String representing the `params' XML-RPC element.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.params (params_list)
|
||||
for i = 1, getn (params_list) do
|
||||
params_list[i] = format (formats.param, toxml.value (params_list[i]))
|
||||
end
|
||||
return format (formats.params, concat (params_list, '\n '))
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param method String with method's name.
|
||||
-- @param params_list Table with list of parameters.
|
||||
-- @return String representing the `methodCall' XML-RPC element.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.methodCall (method, params_list)
|
||||
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 (params_list))
|
||||
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.struct {
|
||||
faultCode = { ["*type"] = "int", ["*value"] = code or faultCode or 1 },
|
||||
faultString = message or faultString or "fatal error",
|
||||
})
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- @param ok Boolean indicating if the response was correct or a
|
||||
-- fault one.
|
||||
-- @param params_list Object containing the response contents.
|
||||
-- @return String representing the `methodResponse' XML-RPC element.
|
||||
---------------------------------------------------------------------
|
||||
function toxml.methodResponse (ok, params_list)
|
||||
local resp
|
||||
if ok then
|
||||
resp = toxml.params (params_list)
|
||||
else
|
||||
resp = toxml.fault (params_list)
|
||||
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 createArray (elemtype)
|
||||
return { type = "array", elemtype = elemtype, }
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Create a representation of a structure with the given members.
|
||||
---------------------------------------------------------------------
|
||||
function createStruct (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 createTypedValue (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 client_encode (method, ...)
|
||||
return toxml.methodCall (method, arg)
|
||||
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 table with the converted response element.
|
||||
---------------------------------------------------------------------
|
||||
function client_decode (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 a table with the parameters.
|
||||
---------------------------------------------------------------------
|
||||
function server_decode (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 responde.
|
||||
---------------------------------------------------------------------
|
||||
function server_encode (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 function.
|
||||
---------------------------------------------------------------------
|
||||
local dispatch = error
|
||||
function server_methods (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 = string.find (name, "^([^.]+)%.(.+)$")
|
||||
if not ok then
|
||||
return tab_or_func[name]
|
||||
else
|
||||
return tab_or_func[obj][method]
|
||||
end
|
||||
end
|
||||
else
|
||||
error ("Argument is neither a table nor a function")
|
||||
end
|
||||
end
|
202
tests/test.lua
Executable file
202
tests/test.lua
Executable file
@ -0,0 +1,202 @@
|
||||
#!/usr/local/bin/lua.5.0
|
||||
-- See Copyright Notice in license.html
|
||||
|
||||
require "xmlrpc"
|
||||
require "xrh"
|
||||
|
||||
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.equal (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 call_test (xml_call, method, ...)
|
||||
local xc = string.gsub (xml_call, "(%p)", "%%%1")
|
||||
xc = string.gsub (xc, "\r?\n%s*", "%%s*")
|
||||
arg.n = nil
|
||||
|
||||
-- client enconding test
|
||||
local meth_call = xmlrpc.client_encode (method, unpack (arg))
|
||||
local s = string.gsub (meth_call, xc, "")
|
||||
s = string.gsub (s, "%s*", "")
|
||||
assert (s == "", s)
|
||||
|
||||
-- server decoding test
|
||||
local meth_call, param = xmlrpc.server_decode (xml_call)
|
||||
assert (meth_call == method, meth_call)
|
||||
assert (table.equal (arg, param))
|
||||
end
|
||||
|
||||
function response_test (xml_resp, lua_obj)
|
||||
-- client decoding test
|
||||
local ok, obj = xmlrpc.client_decode (xml_resp)
|
||||
assert (table.equal (obj, { lua_obj }))
|
||||
|
||||
-- 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.server_encode (lua_obj)
|
||||
local s = string.gsub (meth_resp, xml_resp, "")
|
||||
s = string.gsub (s, "%s*", "")
|
||||
assert (s == "", s)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- call tests.
|
||||
---------------------------------------------------------------------
|
||||
call_test ([[<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>examples.getStateName</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value><int>41</int></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>]], "examples.getStateName", 41)
|
||||
|
||||
call_test ([[<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>examples.getSomething</methodName>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>lowerBound</name>
|
||||
<value><int>18</int></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>upperBound</name>
|
||||
<value><int>139</int></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodCall>]], "examples.getSomething", { lowerBound = 18, upperBound = 139 })
|
||||
|
||||
--[[
|
||||
call_test ([[<?xml version="1.0"?>
|
||||
<methodCall>
|
||||
<methodName>insertTable</methodName>
|
||||
<params>
|
||||
<param><value><string>people</string></value></param>
|
||||
<param><value>
|
||||
<array><data>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>name</name>
|
||||
<value><string>Fulano</string></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>email</name>
|
||||
<value><string>fulano@nowhere.world</string></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>name</name>
|
||||
<value><string>Beltrano</string></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>email</name>
|
||||
<value><string>beltrano@nowhere.world</string></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>name</name>
|
||||
<value><string>Cicrano</string></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>email</name>
|
||||
<value><string>cicrano@nowhere.world</string></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</data></array>
|
||||
</value></param>
|
||||
</params>
|
||||
</methodCall>]],
|
||||
"insertTable",
|
||||
{
|
||||
{ name = "Fulano", email = "fulano@nowhere.world", },
|
||||
{ name = "Beltrano", email = "beltrano@nowhere.world", },
|
||||
{ name = "Cicrano", email = "cicrano@nowhere.world", },
|
||||
})
|
||||
--]]
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- response tests.
|
||||
---------------------------------------------------------------------
|
||||
response_test ([[<?xml version="1.0"?>
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><string>South Dakota</string></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>]], "South Dakota")
|
||||
|
||||
response_test ([[<?xml version="1.0"?>
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>lowerBound</name>
|
||||
<value><int>18</int></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>upperBound</name>
|
||||
<value><int>139</int></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>]], { lowerBound = 18, upperBound = 139 })
|
32
xrc.lua
Executable file
32
xrc.lua
Executable file
@ -0,0 +1,32 @@
|
||||
-- See Copyright Notice in license.html
|
||||
require"xmlrpc"
|
||||
|
||||
local _assert = assert
|
||||
function assert (cond, msg)
|
||||
if not cond then
|
||||
io.stdout:write (xmlrpc.server_encode (
|
||||
{ code = 2, message = msg, },
|
||||
true
|
||||
))
|
||||
os.exit() -- !!!!!!!!!!!
|
||||
end
|
||||
end
|
||||
|
||||
local doc = parsepostdata ()
|
||||
|
||||
local method, arg_table = xmlrpc.server_decode (doc)
|
||||
assert (type(method) == "string")
|
||||
assert (type(arg_table) == "table")
|
||||
|
||||
local func = xmlrpc.dispatch (method)
|
||||
assert (type(func) == "function")
|
||||
|
||||
local result = { pcall (func, unpack (arg_table)) }
|
||||
|
||||
local ok = result[1]
|
||||
tremove (result, 1)
|
||||
if not ok then
|
||||
result = { code = 3, message = result[2], }
|
||||
end
|
||||
|
||||
io.stdout:write (xmlrpc.server_encode (result, not ok))
|
137
xrh.lua
Executable file
137
xrh.lua
Executable file
@ -0,0 +1,137 @@
|
||||
---------------------------------------------------------------------
|
||||
-- XML-RPC over HTTP.
|
||||
-- See Copyright Notice in license.html
|
||||
-- $Id$
|
||||
---------------------------------------------------------------------
|
||||
|
||||
require"luasocket"
|
||||
require"xmlrpc"
|
||||
|
||||
local post = socket.http.post
|
||||
|
||||
xrh = {}
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- 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 xrh.call (url, method, ...)
|
||||
local body, headers, code, err = post {
|
||||
url = url,
|
||||
body = xmlrpc.client_encode (method, unpack (arg)),
|
||||
headers = {
|
||||
["User-agent"] = "LuaXMLRPC",
|
||||
["Content-type"] = "text/xml",
|
||||
},
|
||||
}
|
||||
if tonumber (code) == 200 then
|
||||
return xmlrpc.client_decode (body)
|
||||
else
|
||||
error (err or code)
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
---------------------------------------------------------------------
|
||||
local clients = {}
|
||||
local send_clients = {}
|
||||
function xrh.serve (methods)
|
||||
local s = assert (socket.bind ("localhost", "8080"))
|
||||
s:settimeout (.01)
|
||||
while true do
|
||||
-- look for new clients
|
||||
local client = s:accept ()
|
||||
if client then
|
||||
client:settimeout (1)
|
||||
table.insert (clients, client)
|
||||
end
|
||||
-- receiving clients
|
||||
local rec_cli, _, err = socket.select (clients, nil, .01)
|
||||
if err and err ~= "timeout" then
|
||||
print ("!!", err)
|
||||
end
|
||||
if rec_cli then
|
||||
-- process requests
|
||||
for i, cli in rec_cli do
|
||||
local data, err = cli:receive()
|
||||
if err then
|
||||
print ("!!", err, "(",cli,")")
|
||||
table.remove (clients, i) -- !!!!!!!!!!!!!!!!
|
||||
else
|
||||
local resp = [[<?xml version="1.0"?>
|
||||
<methodResponse>
|
||||
<fault>
|
||||
<value>
|
||||
<struct>
|
||||
<member>
|
||||
<name>faultCode</name>
|
||||
<value><int>1</int></value>
|
||||
</member>
|
||||
<member>
|
||||
<name>faultString</name>
|
||||
<value><string>Still debugging</string></value>
|
||||
</member>
|
||||
</struct>
|
||||
</value>
|
||||
</fault>
|
||||
</methodResponse>]]
|
||||
local err, n = cli:send (string.format ([[HTTP/1.1 200 OK
|
||||
Date: %s
|
||||
Server: Me
|
||||
Content-Type: text/xml
|
||||
Content-Length: %d
|
||||
Connection: close
|
||||
|
||||
%s
|
||||
]], os.date(), string.len(resp), resp))
|
||||
|
||||
print (">>", n, "(",string.len(resp),")")
|
||||
cli:close()
|
||||
table.remove (clients, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function eca ()
|
||||
local c = assert (s:accept ())
|
||||
local req = {}
|
||||
-- headers
|
||||
local r, err
|
||||
repeat
|
||||
r, err = c:receive ()
|
||||
print(">>", '['..r..']', err, r=='') io.flush()
|
||||
table.insert (req, r)
|
||||
until r == ""
|
||||
print(">>", table.concat(req)) io.flush()
|
||||
local err, n = c:send [[HTTP/1.1 200 OK
|
||||
Connection: close
|
||||
Content-Length: 158
|
||||
Content-Type: text/xml
|
||||
|
||||
<?xml version="1.0"?>
|
||||
<methodResponse>
|
||||
<params>
|
||||
<param>
|
||||
<value><string>South Dakota</string></value>
|
||||
</param>
|
||||
</params>
|
||||
</methodResponse>]]
|
||||
|
||||
repeat
|
||||
r, err = c:receive ()
|
||||
print(">>", '['..r..']', err, r=='') io.flush()
|
||||
table.insert (req, r)
|
||||
until r == ""
|
||||
|
||||
--[[
|
||||
while not err do
|
||||
print(">>", '['..req..']', err, req=='') io.flush()
|
||||
req, err = c:receive ()
|
||||
end
|
||||
--]]
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user