Extended maintenance of Ruby 1.9.3 ended on February 23, 2015. Read more
Copyright (C) 2001-2004 by Michael Neumann (mneumann@ntecs.de)
Released under the same term of license as Ruby.
XMLRPC is a lightweight protocol that enables remote procedure calls over HTTP. It is defined at www.xmlrpc.com.
XMLRPC allows you to create simple distributed computing solutions that span computer languages. Its distinctive feature is its simplicity compared to other approaches like SOAP and CORBA.
The Ruby standard library package ‘xmlrpc’ enables you to create a server that implements remote procedures and a client that calls them. Very little code is required to achieve either of these.
Try the following code. It calls a standard demonstration remote procedure.
require 'xmlrpc/client' require 'pp' server = XMLRPC::Client.new2("http://xmlrpc-c.sourceforge.net/api/sample.php") result = server.call("sample.sumAndDifference", 5, 3) pp result
See www.ntecs.de/projects/xmlrpc4r. There is plenty of detail there to use the client and implement a server.
Extensions
Introspection
multiCall
optionally nil values and integers larger than 32 Bit
Server
Standalone XML-RPC server
CGI-based (works with FastCGI)
Apache mod_ruby server
WEBrick servlet
Client
synchronous/asynchronous calls
Basic HTTP-401 Authentification
HTTPS protocol (SSL)
Parsers
NQXML (NQXMLStreamParser, NQXMLTreeParser)
Expat (XMLStreamParser, XMLTreeParser)
REXML (REXMLStreamParser)
xml-scan (XMLScanStreamParser)
Fastest parser is Expat’s XMLStreamParser!
General
possible to choose between XMLParser module (Expat wrapper) and REXML/NQXML (pure Ruby) parsers
Marshalling Ruby objects to Hashs and reconstruct them later from a Hash
SandStorm component architecture Client interface
require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # Call the remote server and get our result result = server.call("sample.sumAndDifference", 5, 3) sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}"
There are two possible ways, of handling a fault-structure:
require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") begin # Call the remote server and get our result result = server.call("sample.sumAndDifference", 5, 3) sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}" rescue XMLRPC::FaultException => e puts "Error: " puts e.faultCode puts e.faultString end
require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # Call the remote server and get our result ok, result = server.call2("sample.sumAndDifference", 5, 3) if ok sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}" else puts "Error: " puts result.faultCode puts result.faultString end
You can create a Proxy
object onto which you can call methods.
This way it looks nicer. Both forms, call and call2 are
supported through proxy and proxy2. You can additionally
give arguments to the Proxy, which will be given to each XML-RPC call using
that Proxy.
require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # Create a Proxy object sample = server.proxy("sample") # Call the remote server and get our result result = sample.sumAndDifference(5,3) sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}"
There are also two ways to define handler, the first is like C/PHP, the second like Java, of course both ways can be mixed:
require "xmlrpc/server" s = XMLRPC::CGIServer.new s.add_handler("sample.sumAndDifference") do |a,b| { "sum" => a + b, "difference" => a - b } end s.serve
require "xmlrpc/server" s = XMLRPC::CGIServer.new class MyHandler def sumAndDifference(a, b) { "sum" => a + b, "difference" => a - b } end end # NOTE: Security Hole (read below)!!! s.add_handler("sample", MyHandler.new) s.serve
To return a fault-structure you have to raise an FaultException e.g.:
raise XMLRPC::FaultException.new(3, "division by Zero")
From Brian Candler:
Above code sample has an extremely nasty security hole, in that you can now call any method of 'MyHandler' remotely, including methods inherited from Object and Kernel! For example, in the client code, you can use puts server.call("sample.send","`","ls") (backtick being the method name for running system processes). Needless to say, 'ls' can be replaced with something else. The version which binds proc objects (or the version presented below in the next section) doesn't have this problem, but people may be tempted to use the second version because it's so nice and 'Rubyesque'. I think it needs a big red disclaimer.
From Michael:
A solution is to undef insecure methods or to use (({XMLRPC::iPIMethods})) as shown below:
class MyHandler def sumAndDifference(a, b) { "sum" => a + b, "difference" => a - b } end end # ... server initialization ... s.add_handler(XMLRPC::iPIMethods("sample"), MyHandler.new) # ...
This adds only public instance methods explicitly declared in class MyHandler (and not those inherited from any other class).
Code sample from the book Ruby Developer’s Guide:
require "xmlrpc/server" class Num INTERFACE = XMLRPC::interface("num") { meth 'int add(int, int)', 'Add two numbers', 'add' meth 'int div(int, int)', 'Divide two numbers' } def add(a, b) a + b end def div(a, b) a / b end end s = XMLRPC::CGIServer.new s.add_handler(Num::INTERFACE, Num.new) s.serve
Same as CGI-based server, only that the line
server = XMLRPC::CGIServer.new
must be changed to
server = XMLRPC::Server.new(8080)
if you want a server listening on port 8080. The rest is the same.
The examples above all use the default parser (which is now since 1.8
REXMLStreamParser) and a default XML writer. If you want to use a
different XML parser, then you have to call the set_parser method
of XMLRPC::Client
instances or instances of subclasses of
XMLRPC::BasicServer
or by editing xmlrpc/config.rb.
Client Example:
# ... server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") server.set_parser(XMLRPC::XMLParser::XMLParser.new) # ...
Server Example:
# ... s = XMLRPC::CGIServer.new s.set_parser(XMLRPC::XMLParser::XMLStreamParser.new) # ...
or:
# ... server = XMLRPC::Server.new(8080) server.set_parser(XMLRPC::XMLParser::NQXMLParser.new) # ...
Note that XMLStreamParser is incredible faster (and uses less memory) than any other parser and scales well for large documents. For example for a 0.5 MB XML document with many tags, XMLStreamParser is ~350 (!) times faster than NQXMLTreeParser and still ~18 times as fast as XMLTreeParser.
You can change the XML-writer by calling method set_writer.
Generated with Rubydoc Rdoc Generator 0.34.4.