summaryrefslogtreecommitdiff
path: root/lib/xmlrpc/server.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/xmlrpc/server.rb')
-rw-r--r--lib/xmlrpc/server.rb557
1 files changed, 243 insertions, 314 deletions
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>))
-* ((<XMLRPC::CGIServer>))
-* ((<XMLRPC::ModRubyServer>))
-* ((<XMLRPC::Server>))
-* ((<XMLRPC::WEBrickServlet>))
-
-= 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 ((<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 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 ((<add_handler|XMLRPC::BasicServer#add_handler>)) 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
- ((<XMLRPC::Client#call|URL:client.html#index:0>)).
- 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 ((<add_handler|XMLRPC::BasicServer#add_handler>)).
- 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 ((<new|XMLRPC::BasicServer.new>))
- 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 ((<add_handler|XMLRPC::BasicServer#add_handler>)).
-
- 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 <code>b==0</code> the client gets an object back of type
+ # XMLRPC::FaultException that has a +faultCode+ and +faultString+ field.
+ #
+ # This is the second form of ((<add_handler|XMLRPC::BasicServer#add_handler>)).
+ # To add an object write:
+ #
+ # server.add_handler("michael", MyHandlerClass.new)
+ #
+ # All public methods of MyHandlerClass are accessible to
+ # the XML-RPC clients by <code>michael."name of method"</code>. 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+ + <code>"name
+ # of method"</code>.
+ #
+ # 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 <code>"system.multicall"</code>.
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 <code>"system.listMethods"</code>,
+ # <code>"system.methodSignature"</code> and
+ # <code>"system.methodHelp"</code>, 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
-((<XMLRPC::BasicServer>))
-
-== Class Methods
---- XMLRPC::CGIServer.new( *a )
- 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.
-
-== 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
+#
+#
+# <b>Note:</b> 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 <b>one</b> 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
-((<XMLRPC::BasicServer>))
-=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
-((<XMLRPC::WEBrickServlet>))
-
-== 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 ((<serve|XMLRPC::Server#serve>)).
-
- Parameters ((|audit|)) and ((|debug|)) are obsolete!
-
- All additionally given parameters in ((|*a|)) are by-passed to ((<XMLRPC::BasicServer.new>)).
-
-== 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 <code>*a</code> 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 ((<set_valid_ip|XMLRPC::Server#set_valid_ip>)) specified
- valid IP addresses.
-
-== Description
-Implements a servlet for use with WEBrick, a pure Ruby (HTTP-) server framework.
-
-== Superclass
-((<XMLRPC::BasicServer>))
-
-=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