From 1df7862b2bf2ba3ebd9d33c6be4882e727fb64f4 Mon Sep 17 00:00:00 2001 From: zzak Date: Thu, 13 Sep 2012 02:22:10 +0000 Subject: * lib/xmlrpc.rb: Documentation for XMLRPC * lib/xmlrpc/datetime.rb: ditto. * lib/xmlrpc/parser.rb: ditto. * lib/xmlrpc/client.rb: ditto. * lib/xmlrpc/utils.rb: ditto. * lib/xmlrpc/README.rdoc: ditto. * lib/xmlrpc/create.rb: ditto. * lib/xmlrpc/base64.rb: ditto. * lib/xmlrpc/config.rb: ditto. * lib/xmlrpc/httpserver.rb: ditto. * lib/xmlrpc/server.rb: ditto. * lib/xmlrpc/marshal.rb: ditto. * lib/xmlrpc/README.txt: ditto. [Bug #6909] [ruby-core:47286] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36958 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/xmlrpc/README.rdoc | 300 ------------------------- lib/xmlrpc/README.txt | 31 --- lib/xmlrpc/base64.rb | 63 ++---- lib/xmlrpc/client.rb | 552 ++++++++++++++++++++++------------------------ lib/xmlrpc/config.rb | 26 ++- lib/xmlrpc/create.rb | 21 +- lib/xmlrpc/datetime.rb | 119 +++++----- lib/xmlrpc/httpserver.rb | 45 ++-- lib/xmlrpc/marshal.rb | 18 +- lib/xmlrpc/parser.rb | 68 ++++-- lib/xmlrpc/server.rb | 557 +++++++++++++++++++++-------------------------- lib/xmlrpc/utils.rb | 44 ++-- 12 files changed, 697 insertions(+), 1147 deletions(-) delete mode 100644 lib/xmlrpc/README.rdoc delete mode 100644 lib/xmlrpc/README.txt (limited to 'lib/xmlrpc') diff --git a/lib/xmlrpc/README.rdoc b/lib/xmlrpc/README.rdoc deleted file mode 100644 index 2faed28cb9..0000000000 --- a/lib/xmlrpc/README.rdoc +++ /dev/null @@ -1,300 +0,0 @@ -= 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 -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}" - -=== 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 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. diff --git a/lib/xmlrpc/README.txt b/lib/xmlrpc/README.txt deleted file mode 100644 index ade842d8b1..0000000000 --- a/lib/xmlrpc/README.txt +++ /dev/null @@ -1,31 +0,0 @@ -= XMLRPC for Ruby, Standard Library Documentation - -== 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. - diff --git a/lib/xmlrpc/base64.rb b/lib/xmlrpc/base64.rb index bfa8c0a2d5..4aac3520c5 100644 --- a/lib/xmlrpc/base64.rb +++ b/lib/xmlrpc/base64.rb @@ -1,46 +1,23 @@ -=begin -= xmlrpc/base64.rb -Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) - -Released under the same term of license as Ruby. - -= Classes -* (()) - -= XMLRPC::Base64 -== Description -This class is necessary for (('xmlrpc4r')) to determine that a string should -be transmitted base64-encoded and not as a raw-string. -You can use (({XMLRPC::Base64})) on the client and server-side as a -parameter and/or return-value. - -== Class Methods ---- XMLRPC::Base64.new( str, state = :dec ) - Creates a new (({XMLRPC::Base64})) instance with string ((|str|)) as the - internal string. When ((|state|)) is (({:dec})) it assumes that the - string ((|str|)) is not in base64 format (perhaps already decoded), - otherwise if ((|state|)) is (({:enc})) it decodes ((|str|)) - and stores it as the internal string. - ---- XMLRPC::Base64.decode( str ) - Decodes string ((|str|)) with base64 and returns that value. - ---- XMLRPC::Base64.encode( str ) - Encodes string ((|str|)) with base64 and returns that value. - -== Instance Methods ---- XMLRPC::Base64#decoded - Returns the internal string decoded. - ---- XMLRPC::Base64#encoded - Returns the internal string encoded with base64. - -=end - -module XMLRPC - +# +# xmlrpc/base64.rb +# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) +# +# Released under the same term of license as Ruby. + +module XMLRPC # :nodoc: + +# This class is necessary for 'xmlrpc4r' to determine that a string should +# be transmitted base64-encoded and not as a raw-string. +# +# You can use XMLRPC::Base64 on the client and server-side as a +# parameter and/or return-value. class Base64 + # Creates a new XMLRPC::Base64 instance with string +str+ as the + # internal string. When +state+ is +:dec+ it assumes that the + # string +str+ is not in base64 format (perhaps already decoded), + # otherwise if +state+ is +:enc+ it decodes +str+ + # and stores it as the internal string. def initialize(str, state = :dec) case state when :enc @@ -52,19 +29,23 @@ class Base64 end end + # Returns the decoded internal string. def decoded @str end + # Returns the base64 encoded internal string. def encoded Base64.encode(@str) end + # Decodes string +str+ with base64 and returns that value. def Base64.decode(str) str.gsub(/\s+/, "").unpack("m")[0] end + # Encodes string +str+ with base64 and returns that value. def Base64.encode(str) [str].pack("m") end diff --git a/lib/xmlrpc/client.rb b/lib/xmlrpc/client.rb index 54f721fd37..c1c2da054c 100644 --- a/lib/xmlrpc/client.rb +++ b/lib/xmlrpc/client.rb @@ -1,279 +1,11 @@ -=begin -= xmlrpc/client.rb -Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) - -Released under the same term of license as Ruby. - -= Classes -* (()) -* (()) - - -= XMLRPC::Client -== Synopsis - require "xmlrpc/client" - - server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) - begin - param = server.call("michael.add", 4, 5) - puts "4 + 5 = #{param}" - rescue XMLRPC::FaultException => e - puts "Error:" - puts e.faultCode - puts e.faultString - end - -or - - require "xmlrpc/client" - - server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) - ok, param = server.call2("michael.add", 4, 5) - if ok then - puts "4 + 5 = #{param}" - else - puts "Error:" - puts param.faultCode - puts param.faultString - end - -== Description -Class (({XMLRPC::Client})) provides remote procedure calls to a XML-RPC server. -After setting the connection-parameters with (()) which -creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure -by sending the (()) or (()) -message to this new instance. The given parameters indicate which method to -call on the remote-side and of course the parameters for the remote procedure. - -== Class Methods ---- XMLRPC::Client.new( host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=false, timeout =nil) - Creates an object which represents the remote XML-RPC server on the - given host ((|host|)). If the server is CGI-based, ((|path|)) is the - path to the CGI-script, which will be called, otherwise (in the - case of a standalone server) ((|path|)) should be (({"/RPC2"})). - ((|port|)) is the port on which the XML-RPC server listens. - If ((|proxy_host|)) is given, then a proxy server listening at - ((|proxy_host|)) is used. ((|proxy_port|)) is the port of the - proxy server. - - Default values for ((|host|)), ((|path|)) and ((|port|)) are 'localhost', '/RPC2' and - '80' respectively using SSL '443'. - - If ((|user|)) and ((|password|)) are given, each time a request is send, - a Authorization header is send. Currently only Basic Authentification is - implemented no Digest. - - If ((|use_ssl|)) is set to (({true})), comunication over SSL is enabled. - Note, that you need the SSL package from RAA installed. - - Parameter ((|timeout|)) is the time to wait for a XML-RPC response, defaults to 30. - ---- XMLRPC::Client.new2( uri, proxy=nil, timeout=nil) ---- XMLRPC::Client.new_from_uri( uri, proxy=nil, timeout=nil) -: uri - URI specifying protocol (http or https), host, port, path, user and password. - Example: https://user:password@host:port/path - -: proxy - Is of the form "host:port". - -: timeout - Defaults to 30. - ---- XMLRPC::Client.new3( hash={} ) ---- XMLRPC::Client.new_from_hash( hash={} ) - Parameter ((|hash|)) has following case-insensitive keys: - * host - * path - * port - * proxy_host - * proxy_port - * user - * password - * use_ssl - * timeout - - Calls (()) with the corresponding values. - -== Instance Methods ---- XMLRPC::Client#call( method, *args ) - Invokes the method named ((|method|)) with the parameters given by - ((|args|)) on the XML-RPC server. - The parameter ((|method|)) is converted into a (({String})) and should - be a valid XML-RPC method-name. - Each parameter of ((|args|)) must be of one of the following types, - where (({Hash})), (({Struct})) and (({Array})) can contain any of these listed ((:types:)): - * (({Fixnum})), (({Bignum})) - * (({TrueClass})), (({FalseClass})) ((({true})), (({false}))) - * (({String})), (({Symbol})) - * (({Float})) - * (({Hash})), (({Struct})) - * (({Array})) - * (({Date})), (({Time})), (({XMLRPC::DateTime})) - * (({XMLRPC::Base64})) - * A Ruby object which class includes XMLRPC::Marshallable (only if Config::ENABLE_MARSHALLABLE is (({true}))). - That object is converted into a hash, with one additional key/value pair "___class___" which contains the class name - for restoring later that object. - - The method returns the return-value from the RPC - ((-stands for Remote Procedure Call-)). - The type of the return-value is one of the above shown, - only that a (({Bignum})) is only allowed when it fits in 32-bit and - that a XML-RPC (('dateTime.iso8601')) type is always returned as - a ((<(({XMLRPC::DateTime}))|URL:datetime.html>)) object and - a (({Struct})) is never returned, only a (({Hash})), the same for a (({Symbol})), where - always a (({String})) is returned. - A (({XMLRPC::Base64})) is returned as a (({String})) from xmlrpc4r version 1.6.1 on. - - If the remote procedure returned a fault-structure, then a - (({XMLRPC::FaultException})) exception is raised, which has two accessor-methods - (({faultCode})) and (({faultString})) of type (({Integer})) and (({String})). - ---- XMLRPC::Client#call2( method, *args ) - The difference between this method and (()) is, that - this method do ((*not*)) raise a (({XMLRPC::FaultException})) exception. - The method returns an array of two values. The first value indicates if - the second value is a return-value ((({true}))) or an object of type - (({XMLRPC::FaultException})). - Both are explained in (()). - - Simple to remember: The "2" in "call2" denotes the number of values it returns. - ---- XMLRPC::Client#multicall( *methods ) - You can use this method to execute several methods on a XMLRPC server which supports - the multi-call extension. - Example: - - s.multicall( - ['michael.add', 3, 4], - ['michael.sub', 4, 5] - ) - # => [7, -1] - ---- XMLRPC::Client#multicall2( *methods ) - Same as (()), but returns like (()) two parameters - instead of raising an (({XMLRPC::FaultException})). - ---- XMLRPC::Client#proxy( prefix, *args ) - Returns an object of class (({XMLRPC::Client::Proxy})), initialized with - ((|prefix|)) and ((|args|)). A proxy object returned by this method behaves - like (()), i.e. a call on that object will raise a - (({XMLRPC::FaultException})) when a fault-structure is returned by that call. - ---- XMLRPC::Client#proxy2( prefix, *args ) - Almost the same like (()) only that a call on the returned - (({XMLRPC::Client::Proxy})) object behaves like (()), i.e. - a call on that object will return two parameters. - - - - ---- XMLRPC::Client#call_async(...) ---- XMLRPC::Client#call2_async(...) ---- XMLRPC::Client#multicall_async(...) ---- XMLRPC::Client#multicall2_async(...) ---- XMLRPC::Client#proxy_async(...) ---- XMLRPC::Client#proxy2_async(...) - In contrast to corresponding methods without "_async", these can be - called concurrently and use for each request a new connection, where the - non-asynchronous counterparts use connection-alive (one connection for all requests) - if possible. - - Note, that you have to use Threads to call these methods concurrently. - The following example calls two methods concurrently: - - Thread.new { - p client.call_async("michael.add", 4, 5) - } - - Thread.new { - p client.call_async("michael.div", 7, 9) - } - - ---- XMLRPC::Client#timeout ---- XMLRPC::Client#user ---- XMLRPC::Client#password - Return the corresponding attributes. - ---- XMLRPC::Client#timeout= (new_timeout) ---- XMLRPC::Client#user= (new_user) ---- XMLRPC::Client#password= (new_password) - Set the corresponding attributes. - - ---- XMLRPC::Client#set_writer( writer ) - Sets the XML writer to use for generating XML output. - Should be an instance of a class from module (({XMLRPC::XMLWriter})). - If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. - ---- XMLRPC::Client#set_parser( parser ) - Sets the XML parser to use for parsing XML documents. - Should be an instance of a class from module (({XMLRPC::XMLParser})). - If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. - ---- XMLRPC::Client#cookie ---- XMLRPC::Client#cookie= (cookieString) - Get and set the HTTP Cookie header. - ---- XMLRPC::Client#http_header_extra= (additionalHeaders) - Set extra HTTP headers that are included in the request. - ---- XMLRPC::Client#http_header_extra - Access the via (()) assigned header. - ---- XMLRPC::Client#http_last_response - Returns the (({Net::HTTPResponse})) object of the last RPC. - -= XMLRPC::Client::Proxy -== Synopsis - require "xmlrpc/client" - - server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) - - michael = server.proxy("michael") - michael2 = server.proxy("michael", 4) - - # both calls should return the same value '9'. - p michael.add(4,5) - p michael2.add(5) - -== Description -Class (({XMLRPC::Client::Proxy})) makes XML-RPC calls look nicer! -You can call any method onto objects of that class - the object handles -(({method_missing})) and will forward the method call to a XML-RPC server. -Don't use this class directly, but use instead method (()) or -(()). - -== Class Methods ---- XMLRPC::Client::Proxy.new( server, prefix, args=[], meth=:call, delim="." ) - Creates an object which provides (({method_missing})). - - ((|server|)) must be of type (({XMLRPC::Client})), which is the XML-RPC server to be used - for a XML-RPC call. ((|prefix|)) and ((|delim|)) will be prepended to the methodname - called onto this object. - - Parameter ((|meth|)) is the method (call, call2, call_async, call2_async) to use for - a RPC. - - ((|args|)) are arguments which are automatically given - to every XML-RPC call before the arguments provides through (({method_missing})). - -== Instance Methods -Every method call is forwarded to the XML-RPC server defined in (()). - -Note: Inherited methods from class (({Object})) cannot be used as XML-RPC names, because they get around -(({method_missing})). - - - -= History - $Id$ - -=end - - - +# xmlrpc/client.rb +# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) +# +# Released under the same term of license as Ruby. +# +# History +# $Id$ +# require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" @@ -281,8 +13,43 @@ require "xmlrpc/utils" # ParserWriterChooseMixin require "net/http" require "uri" -module XMLRPC - +module XMLRPC # :nodoc: + + # Provides remote procedure calls to a XML-RPC server. + # + # After setting the connection-parameters with XMLRPC::Client.new which + # creates a new XMLRPC::Client instance, you can execute a remote procedure + # by sending the XMLRPC::Client#call or XMLRPC::Client#call2 + # message to this new instance. + # + # The given parameters indicate which method to call on the remote-side and + # of course the parameters for the remote procedure. + # + # require "xmlrpc/client" + # + # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) + # begin + # param = server.call("michael.add", 4, 5) + # puts "4 + 5 = #{param}" + # rescue XMLRPC::FaultException => e + # puts "Error:" + # puts e.faultCode + # puts e.faultString + # end + # + # or + # + # require "xmlrpc/client" + # + # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) + # ok, param = server.call2("michael.add", 4, 5) + # if ok then + # puts "4 + 5 = #{param}" + # else + # puts "Error:" + # puts param.faultCode + # puts param.faultString + # end class Client USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})" @@ -291,8 +58,28 @@ module XMLRPC include ParseContentType - # Constructors ------------------------------------------------------------------- - + # Creates an object which represents the remote XML-RPC server on the + # given +host+. If the server is CGI-based, +path+ is the + # path to the CGI-script, which will be called, otherwise (in the + # case of a standalone server) +path+ should be "/RPC2". + # +port+ is the port on which the XML-RPC server listens. + # + # If +proxy_host+ is given, then a proxy server listening at + # +proxy_host+ is used. +proxy_port+ is the port of the + # proxy server. + # + # Default values for +host+, +path+ and +port+ are 'localhost', '/RPC2' and + # '80' respectively using SSL '443'. + # + # If +user+ and +password+ are given, each time a request is sent, + # an Authorization header is sent. Currently only Basic Authentication is + # implemented, no Digest. + # + # If +use_ssl+ is set to +true+, communication over SSL is enabled. + # + # Note, that you need the SSL package from RAA installed. + # + # Parameter +timeout+ is the time to wait for a XML-RPC response, defaults to 30. def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil) @@ -337,6 +124,16 @@ module XMLRPC class << self + # Creates an object which represents the remote XML-RPC server at the + # given +uri+. The URI should have a host, port, path, user and password. + # Example: https://user:password@host:port/path + # + # Raises an ArgumentError if the +uri+ is invalid, + # or if the protocol isn't http or https. + # + # If a +proxy+ is given it should be in the form of "host:port". + # + # The optional +timeout+ defaults to 30 seconds. def new2(uri, proxy=nil, timeout=nil) begin url = URI(uri) @@ -363,6 +160,19 @@ module XMLRPC alias new_from_uri new2 + # Receives a Hash and calls XMLRPC::Client.new + # with the corresponding values. + # + # The +hash+ parameter has following case-insensitive keys: + # * host + # * path + # * port + # * proxy_host + # * proxy_port + # * user + # * password + # * use_ssl + # * timeout def new3(hash={}) # convert all keys into lowercase strings @@ -378,38 +188,76 @@ module XMLRPC end - # Attribute Accessors ------------------------------------------------------------------- - - # add additional HTTP headers to the request + # Add additional HTTP headers to the request attr_accessor :http_header_extra - # makes last HTTP response accessible + # Returns the Net::HTTPResponse object of the last RPC. attr_reader :http_last_response - # Cookie support + # Get and set the HTTP Cookie header. attr_accessor :cookie + # Return the corresponding attributes. attr_reader :timeout, :user, :password + # Sets the Net::HTTP#read_timeout and Net::HTTP#open_timeout to + # +new_timeout+ def timeout=(new_timeout) @timeout = new_timeout @http.read_timeout = @timeout @http.open_timeout = @timeout end + # Changes the user for the Basic Authentication header to +new_user+ def user=(new_user) @user = new_user set_auth end + # Changes the password for the Basic Authentication header to + # +new_password+ def password=(new_password) @password = new_password set_auth end - # Call methods -------------------------------------------------------------- - + # Invokes the method named +method+ with the parameters given by + # +args+ on the XML-RPC server. + # + # The +method+ parameter is converted into a String and should + # be a valid XML-RPC method-name. + # + # Each parameter of +args+ must be of one of the following types, + # where Hash, Struct and Array can contain any of these listed _types_: + # + # * Fixnum, Bignum + # * TrueClass, FalseClass, +true+, +false+ + # * String, Symbol + # * Float + # * Hash, Struct + # * Array + # * Date, Time, XMLRPC::DateTime + # * XMLRPC::Base64 + # * A Ruby object which class includes XMLRPC::Marshallable + # (only if Config::ENABLE_MARSHALLABLE is +true+). + # That object is converted into a hash, with one additional key/value + # pair ___class___ which contains the class name + # for restoring that object later. + # + # The method returns the return-value from the Remote Procedure Call. + # + # The type of the return-value is one of the types shown above. + # + # A Bignum is only allowed when it fits in 32-bit. A XML-RPC + # +dateTime.iso8601+ type is always returned as a XMLRPC::DateTime object. + # Struct is never returned, only a Hash, the same for a Symbol, where as a + # String is always returned. XMLRPC::Base64 is returned as a String from + # xmlrpc4r version 1.6.1 on. + # + # If the remote procedure returned a fault-structure, then a + # XMLRPC::FaultException exception is raised, which has two accessor-methods + # +faultCode+ an Integer, and +faultString+ a String. def call(method, *args) ok, param = call2(method, *args) if ok @@ -419,12 +267,37 @@ module XMLRPC end end + # The difference between this method and XMLRPC::Client#call is, that + # this method will NOT raise a XMLRPC::FaultException exception. + # + # The method returns an array of two values. The first value indicates if + # the second value is +true+ or an XMLRPC::FaultException. + # + # Both are explained in XMLRPC::Client#call. + # + # Simple to remember: The "2" in "call2" denotes the number of values it returns. def call2(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, false) parser().parseMethodResponse(data) end + # Similar to XMLRPC::Client#call, however can be called concurrently and + # use a new connection for each request. In contrast to the corresponding + # method without the +_async+ suffix, which use connect-alive (one + # connection for all requests). + # + # Note, that you have to use Thread to call these methods concurrently. + # The following example calls two methods concurrently: + # + # Thread.new { + # p client.call_async("michael.add", 4, 5) + # } + # + # Thread.new { + # p client.call_async("michael.div", 7, 9) + # } + # def call_async(method, *args) ok, param = call2_async(method, *args) if ok @@ -434,6 +307,9 @@ module XMLRPC end end + # Same as XMLRPC::Client#call2, but can be called concurrently. + # + # See also XMLRPC::Client#call_async def call2_async(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, true) @@ -441,8 +317,14 @@ module XMLRPC end - # Multicall methods -------------------------------------------------------------- - + # You can use this method to execute several methods on a XMLRPC server + # which support the multi-call extension. + # + # s.multicall( + # ['michael.add', 3, 4], + # ['michael.sub', 4, 5] + # ) + # # => [7, -1] def multicall(*methods) ok, params = multicall2(*methods) if ok @@ -452,10 +334,30 @@ module XMLRPC end end + # Same as XMLRPC::Client#multicall, but returns two parameters instead of + # raising an XMLRPC::FaultException. + # + # See XMLRPC::Client#call2 def multicall2(*methods) gen_multicall(methods, false) end + # Similar to XMLRPC::Client#multicall, however can be called concurrently and + # use a new connection for each request. In contrast to the corresponding + # method without the +_async+ suffix, which use connect-alive (one + # connection for all requests). + # + # Note, that you have to use Thread to call these methods concurrently. + # The following example calls two methods concurrently: + # + # Thread.new { + # p client.multicall_async("michael.add", 4, 5) + # } + # + # Thread.new { + # p client.multicall_async("michael.div", 7, 9) + # } + # def multicall_async(*methods) ok, params = multicall2_async(*methods) if ok @@ -465,31 +367,61 @@ module XMLRPC end end + # Same as XMLRPC::Client#multicall2, but can be called concurrently. + # + # See also XMLRPC::Client#multicall_async def multicall2_async(*methods) gen_multicall(methods, true) end - # Proxy generating methods ------------------------------------------ - + # Returns an object of class XMLRPC::Client::Proxy, initialized with + # +prefix+ and +args+. + # + # A proxy object returned by this method behaves like XMLRPC::Client#call, + # i.e. a call on that object will raise a XMLRPC::FaultException when a + # fault-structure is returned by that call. def proxy(prefix=nil, *args) Proxy.new(self, prefix, args, :call) end + # Almost the same like XMLRPC::Client#proxy only that a call on the returned + # XMLRPC::Client::Proxy object will return two parameters. + # + # See XMLRPC::Client#call2 def proxy2(prefix=nil, *args) Proxy.new(self, prefix, args, :call2) end + # Similar to XMLRPC::Client#proxy, however can be called concurrently and + # use a new connection for each request. In contrast to the corresponding + # method without the +_async+ suffix, which use connect-alive (one + # connection for all requests). + # + # Note, that you have to use Thread to call these methods concurrently. + # The following example calls two methods concurrently: + # + # Thread.new { + # p client.proxy_async("michael.add", 4, 5) + # } + # + # Thread.new { + # p client.proxy_async("michael.div", 7, 9) + # } + # def proxy_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call_async) end + # Same as XMLRPC::Client#proxy2, but can be called concurrently. + # + # See also XMLRPC::Client#proxy_async def proxy2_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call2_async) end - private # ---------------------------------------------------------- + private def net_http(host, port, proxy_host, proxy_port) Net::HTTP.new host, port, proxy_host, proxy_port @@ -611,8 +543,39 @@ module XMLRPC + # XML-RPC calls look nicer! + # + # You can call any method onto objects of that class - the object handles + # XMLRPC::Client::Proxy#method_missing and will forward the method call to + # a XML-RPC server. + # + # Don't use this class directly, instead use the public instance method + # XMLRPC::Client#proxy or XMLRPC::Client#proxy2. + # + # require "xmlrpc/client" + # + # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) + # + # michael = server.proxy("michael") + # michael2 = server.proxy("michael", 4) + # + # # both calls should return the same value '9'. + # p michael.add(4,5) + # p michael2.add(5) class Proxy + # Creates an object which provides XMLRPC::Client::Proxy#method_missing. + # + # The given +server+ must be an instance of XMLRPC::Client, which is the + # XML-RPC server to be used for a XML-RPC call. + # + # +prefix+ and +delim+ will be prepended to the method name called onto this object. + # + # An optional parameter +meth+ is the method to use for a RPC. + # It can be either, call, call2, call_async, call2_async + # + # +args+ are arguments which are automatically given to every XML-RPC + # call before being provided through +method_missing+. def initialize(server, prefix, args=[], meth=:call, delim=".") @server = server @prefix = prefix ? prefix + delim : "" @@ -620,6 +583,11 @@ module XMLRPC @meth = meth end + # Every method call is forwarded to the XML-RPC server defined in + # XMLRPC::Client::Proxy#new. + # + # Note: Inherited methods from class Object cannot be used as XML-RPC + # names, because they get around +method_missing+. def method_missing(mid, *args) pre = @prefix + mid.to_s arg = @args + args diff --git a/lib/xmlrpc/config.rb b/lib/xmlrpc/config.rb index 34c3bbaf1b..0213bef2a6 100644 --- a/lib/xmlrpc/config.rb +++ b/lib/xmlrpc/config.rb @@ -3,26 +3,28 @@ # Configuration file for XML-RPC for Ruby # -module XMLRPC +module XMLRPC # :nodoc: module Config - DEFAULT_WRITER = XMLWriter::Simple # or XMLWriter::XMLParser - - # available parser: - # * XMLParser::NQXMLTreeParser - # * XMLParser::NQXMLStreamParser - # * XMLParser::XMLTreeParser - # * XMLParser::XMLStreamParser (fastest) - # * XMLParser::REXMLStreamParser - # * XMLParser::XMLScanStreamParser + # or XMLWriter::XMLParser + DEFAULT_WRITER = XMLWriter::Simple + + # === Available parsers + # + # * XMLParser::NQXMLTreeParser + # * XMLParser::NQXMLStreamParser + # * XMLParser::XMLTreeParser + # * XMLParser::XMLStreamParser (fastest) + # * XMLParser::REXMLStreamParser + # * XMLParser::XMLScanStreamParser DEFAULT_PARSER = XMLParser::REXMLStreamParser - # enable tag + # enable tag ENABLE_NIL_CREATE = false ENABLE_NIL_PARSER = false - # allows integers greater than 32-bit if true + # allows integers greater than 32-bit if +true+ ENABLE_BIGINT = false # enable marshalling ruby objects which include XMLRPC::Marshallable diff --git a/lib/xmlrpc/create.rb b/lib/xmlrpc/create.rb index 7aa0873590..13c9cd8faa 100644 --- a/lib/xmlrpc/create.rb +++ b/lib/xmlrpc/create.rb @@ -1,6 +1,4 @@ # -# Creates XML-RPC call/response documents -# # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ @@ -9,7 +7,7 @@ require "date" require "xmlrpc/base64" -module XMLRPC +module XMLRPC # :nodoc: module XMLWriter @@ -100,6 +98,8 @@ module XMLRPC end # module XMLWriter + # Creates XML-RPC call/response documents + # class Create def initialize(xml_writer = nil) @@ -132,14 +132,14 @@ module XMLRPC # - # generates a XML-RPC methodResponse document + # Generates a XML-RPC methodResponse document # - # if is_ret == false then the params array must + # When +is_ret+ is +false+ then the +params+ array must # contain only one element, which is a structure # of a fault return-value. # - # if is_ret == true then a normal - # return-value of all the given params is created. + # When +is_ret+ is +true+ then a normal + # return-value of all the given +params+ is created. # def methodResponse(is_ret, *params) @@ -167,15 +167,12 @@ module XMLRPC - ##################################### private - ##################################### # - # converts a Ruby object into - # a XML-RPC tag + # Converts a Ruby object into a XML-RPC tag # - def conv2value(param) + def conv2value(param) # :doc: val = case param when Fixnum, Bignum diff --git a/lib/xmlrpc/datetime.rb b/lib/xmlrpc/datetime.rb index d6c80a2cb9..dff2304f92 100644 --- a/lib/xmlrpc/datetime.rb +++ b/lib/xmlrpc/datetime.rb @@ -1,115 +1,95 @@ -=begin -= xmlrpc/datetime.rb -Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) - -Released under the same term of license as Ruby. - -= Classes -* (()) - -= XMLRPC::DateTime -== Description -This class is important to handle XMLRPC (('dateTime.iso8601')) values, -correcly, because normal UNIX-dates (class (({Date}))) only handle dates -from year 1970 on, and class (({Time})) handles dates without the time -component. (({XMLRPC::DateTime})) is able to store a XMLRPC -(('dateTime.iso8601')) value correctly. - -== Class Methods ---- XMLRPC::DateTime.new( year, month, day, hour, min, sec ) - Creates a new (({XMLRPC::DateTime})) instance with the - parameters ((|year|)), ((|month|)), ((|day|)) as date and - ((|hour|)), ((|min|)), ((|sec|)) as time. - Raises (({ArgumentError})) if a parameter is out of range, or ((|year|)) is not - of type (({Integer})). - -== Instance Methods ---- XMLRPC::DateTime#year ---- XMLRPC::DateTime#month ---- XMLRPC::DateTime#day ---- XMLRPC::DateTime#hour ---- XMLRPC::DateTime#min ---- XMLRPC::DateTime#sec - Return the value of the specified date/time component. - ---- XMLRPC::DateTime#mon - Alias for (()). - ---- XMLRPC::DateTime#year=( value ) ---- XMLRPC::DateTime#month=( value ) ---- XMLRPC::DateTime#day=( value ) ---- XMLRPC::DateTime#hour=( value ) ---- XMLRPC::DateTime#min=( value ) ---- XMLRPC::DateTime#sec=( value ) - Set ((|value|)) as the new date/time component. - Raises (({ArgumentError})) if ((|value|)) is out of range, or in the case - of (({XMLRPC::DateTime#year=})) if ((|value|)) is not of type (({Integer})). - ---- XMLRPC::DateTime#mon=( value ) - Alias for (()). - ---- XMLRPC::DateTime#to_time - Return a (({Time})) object of the date/time which (({self})) represents. - If the (('year')) is below 1970, this method returns (({nil})), - because (({Time})) cannot handle years below 1970. - The used timezone is GMT. - ---- XMLRPC::DateTime#to_date - Return a (({Date})) object of the date which (({self})) represents. - The (({Date})) object do ((*not*)) contain the time component (only date). - ---- XMLRPC::DateTime#to_a - Returns all date/time components in an array. - Returns (({[year, month, day, hour, min, sec]})). -=end - +# +# xmlrpc/datetime.rb +# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) +# +# Released under the same term of license as Ruby. +# require "date" -module XMLRPC +module XMLRPC # :nodoc: +# This class is important to handle XMLRPC +dateTime.iso8601+ values, +# correcly, because normal UNIX-dates, ie: Date, only handle dates +# from year 1970 on, and ruby's native Time class handles dates without the +# time component. +# +# XMLRPC::DateTime is able to store a XMLRPC +dateTime.iso8601+ value correctly. class DateTime + # Return the value of the specified date/time component. attr_reader :year, :month, :day, :hour, :min, :sec + # Set +value+ as the new date/time component. + # + # Raises ArgumentError if the given +value+ is out of range, or in the case + # of XMLRPC::DateTime#year= if +value+ is not of type Integer. def year= (value) raise ArgumentError, "date/time out of range" unless value.is_a? Integer @year = value end + # Set +value+ as the new date/time component. + # + # Raises an ArgumentError if the given +value+ isn't between 1 and 12. def month= (value) raise ArgumentError, "date/time out of range" unless (1..12).include? value @month = value end + # Set +value+ as the new date/time component. + # + # Raises an ArgumentError if the given +value+ isn't between 1 and 31. def day= (value) raise ArgumentError, "date/time out of range" unless (1..31).include? value @day = value end + # Set +value+ as the new date/time component. + # + # Raises an ArgumentError if the given +value+ isn't between 0 and 24. def hour= (value) raise ArgumentError, "date/time out of range" unless (0..24).include? value @hour = value end + # Set +value+ as the new date/time component. + # + # Raises an ArgumentError if the given +value+ isn't between 0 and 59. def min= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @min = value end + # Set +value+ as the new date/time component. + # + # Raises an ArgumentError if the given +value+ isn't between 0 and 59. def sec= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @sec = value end + # Alias for XMLRPC::DateTime#month. alias mon month + # Alias for XMLRPC::DateTime#month=. alias mon= month= + # Creates a new XMLRPC::DateTime instance with the + # parameters +year+, +month+, +day+ as date and + # +hour+, +min+, +sec+ as time. + # + # Raises an ArgumentError if a parameter is out of range, + # or if +year+ is not of the Integer type. def initialize(year, month, day, hour, min, sec) self.year, self.month, self.day = year, month, day self.hour, self.min, self.sec = hour, min, sec end + # Return a Time object of the date/time which represents +self+. + # If the @year is below 1970, this method returns +nil+, + # because Time cannot handle years below 1970. + # + # The timezone used is GMT. def to_time if @year >= 1970 Time.gm(*to_a) @@ -118,14 +98,21 @@ class DateTime end end + # Return a Date object of the date which represents +self+. + # + # The Date object do _not_ contain the time component (only date). def to_date Date.new(*to_a[0,3]) end + # Returns all date/time components in an array. + # + # Returns +[year, month, day, hour, min, sec]+. def to_a [@year, @month, @day, @hour, @min, @sec] end + # Returns whether or not all date/time components are an array. def ==(o) self.to_a == Array(o) rescue false end diff --git a/lib/xmlrpc/httpserver.rb b/lib/xmlrpc/httpserver.rb index a9605efa7a..dd0d7417c1 100644 --- a/lib/xmlrpc/httpserver.rb +++ b/lib/xmlrpc/httpserver.rb @@ -1,7 +1,3 @@ -# -# Implements a simple HTTP-server by using John W. Small's (jsmall@laser.net) -# ruby-generic-server. -# # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ @@ -10,11 +6,13 @@ require "gserver" +# Implements a simple HTTP-server by using John W. Small's (jsmall@laser.net) +# ruby-generic-server: GServer. class HttpServer < GServer ## - # handle_obj specifies the object, that receives calls to request_handler - # and ip_auth_handler + # +handle_obj+ specifies the object, that receives calls from +request_handler+ + # and +ip_auth_handler+ def initialize(handle_obj, port = 8080, host = DEFAULT_HOST, maxConnections = 4, stdlog = $stdout, audit = true, debug = true) @handler = handle_obj @@ -23,19 +21,16 @@ class HttpServer < GServer private - # Constants ----------------------------------------------- - CRLF = "\r\n" HTTP_PROTO = "HTTP/1.0" SERVER_NAME = "HttpServer (Ruby #{RUBY_VERSION})" + # Default header for the server name DEFAULT_HEADER = { "Server" => SERVER_NAME } - ## - # Mapping of status code and error message - # + # Mapping of status codes and error messages StatusCodeMapping = { 200 => "OK", 400 => "Bad Request", @@ -45,8 +40,6 @@ private 500 => "Internal Server Error" } - # Classes ------------------------------------------------- - class Request attr_reader :data, :header, :method, :path, :proto @@ -74,10 +67,7 @@ private end end - - ## - # a case-insensitive Hash class for HTTP header - # + # A case-insensitive Hash class for HTTP header class Table include Enumerable @@ -103,15 +93,15 @@ private @hash.each {|k,v| yield k.capitalize, v } end + # Output the Hash table for the HTTP header def writeTo(port) each { |k,v| port << "#{k}: #{v}" << CRLF } end end # class Table - # Helper Methods ------------------------------------------ - - def http_header(header=nil) + # Generates a Hash with the HTTP headers + def http_header(header=nil) # :doc: new_header = Table.new(DEFAULT_HEADER) new_header.update(header) unless header.nil? @@ -121,11 +111,14 @@ private new_header end - def http_date( aTime ) + # Returns a string which represents the time as rfc1123-date of HTTP-date + def http_date( aTime ) # :doc: aTime.gmtime.strftime( "%a, %d %b %Y %H:%M:%S GMT" ) end - def http_resp(status_code, status_message=nil, header=nil, body=nil) + # Returns a string which includes the status code message as, + # http headers, and body for the response. + def http_resp(status_code, status_message=nil, header=nil, body=nil) # :doc: status_message ||= StatusCodeMapping[status_code] str = "" @@ -136,9 +129,11 @@ private str end - # Main Serve Loop ----------------------------------------- - - def serve(io) + # Handles the HTTP request and writes the response back to the client, +io+. + # + # If an Exception is raised while handling the request, the client will receive + # a 500 "Internal Server Error" message. + def serve(io) # :doc: # perform IP authentification unless @handler.ip_auth_handler(io) io << http_resp(403, "Forbidden") diff --git a/lib/xmlrpc/marshal.rb b/lib/xmlrpc/marshal.rb index d121828312..ef1234f801 100644 --- a/lib/xmlrpc/marshal.rb +++ b/lib/xmlrpc/marshal.rb @@ -1,6 +1,4 @@ # -# Marshalling of XML-RPC methodCall and methodResponse -# # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ @@ -11,13 +9,12 @@ require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" -module XMLRPC +module XMLRPC # :nodoc: + # Marshalling of XMLRPC::Create#methodCall and XMLRPC::Create#methodResponse class Marshal include ParserWriterChooseMixin - # class methods ------------------------------- - class << self def dump_call( methodName, *params ) @@ -41,8 +38,6 @@ module XMLRPC end # class self - # instance methods ---------------------------- - def initialize( parser = nil, writer = nil ) set_parser( parser ) set_writer( writer ) @@ -56,16 +51,12 @@ module XMLRPC create.methodResponse( ! param.kind_of?( XMLRPC::FaultException ) , param ) end - ## - # returns [ methodname, params ] - # + # Returns [ methodname, params ] def load_call( stringOrReadable ) parser.parseMethodCall( stringOrReadable ) end - ## - # returns paramOrFault - # + # Returns +paramOrFault+ def load_response( stringOrReadable ) parser.parseMethodResponse( stringOrReadable )[1] end @@ -73,4 +64,3 @@ module XMLRPC end # class Marshal end - diff --git a/lib/xmlrpc/parser.rb b/lib/xmlrpc/parser.rb index 5db139e751..29366017bc 100644 --- a/lib/xmlrpc/parser.rb +++ b/lib/xmlrpc/parser.rb @@ -1,6 +1,3 @@ -# -# Parser for XML-RPC call and response -# # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ @@ -12,7 +9,6 @@ require "xmlrpc/base64" require "xmlrpc/datetime" -# add some methods to NQXML::Node module NQXML class Node @@ -49,28 +45,41 @@ module NQXML end # class Node end # module NQXML -module XMLRPC +module XMLRPC # :nodoc: + # Raised when the remote procedure returns a fault-structure, which has two + # accessor-methods +faultCode+ an Integer, and +faultString+ a String. class FaultException < StandardError attr_reader :faultCode, :faultString + # Creates a new XMLRPC::FaultException instance. + # + # +faultString+ is passed to StandardError as the +msg+ of the Exception. def initialize(faultCode, faultString) @faultCode = faultCode @faultString = faultString super(@faultString) end - # returns a hash + # The +faultCode+ and +faultString+ of the exception in a Hash. def to_h {"faultCode" => @faultCode, "faultString" => @faultString} end end + # Helper class used to convert types. module Convert + + # Converts a String to an Integer + # + # See also String.to_i def self.int(str) str.to_i end + # Converts a String to +true+ or +false+ + # + # Raises an exception if +str+ is not +0+ or +1+ def self.boolean(str) case str when "0" then false @@ -80,10 +89,18 @@ module XMLRPC end end + # Converts a String to a Float + # + # See also String.to_f def self.double(str) str.to_f end + # Converts a the given +str+ to a +dateTime.iso8601+ formatted date. + # + # Raises an exception if the String isn't in +dateTime.iso8601+ format. + # + # See also, XMLRPC::DateTime def self.dateTime(str) case str when /^(-?\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(?:Z|([+-])(\d\d):?(\d\d))?$/ @@ -114,12 +131,16 @@ module XMLRPC end end + # Decodes the given +str+ using XMLRPC::Base64.decode def self.base64(str) XMLRPC::Base64.decode(str) end + # Converts the given +hash+ to a marshalled object. + # + # Returns the given +hash+ if an exception occurs. def self.struct(hash) - # convert to marhalled object + # convert to marshalled object klass = hash["___class___"] if klass.nil? or Config::ENABLE_MARSHALLING == false hash @@ -141,6 +162,15 @@ module XMLRPC end end + # Converts the given +hash+ to an XMLRPC::FaultException object by passing + # the +faultCode+ and +faultString+ attributes of the Hash to + # XMLRPC::FaultException.new + # + # Raises an Exception if the given +hash+ doesn't meet the requirements. + # Those requirements being: + # * 2 keys + # * 'faultCode' key is an Integer + # * 'faultString' key is a String def self.fault(hash) if hash.kind_of? Hash and hash.size == 2 and hash.has_key? "faultCode" and hash.has_key? "faultString" and @@ -154,6 +184,7 @@ module XMLRPC end # module Convert + # Parser for XML-RPC call and response module XMLParser class AbstractTreeParser @@ -168,10 +199,8 @@ module XMLRPC private - # - # remove all whitespaces but in the tags i4, i8, int, boolean.... + # Removes all whitespaces but in the tags i4, i8, int, boolean.... # and all comments - # def removeWhitespacesAndComments(node) remove = [] childs = node.childNodes.to_a @@ -217,9 +246,7 @@ module XMLRPC node end - # - # returns, when successfully the only child-node - # + # Returns, when successfully the only child-node def hasOnlyOneChild(node, name=nil) if node.childNodes.to_a.size != 1 raise "wrong xml-rpc (size)" @@ -236,7 +263,7 @@ module XMLRPC end end - # the node `node` has empty string or string + # The node `node` has empty string or string def text_zero_one(node) nodes = node.childNodes.to_a.size @@ -575,7 +602,6 @@ module XMLRPC end # module StreamParserMixin - # --------------------------------------------------------------------------- class XMLStreamParser < AbstractStreamParser def initialize require "xmlparser" @@ -584,7 +610,7 @@ module XMLRPC } end end # class XMLStreamParser - # --------------------------------------------------------------------------- + class NQXMLStreamParser < AbstractStreamParser def initialize require "nqxml/streamingparser" @@ -613,7 +639,7 @@ module XMLRPC end # class XMLRPCParser end # class NQXMLStreamParser - # --------------------------------------------------------------------------- + class XMLTreeParser < AbstractTreeParser def initialize @@ -665,7 +691,7 @@ module XMLRPC end end # class XMLParser - # --------------------------------------------------------------------------- + class NQXMLTreeParser < AbstractTreeParser def initialize @@ -693,7 +719,7 @@ module XMLRPC end end # class NQXMLTreeParser - # --------------------------------------------------------------------------- + class REXMLStreamParser < AbstractStreamParser def initialize require "rexml/document" @@ -718,7 +744,7 @@ module XMLRPC end end - # --------------------------------------------------------------------------- + class XMLScanStreamParser < AbstractStreamParser def initialize require "xmlscan/parser" @@ -787,7 +813,7 @@ module XMLRPC end end - # --------------------------------------------------------------------------- + XMLParser = XMLTreeParser NQXMLParser = NQXMLTreeParser diff --git a/lib/xmlrpc/server.rb b/lib/xmlrpc/server.rb index b7215385ad..839353da1a 100644 --- a/lib/xmlrpc/server.rb +++ b/lib/xmlrpc/server.rb @@ -1,146 +1,7 @@ -=begin -= xmlrpc/server.rb -Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de) - -Released under the same term of license as Ruby. - -= Classes -* (()) -* (()) -* (()) -* (()) -* (()) - -= XMLRPC::BasicServer -== Description -Is the base class for all XML-RPC server-types (CGI, standalone). -You can add handler and set a default handler. -Do not use this server, as this is/should be an abstract class. - -=== How the method to call is found -The arity (number of accepted arguments) of a handler (method or (({Proc})) object) is -compared to the given arguments submitted by the client for a RPC ((-Remote Procedure Call-)). -A handler is only called if it accepts the number of arguments, otherwise the search -for another handler will go on. When at the end no handler was found, -the (()) will be called. -With this technique it is possible to do overloading by number of parameters, but -only for (({Proc})) handler, because you cannot define two methods of the same name in -the same class. - - -== Class Methods ---- XMLRPC::BasicServer.new( class_delim="." ) - Creates a new (({XMLRPC::BasicServer})) instance, which should not be - done, because (({XMLRPC::BasicServer})) is an abstract class. This - method should be called from a subclass indirectly by a (({super})) call - in the method (({initialize})). The paramter ((|class_delim|)) is used - in (()) when an object is - added as handler, to delimit the object-prefix and the method-name. - -== Instance Methods ---- XMLRPC::BasicServer#add_handler( name, signature=nil, help=nil ) { aBlock } - Adds ((|aBlock|)) to the list of handlers, with ((|name|)) as the name of the method. - Parameters ((|signature|)) and ((|help|)) are used by the Introspection method if specified, - where ((|signature|)) is either an Array containing strings each representing a type of it's - signature (the first is the return value) or an Array of Arrays if the method has multiple - signatures. Value type-names are "int, boolean, double, string, dateTime.iso8601, base64, array, struct". - - Parameter ((|help|)) is a String with informations about how to call this method etc. - - A handler method or code-block can return the types listed at - (()). - When a method fails, it can tell it the client by throwing an - (({XMLRPC::FaultException})) like in this example: - s.add_handler("michael.div") do |a,b| - if b == 0 - raise XMLRPC::FaultException.new(1, "division by zero") - else - a / b - end - end - The client gets in the case of (({b==0})) an object back of type - (({XMLRPC::FaultException})) that has a ((|faultCode|)) and ((|faultString|)) - field. - ---- XMLRPC::BasicServer#add_handler( prefix, obj ) - This is the second form of (()). - To add an object write: - server.add_handler("michael", MyHandlerClass.new) - All public methods of (({MyHandlerClass})) are accessible to - the XML-RPC clients by (('michael."name of method"')). This is - where the ((|class_delim|)) in (()) - has it's role, a XML-RPC method-name is defined by - ((|prefix|)) + ((|class_delim|)) + (('"name of method"')). - ---- XMLRPC::BasicServer#add_handler( interface, obj ) - This is the third form of (()). - - Use (({XMLRPC::interface})) to generate an ServiceInterface object, which - represents an interface (with signature and help text) for a handler class. - - Parameter ((|interface|)) must be of type (({XMLRPC::ServiceInterface})). - Adds all methods of ((|obj|)) which are defined in ((|interface|)) to the - server. - - This is the recommended way of adding services to a server! - - ---- XMLRPC::BasicServer#get_default_handler - Returns the default-handler, which is called when no handler for - a method-name is found. - It is a (({Proc})) object or (({nil})). - ---- XMLRPC::BasicServer#set_default_handler ( &handler ) - Sets ((|handler|)) as the default-handler, which is called when - no handler for a method-name is found. ((|handler|)) is a code-block. - The default-handler is called with the (XML-RPC) method-name as first argument, and - the other arguments are the parameters given by the client-call. - - If no block is specified the default of (({XMLRPC::BasicServer})) is used, which raises a - XMLRPC::FaultException saying "method missing". - - ---- XMLRPC::BasicServer#set_writer( writer ) - Sets the XML writer to use for generating XML output. - Should be an instance of a class from module (({XMLRPC::XMLWriter})). - If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. - ---- XMLRPC::BasicServer#set_parser( parser ) - Sets the XML parser to use for parsing XML documents. - Should be an instance of a class from module (({XMLRPC::XMLParser})). - If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. - ---- XMLRPC::BasicServer#add_introspection - Adds the introspection handlers "system.listMethods", "system.methodSignature" and "system.methodHelp", - where only the first one works. - ---- XMLRPC::BasicServer#add_multicall - Adds the multi-call handler "system.multicall". - ---- XMLRPC::BasicServer#get_service_hook - Returns the service-hook, which is called on each service request (RPC) unless it's (({nil})). - ---- XMLRPC::BasicServer#set_service_hook ( &handler ) - A service-hook is called for each service request (RPC). - You can use a service-hook for example to wrap existing methods and catch exceptions of them or - convert values to values recognized by XMLRPC. You can disable it by passing (({nil})) as parameter - ((|handler|)) . - - The service-hook is called with a (({Proc})) object and with the parameters for this (({Proc})). - An example: - - server.set_service_hook {|obj, *args| - begin - ret = obj.call(*args) # call the original service-method - # could convert the return value - rescue - # rescue exceptions - end - } - -=end - - +# xmlrpc/server.rb +# Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de) +# +# Released under the same term of license as Ruby. require "xmlrpc/parser" require "xmlrpc/create" @@ -149,9 +10,26 @@ require "xmlrpc/utils" # ParserWriterChooseMixin -module XMLRPC +module XMLRPC # :nodoc: +# This is the base class for all XML-RPC server-types (CGI, standalone). +# You can add handler and set a default handler. +# Do not use this server, as this is/should be an abstract class. +# +# === How the method to call is found +# The arity (number of accepted arguments) of a handler (method or Proc +# object) is compared to the given arguments submitted by the client for a +# RPC, or Remote Procedure Call. +# +# A handler is only called if it accepts the number of arguments, otherwise +# the search for another handler will go on. When at the end no handler was +# found, the default_handler, XMLRPC::BasicServer#set_default_handler will be +# called. +# +# With this technique it is possible to do overloading by number of parameters, but +# only for Proc handler, because you cannot define two methods of the same name in +# the same class. class BasicServer include ParserWriterChooseMixin @@ -167,6 +45,14 @@ class BasicServer ERR_MC_EXPECTED_STRUCT = 8 + # Creates a new XMLRPC::BasicServer instance, which should not be + # done, because XMLRPC::BasicServer is an abstract class. This + # method should be called from a subclass indirectly by a +super+ call + # in the initialize method. + # + # The paramter +class_delim+ is used by add_handler, see + # XMLRPC::BasicServer#add_handler, when an object is added as a handler, to + # delimit the object-prefix and the method-name. def initialize(class_delim=".") @handler = [] @default_handler = nil @@ -180,6 +66,52 @@ class BasicServer add_introspection if Config::ENABLE_INTROSPECTION end + # Adds +aBlock+ to the list of handlers, with +name+ as the name of + # the method. + # + # Parameters +signature+ and +help+ are used by the Introspection method if + # specified, where +signature+ is either an Array containing strings each + # representing a type of it's signature (the first is the return value) or + # an Array of Arrays if the method has multiple signatures. + # + # Value type-names are "int, boolean, double, string, dateTime.iso8601, + # base64, array, struct". + # + # Parameter +help+ is a String with information about how to call this method etc. + # + # When a method fails, it can tell the client by throwing an + # XMLRPC::FaultException like in this example: + # + # s.add_handler("michael.div") do |a,b| + # if b == 0 + # raise XMLRPC::FaultException.new(1, "division by zero") + # else + # a / b + # end + # end + # + # In the case of b==0 the client gets an object back of type + # XMLRPC::FaultException that has a +faultCode+ and +faultString+ field. + # + # This is the second form of (()). + # To add an object write: + # + # server.add_handler("michael", MyHandlerClass.new) + # + # All public methods of MyHandlerClass are accessible to + # the XML-RPC clients by michael."name of method". This is + # where the +class_delim+ in XMLRPC::BasicServer.new plays it's role, a + # XML-RPC method-name is defined by +prefix+ + +class_delim+ + "name + # of method". + # + # The third form of +add_handler is to use XMLRPC::Service::Interface to + # generate an object, which represents an interface (with signature and + # help text) for a handler class. + # + # The +interface+ parameter must be an instance of XMLRPC::Service::Interface. + # Adds all methods of +obj+ which are defined in the +interface+ to the server. + # + # This is the recommended way of adding services to a server! def add_handler(prefix, obj_or_signature=nil, help=nil, &block) if block_given? # proc-handler @@ -200,24 +132,62 @@ class BasicServer self end + # Returns the service-hook, which is called on each service request (RPC) + # unless it's +nil+. def get_service_hook @service_hook end + # A service-hook is called for each service request (RPC). + # + # You can use a service-hook for example to wrap existing methods and catch + # exceptions of them or convert values to values recognized by XMLRPC. + # + # You can disable it by passing +nil+ as the +handler+ parameter. + # + # The service-hook is called with a Proc object along with any parameters. + # + # An example: + # + # server.set_service_hook {|obj, *args| + # begin + # ret = obj.call(*args) # call the original service-method + # # could convert the return value + # rescue + # # rescue exceptions + # end + # } + # def set_service_hook(&handler) @service_hook = handler self end + # Returns the default-handler, which is called when no handler for + # a method-name is found. + # + # It is either a Proc object or +nil+. def get_default_handler @default_handler end - def set_default_handler (&handler) + # Sets +handler+ as the default-handler, which is called when + # no handler for a method-name is found. + # + # +handler+ is a code-block. + # + # The default-handler is called with the (XML-RPC) method-name as first + # argument, and the other arguments are the parameters given by the + # client-call. + # + # If no block is specified the default of XMLRPC::BasicServer is + # used, which raises a XMLRPC::FaultException saying "method missing". + def set_default_handler(&handler) @default_handler = handler self end + # Adds the multi-call handler "system.multicall". def add_multicall add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs| unless arrStructs.is_a? Array @@ -260,6 +230,9 @@ class BasicServer self end + # Adds the introspection handlers "system.listMethods", + # "system.methodSignature" and + # "system.methodHelp", where only the first one works. def add_introspection add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do methods = [] @@ -312,15 +285,12 @@ class BasicServer handle(method, *params) end - private # -------------------------------------------------------------- + private def multicall_fault(nr, str) {"faultCode" => nr, "faultString" => str} end - # - # method dispatch - # def dispatch(methodname, *args) for name, obj in @handler if obj.kind_of? Proc @@ -348,9 +318,7 @@ class BasicServer end - # - # returns true, if the arity of "obj" matches - # + # Returns +true+, if the arity of +obj+ matches +n_args+ def check_arity(obj, n_args) ary = obj.arity @@ -373,9 +341,6 @@ class BasicServer end end - # - # - # def handle(methodname, *args) create().methodResponse(*call_method(methodname, *args)) end @@ -384,57 +349,44 @@ class BasicServer end -=begin -= XMLRPC::CGIServer -== Synopsis - require "xmlrpc/server" - - s = XMLRPC::CGIServer.new - - s.add_handler("michael.add") do |a,b| - a + b - end - - s.add_handler("michael.div") do |a,b| - if b == 0 - raise XMLRPC::FaultException.new(1, "division by zero") - else - a / b - end - end - - s.set_default_handler do |name, *args| - raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + - " or wrong number of parameters!") - end - - s.serve - -== Description -Implements a CGI-based XML-RPC server. - -== Superclass -(()) - -== Class Methods ---- XMLRPC::CGIServer.new( *a ) - Creates a new (({XMLRPC::CGIServer})) instance. All parameters given - are by-passed to (()). You can only create - ((*one*)) (({XMLRPC::CGIServer})) instance, because more than one makes - no sense. - -== Instance Methods ---- XMLRPC::CGIServer#serve - Call this after you have added all you handlers to the server. - This method processes a XML-RPC methodCall and sends the answer - back to the client. - Make sure that you don't write to standard-output in a handler, or in - any other part of your program, this would case a CGI-based server to fail! -=end - +# Implements a CGI-based XML-RPC server. +# +# require "xmlrpc/server" +# +# s = XMLRPC::CGIServer.new +# +# s.add_handler("michael.add") do |a,b| +# a + b +# end +# +# s.add_handler("michael.div") do |a,b| +# if b == 0 +# raise XMLRPC::FaultException.new(1, "division by zero") +# else +# a / b +# end +# end +# +# s.set_default_handler do |name, *args| +# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + +# " or wrong number of parameters!") +# end +# +# s.serve +# +# +# Note: Make sure that you don't write to standard-output in a +# handler, or in any other part of your program, this would cause a CGI-based +# server to fail! class CGIServer < BasicServer @@obj = nil + # Creates a new XMLRPC::CGIServer instance. + # + # All parameters given are by-passed to XMLRPC::BasicServer.new. + # + # You can only create one XMLRPC::CGIServer instance, because more + # than one makes no sense. def CGIServer.new(*a) @@obj = super(*a) if @@obj.nil? @@obj @@ -444,6 +396,10 @@ class CGIServer < BasicServer super(*a) end + # Call this after you have added all you handlers to the server. + # + # This method processes a XML-RPC method call and sends the answer + # back to the client. def serve catch(:exit_serve) { length = ENV['CONTENT_LENGTH'].to_i @@ -498,24 +454,24 @@ class CGIServer < BasicServer end -=begin -= XMLRPC::ModRubyServer -== Description -Implements a XML-RPC server, which works with Apache mod_ruby. - -Use it in the same way as CGIServer! - -== Superclass -(()) -=end +# Implements a XML-RPC server, which works with Apache mod_ruby. +# +# Use it in the same way as XMLRPC::CGIServer! class ModRubyServer < BasicServer + # Creates a new XMLRPC::ModRubyServer instance. + # + # All parameters given are by-passed to XMLRPC::BasicServer.new. def initialize(*a) @ap = Apache::request super(*a) end + # Call this after you have added all you handlers to the server. + # + # This method processes a XML-RPC method call and sends the answer + # back to the client. def serve catch(:exit_serve) { header = {} @@ -574,63 +530,47 @@ class ModRubyServer < BasicServer end -=begin -= XMLRPC::Server -== Synopsis - require "xmlrpc/server" - - s = XMLRPC::Server.new(8080) - - s.add_handler("michael.add") do |a,b| - a + b - end - - s.add_handler("michael.div") do |a,b| - if b == 0 - raise XMLRPC::FaultException.new(1, "division by zero") - else - a / b - end - end - - s.set_default_handler do |name, *args| - raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + - " or wrong number of parameters!") - end - - s.serve - -== Description -Implements a standalone XML-RPC server. The method (({serve}))) is left if a SIGHUP is sent to the -program. - -== Superclass -(()) - -== Class Methods ---- XMLRPC::Server.new( port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a ) - Creates a new (({XMLRPC::Server})) instance, which is a XML-RPC server listening on - port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost. - The server is not started, to start it you have to call (()). - - Parameters ((|audit|)) and ((|debug|)) are obsolete! - - All additionally given parameters in ((|*a|)) are by-passed to (()). - -== Instance Methods ---- XMLRPC::Server#serve - Call this after you have added all you handlers to the server. - This method starts the server to listen for XML-RPC requests and answer them. - ---- XMLRPC::Server#shutdown - Stops and shuts the server down. - -=end class WEBrickServlet < BasicServer; end # forward declaration +# Implements a standalone XML-RPC server. The method XMLRPC::Server#serve is +# left if a SIGHUP is sent to the program. +# +# require "xmlrpc/server" +# +# s = XMLRPC::Server.new(8080) +# +# s.add_handler("michael.add") do |a,b| +# a + b +# end +# +# s.add_handler("michael.div") do |a,b| +# if b == 0 +# raise XMLRPC::FaultException.new(1, "division by zero") +# else +# a / b +# end +# end +# +# s.set_default_handler do |name, *args| +# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + +# " or wrong number of parameters!") +# end +# +# s.serve class Server < WEBrickServlet + # Creates a new XMLRPC::Server instance, which is a XML-RPC server + # listening on the given +port+ and accepts requests for the given +host+, + # which is +localhost+ by default. + # + # The server is not started, to start it you have to call + # XMLRPC::Server#serve. + # + # The optional +audit+ and +debug+ parameters are obsolete! + # + # All additionally provided parameters in *a are by-passed to + # XMLRPC::BasicServer.new. def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a) super(*a) require 'webrick' @@ -639,6 +579,8 @@ class Server < WEBrickServlet @server.mount("/", self) end + # Call this after you have added all you handlers to the server. + # This method starts the server to listen for XML-RPC requests and answer them. def serve signals = %w[INT TERM HUP] & Signal.list.keys signals.each { |signal| trap(signal) { @server.shutdown } } @@ -646,60 +588,42 @@ class Server < WEBrickServlet @server.start end + # Stops and shuts the server down. def shutdown @server.shutdown end end -=begin -= XMLRPC::WEBrickServlet -== Synopsis - - require "webrick" - require "xmlrpc/server" - - s = XMLRPC::WEBrickServlet.new - s.add_handler("michael.add") do |a,b| - a + b - end - - s.add_handler("michael.div") do |a,b| - if b == 0 - raise XMLRPC::FaultException.new(1, "division by zero") - else - a / b - end - end - - s.set_default_handler do |name, *args| - raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + - " or wrong number of parameters!") - end - - httpserver = WEBrick::HTTPServer.new(:Port => 8080) - httpserver.mount("/RPC2", s) - trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows - httpserver.start - -== Instance Methods - ---- XMLRPC::WEBrickServlet#set_valid_ip( *ip_addr ) - Specifies the valid IP addresses that are allowed to connect to the server. - Each IP is either a (({String})) or a (({Regexp})). - ---- XMLRPC::WEBrickServlet#get_valid_ip - Return the via method (()) specified - valid IP addresses. - -== Description -Implements a servlet for use with WEBrick, a pure Ruby (HTTP-) server framework. - -== Superclass -(()) - -=end +# Implements a servlet for use with WEBrick, a pure Ruby (HTTP) server +# framework. +# +# require "webrick" +# require "xmlrpc/server" +# +# s = XMLRPC::WEBrickServlet.new +# s.add_handler("michael.add") do |a,b| +# a + b +# end +# +# s.add_handler("michael.div") do |a,b| +# if b == 0 +# raise XMLRPC::FaultException.new(1, "division by zero") +# else +# a / b +# end +# end +# +# s.set_default_handler do |name, *args| +# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + +# " or wrong number of parameters!") +# end +# +# httpserver = WEBrick::HTTPServer.new(:Port => 8080) +# httpserver.mount("/RPC2", s) +# trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows +# httpserver.start class WEBrickServlet < BasicServer def initialize(*a) super @@ -707,8 +631,7 @@ class WEBrickServlet < BasicServer @valid_ip = nil end - # deprecated from WEBrick/1.2.2. - # but does not break anything. + # Deprecated from WEBrick/1.2.2, but does not break anything. def require_path_info? false end @@ -718,6 +641,9 @@ class WEBrickServlet < BasicServer self end + # Specifies the valid IP addresses that are allowed to connect to the server. + # + # Each IP is either a String or a Regexp. def set_valid_ip(*ip_addr) if ip_addr.size == 1 and ip_addr[0].nil? @valid_ip = nil @@ -726,6 +652,9 @@ class WEBrickServlet < BasicServer end end + # Return the valid IP addresses that are allowed to connect to the server. + # + # See also, XMLRPC::Server#set_valid_ip def get_valid_ip @valid_ip end diff --git a/lib/xmlrpc/utils.rb b/lib/xmlrpc/utils.rb index b86509cb3a..186938a56e 100644 --- a/lib/xmlrpc/utils.rb +++ b/lib/xmlrpc/utils.rb @@ -1,32 +1,41 @@ # -# Defines ParserWriterChooseMixin, which makes it possible to choose a -# different XML writer and/or XML parser then the default one. -# The Mixin is used in client.rb (class Client) and server.rb (class -# BasicServer) -# # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de) # # $Id$ # +module XMLRPC # :nodoc: -module XMLRPC - # # This module enables a user-class to be marshalled # by XML-RPC for Ruby into a Hash, with one additional - # key/value pair "___class___" => ClassName + # key/value pair ___class___ => ClassName # module Marshallable end + # Defines ParserWriterChooseMixin, which makes it possible to choose a + # different XMLWriter and/or XMLParser then the default one. + # + # The Mixin is used in client.rb (class XMLRPC::Client) + # and server.rb (class XMLRPC::BasicServer) module ParserWriterChooseMixin + # Sets the XMLWriter to use for generating XML output. + # + # Should be an instance of a class from module XMLRPC::XMLWriter. + # + # If this method is not called, then XMLRPC::Config::DEFAULT_WRITER is used. def set_writer(writer) @create = Create.new(writer) self end + # Sets the XMLParser to use for parsing XML documents. + # + # Should be an instance of a class from module XMLRPC::XMLParser. + # + # If this method is not called, then XMLRPC::Config::DEFAULT_PARSER is used. def set_parser(parser) @parser = parser self @@ -55,11 +64,8 @@ module XMLRPC module Service - # - # base class for Service Interface definitions, used - # by BasicServer#add_handler - # - + # Base class for XMLRPC::Service::Interface definitions, used + # by XMLRPC::BasicServer#add_handler class BasicInterface attr_reader :prefix, :methods @@ -82,7 +88,7 @@ module XMLRPC @methods << [mname, meth_name || mname, sig, help] end - private # --------------------------------- + private def parse_sig(sig) # sig is a String @@ -99,8 +105,8 @@ module XMLRPC end # class BasicInterface # - # class which wraps a Service Interface definition, used - # by BasicServer#add_handler + # Class which wraps a XMLRPC::Service::Interface definition, used + # by XMLRPC::BasicServer#add_handler # class Interface < BasicInterface def initialize(prefix, &p) @@ -116,7 +122,7 @@ module XMLRPC } end - private # --------------------------------- + private def meth(*a) add_method(*a) @@ -142,13 +148,13 @@ module XMLRPC # - # short-form to create a Service::Interface + # Short-form to create a XMLRPC::Service::Interface # def self.interface(prefix, &p) Service::Interface.new(prefix, &p) end - # short-cut for creating a PublicInstanceMethodsInterface + # Short-cut for creating a XMLRPC::Service::PublicInstanceMethodsInterface def self.iPIMethods(prefix) Service::PublicInstanceMethodsInterface.new(prefix) end -- cgit v1.2.3