diff options
author | mneumann <mneumann@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-11-16 14:12:53 +0000 |
---|---|---|
committer | mneumann <mneumann@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-11-16 14:12:53 +0000 |
commit | f6c1872354a8566077c553063e2e9f2e5e290be2 (patch) | |
tree | 55e066b086392619b4d77213581d113989afae4a | |
parent | 597e0c74ba024b59ecc326b5399d06c2b63ac03b (diff) | |
download | ruby-f6c1872354a8566077c553063e2e9f2e5e290be2.tar.gz |
added howto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7287 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | lib/xmlrpc/.document | 1 | ||||
-rw-r--r-- | lib/xmlrpc/README.rdoc | 300 |
2 files changed, 301 insertions, 0 deletions
diff --git a/lib/xmlrpc/.document b/lib/xmlrpc/.document new file mode 100644 index 0000000000..e475c53ed0 --- /dev/null +++ b/lib/xmlrpc/.document @@ -0,0 +1 @@ +README.rdoc diff --git a/lib/xmlrpc/README.rdoc b/lib/xmlrpc/README.rdoc new file mode 100644 index 0000000000..221d675219 --- /dev/null +++ b/lib/xmlrpc/README.rdoc @@ -0,0 +1,300 @@ += XMLRPC for Ruby + +== Author and Copyright + +Copyright (C) 2001-2004 by Michael Neumann (mailto:mneumann@ntecs.de) + +Released under the same term of license as Ruby. + +== Overview + +XMLRPC is a lightweight protocol that enables remote procedure calls over +HTTP. It is defined at http://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. + +== Example + +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 + +== Documentation + +See http://www.ntecs.de/projects/xmlrpc4r. There is plenty of detail there to +use the client and implement a server. + +== Features of XMLRPC for Ruby + +* 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 + +== Howto + +=== Client + + 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}" + +=== Client with XML-RPC fault-structure handling + +There are two possible ways, of handling a fault-structure: + +==== by catching a XMLRPC::FaultException exception + + 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 + +==== by calling "call2" which returns a boolean + + 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 + +=== Client using Proxy + +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 +<i>proxy2</i>. 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}" + +=== CGI-based Server + +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: + +==== C/PHP-like (handler functions) + + require "xmlrpc/server" + + s = XMLRPC::CGIServer.new + + s.add_handler("sample.sumAndDifference") do |a,b| + { "sum" => a + b, "difference" => a - b } + end + + s.serve + +==== Java-like (handler classes) + + 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") + +===== Security Note + +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). + +==== With interface declarations + +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 + +=== Standalone server + +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. + +=== Choosing a different XML Parser or XML Writer + +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 <i>set_parser</i> method of +<tt>XMLRPC::Client</tt> instances or instances of subclasses of +<tt>XMLRPC::BasicServer</tt> 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 <i>set_writer</i>. |