1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
zzak 2012-09-13 02:22:10 +00:00
parent d11ef850b2
commit 1df7862b2b
14 changed files with 1011 additions and 1143 deletions

View file

@ -1,3 +1,20 @@
Thu Sep 13 11:20:00 2012 Zachary Scott <zzak@ruby-lang.org>
* 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]
Thu Sep 13 10:22:11 2012 Takashi Toyoshima <toyoshim@gmail.com>
* configure.in: Don't use PIE on Haiku because loader support is not

301
lib/xmlrpc.rb Normal file
View file

@ -0,0 +1,301 @@
# == 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 (XMLParser::NQXMLStreamParser, XMLParser::NQXMLTreeParser)
# * Expat (XMLParser::XMLStreamParser, XMLParser::XMLTreeParser)
# * REXML (XMLParser::REXMLStreamParser)
# * xml-scan (XMLParser::XMLScanStreamParser)
# * Fastest parser is Expat's XMLParser::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 XMLRPC::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}"
#
# === XMLRPC::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
#
# === Using XMLRPC::Client::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 using XMLRPC::CGIServer
#
# 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 XMLRPC::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::Service::PublicInstanceMethodsInterface 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 XMLRPC::Server
#
# Same as CGI-based server, the only difference being
#
# 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 XMLParser or XMLWriter
#
# The examples above all use the default parser (which is now since 1.8
# XMLParser::REXMLStreamParser) and a default XMLRPC::XMLWriter.
# If you want to use a different XMLParser, then you have to call the
# ParserWriterChooseMixin#set_parser method of XMLRPC::Client instances
# or instances of subclasses of XMLRPC::BasicServer or by editing
# xmlrpc/config.rb.
#
# XMLRPC::Client Example:
#
# # ...
# server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
# server.set_parser(XMLRPC::XMLParser::XMLParser.new)
# # ...
#
# XMLRPC::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 XMLParser::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, XMLParser::XMLStreamParser is ~350 (!) times faster than
# XMLParser::NQXMLTreeParser and still ~18 times as fast as XMLParser::XMLTreeParser.
#
# You can change the XML-writer by calling method ParserWriterChooseMixin#set_writer.
module XMLRPC; end

View file

@ -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
<i>proxy2</i>. You can additionally give arguments to the Proxy, which will be
given to each XML-RPC call using that Proxy.
require "xmlrpc/client"
# Make an object to represent the XML-RPC server.
server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
# Create a Proxy object
sample = server.proxy("sample")
# Call the remote server and get our result
result = sample.sumAndDifference(5,3)
sum = result["sum"]
difference = result["difference"]
puts "Sum: #{sum}, Difference: #{difference}"
=== CGI-based Server
There are also two ways to define handler, the first is
like C/PHP, the second like Java, of course both ways
can be mixed:
==== C/PHP-like (handler functions)
require "xmlrpc/server"
s = XMLRPC::CGIServer.new
s.add_handler("sample.sumAndDifference") do |a,b|
{ "sum" => a + b, "difference" => a - b }
end
s.serve
==== Java-like (handler classes)
require "xmlrpc/server"
s = XMLRPC::CGIServer.new
class MyHandler
def sumAndDifference(a, b)
{ "sum" => a + b, "difference" => a - b }
end
end
# NOTE: Security Hole (read below)!!!
s.add_handler("sample", MyHandler.new)
s.serve
To return a fault-structure you have to raise an FaultException e.g.:
raise XMLRPC::FaultException.new(3, "division by Zero")
===== Security Note
From Brian Candler:
Above code sample has an extremely nasty security hole, in that you can now call
any method of 'MyHandler' remotely, including methods inherited from Object
and Kernel! For example, in the client code, you can use
puts server.call("sample.send","`","ls")
(backtick being the method name for running system processes). Needless to
say, 'ls' can be replaced with something else.
The version which binds proc objects (or the version presented below in the next section)
doesn't have this problem, but people may be tempted to use the second version because it's
so nice and 'Rubyesque'. I think it needs a big red disclaimer.
From Michael:
A solution is to undef insecure methods or to use (({XMLRPC::iPIMethods})) as shown below:
class MyHandler
def sumAndDifference(a, b)
{ "sum" => a + b, "difference" => a - b }
end
end
# ... server initialization ...
s.add_handler(XMLRPC::iPIMethods("sample"), MyHandler.new)
# ...
This adds only public instance methods explicitly declared in class MyHandler
(and not those inherited from any other class).
==== With interface declarations
Code sample from the book Ruby Developer's Guide:
require "xmlrpc/server"
class Num
INTERFACE = XMLRPC::interface("num") {
meth 'int add(int, int)', 'Add two numbers', 'add'
meth 'int div(int, int)', 'Divide two numbers'
}
def add(a, b) a + b end
def div(a, b) a / b end
end
s = XMLRPC::CGIServer.new
s.add_handler(Num::INTERFACE, Num.new)
s.serve
=== Standalone server
Same as CGI-based server, only that the line
server = XMLRPC::CGIServer.new
must be changed to
server = XMLRPC::Server.new(8080)
if you want a server listening on port 8080.
The rest is the same.
=== Choosing a different XML Parser or XML Writer
The examples above all use the default parser (which is now since 1.8
REXMLStreamParser) and a default XML writer. If you want to use a different
XML parser, then you have to call the <i>set_parser</i> method of
<tt>XMLRPC::Client</tt> instances or instances of subclasses of
<tt>XMLRPC::BasicServer</tt> or by editing xmlrpc/config.rb.
Client Example:
# ...
server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
server.set_parser(XMLRPC::XMLParser::XMLParser.new)
# ...
Server Example:
# ...
s = XMLRPC::CGIServer.new
s.set_parser(XMLRPC::XMLParser::XMLStreamParser.new)
# ...
or:
# ...
server = XMLRPC::Server.new(8080)
server.set_parser(XMLRPC::XMLParser::NQXMLParser.new)
# ...
Note that XMLStreamParser is incredible faster (and uses less memory) than any
other parser and scales well for large documents. For example for a 0.5 MB XML
document with many tags, XMLStreamParser is ~350 (!) times faster than
NQXMLTreeParser and still ~18 times as fast as XMLTreeParser.
You can change the XML-writer by calling method <i>set_writer</i>.

View file

@ -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.

View file

@ -1,46 +1,23 @@
=begin
= xmlrpc/base64.rb
Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# xmlrpc/base64.rb
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# Released under the same term of license as Ruby.
Released under the same term of license as Ruby.
= Classes
* ((<XMLRPC::Base64>))
= 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
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

View file

@ -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>))
* ((<XMLRPC::Client::Proxy>))
= 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 ((<XMLRPC::Client.new>)) which
creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure
by sending the ((<call|XMLRPC::Client#call>)) or ((<call2|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.
== 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 ((<XMLRPC::Client.new>)) 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 ((<call|XMLRPC::Client#call>)) 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 ((<call|XMLRPC::Client#call>)).
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 ((<XMLRPC::Client#multicall>)), but returns like ((<XMLRPC::Client#call2>)) 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 ((<XMLRPC::Client#call>)), 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 ((<XMLRPC::Client#proxy>)) only that a call on the returned
(({XMLRPC::Client::Proxy})) object behaves like ((<XMLRPC::Client#call2>)), 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 ((<XMLRPC::Client#http_header_extra=>)) 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 ((<XMLRPC::Client#proxy>)) or
((<XMLRPC::Client#proxy2>)).
== 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 ((<new|XMLRPC::Client::Proxy#new>)).
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 <tt>"/RPC2"</tt>.
# +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 <code>___class___</code> 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 <b>NOT</b> 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

View file

@ -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
# or XMLWriter::XMLParser
DEFAULT_WRITER = XMLWriter::Simple
# available parser:
# * XMLParser::NQXMLTreeParser
# * XMLParser::NQXMLStreamParser
# * XMLParser::XMLTreeParser
# * XMLParser::XMLStreamParser (fastest)
# * XMLParser::REXMLStreamParser
# * XMLParser::XMLScanStreamParser
# === Available parsers
#
# * XMLParser::NQXMLTreeParser
# * XMLParser::NQXMLStreamParser
# * XMLParser::XMLTreeParser
# * XMLParser::XMLStreamParser (fastest)
# * XMLParser::REXMLStreamParser
# * XMLParser::XMLScanStreamParser
DEFAULT_PARSER = XMLParser::REXMLStreamParser
# enable <nil/> tag
# enable <code><nil/></code> 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

View file

@ -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 <value> tag
# Converts a Ruby object into a XML-RPC <code><value></code> tag
#
def conv2value(param)
def conv2value(param) # :doc:
val = case param
when Fixnum, Bignum

View file

@ -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>))
= 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#month>)).
--- 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#month=>)).
--- 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 <code>@year</code> 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

View file

@ -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")

View file

@ -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 <code>[ methodname, params ]</code>
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

View file

@ -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
# * <code>'faultCode'</code> key is an Integer
# * <code>'faultString'</code> 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

View file

@ -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

View file

@ -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 <code>___class___ => ClassName</code>
#
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