xmlrpc4r-1_7_7/ 40755 1750 0 0 7377326627 12305 5ustar michaelwheelxmlrpc4r-1_7_7/doc/ 40755 1750 0 0 7377326633 13047 5ustar michaelwheelxmlrpc4r-1_7_7/doc/Makefile100644 1750 0 53 7332067141 14525 0ustar michaelwheel doc: zsh makedoc.zsh clean: rm *.html xmlrpc4r-1_7_7/doc/howto.rd100644 1750 0 12623 7365046463 14654 0ustar michaelwheel=begin = xmlrpc4r - HOWTO Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) Released under the same term of license as Ruby. = Install You can currently use xmlrpc4r with two parsers, XMLParser and/or NQXML. Both are available at RAA (Ruby Application Archive - (())). If you want to use XMLParser (Expat Module for Ruby), you have to install James Clark's XML Parser Toolkit "expat". I recommend using XMLParser, because xmlrpc4r is better tested with it and XMLParser is much faster than NQXML. The advantage of using NQXML is that it is written in pure Ruby. Then you'll need "xmlrpc4r" of course, which is available at (()). To install xmlrpc4r: tar -xvzf xmlrpc4r-1_7_4.tar.gz cd xmlrpc4r-1_7_4 su root -c "ruby install.rb" = Samples == Client require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # Call the remote server and get our result result = server.call("sample.sumAndDifference", 5, 3) sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}" == Client with XML-RPC fault-structure handling There are two possible ways, of handling a fault-structure: === by catching a XMLRPC::FaultException exception require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") begin # Call the remote server and get our result result = server.call("sample.sumAndDifference", 5, 3) sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}" rescue XMLRPC::FaultException => e puts "Error: " puts e.faultCode puts e.faultString end === by calling "call2" which returns a boolean require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # Call the remote server and get our result ok, result = server.call2("sample.sumAndDifference", 5, 3) if ok sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}" else puts "Error: " puts result.faultCode puts result.faultString end == Client using Proxy You can create a (({Proxy})) object onto which you can call methods. This way it looks nicer. Both forms, "call" and "call2" are supported through "proxy" and "proxy2". You can additionally give arguments to the Proxy, which will be given to each XML-RPC call using that Proxy. require "xmlrpc/client" # Make an object to represent the XML-RPC server. server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php") # Create a Proxy object sample = server.proxy("sample") # Call the remote server and get our result result = sample.sumAndDifference(5,3) sum = result["sum"] difference = result["difference"] puts "Sum: #{sum}, Difference: #{difference}" == CGI-based Server There are also two ways to define handler, the first is like C/PHP, the second like Java, of course both ways can be mixed: === C/PHP-like (handler functions) require "xmlrpc/server" s = XMLRPC::CGIServer.new s.add_hanlder("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 s.add_handler("sample", MyHandler.new) s.serve To return a fault-structre you have to raise an FaultException e.g.: raise XMLRPC::FaultException.new(3, "division by Zero") == 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.6.9 NQXMLParser) and a default XML writer. If you want to use XMLParser or XMLStreamParser, then you have to call the (({#set_parser})) method onto (({XMLRPC::Client})) instances or instances of subclasses of (({XMLRPC::BasicServer})) or by editing lib/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 XMLTreeParser, NQXMLStreamParser or NQXMLTreeParser, 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 (({#set_writer})). Much easier is (when using xmlrpc4r version > 1.6.3) to change the file xmlrpc/config.rb and change there the settings which XML parser/writer to use. = History $Id: howto.rd,v 1.15 2001/10/22 16:45:39 michael Exp $ =end xmlrpc4r-1_7_7/doc/index.rd100644 1750 0 6217 7377326534 14610 0ustar michaelwheel=begin = xmlrpc4r - XML-RPC for Ruby Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) Released under the same term of license as Ruby. == What is XML-RPC ? XML-RPC provides remote procedure calls over HTTP with XML. It is like SOAP but much easier. For more information see the XML-RPC homepage (()). == HOWTO See (()). == Documentation * (()) * (()) * (()) * (()) == Features : 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 : Client * synchronous/asynchronous calls * Basic HTTP-401 Authentification * HTTPS protocol (SSL) : Parser * NQXMLStreamParser * NQXMLTreeParser * XMLStreamParser (fastest) * XMLTreeParser : General * possible to choose between XMLParser Module (Expat wrapper) and NQXML (pure Ruby) parsers * Marshalling Ruby objects to Hashs and reconstruct them later from a Hash * SandStorm component architecture Client interface == ChangeLog See (()). == Download xmlrpc4r can be downloaded from here: * Version 1.7.7 (2001-11-23): (()) * Version 1.7.6 (2001-11-02): (()) * Version 1.7.5 (2001-10-30): (()) * Version 1.7.4 (2001-10-22): (()) * Version 1.7.3 (2001-10-09): (()) * Version 1.7.2 (2001-08-01): (()) * Version 1.7.1 (2001-07-27): (()) * Version 1.7.0 (2001-07-26): (()) * Version 1.6.9 (2001-07-19): (()) * Version 1.6.8 (2001-07-06): (()) * Version 1.6.7 (2001-07-02): (()) * Version 1.6.6 (2001-06-25): (()) * Version 1.6.5 (2001-06-21): (()) * Version 1.6.4 (2001-06-19): (()) * Version 1.6.3 (2001-06-12): (()) * Version 1.6.2 (2001-06-03): (()) == Further information For more information on installation and prerequisites read the (('README')) file of the package. == History $Id: index.rd,v 1.32 2001/11/23 01:58:52 michael Exp $ =end xmlrpc4r-1_7_7/doc/makedoc.zsh100644 1750 0 1422 7332067141 15257 0ustar michaelwheel#! /usr/bin/env zsh RUBY=(/usr/bin/env ruby -p -e) subst='$_.gsub!(/&amp<\/var>;/, %q|&|)' RD=( rd2 -r rd/rd2html-lib --with-css=rubyStyle.css ) $RD --html-title="xmlrpc4r - XML-RPC for Ruby" index.rd | $RUBY "$subst" > index.html $RD --html-title="xmlrpc4r - HOWTO" howto.rd | $RUBY "$subst" > howto.html $RD --html-title="xmlrpc/base64.rb" ../lib/base64.rb | $RUBY "$subst" > base64.html $RD --html-title="xmlrpc/client.rb" ../lib/client.rb | $RUBY "$subst" > client.html $RD --html-title="xmlrpc/server.rb" ../lib/server.rb | $RUBY "$subst" > server.html $RD --html-title="xmlrpc/datetime.rb" ../lib/datetime.rb | $RUBY "$subst" > datetime.html $RD --html-title="ChangeLog for xmlrpc4r" ../ChangeLog | $RUBY "$subst" > ChangeLog.html xmlrpc4r-1_7_7/doc/rubyStyle.css100644 1750 0 3266 7332065654 15661 0ustar michaelwheel/* * style.css: CSS style definition file for `Rubyavailable'. * () * * changed h1.text-align to left (Michael Neumann) * changed background-color and padding of h2 (Michael Neumann) */ body { background: #EEEEEE; color: black; margin-left: 2%; margin-right: 2%; font-size: 10.5pt; font-family: verdana, arial, helvetica, Sans-Serif; } h1 { font-family: "comic sans ms", verdana, sans-serif; text-align: left; margin-top: 5%; margin-right: 10%; } h2, h3, h4, h5, h6 { font-family: verdana, arial, helvetica, Sans-Serif; } h2 { color: #FFFFFF; background: #CC5555; text-align: left; padding-top: 0.04em; padding-bottom: 0.04em; padding-left: 0.2em; } div.header p.status { text-align: right; } div.header p.last-modified { text-align: left; } /* li p { margin-top: -1ex; } */ dt { font-weight: bold; margin-top: 2ex; margin-left: 1em; } address { color: gray; background: #EEEEEE; text-align: right; font-family: Times, serif; font-style: normal; font-variant: normal; font-weight: normal; } pre { border-right: #646464 1px solid; padding-right: 0.5em; border-top: #646464 1px solid; padding-top: 0.5em; border-left: #646464 1px solid; padding-left: 0.5em; border-bottom: #646464 1px solid; padding-bottom: 0.5em; margin-left: 1em; margin-right: 2em; white-space: pre; background-color: #e6e6e6; color: black; } span.download { font-weight: normal; color: blue; background: #EEEEEE; } .path { font-family: Verdana, Arial, Helvetica, sans-serif; } .navi { text-align: right; } xmlrpc4r-1_7_7/doc/index.html100644 1750 0 14544 7377326631 15167 0ustar michaelwheel xmlrpc4r - XML-RPC for Ruby

xmlrpc4r - XML-RPC for Ruby

Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de)

Released under the same term of license as Ruby.

What is XML-RPC ?

XML-RPC provides remote procedure calls over HTTP with XML. It is like SOAP but much easier. For more information see the XML-RPC homepage <URL:http://www.xmlrpc.com/>.

HOWTO

See here.

Documentation

Features

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
Client
  • synchronous/asynchronous calls
  • Basic HTTP-401 Authentification
  • HTTPS protocol (SSL)
Parser
  • NQXMLStreamParser
  • NQXMLTreeParser
  • XMLStreamParser (fastest)
  • XMLTreeParser
General
  • possible to choose between XMLParser Module (Expat wrapper) and NQXML (pure Ruby) parsers
  • Marshalling Ruby objects to Hashs and reconstruct them later from a Hash
  • SandStorm component architecture Client interface

ChangeLog

See here.

Download

xmlrpc4r can be downloaded from here:

Further information

For more information on installation and prerequisites read the README file of the package.

History

$Id: index.rd,v 1.32 2001/11/23 01:58:52 michael Exp $
xmlrpc4r-1_7_7/doc/howto.html100644 1750 0 16135 7377326631 15216 0ustar michaelwheel xmlrpc4r - HOWTO

xmlrpc4r - HOWTO

Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de)

Released under the same term of license as Ruby.

Install

You can currently use xmlrpc4r with two parsers, XMLParser and/or NQXML. Both are available at RAA (Ruby Application Archive - <URL:http://www.ruby-lang.org/en/raa.html>).

If you want to use XMLParser (Expat Module for Ruby), you have to install James Clark's XML Parser Toolkit "expat". I recommend using XMLParser, because xmlrpc4r is better tested with it and XMLParser is much faster than NQXML. The advantage of using NQXML is that it is written in pure Ruby.

Then you'll need "xmlrpc4r" of course, which is available at <URL:http://www.fantasy-coders.de/ruby/xmlrpc4r>.

To install xmlrpc4r:

tar -xvzf xmlrpc4r-1_7_4.tar.gz
cd xmlrpc4r-1_7_4
su root -c "ruby install.rb"

Samples

Client

require "xmlrpc/client"

# Make an object to represent the XML-RPC server.
server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")

# Call the remote server and get our result
result = server.call("sample.sumAndDifference", 5, 3)

sum = result["sum"]
difference = result["difference"]

puts "Sum: #{sum}, Difference: #{difference}"

Client with XML-RPC fault-structure handling

There are two possible ways, of handling a fault-structure:

by catching a XMLRPC::FaultException exception

require "xmlrpc/client"

# Make an object to represent the XML-RPC server.
server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")

begin
  # Call the remote server and get our result
  result = server.call("sample.sumAndDifference", 5, 3)

  sum = result["sum"]
  difference = result["difference"]

  puts "Sum: #{sum}, Difference: #{difference}"

rescue XMLRPC::FaultException => e
  puts "Error: "
  puts e.faultCode
  puts e.faultString
end

by calling "call2" which returns a boolean

require "xmlrpc/client"

# Make an object to represent the XML-RPC server.
server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")

# Call the remote server and get our result
ok, result = server.call2("sample.sumAndDifference", 5, 3)

if ok
  sum = result["sum"]
  difference = result["difference"]

  puts "Sum: #{sum}, Difference: #{difference}"
else
  puts "Error: "
  puts result.faultCode
  puts result.faultString
end

Client using Proxy

You can create a Proxy object onto which you can call methods. This way it looks nicer. Both forms, "call" and "call2" are supported through "proxy" and "proxy2". You can additionally give arguments to the Proxy, which will be given to each XML-RPC call using that Proxy.

require "xmlrpc/client"

# Make an object to represent the XML-RPC server.
server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")

# Create a Proxy object
sample = server.proxy("sample")

# Call the remote server and get our result
result = sample.sumAndDifference(5,3)

sum = result["sum"]
difference = result["difference"]

puts "Sum: #{sum}, Difference: #{difference}"

CGI-based Server

There are also two ways to define handler, the first is like C/PHP, the second like Java, of course both ways can be mixed:

C/PHP-like (handler functions)

require "xmlrpc/server"

s = XMLRPC::CGIServer.new

s.add_hanlder("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

s.add_handler("sample", MyHandler.new)
s.serve

To return a fault-structre you have to raise an FaultException e.g.:

raise XMLRPC::FaultException.new(3, "division by Zero")

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.6.9 NQXMLParser) and a default XML writer. If you want to use XMLParser or XMLStreamParser, then you have to call the #set_parser method onto XMLRPC::Client instances or instances of subclasses of XMLRPC::BasicServer or by editing lib/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 XMLTreeParser, NQXMLStreamParser or NQXMLTreeParser, 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 #set_writer.

Much easier is (when using xmlrpc4r version > 1.6.3) to change
the file xmlrpc/config.rb and change there the settings which
XML parser/writer to use.  

History

$Id: howto.rd,v 1.15 2001/10/22 16:45:39 michael Exp $
xmlrpc4r-1_7_7/doc/base64.html100644 1750 0 5377 7377326631 15130 0ustar michaelwheel xmlrpc/base64.rb

xmlrpc/base64.rb

Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de)

Released under the same term of license as Ruby.

Classes

XMLRPC::Base64

Description

This class is necessary for xmlrpc4r to determine that a string should be transmitted base64-encoded and not as a raw-string. You can use XMLRPC::Base64 on the client and server-side as a parameter and/or return-value.

Class Methods

XMLRPC::Base64.new( str, state = :dec )

Creates a new XMLRPC::Base64 instance with string str as the internal string. When state is :dec it assumes that the string str is not in base64 format (perhaps already decoded), otherwise if state is :enc it decodes str and stores it as the internal string.

XMLRPC::Base64.decode( str )

Decodes string str with base64 and returns that value.

XMLRPC::Base64.encode( str )

Encodes string str with base64 and returns that value.

Instance Methods

XMLRPC::Base64#decoded

Returns the internal string decoded.

XMLRPC::Base64#encoded

Returns the internal string encoded with base64.

History

$Id: base64.rb,v 1.4 2001/07/26 20:29:38 michael Exp $
xmlrpc4r-1_7_7/doc/client.html100644 1750 0 35316 7377326632 15337 0ustar michaelwheel xmlrpc/client.rb

xmlrpc/client.rb

Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de)

Released under the same term of license as Ruby.

Classes

XMLRPC::Client

Synopsis

require "xmlrpc/client"

server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
begin
  param = server.call("michael.add", 4, 5)
  puts "4 + 5 = #{param}"
rescue XMLRPC::FaultException => e
  puts "Error:"
  puts e.faultCode
  puts e.faultString
end

or

require "xmlrpc/client"

server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
ok, param = server.call2("michael.add", 4, 5)
if ok then
  puts "4 + 5 = #{param}"
else
  puts "Error:"
  puts param.faultCode
  puts param.faultString
end

Description

Class XMLRPC::Client provides remote procedure calls to a XML-RPC server. After setting the connection-parameters with XMLRPC::Client.new which creates a new XMLRPC::Client instance, you can execute a remote procedure by sending the call or 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)
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={} )

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 *1. 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 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 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#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::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.

Note: Inherited methods from class Object cannot be used as XML-RPC names, because they get around method_missing.

History

$Id: client.rb,v 1.47 2001/07/20 13:24:56 michael Exp $

*1stands for Remote Procedure Call

xmlrpc4r-1_7_7/doc/server.html100644 1750 0 33752 7377326632 15371 0ustar michaelwheel xmlrpc/server.rb

xmlrpc/server.rb

Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de)

Released under the same term of license as Ruby.

Classes

XMLRPC::BasicServer

Description

Is the base class for all XML-RPC server-types (CGI, standalone). You can add handler and set a default handler. Do not use this server, as this is/should be an abstract class.

How the method to call is found

The arity (number of accepted arguments) of a handler (method or Proc object) is compared to the given arguments submitted by the client for a RPC *1. 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 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 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. 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. 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 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.

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 
  resuce
    # rescue exceptions
  end
}

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!

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

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::BasicServer

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.

The parameters maxConnections, stdlog, audit and debug are passed to the HTTP server and specify it's behaviour more precise.

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.

History

$Id: server.rb,v 1.45 2001/11/23 01:52:08 michael Exp $    

*1Remote Procedure Call

xmlrpc4r-1_7_7/doc/datetime.html100644 1750 0 12320 7377326632 15643 0ustar michaelwheel xmlrpc/datetime.rb

xmlrpc/datetime.rb

Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de)

Released under the same term of license as Ruby.

Classes

XMLRPC::DateTime

Description

This class is important to handle XMLRPC dateTime.iso8601 values, correcly, because normal UNIX-dates (class Date) only handle dates from year 1970 on, and class Time handles dates without the time component. XMLRPC::DateTime is able to store a XMLRPC dateTime.iso8601 value correctly.

Class Methods

XMLRPC::DateTime.new( year, month, day, hour, min, sec )

Creates a new XMLRPC::DateTime instance with the parameters year, month, day as date and hour, min, sec as time. Raises ArgumentError if a parameter is out of range, or year is not of type Integer.

Instance Methods

XMLRPC::DateTime#year
XMLRPC::DateTime#month
XMLRPC::DateTime#day
XMLRPC::DateTime#hour
XMLRPC::DateTime#min
XMLRPC::DateTime#sec

Return the value of the specified date/time component.

XMLRPC::DateTime#mon

Alias for XMLRPC::DateTime#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].

History

$Id: datetime.rb,v 1.5 2001/02/07 20:26:30 michael Exp $
xmlrpc4r-1_7_7/doc/ChangeLog.html100644 1750 0 22736 7377326633 15713 0ustar michaelwheel ChangeLog for xmlrpc4r

ChangeLog for xmlrpc4r

1.7.7 (2001-11-23)
  • fixed bug for mswin32 Ruby (signal HUP). Submitted by Martin Stannard.
1.7.6 (2001-11-02)
  • fixed bug in StreamParserMixin (NQXMLStreamParser and XMLStreamParser): <boolean>0</boolean> resulted in "" instead of false (found by covert thaddeus).
1.7.5 (2001-10-30)
  • fixed bug in XMLParser::XMLStreamParser (found by covert thaddeus).
1.7.4 (2001-10-22)
  • added testcase for bug below
  • create.rb: fixed bug when used with XMLRPC::Marshal
1.7.3 (2001-10-09)
  • server.rb: when platform=mingw use trap(1) instead of trap("HUP")
  • fixed bug in stream parsers (both NQXML and XMLParser). Instead of a XMLRPC::FaultException a Hash was returned for the "fault" tag. Added to the testcases.
  • fixed bug in method dispatching (server.rb), found by Andreas Bolka
1.7.2 (2001-08-01)
  • added xmlrpc/marshal.rb for simple XML-RPC methodCall/Response parsing/creating
  • changed installer
1.7.1 (2001-07-27)
  • NQXMLStreamParser is now the default parser
  • added NQXMLStreamParser (slightly faster than NQXMLTreeParser, but scales a bit better for larger documents)
  • Base64: remove whitespaces
1.7 (2001-07-26)
  • added XMLStreamParser; on the average 20 times faster than NQXMLParser and still about twice as fast as XMLParser (DOM). XMLStreamParser scales well for large XML documents (e.g. 0.5 MB in size), so is it ~350 (!) times faster than NQXMLParser and still ~18 times faster than XMLParser.
1.6.9 (2001-07-19)
  • added redist/ directory (TCPSocketPipe.rb, application.rb and dump.rb)
  • now NQXML is the default parser
  • improved HttpServer (used for standalone server)
1.6.8 (2001-07-06)
  • added server-side support for mod_ruby (XMLRPC::ModRubyServer)
  • added Service::PublicInstanceMethodsInterface, or short form with method XMLRPC::iPIMethods, which allows to add all instance methods of a class as handlers to a server
  • added Service::Interface class (or method XMLRPC::interface) and a third form of BasicServer#add_handler(interface, obj)
1.6.7 (2001-07-02)
  • Client: added two new constructors:

    • Client.new2(uri, proxy=nil, timeout=nil)
    • Client.new3(hash={})
  • Client: added read-timeout (method timeout/timeout=)
  • Client: added asynchronous methods: call_async, call2_async, multicall_async, mutlicall2_async, proxy_async, proxy2_async
  • Client: if user/password specified sends every time a Authorization header (Basic), do not check WWW-Authentificate header.
  • includes new version of GServer.rb which fixed two minor logging-misbehaviours
1.6.6 (2001-06-25)
  • added Client-interface wrapper for SandStorm component architecture (see SourceForge.net). See file samples/sandstorm/active.rb
  • added Basic HTTP (401) Authorization to Client and support for SSL.

    Client#new(host, url, port, proxy_host, proxy_port, user, password, use_ssl)

    For SSL you need the SSL package from RAA.

  • added full support for Introspection (only proc-handlers are supported)
  • instance variables which value is nil are not marshalled unless ENABLE_NIL_CREATE is true
  • Marshallable classes need not have method initialize without arguments (adapted from SOAP4R)
  • changed config.rb (made it simpler)
  • added two flags ENABLE_MULTICALL and ENABLE_INTROSPECTION to config.rb
1.6.5 (2001-06-21)
  • modified multicall/multicall2 return value [1,2,3] instead of [[1], [2], [3]]
  • CGIServer works now with FastCGI (see samples/xml.fcgi)
  • renamed Server#stop to Server#shutdown
  • added XMLRPC::Marshallable, to marshall any Ruby object to a hash and restore the object later from that hash.
  • fixed bug where <value> </value> was stripped to ""
1.6.4 (2001-06-19)
  • clients can use Symbol as type which is converted to a String
  • added <nil/> (optionally) as well as BigInt (Bignum's > 32 bits)
  • added configuration file (config.rb) for changing globally the parser/writer to use as well as which features to enable
1.6.3 (2001-06-12)
  • fixed default_handler bug
  • added system.multicall extension
  • added parser test-cases
  • fixed bug: <value></value> was invalid (found by Thaddeus Covert)
  • added Introspection (BasicServer#add_introspection) (by Neil Conway)
  • added service-hook (which is called for each RPC)
1.6.2 (2001-06-03)
  • fixed bug; in create.rb XMLWrite::Simple did not escape text, thanx to Colin Steele
  • a XMLRPC::Base64 object is no longer returned from a RPC, instead a Ruby String is returned.
1.6.1
  • changed HOWTO (added information on how to use NQXML)
  • NQXML parser support
  • possibility to choose between different XML parsers and XML writers, with Client#set_parser/#set_writer and BasicServer#set_parser/#set_writer
  • added HTTP.version_1_1, so now works with Ruby versions > 1.7
  • now you can do XML-RPC calls through a proxy server (Client.new). Thanks to Hiroshi.
1.6
  • added RAA (Ruby Application Archive) XML-RPC example TkRAA
  • added XMLRPC::Client#proxy and #proxy2 as well as subclass Client::Proxy
  • fixed another empty string bug, which occured when an empty name-tag (hash-key) was used.
1.5.4
  • fixed empty string bug, thanks to NaHi
1.5.3
  • added HOWTO
  • XMLRPC::DateTime.new and all setter-methods, raise now an ArgumentError if the value is out of range
1.5.2
  • added Struct as possible type in a XMLRPC::Client#call/call2 or as a return value from a server-handler.
1.5.1
  • now works also with Windows (validates)
  • standalone-server (XMLRPC::Server) works correctly (changed \n to \r\n), and validates
  • XMLRPC::Server.new has now a second paramter "host" to specify the host to listen on
1.5
  • allow BigNum's that fit in 32-bit
  • now, always check the parity of a method before calling it
  • in server.rb, BasicServer#set/get_argument_error_handler removed
  • in server.rb, BasicServer.new removed argument "check_parity", now always on
  • introduced new type XMLRPC::DateTime to handle times which year is before 1970 (DateTime is now always returned, no more Date/Time)
  • xmlrpc4r now validates to the validator1 test-suite
  • added validator sample
  • fixed a bug in parser, which causes the validator-suite to fail
  • started writing ChangeLog
1.4

History

$Id: ChangeLog,v 1.45 2001/11/23 01:53:43 michael Exp $
xmlrpc4r-1_7_7/ChangeLog100644 1750 0 14112 7377326047 14167 0ustar michaelwheel=begin = ChangeLog for xmlrpc4r :1.7.7 (2001-11-23) * fixed bug for mswin32 Ruby (signal HUP). Submitted by Martin Stannard. :1.7.6 (2001-11-02) * fixed bug in StreamParserMixin (NQXMLStreamParser and XMLStreamParser): 0 resulted in "" instead of false (found by covert thaddeus). :1.7.5 (2001-10-30) * fixed bug in XMLParser::XMLStreamParser (found by covert thaddeus). :1.7.4 (2001-10-22) * added testcase for bug below * create.rb: fixed bug when used with XMLRPC::Marshal :1.7.3 (2001-10-09) * server.rb: when platform=mingw use trap(1) instead of trap("HUP") * fixed bug in stream parsers (both NQXML and XMLParser). Instead of a XMLRPC::FaultException a Hash was returned for the "fault" tag. Added to the testcases. * fixed bug in method dispatching (server.rb), found by Andreas Bolka :1.7.2 (2001-08-01) * added xmlrpc/marshal.rb for simple XML-RPC methodCall/Response parsing/creating * changed installer :1.7.1 (2001-07-27) * NQXMLStreamParser is now the default parser * added NQXMLStreamParser (slightly faster than NQXMLTreeParser, but scales a bit better for larger documents) * Base64: remove whitespaces :1.7 (2001-07-26) * added XMLStreamParser; on the average 20 times faster than NQXMLParser and still about twice as fast as XMLParser (DOM). XMLStreamParser scales well for large XML documents (e.g. 0.5 MB in size), so is it ~350 (!) times faster than NQXMLParser and still ~18 times faster than XMLParser. :1.6.9 (2001-07-19) * added redist/ directory (TCPSocketPipe.rb, application.rb and dump.rb) * now NQXML is the default parser * improved HttpServer (used for standalone server) :1.6.8 (2001-07-06) * added server-side support for mod_ruby (XMLRPC::ModRubyServer) * added Service::PublicInstanceMethodsInterface, or short form with method XMLRPC::iPIMethods, which allows to add all instance methods of a class as handlers to a server * added Service::Interface class (or method XMLRPC::interface) and a third form of BasicServer#add_handler(interface, obj) :1.6.7 (2001-07-02) * Client: added two new constructors: * Client.new2(uri, proxy=nil, timeout=nil) * Client.new3(hash={}) * Client: added read-timeout (method timeout/timeout=) * Client: added asynchronous methods: call_async, call2_async, multicall_async, mutlicall2_async, proxy_async, proxy2_async * Client: if user/password specified sends every time a Authorization header (Basic), do not check WWW-Authentificate header. * includes new version of GServer.rb which fixed two minor logging-misbehaviours :1.6.6 (2001-06-25) * added Client-interface wrapper for SandStorm component architecture (see SourceForge.net). See file samples/sandstorm/active.rb * added Basic HTTP (401) Authorization to Client and support for SSL. Client#new(host, url, port, proxy_host, proxy_port, user, password, use_ssl) For SSL you need the SSL package from RAA. * added full support for Introspection (only proc-handlers are supported) * instance variables which value is nil are not marshalled unless ENABLE_NIL_CREATE is true * Marshallable classes need not have method initialize without arguments (adapted from SOAP4R) * changed config.rb (made it simpler) * added two flags ENABLE_MULTICALL and ENABLE_INTROSPECTION to config.rb :1.6.5 (2001-06-21) * modified multicall/multicall2 return value [1,2,3] instead of [[1], [2], [3]] * CGIServer works now with FastCGI (see samples/xml.fcgi) * renamed Server#stop to Server#shutdown * added XMLRPC::Marshallable, to marshall any Ruby object to a hash and restore the object later from that hash. * fixed bug where was stripped to "" :1.6.4 (2001-06-19) * clients can use Symbol as type which is converted to a String * added (optionally) as well as BigInt (Bignum's > 32 bits) * added configuration file (config.rb) for changing globally the parser/writer to use as well as which features to enable :1.6.3 (2001-06-12) * fixed default_handler bug * added system.multicall extension * added parser test-cases * fixed bug: was invalid (found by Thaddeus Covert) * added Introspection (BasicServer#add_introspection) (by Neil Conway) * added service-hook (which is called for each RPC) :1.6.2 (2001-06-03) * fixed bug; in create.rb XMLWrite::Simple did not escape text, thanx to Colin Steele * a XMLRPC::Base64 object is no longer returned from a RPC, instead a Ruby String is returned. :1.6.1 * changed HOWTO (added information on how to use NQXML) * NQXML parser support * possibility to choose between different XML parsers and XML writers, with Client#set_parser/#set_writer and BasicServer#set_parser/#set_writer * added HTTP.version_1_1, so now works with Ruby versions > 1.7 * now you can do XML-RPC calls through a proxy server (Client.new). Thanks to Hiroshi. :1.6 * added RAA (Ruby Application Archive) XML-RPC example TkRAA * added XMLRPC::Client#proxy and #proxy2 as well as subclass Client::Proxy * fixed another empty string bug, which occured when an empty name-tag (hash-key) was used. : 1.5.4 * fixed empty string bug, thanks to NaHi : 1.5.3 * added HOWTO * XMLRPC::DateTime.new and all setter-methods, raise now an ArgumentError if the value is out of range : 1.5.2 * added Struct as possible type in a XMLRPC::Client#call/call2 or as a return value from a server-handler. : 1.5.1 * now works also with Windows (validates) * standalone-server (XMLRPC::Server) works correctly (changed \n to \r\n), and validates * XMLRPC::Server.new has now a second paramter "host" to specify the host to listen on : 1.5 * allow BigNum's that fit in 32-bit * now, always check the parity of a method before calling it * in server.rb, BasicServer#set/get_argument_error_handler removed * in server.rb, BasicServer.new removed argument "check_parity", now always on * introduced new type XMLRPC::DateTime to handle times which year is before 1970 (DateTime is now always returned, no more Date/Time) * xmlrpc4r now validates to the validator1 test-suite * added validator sample * fixed a bug in parser, which causes the validator-suite to fail * started writing ChangeLog : 1.4 = History $Id: ChangeLog,v 1.45 2001/11/23 01:53:43 michael Exp $ =end xmlrpc4r-1_7_7/README100644 1750 0 5306 7337264373 13261 0ustar michaelwheel$Id: README,v 1.23 2001/08/17 18:56:59 michael Exp $ XML-RPC for Ruby Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) License is the same as Ruby's For more information about XML-RPC look at http://www.xmlrpc.com. ACKNOWLEDGMENTS =============== John W. Small (jsmall@laser.net): * I included this ruby-generic-server into this package and use it as a base for the Standalone XML-RPC server. For copyright notice and license, see file "redist/GServer.rb". It is available from RAA. NAKAMURA Hiroshi (NaHi): * Many thanks to him, author of SOAP4R, for idea of marshalling Ruby objects and it's implementation. Helped to find several bugs. * included his TCPSocketPipe.rb and application.rb (see redist/), as well as the modified monitor.rb in samples/monitor. Neil Conway: Inspired and helped implementing Introspection support Colin Steele bug fix patch for mod_ruby Thaddeus Covert bug fix and all the others I forgot :-) PREREQUISITES ============= You need either NQXML (tested with 0.6.1, 1.0.3 and 1.1.1) or XMLParser (tested with version 0.6.1) from RAA, and a Ruby version >= 1.6. Note that you have to edit the config.rb file in directory lib if you want to change the used parser (default is now (since 1.6.9) NQXMLParser). TEST ===== If you want, you can execute the testcases, to make sure, all (for which testcases exist) works correctly. Therefore you need "RUNIT" from RAA installed. Then go into directory "test" (you have to go into this directory, otherwise it will not work!!!), and run "ruby test.rb". If in the last line there's an "OK", all works as expected. INSTALL ======= Edit the lib/config.rb file to configure which XML parser/writer to use or which features to enable. Type "ruby install.rb" in current directory. Make sure you have root priviledges before you do this. The XML-RPC library files are installed in your site_ruby directory, of the actual ruby-version (e.g. "site_ruby/1.6") under the directory "xmlrpc". All files in directory redist/ are copied to "site_ruby/1.6". DOCUMENTATION ============= Open doc/index.html in a web-browser. SAMPLES ======= See samples/validator/validator1.rb for a very good example. I've also included one example of an XML-RPC cgi-based server and a ruby-program which calles it. "samples/xml.cgi" is the cgi-based server, which should be placed into your cgi-bin directory of your web-server. "sampels/call.rb" is the client-side which calls the server (check the URL /cgi-bin/xml.cgi in samples/call.rb if it points to the cgi-based server-script) PROBLEMS ======== A problem is that XML-RPC do not specify the timezone. I use Time.gm(...) to create a Time object! TODO ==== See file ToDo. xmlrpc4r-1_7_7/ToDo100644 1750 0 4041 7360616473 13162 0ustar michaelwheel$Id: ToDo,v 1.29 2001/10/09 15:52:27 michael Exp $ - use Date3, URb - allow parameter names in signatures: "int methodName(int a, string b )" - convertion-hook - Service Registry that creates WSDL (Web Service Description Languag) - Mix-in for service classes - Server: do method-lookup with Hash - Conversion-class which handles conversion from and to XMLRPC. - write test-cases - write documentation (3/4 done) - declare exceptions (e.g. ParserException...) - add the method-name to the FaultException? - client do not handle HTTP 301 redirects - "400 Bad Request" on not valid XML ? - XML pretty print? - write more/better samples - Server method hooks (e.g. for converting types and catching exceptions): class Service ... end Server.set_hook {|params| begin x = yield params # convert x rescue # rescue exceptions end } or alternative two hook functions, one for converting paramerters and one for converting the result. Server.set_call_hook {|params| # convert params and return them } Server.set_result_hook {...} * file server.rb: trap("HUP") does not work with mingw => trap(1) works * convert from DOM to SAX ? (faster) * connection alive * Apache Mod Server * FastCGI server * a Java XMLRPC implementation had . should implement? * implement new features of non-standard XML-RPC extensions * service introspection * add support for NQXML * access XML-RPC server via Proxy * RPCs like michael.add(2,3) => method_missing * raise exception, when DateTime.new or setters get parameters which are out of range (e.g. month=13) * make it work under Windows * test validation with standalone server * TCPServer.new(host, port) in EServer.rb * Ruby's fixnum only 30 bit (without sign)? Allow Bignum of 32 bit? * XMLRPC::DateTime class (? date3.rb) * conform to validator1 suite * check arity (if check_arity is true) before calling hanlder * argument_error_handler, which is called due to a ArgumentError exception * added standalone server * add Date <-> Time conversions * base64 type * dateTime.iso8601 type xmlrpc4r-1_7_7/install.rb100644 1750 0 1433 7331510247 14355 0ustar michaelwheel#!/usr/bin/env ruby # # $Id: install.rb,v 1.11 2001/07/31 11:04:07 michael Exp $ # Install XML-RPC # require "rbconfig" require "ftools" INST = [ { :srcpath => "lib", :dstpath => Config::CONFIG["sitelibdir"] + "/" + "xmlrpc", :files => %w(base64.rb client.rb config.rb create.rb datetime.rb httpserver.rb marshal.rb parser.rb server.rb utils.rb) }, { :srcpath => "redist", :dstpath => Config::CONFIG["sitelibdir"], :files => %w(GServer.rb TCPSocketPipe.rb application.rb dump.rb) } ] begin for inst in INST File.mkpath inst[:dstpath], true for name in inst[:files] File.install "#{ inst[:srcpath] }/#{name}", "#{ inst[:dstpath] }/#{name}", 0644, true end end rescue puts "install failed!" puts $! else puts "install succeed!" end xmlrpc4r-1_7_7/lib/ 40755 1750 0 0 7377326626 13052 5ustar michaelwheelxmlrpc4r-1_7_7/lib/base64.rb100644 1750 0 3355 7330076662 14555 0ustar michaelwheel=begin = xmlrpc/base64.rb Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) Released under the same term of license as Ruby. = Classes * (()) = XMLRPC::Base64 == Description This class is necessary for (('xmlrpc4r')) to determine that a string should be transmitted base64-encoded and not as a raw-string. You can use (({XMLRPC::Base64})) on the client and server-side as a parameter and/or return-value. == Class Methods --- XMLRPC::Base64.new( str, state = :dec ) Creates a new (({XMLRPC::Base64})) instance with string ((|str|)) as the internal string. When ((|state|)) is (({:dec})) it assumes that the string ((|str|)) is not in base64 format (perhaps already decoded), otherwise if ((|state|)) is (({:enc})) it decodes ((|str|)) and stores it as the internal string. --- XMLRPC::Base64.decode( str ) Decodes string ((|str|)) with base64 and returns that value. --- XMLRPC::Base64.encode( str ) Encodes string ((|str|)) with base64 and returns that value. == Instance Methods --- XMLRPC::Base64#decoded Returns the internal string decoded. --- XMLRPC::Base64#encoded Returns the internal string encoded with base64. =end module XMLRPC class Base64 def initialize(str, state = :dec) case state when :enc @str = Base64.decode(str) when :dec @str = str else raise ArgumentError, "wrong argument; either :enc or :dec" end end def decoded @str end def encoded Base64.encode(@str) end def Base64.decode(str) str.gsub(/\s+/, "").unpack("m")[0] end def Base64.encode(str) [str].pack("m") end end end # module XMLRPC =begin = History $Id: base64.rb,v 1.4 2001/07/26 20:29:38 michael Exp $ =end xmlrpc4r-1_7_7/lib/client.rb100644 1750 0 41261 7326030450 14753 0ustar michaelwheel=begin = xmlrpc/client.rb Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) Released under the same term of license as Ruby. = Classes * (()) * (()) = XMLRPC::Client == Synopsis require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) begin param = server.call("michael.add", 4, 5) puts "4 + 5 = #{param}" rescue XMLRPC::FaultException => e puts "Error:" puts e.faultCode puts e.faultString end or require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) ok, param = server.call2("michael.add", 4, 5) if ok then puts "4 + 5 = #{param}" else puts "Error:" puts param.faultCode puts param.faultString end == Description Class (({XMLRPC::Client})) provides remote procedure calls to a XML-RPC server. After setting the connection-parameters with (()) which creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure by sending the (()) or (()) message to this new instance. The given parameters indicate which method to call on the remote-side and of course the parameters for the remote procedure. == Class Methods --- XMLRPC::Client.new( host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=false, timeout =nil) Creates an object which represents the remote XML-RPC server on the given host ((|host|)). If the server is CGI-based, ((|path|)) is the path to the CGI-script, which will be called, otherwise (in the case of a standalone server) ((|path|)) should be (({"/RPC2"})). ((|port|)) is the port on which the XML-RPC server listens. If ((|proxy_host|)) is given, then a proxy server listening at ((|proxy_host|)) is used. ((|proxy_port|)) is the port of the proxy server. Default values for ((|host|)), ((|path|)) and ((|port|)) are 'localhost', '/RPC2' and '80' respectively using SSL '443'. If ((|user|)) and ((|password|)) are given, each time a request is send, a Authorization header is send. Currently only Basic Authentification is implemented no Digest. If ((|use_ssl|)) is set to (({true})), comunication over SSL is enabled. Note, that you need the SSL package from RAA installed. Parameter ((|timeout|)) is the time to wait for a XML-RPC response, defaults to 30. --- XMLRPC::Client.new2( uri, proxy=nil, timeout=nil) : 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={} ) Parameter ((|hash|)) has following case-insensitive keys: * host * path * port * proxy_host * proxy_port * user * password * use_ssl * timeout Calls (()) with the corresponding values. == Instance Methods --- XMLRPC::Client#call( method, *args ) Invokes the method named ((|method|)) with the parameters given by ((|args|)) on the XML-RPC server. The parameter ((|method|)) is converted into a (({String})) and should be a valid XML-RPC method-name. Each parameter of ((|args|)) must be of one of the following types, where (({Hash})), (({Struct})) and (({Array})) can contain any of these listed ((:types:)): * (({Fixnum})), (({Bignum})) * (({TrueClass})), (({FalseClass})) ((({true})), (({false}))) * (({String})), (({Symbol})) * (({Float})) * (({Hash})), (({Struct})) * (({Array})) * (({Date})), (({Time})), (({XMLRPC::DateTime})) * (({XMLRPC::Base64})) * A Ruby object which class includes XMLRPC::Marshallable (only if Config::ENABLE_MARSHALLABLE is (({true}))). That object is converted into a hash, with one additional key/value pair "___class___" which contains the class name for restoring later that object. The method returns the return-value from the RPC ((-stands for Remote Procedure Call-)). The type of the return-value is one of the above shown, only that a (({Bignum})) is only allowed when it fits in 32-bit and that a XML-RPC (('dateTime.iso8601')) type is always returned as a ((<(({XMLRPC::DateTime}))|URL:datetime.html>)) object and a (({Struct})) is never returned, only a (({Hash})), the same for a (({Symbol})), where always a (({String})) is returned. A (({XMLRPC::Base64})) is returned as a (({String})) from xmlrpc4r version 1.6.1 on. If the remote procedure returned a fault-structure, then a (({XMLRPC::FaultException})) exception is raised, which has two accessor-methods (({faultCode})) and (({faultString})) of type (({Integer})) and (({String})). --- XMLRPC::Client#call2( method, *args ) The difference between this method and (()) is, that this method do ((*not*)) raise a (({XMLRPC::FaultException})) exception. The method returns an array of two values. The first value indicates if the second value is a return-value ((({true}))) or an object of type (({XMLRPC::FaultException})). Both are explained in (()). --- XMLRPC::Client#multicall( *methods ) You can use this method to execute several methods on a XMLRPC server which supports the multi-call extension. Example: s.multicall( ['michael.add', 3, 4], ['michael.sub', 4, 5] ) # => [7, -1] --- XMLRPC::Client#multicall2( *methods ) Same as (()), but returns like (()) two parameters instead of raising an (({XMLRPC::FaultException})). --- XMLRPC::Client#proxy( prefix, *args ) Returns an object of class (({XMLRPC::Client::Proxy})), initialized with ((|prefix|)) and ((|args|)). A proxy object returned by this method behaves like (()), i.e. a call on that object will raise a (({XMLRPC::FaultException})) when a fault-structure is returned by that call. --- XMLRPC::Client#proxy2( prefix, *args ) Almost the same like (()) only that a call on the returned (({XMLRPC::Client::Proxy})) object behaves like (()), i.e. a call on that object will return two parameters. --- XMLRPC::Client#call_async(...) --- XMLRPC::Client#call2_async(...) --- XMLRPC::Client#multicall_async(...) --- XMLRPC::Client#multicall2_async(...) --- XMLRPC::Client#proxy_async(...) --- XMLRPC::Client#proxy2_async(...) In contrast to corresponding methods without "_async", these can be called concurrently and use for each request a new connection, where the non-asynchronous counterparts use connection-alive (one connection for all requests) if possible. Note, that you have to use Threads to call these methods concurrently. The following example calls two methods concurrently: Thread.new { p client.call_async("michael.add", 4, 5) } Thread.new { p client.call_async("michael.div", 7, 9) } --- XMLRPC::Client#timeout --- XMLRPC::Client#user --- XMLRPC::Client#password Return the corresponding attributes. --- XMLRPC::Client#timeout= (new_timeout) --- XMLRPC::Client#user= (new_user) --- XMLRPC::Client#password= (new_password) Set the corresponding attributes. --- XMLRPC::Client#set_writer( writer ) Sets the XML writer to use for generating XML output. Should be an instance of a class from module (({XMLRPC::XMLWriter})). If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. --- XMLRPC::Client#set_parser( parser ) Sets the XML parser to use for parsing XML documents. Should be an instance of a class from module (({XMLRPC::XMLParser})). If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. = XMLRPC::Client::Proxy == Synopsis require "xmlrpc/client" server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80) michael = server.proxy("michael") michael2 = server.proxy("michael", 4) # both calls should return the same value '9'. p michael.add(4,5) p michael2.add(5) == Description Class (({XMLRPC::Client::Proxy})) makes XML-RPC calls look nicer! You can call any method onto objects of that class - the object handles (({method_missing})) and will forward the method call to a XML-RPC server. Don't use this class directly, but use instead method (()) or (()). == Class Methods --- XMLRPC::Client::Proxy.new( server, prefix, args=[], meth=:call, delim="." ) Creates an object which provides (({method_missing})). ((|server|)) must be of type (({XMLRPC::Client})), which is the XML-RPC server to be used for a XML-RPC call. ((|prefix|)) and ((|delim|)) will be prepended to the methodname called onto this object. Parameter ((|meth|)) is the method (call, call2, call_async, call2_async) to use for a RPC. ((|args|)) are arguments which are automatically given to every XML-RPC call before the arguments provides through (({method_missing})). == Instance Methods Every method call is forwarded to the XML-RPC server defined in (()). Note: Inherited methods from class (({Object})) cannot be used as XML-RPC names, because they get around (({method_missing})). = History $Id: client.rb,v 1.47 2001/07/20 13:24:56 michael Exp $ =end require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" # ParserWriterChooseMixin require "net/http" module XMLRPC class Client USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})" include ParserWriterChooseMixin # Constructors ------------------------------------------------------------------- def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=nil, timeout=nil) @host = host || "localhost" @path = path || "/RPC2" @proxy_host = proxy_host @proxy_port = proxy_port @proxy_host ||= 'localhost' if @proxy_port != nil @proxy_port ||= 8080 if @proxy_host != nil @use_ssl = use_ssl || false @timeout = timeout || 30 if use_ssl require "net/https" @port = port || 443 else @port = port || 80 end @user, @password = user, password set_auth # convert ports to integers @port = @port.to_i if @port != nil @proxy_port = @proxy_port.to_i if @proxy_port != nil # HTTP object for synchronous calls Net::HTTP.version_1_2 @http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port) @http.use_ssl = @use_ssl if @use_ssl @http.read_timeout = @timeout @http.open_timeout = @timeout @parser = nil @create = nil end def self.new2(uri, proxy=nil, timeout=nil) if uri =~ /^([^:]+):\/\/(([^@]+)@)?([^\/]+)(\/.*)?$/ proto = $1 user, passwd = ($3 || "").split(":") host, port = $4.split(":") path = $5 if proto != "http" and proto != "https" raise "Wrong protocol specified. Only http or https allowed!" end else raise "Wrong URI as parameter!" end proxy_host, proxy_port = (proxy || "").split(":") self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout) end def self.new3(hash={}) # convert all keys into lowercase strings h = {} hash.each { |k,v| h[k.to_s.downcase] = v } self.new(h['host'], h['path'], h['port'], h['proxy_port'], h['user'], h['password'], h['use_ssl'], h['timeout']) end # Attribute Accessors ------------------------------------------------------------------- attr_reader :timeout, :user, :password def timeout=(new_timeout) @timeout = new_timeout @http.read_timeout = @timeout @http.open_timeout = @timeout end def user=(new_user) @user = new_user set_auth end def password=(new_password) @password = new_password set_auth end # Call methods -------------------------------------------------------------- def call(method, *args) ok, param = call2(method, *args) if ok param else raise param end end def call2(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, false) parser().parseMethodResponse(data) end def call_async(method, *args) ok, param = call2_async(method, *args) if ok param else raise param end end def call2_async(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, true) parser().parseMethodResponse(data) end # Multicall methods -------------------------------------------------------------- def multicall(*methods) ok, params = multicall2(*methods) if ok params else raise params end end def multicall2(*methods) gen_multicall(methods, false) end def multicall_async(*methods) ok, params = multicall2_async(*methods) if ok params else raise params end end def multicall2_async(*methods) gen_multicall(methods, true) end # Proxy generating methods ------------------------------------------ def proxy(prefix, *args) Proxy.new(self, prefix, args, :call) end def proxy2(prefix, *args) Proxy.new(self, prefix, args, :call2) end def proxy_async(prefix, *args) Proxy.new(self, prefix, args, :call_async) end def proxy2_async(prefix, *args) Proxy.new(self, prefix, args, :call2_async) end private # ---------------------------------------------------------- def set_auth if @user.nil? @auth = nil else a = "#@user" a << ":#@password" if @password != nil @auth = ("Basic " + [a].pack("m")).chomp end end def do_rpc(request, async=false) header = { "User-Agent" => USER_AGENT, "Content-Type" => "text/xml", "Content-Length" => request.size.to_s, "Connection" => (async ? "close" : "keep-alive") } if @auth != nil # add authorization header header["Authorization"] = @auth end if async # use a new HTTP object for each call Net::HTTP.version_1_2 http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port) http.use_ssl = @use_ssl if @use_ssl http.read_timeout = @timeout http.open_timeout = @timeout else # reuse the HTTP object for each call => connection alive is possible http = @http end # post request resp = http.post2(@path, request, header) data = resp.body http.finish if async if resp.code == "401" # Authorization Required raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}" elsif resp.code[0,1] != "2" raise "HTTP-Error: #{resp.code} #{resp.message}" end if resp["Content-Type"] != "text/xml" if resp["Content-Type"] == "text/html" raise "Wrong content-type: \n#{data}" else raise "Wrong content-type" end end expected = resp["Content-Length"] || "" if data.nil? or data.size == 0 raise "Wrong size. Was #{data.size}, should be #{expected}" elsif expected.to_i != data.size and resp["Transfer-Encoding"].nil? raise "Wrong size. Was #{data.size}, should be #{expected}" end return data end def gen_multicall(methods=[], async=false) meth = :call2 meth = :call2_async if async ok, params = self.send(meth, "system.multicall", methods.collect {|m| {'methodName' => m[0], 'params' => m[1..-1]} } ) if ok params = params.collect do |param| if param.is_a? Array param[0] elsif param.is_a? Hash XMLRPC::FaultException.new(param["faultCode"], param["faultString"]) else raise "Wrong multicall return value" end end end return ok, params end class Proxy def initialize(server, prefix, args=[], meth=:call, delim=".") @server = server @prefix = prefix + delim @args = args @meth = meth end def method_missing(mid, *args) pre = @prefix + mid.to_s arg = @args + args @server.send(@meth, pre, *arg) end end # class Proxy end # class Client end # module XMLRPC xmlrpc4r-1_7_7/lib/config.rb100644 1750 0 1621 7330327245 14724 0ustar michaelwheel# # $Id: config.rb,v 1.8 2001/07/27 18:10:45 michael Exp $ # Configuration file for XML-RPC for Ruby # module XMLRPC module Config DEFAULT_WRITER = XMLWriter::Simple # or XMLWriter::XMLParser # available parser: # * XMLParser::NQXMLTreeParser # * XMLParser::NQXMLStreamParser # * XMLParser::XMLTreeParser # * XMLParser::XMLStreamParser (fastest) DEFAULT_PARSER = XMLParser::NQXMLStreamParser # enable tag ENABLE_NIL_CREATE = false ENABLE_NIL_PARSER = false # allows integers greater than 32-bit if true ENABLE_BIGINT = false # enable marshalling ruby objects which include XMLRPC::Marshallable ENABLE_MARSHALLING = true # enable multiCall extension by default ENABLE_MULTICALL = false # enable Introspection extension by default ENABLE_INTROSPECTION = false end end xmlrpc4r-1_7_7/lib/create.rb100644 1750 0 13560 7365046127 14754 0ustar michaelwheel# # Creates XML-RPC call/response documents # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: create.rb,v 1.26 2001/10/22 16:41:59 michael Exp $ # require "date" require "xmlrpc/base64" module XMLRPC module XMLWriter class Abstract def ele(name, *children) element(name, nil, *children) end def tag(name, txt) element(name, nil, text(txt)) end end class Simple < Abstract def document_to_str(doc) doc end def document(*params) params.join("") end def pi(name, *params) "" end def element(name, attrs, *children) raise "attributes not yet implemented" unless attrs.nil? if children.empty? "<#{name}/>" else "<#{name}>" + children.join("") + "" end end def text(txt) cleaned = txt.dup cleaned.gsub!(/&/, '&') cleaned.gsub!(//, '>') cleaned end end # class Simple class XMLParser < Abstract def initialize require "xmltreebuilder" end def document_to_str(doc) doc.to_s end def document(*params) XML::SimpleTree::Document.new(*params) end def pi(name, *params) XML::SimpleTree::ProcessingInstruction.new(name, *params) end def element(name, attrs, *children) XML::SimpleTree::Element.new(name, attrs, *children) end def text(txt) XML::SimpleTree::Text.new(txt) end end # class XMLParser end # module XMLWriter class Create def initialize(xml_writer = nil) @writer = xml_writer || Config::DEFAULT_WRITER.new end def methodCall(name, *params) name = name.to_s if name !~ /[a-zA-Z0-9_.:\/]+/ raise ArgumentError, "Wrong XML-RPC method-name" end parameter = params.collect do |param| @writer.ele("param", conv2value(param)) end if not parameter.empty? then parameter = [@writer.ele("params", *parameter)] end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodCall", @writer.tag("methodName", name), *parameter # is nothing when == [] ) ) @writer.document_to_str(tree) + "\n" end # # generates a XML-RPC methodResponse document # # if is_ret == 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. # def methodResponse(is_ret, *params) if is_ret resp = params.collect do |param| @writer.ele("param", conv2value(param)) end resp = [@writer.ele("params", *resp)] else if params.size != 1 or params[0] === XMLRPC::FaultException raise ArgumentError, "no valid fault-structure given" end resp = @writer.ele("fault", conv2value(params[0].to_h)) end tree = @writer.document( @writer.pi("xml", 'version="1.0"'), @writer.ele("methodResponse", resp) ) @writer.document_to_str(tree) + "\n" end ##################################### private ##################################### # # converts a Ruby object into # a XML-RPC tag # def conv2value(param) val = case param when Fixnum @writer.tag("i4", param.to_s) when Bignum if Config::ENABLE_BIGINT @writer.tag("i4", param.to_s) else if param >= -(2**31) and param <= (2**31-1) @writer.tag("i4", param.to_s) else raise "Bignum is too big! Must be signed 32-bit integer!" end end when TrueClass, FalseClass @writer.tag("boolean", param ? "1" : "0") when String @writer.tag("string", param) when Symbol @writer.tag("string", param.to_s) when NilClass if Config::ENABLE_NIL_CREATE @writer.ele("nil") else raise "Wrong type NilClass. Not allowed!" end when Float @writer.tag("double", param.to_s) when Struct h = param.members.collect do |key| value = param[key] @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Hash # TODO: can a Hash be empty? h = param.collect do |key, value| @writer.ele("member", @writer.tag("name", key.to_s), conv2value(value) ) end @writer.ele("struct", *h) when Array # TODO: can an Array be empty? a = param.collect {|v| conv2value(v) } @writer.ele("array", @writer.ele("data", *a) ) when Date t = param @writer.tag("dateTime.iso8601", format("%.4d%02d%02dT00:00:00", t.year, t.month, t.day)) when Time @writer.tag("dateTime.iso8601", param.strftime("%Y%m%dT%H:%M:%S")) when XMLRPC::DateTime @writer.tag("dateTime.iso8601", format("%.4d%02d%02dT%02d:%02d:%02d", *param.to_a)) when XMLRPC::Base64 @writer.tag("base64", param.encoded) else if Config::ENABLE_MARSHALLING and param.class.included_modules.include? XMLRPC::Marshallable # convert Ruby object into Hash ret = {"___class___" => param.class.name} param.__get_instance_variables.each {|name, val| if val.nil? ret[name] = val if Config::ENABLE_NIL_CREATE else ret[name] = val end } return conv2value(ret) else ok, pa = wrong_type(param) if ok return conv2value(pa) else raise "Wrong type!" end end end @writer.ele("value", val) end def wrong_type(value) false end end # class Create end # module XMLRPC xmlrpc4r-1_7_7/lib/datetime.rb100644 1750 0 7100 7240327566 15257 0ustar michaelwheel=begin = xmlrpc/datetime.rb Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) Released under the same term of license as Ruby. = Classes * (()) = XMLRPC::DateTime == Description This class is important to handle XMLRPC (('dateTime.iso8601')) values, correcly, because normal UNIX-dates (class (({Date}))) only handle dates from year 1970 on, and class (({Time})) handles dates without the time component. (({XMLRPC::DateTime})) is able to store a XMLRPC (('dateTime.iso8601')) value correctly. == Class Methods --- XMLRPC::DateTime.new( year, month, day, hour, min, sec ) Creates a new (({XMLRPC::DateTime})) instance with the parameters ((|year|)), ((|month|)), ((|day|)) as date and ((|hour|)), ((|min|)), ((|sec|)) as time. Raises (({ArgumentError})) if a parameter is out of range, or ((|year|)) is not of type (({Integer})). == Instance Methods --- XMLRPC::DateTime#year --- XMLRPC::DateTime#month --- XMLRPC::DateTime#day --- XMLRPC::DateTime#hour --- XMLRPC::DateTime#min --- XMLRPC::DateTime#sec Return the value of the specified date/time component. --- XMLRPC::DateTime#mon Alias for (()). --- XMLRPC::DateTime#year=( value ) --- XMLRPC::DateTime#month=( value ) --- XMLRPC::DateTime#day=( value ) --- XMLRPC::DateTime#hour=( value ) --- XMLRPC::DateTime#min=( value ) --- XMLRPC::DateTime#sec=( value ) Set ((|value|)) as the new date/time component. Raises (({ArgumentError})) if ((|value|)) is out of range, or in the case of (({XMLRPC::DateTime#year=})) if ((|value|)) is not of type (({Integer})). --- XMLRPC::DateTime#mon=( value ) Alias for (()). --- XMLRPC::DateTime#to_time Return a (({Time})) object of the date/time which (({self})) represents. If the (('year')) is below 1970, this method returns (({nil})), because (({Time})) cannot handle years below 1970. The used timezone is GMT. --- XMLRPC::DateTime#to_date Return a (({Date})) object of the date which (({self})) represents. The (({Date})) object do ((*not*)) contain the time component (only date). --- XMLRPC::DateTime#to_a Returns all date/time components in an array. Returns (({[year, month, day, hour, min, sec]})). =end require "date" module XMLRPC class DateTime attr_reader :year, :month, :day, :hour, :min, :sec def year= (value) raise ArgumentError, "date/time out of range" unless value.is_a? Integer @year = value end def month= (value) raise ArgumentError, "date/time out of range" unless (1..12).include? value @month = value end def day= (value) raise ArgumentError, "date/time out of range" unless (1..31).include? value @day = value end def hour= (value) raise ArgumentError, "date/time out of range" unless (0..24).include? value @hour = value end def min= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @min = value end def sec= (value) raise ArgumentError, "date/time out of range" unless (0..59).include? value @sec = value end alias mon month alias mon= month= 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 def to_time if @year >= 1970 Time.gm(*to_a) else nil end end def to_date Date.new(*to_a[0,3]) end def to_a [@year, @month, @day, @hour, @min, @sec] end end end # module XMLRPC =begin = History $Id: datetime.rb,v 1.5 2001/02/07 20:26:30 michael Exp $ =end xmlrpc4r-1_7_7/lib/httpserver.rb100644 1750 0 7127 7325546350 15700 0ustar michaelwheel# # Implements a simple HTTP-server by using John W. Small's (jsmall@laser.net) # ruby-generic-server. # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: httpserver.rb,v 1.10 2001/07/19 12:04:56 michael Exp $ # require "GServer" class HttpServer < GServer def initialize(handler, port = 8080, host = DEFAULT_HOST, maxConnections = 4, stdlog = $stdout, audit = true, debug = true) @handler = handler super(port, host, maxConnections, stdlog, audit, debug) end private # Constants ----------------------------------------------- CRLF = "\r\n" HTTP_PROTO = "HTTP/1.0" SERVER_NAME = "HttpServer (Ruby #{RUBY_VERSION})" DEFAULT_HEADER = { "Server" => SERVER_NAME } ## # Mapping of status code and error message # StatusCodeMapping = { 200 => "OK", 400 => "Bad Request", 405 => "Method Not Allowed", 411 => "Length Required", 500 => "Internal Server Error" } # Classes ------------------------------------------------- class Request attr_reader :data, :header, :method, :path, :proto def initialize(data, method=nil, path=nil, proto=nil) @header, @data = Table.new, data @method, @path, @proto = method, path, proto end def content_length len = @header['Content-Length'] return nil if len.nil? return len.to_i end end class Response attr_reader :header attr_accessor :body, :status, :status_message def initialize(status=200) @status = status @header = Table.new end end ## # a case-insensitive Hash class for HTTP header # class Table include Enumerable def initialize(hash={}) @hash = hash update(hash) end def [](key) @hash[key.to_s.capitalize] end def []=(key, value) @hash[key.to_s.capitalize] = value end def update(hash) hash.each {|k,v| self[k] = v} self end def each @hash.each {|k,v| yield k.capitalize, v } end def writeTo(port) each { |k,v| port << "#{k}: #{v}" << CRLF } end end # class Table # Helper Methods ------------------------------------------ def http_header(header=nil) new_header = Table.new(DEFAULT_HEADER) new_header.update(header) unless header.nil? new_header["Connection"] = "close" new_header["Date"] = http_date(Time.now) new_header end def http_date( aTime ) aTime.gmtime.strftime( "%a, %d %b %Y %H:%M:%S GMT" ) end def http_resp(status_code, status_message=nil, header=nil, body=nil) status_message ||= StatusCodeMapping[status_code] str = "" str << "#{HTTP_PROTO} #{status_code} #{status_message}" << CRLF http_header(header).writeTo(str) str << CRLF str << body unless body.nil? str end # Main Serve Loop ----------------------------------------- def serve(io) # parse first line if io.gets =~ /^(\S+)\s+(\S+)\s+(\S+)/ request = Request.new(io, $1, $2, $3) else io << http_resp(400, "Bad Request") return end # parse HTTP headers while (line=io.gets) !~ /^(\n|\r)/ if line =~ /^([\w-]+):\s*(.*)$/ request.header[$1] = $2.strip end end io.binmode response = Response.new # execute script handler @handler.call(request, response) # write response back to the client io << http_resp(response.status, response.status_message, response.header, response.body) rescue Exception => e io << http_resp(500, "Internal Server Error") end end # class HttpServer xmlrpc4r-1_7_7/lib/marshal.rb100644 1750 0 3066 7340157407 15115 0ustar michaelwheel# # Marshalling of XML-RPC methodCall and methodResponse # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: marshal.rb,v 1.3 2001/08/20 09:57:27 michael Exp $ # require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/utils" module XMLRPC class Marshal include ParserWriterChooseMixin # class methods ------------------------------- class << self def dump_call( methodName, *params ) new.dump_call( methodName, *params ) end def dump_response( param ) new.dump_response( param ) end def load_call( stringOrReadable ) new.load_call( stringOrReadable ) end def load_response( stringOrReadable ) new.load_response( stringOrReadable ) end alias dump dump_response alias load load_response end # class self # instance methods ---------------------------- def initialize( parser = nil, writer = nil ) set_parser( parser ) set_writer( writer ) end def dump_call( methodName, *params ) create.methodCall( methodName, *params ) end def dump_response( param ) create.methodResponse( ! param.kind_of?( XMLRPC::FaultException ) , param ) end ## # returns [ methodname, params ] # def load_call( stringOrReadable ) parser.parseMethodCall( stringOrReadable ) end ## # returns paramOrFault # def load_response( stringOrReadable ) parser.parseMethodResponse( stringOrReadable )[1] end end # class Marshal end xmlrpc4r-1_7_7/lib/parser.rb100644 1750 0 35401 7370475330 15001 0ustar michaelwheel# # Parser for XML-RPC call and response # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: parser.rb,v 1.37 2001/11/02 10:52:08 michael Exp $ # require "date" require "xmlrpc/base64" require "xmlrpc/datetime" # add some methods to NQXML::Node module NQXML class Node def removeChild(node) @children.delete(node) end def childNodes @children end def hasChildNodes not @children.empty? end def [] (index) @children[index] end def nodeType if @entity.instance_of? NQXML::Text then :TEXT elsif @entity.instance_of? NQXML::Comment then :COMMENT #elsif @entity.instance_of? NQXML::Element then :ELEMENT elsif @entity.instance_of? NQXML::Tag then :ELEMENT else :ELSE end end def nodeValue #TODO: error when wrong Entity-type @entity.text end def nodeName #TODO: error when wrong Entity-type @entity.name end end # class Node end # module NQXML module XMLRPC class FaultException < Exception attr_reader :faultCode, :faultString def initialize(faultCode, faultString) @faultCode = faultCode @faultString = faultString end # returns a hash def to_h {"faultCode" => @faultCode, "faultString" => @faultString} end end module Convert def self.int(str) str.to_i end def self.boolean(str) case str when "0" then false when "1" then true else raise "RPC-value of type boolean is wrong" end end def self.double(str) str.to_f end def self.dateTime(str) if str =~ /^(-?\d\d\d\d)(\d\d)(\d\d)T(\d\d):(\d\d):(\d\d)$/ then # TODO: Time.gm ??? .local ??? a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i} XMLRPC::DateTime.new(*a) #if a[0] >= 1970 then # Time.gm(*a) #else # Date.new(*a[0,3]) #end else raise "wrong dateTime.iso8601 format" end end def self.base64(str) XMLRPC::Base64.decode(str) end def self.struct(hash) # convert to marhalled object klass = hash["___class___"] if klass.nil? or Config::ENABLE_MARSHALLING == false hash else begin mod = Module klass.split("::").each {|const| mod = mod.const_get const.strip } Thread.critical = true # let initialize take 0 parameters mod.module_eval %{ begin alias __initialize initialize rescue NameError end def initialize; end } obj = mod.new # restore old initialize mod.module_eval %{ undef initialize begin alias initialize __initialize rescue NameError end } Thread.critical = false hash.delete "___class___" hash.each {|k,v| obj.__set_instance_variable(k, v) } obj rescue hash end end end def self.fault(hash) if hash.kind_of? Hash and hash.size == 2 and hash.has_key? "faultCode" and hash.has_key? "faultString" and hash["faultCode"].kind_of? Integer and hash["faultString"].kind_of? String XMLRPC::FaultException.new(hash["faultCode"], hash["faultString"]) else raise "wrong fault-structure: #{hash.inspect}" end end end # module Convert module XMLParser class AbstractTreeParser def parseMethodResponse(str) methodResponse_document(createCleanedTree(str)) end def parseMethodCall(str) methodCall_document(createCleanedTree(str)) end private # # remove all whitespaces but in the tags i4, int, boolean.... # and all comments # def removeWhitespacesAndComments(node) remove = [] childs = node.childNodes.to_a childs.each do |nd| case _nodeType(nd) when :TEXT # TODO: add nil? unless %w(i4 int boolean string double dateTime.iso8601 base64).include? node.nodeName if node.nodeName == "value" if not node.childNodes.to_a.detect {|n| _nodeType(n) == :ELEMENT}.nil? remove << nd if nd.nodeValue.strip == "" end else remove << nd if nd.nodeValue.strip == "" end end when :COMMENT remove << nd else removeWhitespacesAndComments(nd) end end remove.each { |i| node.removeChild(i) } end def nodeMustBe(node, name) cmp = case name when Array name.include?(node.nodeName) when String name == node.nodeName else raise "error" end if not cmp then raise "wrong xml-rpc (name)" end node end # # returns, when successfully the only child-node # def hasOnlyOneChild(node, name=nil) if node.childNodes.to_a.size != 1 raise "wrong xml-rpc (size)" end if name != nil then nodeMustBe(node.firstChild, name) end end def assert(b) if not b then raise "assert-fail" end end # the node `node` has empty string or string def text_zero_one(node) nodes = node.childNodes.to_a.size if nodes == 1 text(node.firstChild) elsif nodes == 0 "" else raise "wrong xml-rpc (size)" end end def integer(node) #TODO: check string for float because to_i returnsa # 0 when wrong string nodeMustBe(node, %w(i4 int)) hasOnlyOneChild(node) Convert.int(text(node.firstChild)) end def boolean(node) nodeMustBe(node, "boolean") hasOnlyOneChild(node) Convert.boolean(text(node.firstChild)) end def v_nil(node) nodeMustBe(node, "nil") assert( node.childNodes.to_a.size == 0 ) nil end def string(node) nodeMustBe(node, "string") text_zero_one(node) end def double(node) #TODO: check string for float because to_f returnsa # 0.0 when wrong string nodeMustBe(node, "double") hasOnlyOneChild(node) Convert.double(text(node.firstChild)) end def dateTime(node) nodeMustBe(node, "dateTime.iso8601") hasOnlyOneChild(node) Convert.dateTime( text(node.firstChild) ) end def base64(node) nodeMustBe(node, "base64") #hasOnlyOneChild(node) Convert.base64(text_zero_one(node)) end def member(node) nodeMustBe(node, "member") assert( node.childNodes.to_a.size == 2 ) [ name(node[0]), value(node[1]) ] end def name(node) nodeMustBe(node, "name") #hasOnlyOneChild(node) text_zero_one(node) end def array(node) nodeMustBe(node, "array") hasOnlyOneChild(node, "data") data(node.firstChild) end def data(node) nodeMustBe(node, "data") node.childNodes.to_a.collect do |val| value(val) end end def param(node) nodeMustBe(node, "param") hasOnlyOneChild(node, "value") value(node.firstChild) end def methodResponse(node) nodeMustBe(node, "methodResponse") hasOnlyOneChild(node, %w(params fault)) child = node.firstChild case child.nodeName when "params" [ true, params(child,false) ] when "fault" [ false, fault(child) ] else raise "unexpected error" end end def methodName(node) nodeMustBe(node, "methodName") hasOnlyOneChild(node) text(node.firstChild) end def params(node, call=true) nodeMustBe(node, "params") if call node.childNodes.to_a.collect do |n| param(n) end else # response (only one param) hasOnlyOneChild(node) param(node.firstChild) end end def fault(node) nodeMustBe(node, "fault") hasOnlyOneChild(node, "value") f = value(node.firstChild) Convert.fault(f) end # _nodeType is defined in the subclass def text(node) assert( _nodeType(node) == :TEXT ) assert( node.hasChildNodes == false ) assert( node.nodeValue != nil ) node.nodeValue.to_s end def struct(node) nodeMustBe(node, "struct") hash = {} node.childNodes.to_a.each do |me| n, v = member(me) hash[n] = v end Convert.struct(hash) end def value(node) nodeMustBe(node, "value") nodes = node.childNodes.to_a.size if nodes == 0 return "" elsif nodes > 1 raise "wrong xml-rpc (size)" end child = node.firstChild case _nodeType(child) when :TEXT text_zero_one(node) when :ELEMENT case child.nodeName when "i4", "int" then integer(child) when "boolean" then boolean(child) when "string" then string(child) when "double" then double(child) when "dateTime.iso8601" then dateTime(child) when "base64" then base64(child) when "struct" then struct(child) when "array" then array(child) when "nil" if Config::ENABLE_NIL_PARSER v_nil(child) else raise "wrong/unknown XML-RPC type 'nil'" end else raise "wrong/unknown XML-RPC type" end else raise "wrong type of node" end end def methodCall(node) nodeMustBe(node, "methodCall") assert( (1..2).include? node.childNodes.to_a.size ) name = methodName(node[0]) if node.childNodes.to_a.size == 2 then pa = params(node[1]) else # no parameters given pa = [] end [name, pa] end end # module TreeParserMixin class AbstractStreamParser def parseMethodResponse(str) parser = @parser_class.new parser.parse(str) raise "No valid method response!" if parser.method_name != nil if parser.fault != nil # is a fault structure [false, parser.fault] else # is a normal return value raise "Missing return value!" if parser.params.size == 0 raise "To many return values. Only one allowed!" if parser.params.size > 1 [true, parser.params[0]] end end def parseMethodCall(str) parser = @parser_class.new parser.parse(str) raise "No valid method call - missing method name!" if parser.method_name.nil? [parser.method_name, parser.params] end end module StreamParserMixin attr_reader :params attr_reader :method_name attr_reader :fault def initialize(*a) super(*a) @params = [] @values = [] @val_stack = [] @names = [] @name = [] @structs = [] @struct = {} @method_name = nil @fault = nil @data = nil end def startElement(name, attrs) @data = nil case name when "value" @value = nil when "nil" raise "wrong/unknown XML-RPC type 'nil'" unless Config::ENABLE_NIL_PARSER @value = :nil when "array" @val_stack << @values @values = [] when "struct" @names << @name @name = [] @structs << @struct @struct = {} end end def endElement(name) @data ||= "" case name when "string" @value = @data when "i4", "int" @value = Convert.int(@data) when "boolean" @value = Convert.boolean(@data) when "double" @value = Convert.double(@data) when "dateTime.iso8601" @value = Convert.dateTime(@data) when "base64" @value = Convert.base64(@data) when "value" @value = @data if @value.nil? @values << (@value == :nil ? nil : @value) when "array" @value = @values @values = @val_stack.pop when "struct" @value = @struct @name = @names.pop @struct = @structs.pop when "name" @name[0] = @data when "member" @struct[@name[0]] = @values.pop when "param" @params << @values[0] @values = [] when "fault" @fault = Convert.fault(@values[0]) when "methodName" @method_name = @data end @data = nil end def character(data) if @data @data << data else @data = data end end end # module StreamParserMixin class XMLStreamParser < AbstractStreamParser def initialize require "xmlparser" eval %{ class XMLRPCParser < ::XMLParser include StreamParserMixin end } @parser_class = XMLRPCParser end end # class XMLStreamParser class NQXMLStreamParser < AbstractStreamParser def initialize require "nqxml/streamingparser" @parser_class = XMLRPCParser end class XMLRPCParser include StreamParserMixin def parse(str) parser = NQXML::StreamingParser.new(str) parser.each do |ele| case ele when NQXML::Text @data = ele.text #character(ele.text) when NQXML::Tag if ele.isTagEnd endElement(ele.name) else startElement(ele.name, ele.attrs) end end end # do end # method parse end # class XMLRPCParser end # class NQXMLStreamParser class XMLTreeParser < AbstractTreeParser def initialize require "xmltreebuilder" end private def _nodeType(node) tp = node.nodeType if tp == XML::SimpleTree::Node::TEXT then :TEXT elsif tp == XML::SimpleTree::Node::COMMENT then :COMMENT elsif tp == XML::SimpleTree::Node::ELEMENT then :ELEMENT else :ELSE end end def methodResponse_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodResponse") methodResponse(node.firstChild) end def methodCall_document(node) assert( node.nodeType == XML::SimpleTree::Node::DOCUMENT ) hasOnlyOneChild(node, "methodCall") methodCall(node.firstChild) end def createCleanedTree(str) doc = XML::SimpleTreeBuilder.new.parse(str) doc.documentElement.normalize removeWhitespacesAndComments(doc) doc end end # class XMLParser class NQXMLTreeParser < AbstractTreeParser def initialize require "nqxml/treeparser" end private def _nodeType(node) node.nodeType end def methodResponse_document(node) methodResponse(node) end def methodCall_document(node) methodCall(node) end def createCleanedTree(str) doc = ::NQXML::TreeParser.new(str).document.rootNode removeWhitespacesAndComments(doc) doc end end # class NQXMLTreeParser XMLParser = XMLTreeParser NQXMLParser = NQXMLTreeParser end # module XMLParser end # module XMLRPC xmlrpc4r-1_7_7/lib/server.rb100644 1750 0 47470 7377325710 15027 0ustar michaelwheel=begin = xmlrpc/server.rb Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) Released under the same term of license as Ruby. = Classes * (()) * (()) * (()) * (()) = XMLRPC::BasicServer == Description Is the base class for all XML-RPC server-types (CGI, standalone). You can add handler and set a default handler. Do not use this server, as this is/should be an abstract class. === How the method to call is found The arity (number of accepted arguments) of a handler (method or (({Proc})) object) is compared to the given arguments submitted by the client for a RPC ((-Remote Procedure Call-)). A handler is only called if it accepts the number of arguments, otherwise the search for another handler will go on. When at the end no handler was found, the (()) will be called. With this technique it is possible to do overloading by number of parameters, but only for (({Proc})) handler, because you cannot define two methods of the same name in the same class. == Class Methods --- XMLRPC::BasicServer.new( class_delim="." ) Creates a new (({XMLRPC::BasicServer})) instance, which should not be done, because (({XMLRPC::BasicServer})) is an abstract class. This method should be called from a subclass indirectly by a (({super})) call in the method (({initialize})). The paramter ((|class_delim|)) is used in (()) when an object is added as handler, to delimit the object-prefix and the method-name. == Instance Methods --- XMLRPC::BasicServer#add_handler( name, signature=nil, help=nil ) { aBlock } Adds ((|aBlock|)) to the list of handlers, with ((|name|)) as the name of the method. Parameters ((|signature|)) and ((|help|)) are used by the Introspection method if specified, where ((|signature|)) is either an Array containing strings each representing a type of it's signature (the first is the return value) or an Array of Arrays if the method has multiple signatures. Value type-names are "int, boolean, double, string, dateTime.iso8601, base64, array, struct". Parameter ((|help|)) is a String with informations about how to call this method etc. A handler method or code-block can return the types listed at (()). When a method fails, it can tell it the client by throwing an (({XMLRPC::FaultException})) like in this example: s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end The client gets in the case of (({b==0})) an object back of type (({XMLRPC::FaultException})) that has a ((|faultCode|)) and ((|faultString|)) field. --- XMLRPC::BasicServer#add_handler( prefix, obj ) This is the second form of (()). To add an object write: server.add_handler("michael", MyHandlerClass.new) All public methods of (({MyHandlerClass})) are accessible to the XML-RPC clients by (('michael."name of method"')). This is where the ((|class_delim|)) in (()) has it's role, a XML-RPC method-name is defined by ((|prefix|)) + ((|class_delim|)) + (('"name of method"')). --- XMLRPC::BasicServer#add_handler( interface, obj ) This is the third form of (()). Use (({XMLRPC::interface})) to generate an ServiceInterface object, which represents an interface (with signature and help text) for a handler class. Parameter ((|interface|)) must be of type (({XMLRPC::ServiceInterface})). Adds all methods of ((|obj|)) which are defined in ((|interface|)) to the server. This is the recommended way of adding services to a server! --- XMLRPC::BasicServer#get_default_handler Returns the default-handler, which is called when no handler for a method-name is found. It is a (({Proc})) object or (({nil})). --- XMLRPC::BasicServer#set_default_handler ( &handler ) Sets ((|handler|)) as the default-handler, which is called when no handler for a method-name is found. ((|handler|)) is a code-block. The default-handler is called with the (XML-RPC) method-name as first argument, and the other arguments are the parameters given by the client-call. If no block is specified the default of (({XMLRPC::BasicServer})) is used, which raises a XMLRPC::FaultException saying "method missing". --- XMLRPC::BasicServer#set_writer( writer ) Sets the XML writer to use for generating XML output. Should be an instance of a class from module (({XMLRPC::XMLWriter})). If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used. --- XMLRPC::BasicServer#set_parser( parser ) Sets the XML parser to use for parsing XML documents. Should be an instance of a class from module (({XMLRPC::XMLParser})). If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used. --- XMLRPC::BasicServer#add_introspection Adds the introspection handlers "system.listMethods", "system.methodSignature" and "system.methodHelp", where only the first one works. --- XMLRPC::BasicServer#add_multicall Adds the multi-call handler "system.multicall". --- XMLRPC::BasicServer#get_service_hook Returns the service-hook, which is called on each service request (RPC) unless it's (({nil})). --- XMLRPC::BasicServer#set_service_hook ( &handler ) A service-hook is called for each service request (RPC). You can use a service-hook for example to wrap existing methods and catch exceptions of them or convert values to values recognized by XMLRPC. You can disable it by passing (({nil})) as parameter ((|handler|)) . The service-hook is called with a (({Proc})) object and with the parameters for this (({Proc})). An example: server.set_service_hook {|obj, *args| begin ret = obj.call(*args) # call the original service-method # could convert the return value resuce # rescue exceptions end } =end require "xmlrpc/parser" require "xmlrpc/create" require "xmlrpc/config" require "xmlrpc/httpserver" require "xmlrpc/utils" # ParserWriterChooseMixin module XMLRPC class BasicServer include ParserWriterChooseMixin ERR_METHOD_MISSING = 1 ERR_UNCAUGHT_EXCEPTION = 2 ERR_MC_WRONG_PARAM = 3 ERR_MC_MISSING_PARAMS = 4 ERR_MC_MISSING_METHNAME = 5 ERR_MC_RECURSIVE_CALL = 6 ERR_MC_WRONG_PARAM_PARAMS = 7 ERR_MC_EXPECTED_STRUCT = 8 def initialize(class_delim=".") @handler = [] @default_handler = nil @service_hook = nil @class_delim = class_delim @create = nil @parser = nil add_multicall if Config::ENABLE_MULTICALL add_introspection if Config::ENABLE_INTROSPECTION end def add_handler(prefix, obj_or_signature=nil, help=nil, &block) if block_given? # proc-handler @handler << [prefix, block, obj_or_signature, help] else if prefix.kind_of? String # class-handler raise ArgumentError, "Expected non-nil value" if obj_or_signature.nil? @handler << [prefix + @class_delim, obj_or_signature] elsif prefix.kind_of? XMLRPC::Service::BasicInterface # class-handler with interface # add all methods @handler += prefix.get_methods(obj_or_signature, @class_delim) else raise ArgumentError, "Wrong type for parameter 'prefix'" end end self end def get_service_hook @service_hook end def set_service_hook(&handler) @service_hook = handler self end def get_default_handler @default_handler end def set_default_handler (&handler) @default_handler = handler self end def add_multicall add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs| unless arrStructs.is_a? Array raise XMLRPC::FaultException.new(ERR_MC_WRONG_PARAM, "system.multicall expects an array") end arrStructs.collect {|call| if call.is_a? Hash methodName = call["methodName"] params = call["params"] if params.nil? multicall_fault(ERR_MC_MISSING_PARAMS, "Missing params") elsif methodName.nil? multicall_fault(ERR_MC_MISSING_METHNAME, "Missing methodName") else if methodName == "system.multicall" multicall_fault(ERR_MC_RECURSIVE_CALL, "Recursive system.multicall forbidden") else unless params.is_a? Array multicall_fault(ERR_MC_WRONG_PARAM_PARAMS, "Parameter params have to be an Array") else ok, val = call_method(methodName, *params) if ok # correct return value [val] else # exception multicall_fault(val.faultCode, val.faultString) end end end end else multicall_fault(ERR_MC_EXPECTED_STRUCT, "system.multicall expected struct") end } end # end add_handler self end def add_introspection add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do methods = [] @handler.each do |name, obj| if obj.kind_of? Proc methods << name else obj.methods.each {|meth| methods << name + meth} end end methods end add_handler("system.methodSignature", %w(array string), "Returns method signature") do |meth| sigs = [] @handler.each do |name, obj, sig| if obj.kind_of? Proc and sig != nil and name == meth if sig[0].kind_of? Array # sig contains multiple signatures, e.g. [["array"], ["array", "string"]] sig.each {|s| sigs << s} else # sig is a single signature, e.g. ["array"] sigs << sig end end end sigs.uniq! || sigs # remove eventually duplicated signatures end add_handler("system.methodHelp", %w(string string), "Returns help on using this method") do |meth| help = nil @handler.each do |name, obj, sig, hlp| if obj.kind_of? Proc and name == meth help = hlp break end end help || "" end self end def process(data) method, params = parser().parseMethodCall(data) handle(method, *params) end 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 next unless methodname == name else next unless methodname =~ /^#{name}(.+)$/ next unless obj.respond_to? $1 obj = obj.method($1) end if check_arity(obj, args.size) if @service_hook.nil? return obj.call(*args) else return @service_hook.call(obj, *args) end end end if @default_handler.nil? raise XMLRPC::FaultException.new(ERR_METHOD_MISSING, "Method #{methodname} missing or wrong number of parameters!") else @default_handler.call(methodname, *args) end end # # returns true, if the arity of "obj" matches # def check_arity(obj, n_args) ary = obj.arity if ary >= 0 n_args == ary else n_args >= (ary+1).abs end end def call_method(methodname, *args) begin [true, dispatch(methodname, *args)] rescue XMLRPC::FaultException => e [false, e] rescue Exception => e [false, XMLRPC::FaultException.new(ERR_UNCAUGHT_EXCEPTION, "Uncaught exception #{e.message} in method #{methodname}")] end end # # # def handle(methodname, *args) create().methodResponse(*call_method(methodname, *args)) end end =begin = XMLRPC::CGIServer == Synopsis require "xmlrpc/server" s = XMLRPC::CGIServer.new s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.serve == Description Implements a CGI-based XML-RPC server. == Superclass (()) == Class Methods --- XMLRPC::CGIServer.new( *a ) Creates a new (({XMLRPC::CGIServer})) instance. All parameters given are by-passed to (()). You can only create ((*one*)) (({XMLRPC::CGIServer})) instance, because more than one makes no sense. == Instance Methods --- XMLRPC::CGIServer#serve Call this after you have added all you handlers to the server. This method processes a XML-RPC methodCall and sends the answer back to the client. Make sure that you don't write to standard-output in a handler, or in any other part of your program, this would case a CGI-based server to fail! =end class CGIServer < BasicServer @@obj = nil def CGIServer.new(*a) @@obj = super(*a) if @@obj.nil? @@obj end def initialize(*a) super(*a) end def serve catch(:exit_serve) { length = ENV['CONTENT_LENGTH'].to_i http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST" http_error(400, "Bad Request") unless ENV['CONTENT_TYPE'] == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? $stdin.binmode if $stdin.respond_to? :binmode data = $stdin.read(length) http_error(400, "Bad Request") if data.nil? or data.size != length http_write(process(data), "Content-type" => "text/xml") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

#{err}

Unexpected error occured while processing XML-RPC request!

MSGEND http_write(msg, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.size.to_s str = "" h.each {|key, value| str << "#{key}: #{value}\r\n"} str << "\r\n#{body}" print str end end =begin = XMLRPC::ModRubyServer == Description Implements a XML-RPC server, which works with Apache mod_ruby. Use it in the same way as CGIServer! == Superclass (()) =end class ModRubyServer < BasicServer @@obj = nil def ModRubyServer.new(*a) @@obj = super(*a) if @@obj.nil? @@obj end def initialize(*a) @ap = Apache::request super(*a) end def serve catch(:exit_serve) { header = {} @ap.each_header {|key, value| header[key.capitalize] = value} length = header['Content-length'].to_i http_error(405, "Method Not Allowed") unless @ap.request_method == "POST" http_error(400, "Bad Request") unless header['Content-type'] == "text/xml" http_error(411, "Length Required") unless length > 0 # TODO: do we need a call to binmode? @ap.binmode data = @ap.read(length) http_error(400, "Bad Request") if data.nil? or data.size != length http_write(process(data), 200, "Content-type" => "text/xml") } end private def http_error(status, message) err = "#{status} #{message}" msg = <<-"MSGEND" #{err}

#{err}

Unexpected error occured while processing XML-RPC request!

MSGEND http_write(msg, status, "Status" => err, "Content-type" => "text/html") throw :exit_serve # exit from the #serve method end def http_write(body, status, header) h = {} header.each {|key, value| h[key.to_s.capitalize] = value} h['Status'] ||= "200 OK" h['Content-length'] ||= body.size.to_s h.each {|key, value| @ap[key] = value } @ap.content_type = h["Content-type"] @ap.status = status.to_i @ap.send_http_header @ap.print body end end =begin = XMLRPC::Server == Synopsis require "xmlrpc/server" s = XMLRPC::Server.new(8080) s.add_handler("michael.add") do |a,b| a + b end s.add_handler("michael.div") do |a,b| if b == 0 raise XMLRPC::FaultException.new(1, "division by zero") else a / b end end s.set_default_handler do |name, *args| raise XMLRPC::FaultException.new(-99, "Method #{name} missing" + " or wrong number of parameters!") end s.serve == Description Implements a standalone XML-RPC server. The method (({serve}))) is left if a SIGHUP is sent to the program. == Superclass (()) == Class Methods --- XMLRPC::Server.new( port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a ) Creates a new (({XMLRPC::Server})) instance, which is a XML-RPC server listening on port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost. The server is not started, to start it you have to call (()). The parameters ((|maxConnections|)), ((|stdlog|)), ((|audit|)) and ((|debug|)) are passed to the HTTP server and specify it's behaviour more precise. All additionally given parameters in ((|*a|)) are by-passed to (()). == Instance Methods --- XMLRPC::Server#serve Call this after you have added all you handlers to the server. This method starts the server to listen for XML-RPC requests and answer them. --- XMLRPC::Server#shutdown Stops and shuts the server down. =end class Server < BasicServer def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a) super(*a) handler = self.method(:request_handler).to_proc @server = ::HttpServer.new(handler, port, host, maxConnections, stdlog, audit, debug) end def serve if RUBY_PLATFORM =~ /mingw|mswin32/ signal = 1 else signal = "HUP" end trap(signal) { @server.shutdown } @server.start.join end def shutdown @server.shutdown end private def request_handler(request, response) $stderr.puts "in request_handler" if $DEBUG if request.method != "POST" # Method not allowed response.status = 405 return end if request.header['Content-type'] != "text/xml" # Bad request response.status = 400 return end length = request.content_length || 0 unless length > 0 # Length required response.status = 411 return end data = request.data.read(length) if data.nil? or data.size != length # Bad request response.status = 400 return end resp = process(data) raise if resp.nil? or resp.size <= 0 # => Internal Server Error response.status = 200 response.header['Content-Length'] = resp.size response.header['Content-Type'] = "text/xml" response.body = resp end end end # module XMLRPC =begin = History $Id: server.rb,v 1.45 2001/11/23 01:52:08 michael Exp $ =end xmlrpc4r-1_7_7/lib/utils.rb100644 1750 0 7032 7330506612 14616 0ustar michaelwheel# # 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 by Michael Neumann (neumann@s-direktnet.de) # # $Id: utils.rb,v 1.8 2001/07/28 10:01:46 michael Exp $ # 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 # module Marshallable def __get_instance_variables instance_variables.collect {|var| [var[1..-1], eval(var)] } end def __set_instance_variable(key, value) eval("@#$1 = value") if key =~ /^([\w_][\w_0-9]*)$/ end end module ParserWriterChooseMixin def set_writer(writer) @create = Create.new(writer) self end def set_parser(parser) @parser = parser self end private def create # if set_writer was not already called then call it now if @create.nil? then set_writer(Config::DEFAULT_WRITER.new) end @create end def parser # if set_parser was not already called then call it now if @parser.nil? then set_parser(Config::DEFAULT_PARSER.new) end @parser end end # module ParserWriterChooseMixin module Service # # base class for Service Interface definitions, used # by BasicServer#add_handler # class BasicInterface attr_reader :prefix, :methods def initialize(prefix) @prefix = prefix @methods = [] end def add_method(sig, help=nil, meth_name=nil) mname = nil sig = [sig] if sig.kind_of? String sig = sig.collect do |s| name, si = parse_sig(s) raise "Wrong signatures!" if mname != nil and name != mname mname = name si end @methods << [mname, meth_name || mname, sig, help] end private # --------------------------------- def parse_sig(sig) # sig is a String if sig =~ /^\s*(\w+)\s+([^(]+)(\(([^)]*)\))?\s*$/ params = [$1] name = $2.strip $4.split(",").each {|i| params << i.strip} if $4 != nil return name, params else raise "Syntax error in signature" end end end # class BasicInterface # # class which wraps a Service Interface definition, used # by BasicServer#add_handler # class Interface < BasicInterface def initialize(prefix, &p) raise "No interface specified" if p.nil? super(prefix) instance_eval &p end def get_methods(obj, delim=".") prefix = @prefix + delim @methods.collect { |name, meth, sig, help| [prefix + name, obj.method(meth).to_proc, sig, help] } end private # --------------------------------- def meth(*a) add_method(*a) end end # class Interface class PublicInstanceMethodsInterface < BasicInterface def initialize(prefix) super(prefix) end def get_methods(obj, delim=".") prefix = @prefix + delim obj.class.public_instance_methods.collect { |name| [prefix + name, obj.method(name).to_proc, nil, nil] } end end end # module Service # # short-form to create a Service::Interface # def self.interface(prefix, &p) Service::Interface.new(prefix, &p) end # short-cut for creating a PublicInstanceMethodsInterface def self.iPIMethods(prefix) Service::PublicInstanceMethodsInterface.new(prefix) end end # module XMLRPC xmlrpc4r-1_7_7/redist/ 40755 1750 0 0 7377326626 13576 5ustar michaelwheelxmlrpc4r-1_7_7/redist/GServer.rb100644 1750 0 10263 7325546247 15613 0ustar michaelwheel# Copyright (C) 2001 John W. Small All Rights Reserved # mailto:jsmall@laser.net subject:ruby-generic-server # Freeware require "socket" require "thread" class GServer DEFAULT_HOST = "127.0.0.1" def serve(io) end @@services = {} # Hash of opened ports, i.e. services @@servicesMutex = Mutex.new def GServer.stop(port, host = DEFAULT_HOST) @@servicesMutex.synchronize { @@services[host][port].stop } end def GServer.in_service?(port, host = DEFAULT_HOST) @@services.has_key?(host) and @@services[host].has_key?(port) end def stop @connectionsMutex.synchronize { if @tcpServerThread @tcpServerThread.raise "stop" end } end def stopped? @tcpServerThread == nil end def shutdown @shutdown = true end def connections @connections.size end def join @tcpServerThread.join if @tcpServerThread end attr_reader :port, :host, :maxConnections attr_accessor :stdlog, :audit, :debug def connecting(client) addr = client.peeraddr log("#{self.class.to_s} #{@host}:#{@port} client:#{addr[1]} " + "#{addr[2]}<#{addr[3]}> connect") true end def disconnecting(clientPort) log("#{self.class.to_s} #{@host}:#{@port} " + "client:#{clientPort} disconnect") end protected :connecting, :disconnecting def starting() log("#{self.class.to_s} #{@host}:#{@port} start") end def stopping() log("#{self.class.to_s} #{@host}:#{@port} stop") end protected :starting, :stopping def error(detail) log(detail.backtrace.join("\n")) end def log(msg) if @stdlog @stdlog.puts("[#{Time.new.ctime}] %s" % msg) @stdlog.flush end end protected :error, :log def initialize(port, host = DEFAULT_HOST, maxConnections = 4, stdlog = $stderr, audit = false, debug = false) @tcpServerThread = nil @port = port @host = host @maxConnections = maxConnections @connections = [] @connectionsMutex = Mutex.new @connectionsCV = ConditionVariable.new @stdlog = stdlog @audit = audit @debug = debug end def start(maxConnections = -1) raise "running" if !stopped? @shutdown = false @maxConnections = maxConnections if maxConnections > 0 @@servicesMutex.synchronize { if GServer.in_service?(@port,@host) raise "Port already in use: #{host}:#{@port}!" end @tcpServer = TCPServer.new(@host,@port) @port = @tcpServer.addr[1] @@services[@host] = {} unless @@services.has_key?(@host) @@services[@host][@port] = self; } @tcpServerThread = Thread.new { begin starting if @audit while !@shutdown @connectionsMutex.synchronize { while @connections.size >= @maxConnections @connectionsCV.wait(@connectionsMutex) end } client = @tcpServer.accept @connections << Thread.new(client) { |myClient| begin myPort = myClient.peeraddr[1] serve(myClient) if !@audit or connecting(myClient) rescue => detail error(detail) if @debug ensure begin myClient.close rescue end @connectionsMutex.synchronize { @connections.delete(Thread.current) @connectionsCV.signal } disconnecting(myPort) if @audit end } end rescue => detail error(detail) if @debug ensure begin @tcpServer.close rescue end if @shutdown @connectionsMutex.synchronize { while @connections.size > 0 @connectionsCV.wait(@connectionsMutex) end } else @connections.each { |c| c.raise "stop" } end @tcpServerThread = nil @@servicesMutex.synchronize { @@services[@host].delete(@port) } stopping if @audit end } self end end xmlrpc4r-1_7_7/redist/TCPSocketPipe.rb100755 1750 0 14561 7325546247 16663 0ustar michaelwheel#!/usr/bin/env ruby # TCPSocketPipe.rb -- Creates I/O pipes for TCP socket tunneling. # Copyright (C) 1999-2001 NAKAMURA, Hiroshi # This application is copyrighted free software by NAKAMURA, Hiroshi. # You can redistribute it and/or modify it under the same term as Ruby. RCS_ID = %q$Id: TCPSocketPipe.rb,v 1.1 2001/07/19 12:03:51 michael Exp $ # Ruby bundled library require 'socket' require 'getopts' # Extra library # 'application.rb' by nakahiro@sarion.co.jp # http://www.jin.gr.jp/~nahi/Ruby/ruby.shtml#application require 'application' # 'dump.rb' by miche@e-mail.ne.jp # http://www.geocities.co.jp/SiliconValley-Oakland/2986/ require 'dump' class TCPSocketPipe < Application include Log::Severity include Socket::Constants attr_accessor :dumpRequest attr_accessor :dumpResponse attr_accessor :dumpBytes attr_accessor :dumpBigEndian attr_accessor :dumpWidth private Timeout = 100 # [sec] ReadBlockSize = 10 * 1024 # [byte] class SessionPool public def each @pool.each do |i| yield i end end def add( serverSock, clientSock ) @pool.push( Session.new( serverSock, clientSock )) end def del( session ) @pool.delete_if do |i| session.equal?( i ) end end private class Session attr( :server ) attr( :client ) private def initialize( server = nil, client = nil ) @server = server @client = client end end def initialize @pool = [] end end AppName = 'TCPSocketPipe' ShiftAge = 0 ShiftSize = 0 def initialize( srcPort, destName, destPort ) super( AppName ) setLog( AppName + '.log', ShiftAge, ShiftSize ) @srcPort = srcPort.to_i @destName = destName @destPort = destPort.to_i @dumpRequest = true @dumpResponse = false @dumpBytes = 1 @dumpWidth = 16 @dumpBigEndian = false @sessionPool = SessionPool.new() end def run @waitSock = TCPServer.new( @srcPort ) begin dumpStart while true readWait = [] @sessionPool.each do |session| readWait.push( session.server ).push( session.client ) end readWait.unshift( @waitSock ) readReady, writeReady, except = IO.select( readWait, nil, nil, Timeout ) next unless readReady readReady.each do |sock| if ( @waitSock.equal?( sock )) newSock = @waitSock.accept dumpAccept( newSock.peeraddr[2] ) if !addSession( newSock ) log( SEV_WARN, 'Closing server socket...' ) newSock.close() end else @sessionPool.each do |session| transfer( session, true ) if ( sock.equal?( session.server )) transfer( session, false ) if ( sock.equal?( session.client )) end end end end ensure @waitSock.close() dumpEnd end end def transfer( session, bServer ) readSock = nil writeSock = nil if ( bServer ) readSock = session.server writeSock = session.client else readSock = session.client writeSock = session.server end readBuf = '' begin readBuf << readSock.sysread( ReadBlockSize ) rescue EOFError closeSession( session ) return rescue Errno::ECONNRESET log( SEV_INFO, "#{$!} while reading." ) closeSession( session ) return rescue log( SEV_WARN, "Detected an exception. Stopping ... #{$!}\n" << $@.join( "\n" )) closeSession( session ) return end if ( bServer ) dumpTransferData( true, readBuf ) if @dumpRequest else dumpTransferData( false, readBuf ) if @dumpResponse end writeSize = 0 while ( writeSize < readBuf.size ) begin writeSize += writeSock.syswrite( readBuf[writeSize..-1] ) rescue Errno::ECONNRESET log( SEV_INFO, "#{$!} while writing." ) closeSession( session ) return rescue log( SEV_WARN, "Detected an exception. Stopping ... #{$!}\n" << $@.join( "\n" )) closeSession( session ) return end end end def addSession( serverSock ) begin clientSock = TCPSocket.new( @destName, @destPort ) rescue log( SEV_ERROR, 'Create client socket failed.' ) return end @sessionPool.add( serverSock, clientSock ) dumpAddSession end def closeSession( session ) session.server.close() session.client.close() @sessionPool.del( session ) dumpCloseSession end def dumpStart log( SEV_INFO, 'Started ... SrcPort=%s, DestName=%s, DestPort=%s' % [ @srcPort, @destName, @destPort ] ) end def dumpAccept( from ) log( SEV_INFO, 'Accepted ... from ' << from ) end def dumpAddSession log( SEV_INFO, 'Connection established.' ) end def dumpTransferData( isFromSrcToDestP, data ) if isFromSrcToDestP log( SEV_INFO, 'Transfer data ... [src] -> [dest]' ) else log( SEV_INFO, 'Transfer data ... [src] <- [dest]' ) end dumpData( data ) end def dumpData( data ) log( SEV_INFO, "Transferred data;\n" << Debug.dump( data, "x#{ @dumpBytes }", @dumpBigEndian, @dumpWidth, 0 )) end def dumpCloseSession log( SEV_INFO, 'Connection closed.' ) end def dumpEnd log( SEV_INFO, 'Stopped ... SrcPort=%s, DestName=%s, DestPort=%s' % [ @srcPort, @destName, @destPort ] ) end end def main getopts( 'des', 'w:', 'x:' ) srcPort = ARGV.shift destName = ARGV.shift destPort = ARGV.shift usage() if ( !srcPort or !destName or !destPort ) # To run as a daemon... if $OPT_s exit! if fork Process.setsid exit! if fork STDIN.close STDOUT.close STDERR.close end app = TCPSocketPipe.new( srcPort, destName, destPort ) app.dumpResponse = true if $OPT_d app.dumpBigEndian = true if $OPT_e app.dumpWidth = $OPT_w.to_i if $OPT_w app.dumpBytes = $OPT_x.to_i if $OPT_x app.start() end def usage STDERR.print < 0 ) && ( @dev.stat.size > @shiftSize )) else now = Time.now limitTime = case @shiftAge when /^daily$/ eod( now - 1 * SiD ) when /^weekly$/ eod( now - (( now.wday + 1 ) * SiD )) when /^monthly$/ eod( now - now.mday * SiD ) else now end return ( @dev.stat.mtime <= limitTime ) end end def shiftLog # At first, close the device if opened. if ( @dev ) @dev.close @dev = nil end if ( @shiftAge.is_a?( Integer )) ( @shiftAge-3 ).downto( 0 ) do |i| if ( FileTest.exist?( "#{@fileName}.#{i}" )) File.rename( "#{@fileName}.#{i}", "#{@fileName}.#{i+1}" ) end end File.rename( "#{@fileName}", "#{@fileName}.0" ) return true else now = Time.now postfixTime = case @shiftAge when /^daily$/ eod( now - 1 * SiD ) when /^weekly$/ eod( now - (( now.wday + 1 ) * SiD )) when /^monthly$/ eod( now - now.mday * SiD ) else now end postfix = postfixTime.strftime( "%Y%m%d" ) # YYYYMMDD ageFile = "#{@fileName}.#{postfix}" if ( FileTest.exist?( ageFile )) raise RuntimeError.new( "'#{ ageFile }' already exists." ) end File.rename( "#{@fileName}", ageFile ) return true end end private SiD = 24 * 60 * 60 def eod( t ) Time.mktime( t.year, t.month, t.mday, 23, 59, 59 ) end end def initialize( log, shiftAge = 3, shiftSize = 102400 ) @logDev = nil if ( log.is_a?( IO )) # IO was given. Use it as a log device. @logDev = LogDev.new( log ) elsif ( log.is_a?( String )) # String was given. Open the file as a log device. dev = if ( FileTest.exist?( log.to_s )) open( log.to_s, ( File::WRONLY | File::APPEND )) else createLogFile( log.to_s ) end @logDev = LogDev.new( dev, log ) else raise ArgumentError.new( 'Wrong argument(log)' ) end @logDev.shiftAge = shiftAge @logDev.shiftSize = shiftSize @sevThreshold = SEV_DEBUG @kCode = Kconv::EUC end def createLogFile( fileName ) logDev = open( fileName, ( File::WRONLY | File::APPEND | File::CREAT )) addLogHeader( logDev ) logDev end def addLogHeader( file ) file.syswrite( "# Logfile created on %s by %s\n" % [ Time.now.to_s, ProgName ]) end %q$Id: application.rb,v 1.1 2001/07/19 12:03:51 michael Exp $ =~ /: (\S+),v (\S+)/ ProgName = "#{$1}/#{$2}" # Severity label for logging. ( max 5 char ) SEV_LABEL = %w( DEBUG INFO WARN ERROR CAUTN FATAL ANY ); def formatSeverity( severity ) SEV_LABEL[ severity ] || 'UNKNOWN' end def formatDatetime( dateTime ) dateTime.to_s << ' ' << "%6d" % dateTime.usec end def formatComment( comment ) newComment = comment.dup # Remove white characters at the end of line. newComment.sub!( '/[ \t\r\f\n]*$/', '' ) # Japanese Kanji char code conversion. if ( Kconv::guess( newComment ) != @kCode ) newComment = Kconv::kconv( newComment, @kCode, Kconv::AUTO ) end newComment end def formatMessage( severity, timestamp, comment, program ) message = '%s, [%s #%d] %5s -- %s: %s' << "\n" message % [ severity[ 0 .. 0 ], timestamp, $$, severity, program, comment ] end end # SYNOPSIS # Application.new( appName ) # # ARGS # appName Name String of the application. # # DESCRIPTION # An application for easy logging. # class Application include Log::Severity public attr_reader :appName, :logDev, :status def initialize( name = '' ) @appName = name @status = false @logDev = STDERR @shiftAge = 0 # means 'no shifting' @shiftSize = 102400 end # SYNOPSIS # Application.start() # # DESCRIPTION # Start the application. # # RETURN # Status code. # def start() @log = Log.new( @logDev, @shiftAge, @shiftSize ) begin log( SEV_INFO, "Start of #{ @appName }." ) @status = run() rescue log( SEV_FATAL, "Detected an exception. Stopping ... #{$!} (#{$!.type})\n" << $@.join( "\n" )) ensure log( SEV_INFO, "End of #{ @appName }. (status: #{ @status.to_s })" ) end @status end # SYNOPSIS # Application.setLog( log, shiftAge, shiftSize ) # # ARGS # ( see class Log ) # # DESCRIPTION # Log device setting of the application. # # RETURN # Always true. # def setLog( log, shiftAge = 0, shiftSize = 102400 ) @logDev = log @shiftAge = shiftAge @shiftSize = shiftSize true end protected def log( severity, message ) @log.add( severity, message, @appName ) end # private method 'run' must be defined in derived classes. private # virtual def run() raise RuntimeError.new( 'Method run must be defined in the derived class.' ) end end xmlrpc4r-1_7_7/redist/dump.rb100755 1750 0 4326 7325546247 15171 0ustar michaelwheel#!/usr/local/bin/ruby -w # ver.0.1 create # ver.0.2 print -> buffering thanx to nahi module Debug DumpFormat = { "o4" => [ ' %011o', '' ], "o2" => [ ' %06o', '' ], "o1" => [ ' %03o', ' ' ], "d4" => [ ' %10d', '' ], "d2" => [ ' %5d', '' ], "d1" => [ ' %3d', ' ' ], "x4" => [ ' %08x', '' ], "x2" => [ ' %04x', '' ], "x1" => [ ' %02x', ' ' ] } UnpackFormat = { 4 => [ 'N', 'V' ], 2 => [ 'n', 'v' ], 1 => [ 'C', 'C' ] } def dump(buf, param = "x2", bigendian = false, width = 16, offset0 = 0) raise "Not suppored dump format '#{param}'" unless DumpFormat.has_key?(param) result = "" format = param[0, 1] datasize = param[1, 1].to_i raise "Width must be > 0" unless width > 0 raise "Width must be any times by #{datasize}" if width % datasize > 0 dumpfmt0, alignfmt = DumpFormat[param] unpackfmt, unpackfmt2 = UnpackFormat[datasize] unpackfmt = unpackfmt2 unless bigendian chunk = buf[offset0..-1] dumpsize = chunk.size dumpfmt = dumpfmt0 * (width / datasize) (dumpsize / width).times do |i| offset = i * width buf = chunk[offset, width] bin = buf.unpack("#{unpackfmt}*") result += sprintf('%07' + format + dumpfmt, offset + offset0, *bin) result += ' ' + buf.tr("\000-\037\177", '.') if datasize == 1 result += "\n" end fragment = dumpsize % width if fragment > 0 offset = dumpsize - fragment buf = chunk[offset, fragment] buf0 = buf.dup fraalign = fragment % datasize if fraalign > 0 fraalign = datasize - fraalign if bigendian # buf0[fragment + fraalign - (datasize - fraalign) - 1, 0] = "\0" * fraalign buf0 += "\0" * fraalign # ??? else buf0 += "\0" * fraalign end end bin = buf0.unpack("#{unpackfmt}*") result += sprintf('%07' + format + dumpfmt0 * bin.size, offset + offset0, *bin) if datasize == 1 alignment = width - fragment result += alignfmt * alignment result += ' ' + buf.tr("\000-\037\177", '.') + ' ' * alignment end result += "\n" end result += sprintf("%07x\n", dumpsize) result end module_function :dump end class String def datadump Debug::dump(self, "x1") end end if __FILE__ == $0 while gets print Debug::dump($_) print $_.datadump end end xmlrpc4r-1_7_7/samples/ 40755 1750 0 0 7377326627 13751 5ustar michaelwheelxmlrpc4r-1_7_7/samples/raa/ 40755 1750 0 0 7377326627 14514 5ustar michaelwheelxmlrpc4r-1_7_7/samples/raa/raa.rb100644 1750 0 1277 7256716375 15707 0ustar michaelwheel#!/usr/bin/env ruby # # This library provides access to the XML-RPC interface # of RAA (Ruby Application Archive) # # $Id: raa.rb,v 1.2 2001/03/23 18:59:09 michael Exp $ # require "xmlrpc/client" class RAA def initialize(host, path, port=80) @server = XMLRPC::Client.new(host, path, port) @raa = @server.proxy("raa") end def getAllListings @raa.getAllListings end def getProductTree @raa.getProductTree end def getInfoFromCategory(major, minor) @raa.getInfoFromCategory(:major => major, :minor => minor) end def getModifiedInfoSince(time) @raa.getModifiedInfoSince(time) end def getInfoFromName(name) @raa.getInfoFromName(name) end end xmlrpc4r-1_7_7/samples/raa/raa_fox.rb100644 1750 0 3574 7323134473 16551 0ustar michaelwheel require "fox" require "responder" include Fox class RAAFoxWindow < FXMainWindow include Responder ID_TREE, = enum(FXMainWindow::ID_LAST, 1) def initialize(app) super(app, "RAA FOX", nil, nil, DECOR_ALL, 0, 0, 640, 480) FXMAPFUNC(SEL_CLICKED, ID_TREE, "onCmdTree") contents = FXHorizontalFrame.new(self, LAYOUT_FILL_X|LAYOUT_FILL_Y) vert_left = FXVerticalFrame.new(contents, LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_LEFT,0,0,0,0,10,10,10,10) vert_right = FXVerticalFrame.new(contents, LAYOUT_FILL_X|LAYOUT_FILL_Y|LAYOUT_RIGHT,0,0,0,0,10,10,10,10) FXLabel.new(vert_right, "haljljlj", nil, LAYOUT_FILL_X) @tree_list = FXTreeList.new(vert_left, 0, nil, 0, (HSCROLLING_OFF| TREELIST_SHOWS_LINES|TREELIST_SHOWS_BOXES|FRAME_SUNKEN|FRAME_THICK| LAYOUT_FILL_X|LAYOUT_FILL_Y), 0, 0, 0, 0) @tree_list.target = self @tree_list.selector = ID_TREE end def onCmdTree(sender, sel, ptr) p @elems[ptr] end def fill_tree_list(tree) @elems = {} root = @tree_list.getFirstItem root = @tree_list.addItemLast(root, "RAA", nil, nil, nil, true) @elems[root] = [] tree.each {|k1,v1| ele = @tree_list.addItemLast(root, k1, nil, nil, nil, true) @elems[ele] = [k1] v1.each {|k2,v2| ele2 = @tree_list.addItemLast(ele, k2, nil, nil, nil, true) @elems[ele2] = [k1, k2] v2.each {|k3| ele3 = @tree_list.addItemLast(ele2, k3, nil, nil, nil, true) @elems[ele3] = [k1,k2,k3] } } } end def create super show(PLACEMENT_SCREEN) end end # class RAAFoxWindow def run application = FXApp.new("RAAFox", "RAA FOX") application.init(ARGV) x = RAAFoxWindow.new(application) x.fill_tree_list( {"Application" => {"Server" => ["hallo", "leute"], "Mist" => []}, "Library" => {} }) application.create application.run end run xmlrpc4r-1_7_7/samples/raa/raa_test.rb100644 1750 0 2233 7256717527 16737 0ustar michaelwheel#!/usr/bin/env ruby # # This sample demonstrates how to call the XML-RPC interface # of RAA (Ruby Application Archive) # # $Id: raa_test.rb,v 1.4 2001/03/23 19:09:11 michael Exp $ # require "raa" raa = RAA.new("www.ruby-lang.org", "/~nahi/xmlrpc/raa/") # # Returns an array of all names (strings) # of the packages at RAA # p raa.getAllListings # # Returns a hash, containing the main sections of RAA as keys # (Application, Library, Documentation, Ports...) and the # corresponding values are also hashs which values are # the subsections, the values are arrays containing the # names of the packages under this section. # p raa.getProductTree # # Returns an array of hashes, where each hash # describes completely a RAA package. # Only packages in section "Library" and subsection # "XML" are returned. # p raa.getInfoFromCategory( "Library", "XML" ) # # The package which name is "XML-RPC" is returned as a # hash containing all the info of that package (same as above). # p raa.getInfoFromName( "XML-RPC" ) # # Get all packages (in an array) which has been # modified since the given time. # p raa.getModifiedInfoSince( Time.at( Time.now.to_i - 24 * 3600 ) ) xmlrpc4r-1_7_7/samples/raa/raa_tk.rb100644 1750 0 7345 7256714300 16371 0ustar michaelwheel#!/usr/bin/env ruby # # Tk client for XML-RPC RAA Interface # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: raa_tk.rb,v 1.4 2001/03/23 18:41:04 michael Exp $ # require "tk" require "tkscrollbox" require "raa" HOST = ARGV.shift || "www.ruby-lang.org" PATH = ARGV.shift || "/~nahi/xmlrpc/raa/" PORT = (ARGV.shift || 80).to_i INDENT = " " raa = RAA.new(HOST, PATH, PORT) root = TkRoot.new { title "TkRAA (XML-RPC)"; width "600"} lframe = TkFrame.new(root) rframe = TkFrame.new(root) def generate_listing(raa) l = [] t = raa.getProductTree t.keys.sort.each {|i| l << { :text => i, :type => :maj } t[i].keys.sort.each {|j| l << { :text => j, :type => :min } t[i][j].sort.each {|k| l << { :text => k, :type => :entry } } } } return l end $list = generate_listing(raa) list = TkScrollbox.new(lframe) { relief 'raised' setgrid 'yes' pack 'side' => 'left', 'fill' => 'both', 'expand' => 'yes' } $list.each {|i| txt = i[:text] list.insert('end', case i[:type] when :maj then txt when :min then INDENT + txt when :entry then (INDENT*2) + txt end ) } list.bind("ButtonRelease-1") { index = list.curselection[0].to_i entry = $list[index] if entry[:type] == :entry then info = raa.getInfoFromName(entry[:text]) $product.keys.each {|k| $product[k].value = info["product"][k.to_s] } $owner.keys.each {|k| $owner[k].value = info["owner"][k.to_s] } $category.keys.each {|k| $category[k].value = info["category"][k.to_s] } $update.value = info["update"].to_time.to_s end } $product = {} $product[:download] = TkVariable.new $product[:status] = TkVariable.new $product[:version] = TkVariable.new $product[:license] = TkVariable.new $product[:name] = TkVariable.new $product[:homepage] = TkVariable.new $product[:description] = TkVariable.new $owner = {} $owner[:email] = TkVariable.new $owner[:name] = TkVariable.new $owner[:id] = TkVariable.new $category = {} $category[:major] = TkVariable.new $category[:minor] = TkVariable.new $update = TkVariable.new def label_entry(parent, label, tkvar, row, klass_entry=TkEntry) TkLabel.new(parent) { text label }.grid('row' => row, 'column' => 0, 'sticky' => 'w') klass_entry.new(parent) { textvariable tkvar width 50 }.grid('row' => row, 'column' => 1) end def label(parent, label, row) TkLabel.new(parent) { text label }.grid('row' => row, 'column' => 1, 'sticky' => 'w') end rtframe = TkFrame.new(rframe) rbframe = TkFrame.new(rframe) TkButton.new(rtframe) { text "Exit" command { exit } pack 'side' => 'left' } prod = rbframe label prod, "Product",0 label_entry(prod, "Name", $product[:name], 5) label_entry(prod, "Version", $product[:version], 3) label_entry(prod, "Status", $product[:status], 2) label_entry(prod, "License", $product[:license], 4) label_entry(prod, "Homepage", $product[:homepage], 6) label_entry(prod, "Download", $product[:download], 1) label_entry(prod, "Description", $product[:description], 7) owner = rbframe label owner, "Owner",8 label_entry(owner, "Name", $owner[:name], 10) label_entry(owner, "Email", $owner[:email], 9) label_entry(owner, "Id", $owner[:id], 11) categ = rbframe label categ, "Category",12 label_entry(categ, "Major", $category[:major], 13) label_entry(categ, "Minor", $category[:minor], 14) label rbframe, "Update",15 label_entry(rbframe, "Update", $update, 16) label rbframe, "", 17 rtframe.pack 'side' => 'top', 'fill' => 'both' rbframe.pack 'side' => 'bottom', 'fill' => 'both' lframe.pack 'side' => 'left', 'fill' => 'both', 'expand' => 'yes' rframe.pack 'side' => 'right', 'fill' => 'both', 'expand' => 'yes' Tk.mainloop xmlrpc4r-1_7_7/samples/raa/responder.rb100644 1750 0 2255 7323134473 17126 0ustar michaelwheel# Enumeration def enum(start, count) (start...(start+count)).to_a end module Responder # Initialize the array of associations for the class as empty @@assocs = [] # Look up array index of this message map entry def assocIndex(lo, hi) currIndex = -1 @@assocs.each_index { |i| if @@assocs[i][0] == lo && @@assocs[i][1] == hi currIndex = i end } return currIndex end # Add new or replace existing map entry def addMapEntry(lo, hi, func) currIndex = assocIndex(lo, hi) if currIndex < 0 @@assocs.push([lo, hi, func]) else @@assocs[currIndex] = [lo, hi, func] end end # Define range of function types def FXMAPTYPES(typelo, typehi, func) addMapEntry(MKUINT(MINKEY, typelo), MKUINT(MAXKEY, typehi), func) end # Define one function type def FXMAPTYPE(type, func) addMapEntry(MKUINT(MINKEY, type), MKUINT(MAXKEY, type), func) end # Define range of functions def FXMAPFUNCS(type, keylo, keyhi, func) addMapEntry(MKUINT(keylo, type), MKUINT(keyhi, type), func) end # Define one function def FXMAPFUNC(type, id, func) addMapEntry(MKUINT(id, type), MKUINT(id, type), func) end end xmlrpc4r-1_7_7/samples/call.rb100644 1750 0 715 7321077372 15256 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/client" #server = XMLRPC::Client.new("localhost", "/cgi-bin/xml.cgi", 80) server = XMLRPC::Client.new2("http://michael:neumann@localhost:8070/cgi-bin/xml.cgi") #server = XMLRPC::Client.new("localhost", "/cgi-bin/xml.fcgi", 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 p server.call("system.listMethods") xmlrpc4r-1_7_7/samples/multicall.rb100644 1750 0 644 7321077372 16332 0ustar michaelwheelrequire "xmlrpc/client" server = XMLRPC::Client.new("localhost", "/cgi-bin/xml.cgi", 8070) p server.multicall( ['michael.add', 4, 5], ['michael.sub', 4, 3], ['michael.div', 3, 0] ) p server.call('system.multicall', [ { 'methodName' => 'michael.add', 'params' => [4, 5] }, { 'methodName' => 'michael.sub', 'params' => [4, 3] }, { 'methodName' => 'michael.div', 'params' => [3, 0] } ]) xmlrpc4r-1_7_7/samples/perf_async.rb100644 1750 0 726 7320104420 16456 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/client" require "thread" server = XMLRPC::Client.new2("http://michael:neumann@localhost/cgi-bin/xml.cgi") start = Time.now thr = [] 10.times do thr << Thread.new { ok, param = server.call2_async("michael.add", 4, 5) p param } end thr.each {|t| t.join} end1 = Time.now 10.times do ok, param = server.call2("michael.add", 4, 5) p param end end2 = Time.now puts puts p (end1-start).to_i p (end2-end1).to_i xmlrpc4r-1_7_7/samples/xml.cgi100755 1750 0 1136 7325551265 15325 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/server" class MyHandlerClass def sub(a,b) a-b end def exp(a,b) a ** b end end s = XMLRPC::Server.new(8080, "127.0.0.1", 4, nil, true, true) # if you want a standalone server #s = XMLRPC::CGIServer.new s.add_handler("michael.add") {|a,b| a+b } s.add_handler("michael.div") {|a,b| if b == 0 raise XMLRPC::FaultException.new 1, "division by zero" else a / b end } #s.add_handler("michael", MyHandlerClass.new) s.add_handler(XMLRPC::iPIMethods("michael"), MyHandlerClass.new) s.add_multicall s.add_introspection s.serve xmlrpc4r-1_7_7/samples/xml.fcgi100755 1750 0 760 7314111271 15440 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/server" require "fcgi" class MyHandlerClass def sub(a,b) a-b end def exp(a,b) a ** b end end s = XMLRPC::CGIServer.new s.add_handler("michael.add") {|a,b| a+b } s.add_handler("michael.div") {|a,b| if b == 0 raise XMLRPC::FaultException.new 1, "division by zero" else a / b end } s.add_handler("michael", MyHandlerClass.new) s.add_multicall s.add_introspection FCGI.each_request {|f| $stdin = f.in s.serve } xmlrpc4r-1_7_7/samples/xml2.cgi100755 1750 0 756 7320343424 15365 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/server" IMyHandlerClass = XMLRPC::interface("michael") { meth "int sub(int, int)", "Subtracts two integer" meth "double exp(double, double)", "Exponent", :exp } class MyHandlerClass def sub(a,b) a-b end def exp(a,b) a ** b end end s = XMLRPC::Server.new(8070, "127.0.0.1", 4, nil, true, true) # if you want a standalone server s.add_handler(IMyHandlerClass, MyHandlerClass.new) s.add_multicall s.add_introspection s.serve xmlrpc4r-1_7_7/samples/chat/ 40755 1750 0 0 7377326626 14667 5ustar michaelwheelxmlrpc4r-1_7_7/samples/chat/client.rb100644 1750 0 2541 7323134470 16552 0ustar michaelwheel#!/usr/bin/env ruby # # The chat client # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: client.rb,v 1.1 2001/07/11 20:38:16 michael Exp $ # require "xmlrpc/client" require "xmlrpc/server" require "gtk" CLIENT_HOST = "localhost" CLIENT_PORT = (ARGV[0] || 7001).to_i SERVER_HOST = "localhost" SERVER_PORT = "7000" CHANNEL = "mychannel" s = XMLRPC::Server.new(CLIENT_PORT) s.add_handler("chat.client.message") do |channel, message| # $msg.configure('text'=>$msg.cget('text') + message) true end chat_server = XMLRPC::Client.new(SERVER_HOST, "/RPC2", SERVER_PORT) chat_server.call("chat.server.connect", CHANNEL, CLIENT_HOST, CLIENT_PORT) server_thread = Thread.new(s) do |server| server.serve end window = Gtk::Window.new(Gtk::WINDOW_TOPLEVEL) window.signal_connect("delete_event") do exit end window.signal_connect("destroy_event") do exit end window.realize box = Gtk::VBox.new(FALSE, 0) window.add(box) box.show $str = "Hello, world." $text = Gtk::Text.new(Gtk::Adjustment.new(0,0,0,0,0,0), Gtk::Adjustment.new(0,0,0,0,0,0)) box.pack_start($text) $text.show button = Gtk::Button.new("append") box.pack_start(button) button.show button.signal_connect("clicked") do |w| #chat_server.call("chat.server.send", CHANNEL, $entry.value+"\n") $text.insert_text($str + "\n", $text.get_point) end window.show Gtk.main xmlrpc4r-1_7_7/samples/chat/client.rb.tk100644 1750 0 2275 7323134470 17173 0ustar michaelwheel#!/usr/bin/env ruby # # The chat client # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: client.rb.tk,v 1.1 2001/07/11 20:38:16 michael Exp $ # require "xmlrpc/client" require "xmlrpc/server" require "tk" CLIENT_HOST = "localhost" CLIENT_PORT = (ARGV[0] || 7001).to_i SERVER_HOST = "localhost" SERVER_PORT = "7000" CHANNEL = "mychannel" require "thread" $mutex = Mutex.new s = XMLRPC::Server.new(CLIENT_PORT) s.add_handler("chat.client.message") do |channel, message| $mutex.synchronize { $msg.configure('text'=>$msg.cget('text') + message) } true end chat_server = XMLRPC::Client.new(SERVER_HOST, "/RPC2", SERVER_PORT) chat_server.call("chat.server.connect", CHANNEL, CLIENT_HOST, CLIENT_PORT) server_thread = Thread.new(s) do |server| server.serve end root = TkRoot.new { title "Chat-Demo (#{CLIENT_PORT})" } $entry = TkVariable.new $msg = TkMessage.new(root) { pack } TkEntry.new(root) { textvariable $entry pack } TkButton.new(root) { text "send" command { $mutex.synchronize { Thread.new { chat_server.call("chat.server.send", CHANNEL, $entry.value+"\n") } $entry.value = "" } } pack } Tk.mainloop xmlrpc4r-1_7_7/samples/chat/server.rb100644 1750 0 1724 7323134470 16604 0ustar michaelwheel#!/usr/bin/env ruby # # The multicast server # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: server.rb,v 1.1 2001/07/11 20:38:16 michael Exp $ # require "xmlrpc/client" require "xmlrpc/server" class ChatServer def initialize @channel = {} end def connect(channel, host, port) rpc_path = [host, port] key = channel.to_s @channel[key] ||= [] @channel[key] << rpc_path end def disconnect(channel, host, port) rpc_path = [host, port] arr = @channel[channel.to_s] arr.delete(rpc_path) if arr end def send(channel, message) arr = @channel[channel.to_s] return false if arr.nil? arr.each do |host, port| server = XMLRPC::Client.new(host, "/RPC2", port) server.call2("chat.client.message", channel, message) end true end end if $0 == __FILE__ port = ARGV[0] || 7000 s = XMLRPC::Server.new(port.to_i) s.add_handler("chat.server", ChatServer.new) s.serve end xmlrpc4r-1_7_7/samples/introspection/ 40755 1750 0 0 7377326626 16650 5ustar michaelwheelxmlrpc4r-1_7_7/samples/introspection/client.rb100644 1750 0 417 7315452445 20521 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/client" server = XMLRPC::Client.new("localhost", "/RPC2", 8070) server.call("system.listMethods").each do |m| p m p server.call("system.methodSignature", m) p server.call("system.methodHelp", m) puts "---------------" end xmlrpc4r-1_7_7/samples/introspection/server.rb100755 1750 0 655 7315452445 20560 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/server" s = XMLRPC::Server.new(8070) # if you want a standalone server s.add_handler("michael.add", %w(int int int), "adds two integers") {|a,b| a+b } s.add_handler("michael.div", [%w(int int int), %w(double double double)], "divides two numbers") {|a,b| if b == 0 raise XMLRPC::FaultException.new 1, "division by zero" else a / b end } s.add_introspection s.serve xmlrpc4r-1_7_7/samples/marshallable/ 40755 1750 0 0 7377326627 16400 5ustar michaelwheelxmlrpc4r-1_7_7/samples/marshallable/client.rb100644 1750 0 225 7314221164 20234 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/client" require "person" server = XMLRPC::Client.new("localhost", "/RPC2", 8070) p server.call("test.person") xmlrpc4r-1_7_7/samples/marshallable/person.rb100644 1750 0 214 7314444124 20265 0ustar michaelwheel class Person include XMLRPC::Marshallable attr_reader :name, :age def initialize(name, age) @name, @age = name, age end end xmlrpc4r-1_7_7/samples/marshallable/server.rb100755 1750 0 243 7314444124 20272 0ustar michaelwheel#!/usr/bin/env ruby require "xmlrpc/server" require "person" s = XMLRPC::Server.new(8070) s.add_handler("test.person") { Person.new("Michael", 21) } s.serve xmlrpc4r-1_7_7/samples/monitor/ 40755 1750 0 0 7377326627 15440 5ustar michaelwheelxmlrpc4r-1_7_7/samples/monitor/monitor.rb100755 1750 0 6445 7325547623 17557 0ustar michaelwheel#!/usr/bin/env ruby # # TCP Tunnel # Copyright (c) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: monitor.rb,v 1.1 2001/07/19 12:16:19 michael Exp $ # # Modified to use TCPSocketPipe and some tk view. # Copyright (c) 2001 NAKAMURA Hiroshi. # This application is copyrighted free software by Michael Neumann and # NAKAMURA, Hiroshi. You can redistribute it and/or modify it under # the same term as Ruby or under BSD License. require 'TCPSocketPipe' require 'tk' unless ARGV.size == 3 puts "USAGE: #$0 srcPort destName destPort" puts " e.g. #$0 8070 localhost 8080" exit 1 end LISTENHOST = 'localhost' LISTENPORT = ARGV.shift TUNNELHOST = ARGV.shift TUNNELPORT = ARGV.shift WIDTH = 50 HEIGHT = 35 root = TkRoot.new { title "TCP Tunnel/Monitor: Tunneling #{LISTENHOST}:#{LISTENPORT} to #{TUNNELHOST}:#{TUNNELPORT}" } top = TkFrame.new(root) { pack( 'side' => 'top', 'fill' => 'x' ) } bottom2 = TkFrame.new(root) { pack( 'side' => 'bottom', 'fill' => 'both' ) } bottom3 = TkFrame.new(bottom2) { pack 'side' => 'bottom', 'fill' => 'x' } bottom = TkFrame.new(bottom2) { pack( 'side' => 'top', 'fill' => 'both' ) } bot_label = TkLabel.new(bottom3) { text "Listening for connections on port #{LISTENPORT} for host #{LISTENHOST}" pack } llabel = TkLabel.new(top) { text "From #{LISTENHOST}:#{LISTENPORT}" pack 'side' => 'right' } rlabel = TkLabel.new(top) { text "From #{TUNNELHOST}:#{TUNNELPORT} " pack 'side' => 'left' } $ltext = TkText.new(bottom, 'width' => WIDTH, 'height' => HEIGHT) { pack( 'side' => 'left', 'fill' => 'y' ) } $rtext = TkText.new(bottom, 'width' => WIDTH, 'height' => HEIGHT) { pack( 'side' => 'right', 'fill' => 'y' ) } scroll = TkScrollbar.new(bottom) { command proc { |arg| $ltext.yview *arg $rtext.yview *arg } pack( 'side' => 'right', 'fill' => 'y' ) } $ltext.configure( 'yscrollcommand' => proc { |arg| scroll.set *arg } ) $ltext.yscrollcommand( proc { |arg| scroll.set *arg } ) $rtext.configure( 'yscrollcommand' => proc { |arg| scroll.set *arg } ) $rtext.yscrollcommand( proc { |arg| scroll.set *arg } ) $sessionCount = 0 $sessionResetP = false TkButton.new(top) { text "Clear" command { $ltext.value = "" $rtext.value = "" $sessionResetP = true } pack } class TCPSocketPipe < Application def dumpTransferData( isFromSrcToDestP, data ) if isFromSrcToDestP log( SEV_INFO, 'Transfer data ... [src] -> [dest]' ) $ltext.insert( 'end', data ) unless $sessionResetP else log( SEV_INFO, 'Transfer data ... [src] <- [dest]' ) $rtext.insert( 'end', data ) unless $sessionResetP end dumpData( data ) end def dumpAddSession $sessionCount += 1 str = "----" $ltext.insert( 'end', str + '-' * ( WIDTH - str.size ) << "\n" ) $rtext.insert( 'end', str + '-' * ( WIDTH - str.size ) << "\n" ) end def dumpCloseSession if $sessionResetP $sessionCount = 0 $sessionResetP = false return end str = "----" $ltext.insert( 'end', "\n" << str << '-' * ( WIDTH - str.size ) << "\n" ) $rtext.insert( 'end', "\n" << str << '-' * ( WIDTH - str.size ) << "\n" ) end end Thread.new { app = TCPSocketPipe.new( LISTENPORT, TUNNELHOST, TUNNELPORT ) app.dumpResponse = true app.start() } Tk.mainloop xmlrpc4r-1_7_7/samples/sandstorm/ 40755 1750 0 0 7377326627 15763 5ustar michaelwheelxmlrpc4r-1_7_7/samples/sandstorm/active.rb100644 1750 0 2353 7325551504 17646 0ustar michaelwheel# # Client-interface wrapper for Sand-Storm component architecture # (sstorm.sourceforge.net) # # $Id: active.rb,v 1.5 2001/07/19 12:32:04 michael Exp $ # require "xmlrpc/client" module Active class Registry attr_reader :registry def initialize(uri=nil, host=nil, port=nil) @server = host || ENV['ACTIVE_REGISTRY_HOST'] || 'localhost' @port = port || ENV['ACTIVE_REGISTRY_PORT'] || 1422 @uri = uri || ENV['ACTIVE_REGISTRY_URI'] || '/RPC2' @active = XMLRPC::Client.new(@server, @uri, @port.to_i) @registry = @active.proxy("active.registry") end def getComponent(comp) info = @registry.getComponent(comp) XMLRPC::Client.new(info['host'], info['uri'], info['port']).proxy(comp) end def getComponents @registry.getComponents end def getComponentInfo(comp) @registry.getComponent(comp) end def setComponent(name, uri, host, port) @registry.setComponent(name, uri, host, port) end def addComponent(name, uri, host, port) @registry.addComponent(name, uri, host, port) end def removeComponent(name) @registry.removeComponent(name) end end # class Registry Client = Registry end # module Active xmlrpc4r-1_7_7/samples/tcptunnel/ 40755 1750 0 0 7377326627 15765 5ustar michaelwheelxmlrpc4r-1_7_7/samples/tcptunnel/README100644 1750 0 32 7325547502 16663 0ustar michaelwheelsee ../monitor/monitor.rb xmlrpc4r-1_7_7/samples/validator/ 40755 1750 0 0 7377326627 15736 5ustar michaelwheelxmlrpc4r-1_7_7/samples/validator/validator1.rb100644 1750 0 5576 7237266732 20436 0ustar michaelwheel#! /usr/bin/env ruby # # An implementation of tests for the the first validator suite # (validator1) as shown on http://www.xmlrpc.com/validator1Docs # For validated hosts, see http://validator.xmlrpc.com where # 149.225.142.138, 149.225.145.228, 149.225.114.66 (all NetBSD) and # 149.225.117.236 (Windows 98) were my hosts. # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: validator1.rb,v 1.4 2001/02/04 14:57:30 michael Exp $ # class Validator1 # # Takes single parameter, array of structs, where # each structure has at least the three elements # "moe", "larry" and "curly" which are all integers. # Had to return the sum of all struct-elements named # "curly". # def arrayOfStructsTest(arr) sum = 0 arr.each do |struc| sum += struc["curly"] end sum end # # Takes single paramter, a string, and returns # the a struct with the elements # "ctLeftAngleBrackets", "ctRightAngleBrackets", # "ctAmpersands", "ctApostrophes", "ctQuotes", # which counts the occurences of the characters # "<", ">", "&", "'", '"' # def countTheEntities(str) { :ctLeftAngleBrackets => str.count("<"), :ctRightAngleBrackets => str.count(">"), :ctAmpersands => str.count("&"), :ctApostrophes => str.count("'"), :ctQuotes => str.count('"') } end # # Takes single parameter, a struct, must return # sum of the three elements "moe", "larry" and "curly" # def easyStructTest(struc) struc["moe"] + struc["larry"] + struc["curly"] end # # Takes single paramter, a struct, must return this # struct. # def echoStructTest(struc) struc end # # Takes six parameters and must return an array of this parameters # def manyTypesTest(number, boolean, string, double, dateTime, base64) [number, boolean, string, double, dateTime, base64] end # # Takes single parameter, an array of strings, must return # concatenated string of first and last element of the array. # def moderateSizeArrayCheck(arr) arr[0] + arr[-1] end # # Takes single parameter, a nested struct that models a calendar. # The entry for April 1, 2000 contains three elements "moe", "larry" # and "curly". Return the sum of these three elements. # def nestedStructTest(struc) s = struc["2000"]["04"]["01"] s["moe"] + s["larry"] + s["curly"] end # # Takes single parameter, a number and returns a struct # containing three elements "times10", "times100" and # "times1000" where the values are the multiplication by # 10, 100, or 1000. # def simpleStructReturnTest(n) { :times10 => n * 10, :times100 => n * 100, :times1000 => n * 1000 } end end if __FILE__ == $0 require "xmlrpc/server" s = XMLRPC::Server.new(8080, "0.0.0.0") s.add_handler("validator1", Validator1.new) s.serve end xmlrpc4r-1_7_7/samples/wwwsrv/ 40755 1750 0 0 7377326627 15330 5ustar michaelwheelxmlrpc4r-1_7_7/samples/wwwsrv/srv.conf100644 1750 0 1050 7326031277 17066 0ustar michaelwheel__HOST__ HOSTNAME = '0.0.0.0' PORT = 8000 STRICT = false # WWWsrv::Server object initialization parameters are defined in this # section. When parameters are omitted, default parameters are used. __SERVER__ # A new created WWWsrv::Server object is set up in this section. # SERVER constant variable is bound to a new server object. require 'srv' srv = XMLRPC::WWWServer::new( XMLRPC::BasicServer.new. add_handler("michael.add") {|a,b| a + b}. add_handler("michael.sub") {|a,b| a - b}. add_introspection ) SERVER.mount(srv, '/') xmlrpc4r-1_7_7/samples/wwwsrv/srv.rb100644 1750 0 1755 7326031277 16560 0ustar michaelwheelrequire "xmlrpc/server" module XMLRPC class WWWServer < WWWsrv::Document def initialize(server) @server = server end def session(sid, srv_opt, prefix, request, response) srv_opt.log.debug "sid #{sid}: debug #{type}" case (request.method) when 'POST' if request.header.content_type != "text/xml" response.status = 400 http_error(response) end length = request.header.content_length.to_i if length <= 0 response.status = 411 http_error(response) end #request.content.binmode data = request.content.read(length) if data.nil? or data.size != length response.status = 400 http_error(response) end resp = @server.process(data) response.status = 200 response.header.content_type = 'text/xml' yield(response) yield(resp) else response.status = 405 http_error(response) end end end # class WWWServer end # module XMLRPC xmlrpc4r-1_7_7/test/ 40755 1750 0 0 7377326627 13264 5ustar michaelwheelxmlrpc4r-1_7_7/test/bench_parser.rb100644 1750 0 3302 7330255706 16323 0ustar michaelwheel#! /usr/bin/env ruby # Benchmark for Parser # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: bench_parser.rb,v 1.3 2001/07/27 12:17:10 michael Exp $ # require "xmlrpc/parser" require "xmlrpc/server" require "benchmark" include Benchmark def create_middle XMLRPC::Create.new.methodCall( "test", (1..100).to_a, ("hallo".."halpo").to_a ) end def rec_struct(width, value, n) return value if n == 0 x = [] width.times { x << rec_struct(width, value, n-1) } x end def create_huge XMLRPC::Create.new.methodResponse(true, rec_struct(5, {"name" => 4343, "value" => "halkjkjk"}, 5) ) end def create_base64(size) XMLRPC::Create.new.methodResponse(true, XMLRPC::Base64.new("T" * size)) end FILES = { "small" => [:call, File.readlines("files/value.xml").to_s], "middle" => [:call, create_middle], "large" => [:response, File.readlines("files/xml1.xml").to_s], "huge" => [:response, create_huge, 1], "base64" => [:response, create_base64(1024*1024)] } PARSER = { "XMLTreeParser" => XMLRPC::XMLParser::XMLTreeParser.new, "NQXMLTreeParser" => XMLRPC::XMLParser::NQXMLTreeParser.new, "XMLStreamParser" => XMLRPC::XMLParser::XMLStreamParser.new, "NQXMLStreamParser" => XMLRPC::XMLParser::NQXMLStreamParser.new } N = 50 bm(40) do |test| PARSER.each do |name, parser| FILES.each do |file, data| GC.start test.report("#{name} - #{file} (#{data[1].size} bytes)") do if data[0] == :call (data[2] || N).times { parser.parseMethodCall(data[1]) } elsif data[0] == :response (data[2] || N).times { parser.parseMethodResponse(data[1]) } end end end end end xmlrpc4r-1_7_7/test/test.rb100644 1750 0 676 7365046254 14646 0ustar michaelwheel def require(file) if file =~ /^xmlrpc\/(.*)$/ file = "../lib/#$1" p file super(file) else super end end require "runit/cui/testrunner" require "test_datetime" require "test_parser" require "test_features" require "test_marshal" RUNIT::CUI::TestRunner.run(Test_DateTime.suite) RUNIT::CUI::TestRunner.run(Test_Parser.suite) RUNIT::CUI::TestRunner.run(Test_Features.suite) RUNIT::CUI::TestRunner.run(Test_Marshal.suite) xmlrpc4r-1_7_7/test/test_datetime.rb100644 1750 0 11123 7240324547 16543 0ustar michaelwheel#! /usr/bin/env ruby # # Testcase for file "datetime.rb" # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: test_datetime.rb,v 1.2 2001/02/07 20:00:39 michael Exp $ # require "runit/testcase" require "xmlrpc/datetime" class Test_DateTime < RUNIT::TestCase def test_new dt = createDateTime assert_instance_of(XMLRPC::DateTime, dt) end def test_new_exception assert_exception(ArgumentError) { XMLRPC::DateTime.new(4.5, 13, 32, 25, 60, 60) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 32, 25, 60, 60) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 25, 60, 60) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 60, 60) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 59, 60) } assert_no_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 59, 59) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 0, 0, -1, -1, -1) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 0, -1, -1, -1) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, -1, -1, -1) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, -1, -1) } assert_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, 0, -1) } assert_no_exception(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, 0, 0) } end def test_get_values y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) assert_equal(y, dt.year) assert_equal(m, dt.month) assert_equal(m, dt.mon) assert_equal(d, dt.day) assert_equal(h, dt.hour) assert_equal(mi,dt.min) assert_equal(s, dt.sec) end def test_set_values dt = createDateTime y, m, d, h, mi, s = 1950, 12, 9, 8, 52, 30 dt.year = y dt.month = m dt.day = d dt.hour = h dt.min = mi dt.sec = s assert_equal(y, dt.year) assert_equal(m, dt.month) assert_equal(m, dt.mon) assert_equal(d, dt.day) assert_equal(h, dt.hour) assert_equal(mi,dt.min) assert_equal(s, dt.sec) dt.mon = 5 assert_equal(5, dt.month) assert_equal(5, dt.mon) end def test_set_exception dt = createDateTime assert_exception(ArgumentError) { dt.year = 4.5 } assert_no_exception(ArgumentError) { dt.year = -2000 } assert_exception(ArgumentError) { dt.month = 0 } assert_exception(ArgumentError) { dt.month = 13 } assert_no_exception(ArgumentError) { dt.month = 7 } assert_exception(ArgumentError) { dt.mon = 0 } assert_exception(ArgumentError) { dt.mon = 13 } assert_no_exception(ArgumentError) { dt.mon = 7 } assert_exception(ArgumentError) { dt.day = 0 } assert_exception(ArgumentError) { dt.day = 32 } assert_no_exception(ArgumentError) { dt.day = 16 } assert_exception(ArgumentError) { dt.hour = -1 } assert_exception(ArgumentError) { dt.hour = 25 } assert_no_exception(ArgumentError) { dt.hour = 12 } assert_exception(ArgumentError) { dt.min = -1 } assert_exception(ArgumentError) { dt.min = 60 } assert_no_exception(ArgumentError) { dt.min = 30 } assert_exception(ArgumentError) { dt.sec = -1 } assert_exception(ArgumentError) { dt.sec = 60 } assert_no_exception(ArgumentError) { dt.sec = 30 } end def test_to_a y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) a = dt.to_a assert_instance_of(Array, a) assert_equal(6, a.size, "Returned array has wrong size") assert_equal(y, a[0]) assert_equal(m, a[1]) assert_equal(d, a[2]) assert_equal(h, a[3]) assert_equal(mi, a[4]) assert_equal(s, a[5]) end def test_to_time1 y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) time = dt.to_time assert_not_nil(time) assert_equal(y, time.year) assert_equal(m, time.month) assert_equal(d, time.day) assert_equal(h, time.hour) assert_equal(mi, time.min) assert_equal(s, time.sec) end def test_to_time2 dt = createDateTime dt.year = 1969 assert_nil(dt.to_time) end def test_to_date1 y, m, d, h, mi, s = 1970, 3, 24, 12, 0, 5 dt = XMLRPC::DateTime.new(y, m, d, h, mi, s) date = dt.to_date assert_equal(y, date.year) assert_equal(m, date.month) assert_equal(d, date.day) end def test_to_date2 dt = createDateTime dt.year = 666 assert_equal(666, dt.to_date.year) end def createDateTime XMLRPC::DateTime.new(1970, 3, 24, 12, 0, 5) end end xmlrpc4r-1_7_7/test/test_features.rb100644 1750 0 1602 7365046254 16552 0ustar michaelwheel#! /usr/bin/env ruby # # Testcase for Parser # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: test_features.rb,v 1.3 2001/10/22 16:43:24 michael Exp $ # require "runit/testcase" require "xmlrpc/create" require "xmlrpc/parser" require "xmlrpc/config" module XMLRPC module Config ENABLE_NIL_CREATE = true ENABLE_NIL_PARSER = true end end class Test_Features < RUNIT::TestCase def setup @c = [ XMLRPC::Create.new(XMLRPC::XMLWriter::Simple.new), XMLRPC::Create.new(XMLRPC::XMLWriter::XMLParser.new) ] @p = [ XMLRPC::XMLParser::NQXMLParser.new, XMLRPC::XMLParser::XMLParser.new ] end def test_nil params = [nil, {"test" => nil}, [nil, 1, nil]] @c.each do |c| str = c.methodCall("test", *params) @p.each do |p| para = p.parseMethodCall(str) assert_equal(para[1], params) end end end end xmlrpc4r-1_7_7/test/test_marshal.rb100644 1750 0 3656 7370517607 16377 0ustar michaelwheel#! /usr/bin/env ruby # # Testcase for Parser # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: test_marshal.rb,v 1.2 2001/11/02 13:28:39 michael Exp $ # require "runit/testcase" require "xmlrpc/marshal" class Test_Marshal < RUNIT::TestCase def test1_dump_response assert_no_exception(NameError) { XMLRPC::Marshal.dump_response('arg') } end def test1_dump_call assert_no_exception(NameError) { XMLRPC::Marshal.dump_call('methodName', 'arg') } end def test2_dump_load_response value = [1, 2, 3, {"test" => true}, 3.4] res = XMLRPC::Marshal.dump_response(value) assert_equal(value, XMLRPC::Marshal.load_response(res)) end def test2_dump_load_call methodName = "testMethod" value = [1, 2, 3, {"test" => true}, 3.4] exp = [methodName, [value, value]] res = XMLRPC::Marshal.dump_call(methodName, value, value) assert_equal(exp, XMLRPC::Marshal.load_call(res)) end def test_parser_values xp = XMLRPC::XMLParser parser = [ xp::NQXMLTreeParser, xp::NQXMLStreamParser, xp::XMLTreeParser, xp::XMLStreamParser ] v1 = [ 1, -7778, # integers 1.0, 0.0, -333.0, 2343434343.0, # floats false, true, true, false, # booleans "Hallo", "with < and >", "" # strings ] v2 = [ [v1, v1, v1], {"a" => v1} ] v3 = [ XMLRPC::Base64.new("\001"*1000), # base64 :aSymbol, :anotherSym # symbols (-> string) ] v3_exp = [ "\001"*1000, "aSymbol", "anotherSym" ] for pars in parser do m = XMLRPC::Marshal.new(pars.new) assert_equal( v1, m.load_response(m.dump_response(v1)) ) assert_equal( v2, m.load_response(m.dump_response(v2)) ) assert_equal( v3_exp, m.load_response(m.dump_response(v3)) ) end # missing, Date, Time, DateTime # Struct end end xmlrpc4r-1_7_7/test/test_parser.rb100644 1750 0 7757 7370476564 16260 0ustar michaelwheel#! /usr/bin/env ruby # # Testcase for Parser # # Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) # # $Id: test_parser.rb,v 1.8 2001/11/02 11:03:16 michael Exp $ # require "runit/testcase" require "xmlrpc/parser" class Test_Parser < RUNIT::TestCase def setup @xml1 = File.readlines("files/xml1.xml").to_s @expected1 = File.readlines("files/xml1.expected").to_s.chomp @xml2 = File.readlines("files/value.xml").to_s @expected2 = File.readlines("files/value.expected").to_s.chomp @xml3 = File.readlines("files/bug_covert.xml").to_s @expected3 = File.readlines("files/bug_covert.expected").to_s.chomp @xml4 = File.readlines("files/bug_bool.xml").to_s @expected4 = File.readlines("files/bug_bool.expected").to_s.chomp end def test1_XMLTreeParser p = XMLRPC::XMLParser::XMLTreeParser.new assert_equal(@expected1, p.parseMethodResponse(@xml1).inspect) end def test1_XMLStreamParser p = XMLRPC::XMLParser::XMLStreamParser.new assert_equal(@expected1, p.parseMethodResponse(@xml1).inspect) end def test1_NQXMLTreeParser p = XMLRPC::XMLParser::NQXMLTreeParser.new assert_equal(@expected1, p.parseMethodResponse(@xml1).inspect) end def test1_NQXMLStreamParser p = XMLRPC::XMLParser::NQXMLStreamParser.new assert_equal(@expected1, p.parseMethodResponse(@xml1).inspect) end # ---------------------------------------------------------- def test2_XMLTreeParser p = XMLRPC::XMLParser::XMLTreeParser.new assert_equal(@expected2, p.parseMethodCall(@xml2).inspect) end def test2_XMLStreamParser p = XMLRPC::XMLParser::XMLStreamParser.new assert_equal(@expected2, p.parseMethodCall(@xml2).inspect) end def test2_NQXMLTreeParser p = XMLRPC::XMLParser::NQXMLTreeParser.new assert_equal(@expected2, p.parseMethodCall(@xml2).inspect) end def test2_NQXMLStreamParser p = XMLRPC::XMLParser::NQXMLStreamParser.new assert_equal(@expected2, p.parseMethodCall(@xml2).inspect) end # ---------------------------------------------------------- # bug (in XMLStreamParser) found by covert, thaddeus on 31.10.2001 def test3_XMLTreeParser p = XMLRPC::XMLParser::XMLTreeParser.new assert_equal(@expected3, p.parseMethodResponse(@xml3).inspect) end def test3_XMLStreamParser p = XMLRPC::XMLParser::XMLStreamParser.new assert_equal(@expected3, p.parseMethodResponse(@xml3).inspect) end def test3_NQXMLTreeParser p = XMLRPC::XMLParser::NQXMLTreeParser.new assert_equal(@expected3, p.parseMethodResponse(@xml3).inspect) end def test3_NQXMLStreamParser p = XMLRPC::XMLParser::NQXMLStreamParser.new assert_equal(@expected3, p.parseMethodResponse(@xml3).inspect) end # ---------------------------------------------------------- # bug (in StreamParserMixin) found by covert, thaddeus on 02.11.2001 def test4_XMLTreeParser p = XMLRPC::XMLParser::XMLTreeParser.new assert_equal(@expected4, p.parseMethodResponse(@xml4).inspect) end def test4_XMLStreamParser p = XMLRPC::XMLParser::XMLStreamParser.new assert_equal(@expected4, p.parseMethodResponse(@xml4).inspect) end def test4_NQXMLTreeParser p = XMLRPC::XMLParser::NQXMLTreeParser.new assert_equal(@expected4, p.parseMethodResponse(@xml4).inspect) end def test4_NQXMLStreamParser p = XMLRPC::XMLParser::NQXMLStreamParser.new assert_equal(@expected4, p.parseMethodResponse(@xml4).inspect) end # ---------------------------------------------------------- def test_fault doc = File.readlines("files/fault.xml").to_s for parser in %w(XMLTreeParser XMLStreamParser NQXMLTreeParser NQXMLStreamParser) flag, fault = eval("XMLRPC::XMLParser::#{parser}.new").parseMethodResponse(doc) assert_equal(flag, false) unless fault.is_a? XMLRPC::FaultException assert(false, "must be an instance of class XMLRPC::FaultException") end assert_equal(fault.faultCode, 4) assert_equal(fault.faultString, "an error message") end end end xmlrpc4r-1_7_7/test/files/ 40755 1750 0 0 7377326627 14366 5ustar michaelwheelxmlrpc4r-1_7_7/test/files/bug_bool.expected100644 1750 0 16 7370476615 17727 0ustar michaelwheel[true, false] xmlrpc4r-1_7_7/test/files/bug_bool.xml100644 1750 0 223 7370476571 16747 0ustar michaelwheel 0 xmlrpc4r-1_7_7/test/files/bug_covert.expected100644 1750 0 245 7370100657 20310 0ustar michaelwheel[true, "Site,SANs,Array\nConfigured Capacity,Array Reserved Capacity,Array Ava\nilable Capacity,Array % Reserved,Host Allocated,Host Used,Host Free,Host %\nUsed\n"] xmlrpc4r-1_7_7/test/files/bug_covert.xml100644 1750 0 422 7370100657 17304 0ustar michaelwheelSite,SANs,Array Configured Capacity,Array Reserved Capacity,Array Ava ilable Capacity,Array % Reserved,Host Allocated,Host Used,Host Free,Host % Used xmlrpc4r-1_7_7/test/files/fault.xml100644 1750 0 531 7360602415 16257 0ustar michaelwheel faultCode 4 faultString an error message xmlrpc4r-1_7_7/test/files/value.expected100644 1750 0 64 7314071517 17244 0ustar michaelwheel["Test", ["Hallo Leute", " Hallo ", "", " "]] xmlrpc4r-1_7_7/test/files/value.xml100644 1750 0 527 7314071517 16267 0ustar michaelwheel Test Hallo Leute Hallo xmlrpc4r-1_7_7/test/files/xml1.expected100644 1750 0 12636 7311170372 17075 0ustar michaelwheel[true, [{"objectName"=>"AdministratorDO", "OID"=>"1", "telephone1"=>"1-508-791-1267", "email"=>"hbaker@yahoo.com", "adminId"=>"hbaker", "telephone2"=>"1-800-445-2588", "subscriber"=>"MegaCorp", "lastName"=>"Baker", "password"=>"p1111"}, {"objectName"=>"AdministratorDO", "OID"=>"3", "telephone1"=>"1-781-789-9089", "email"=>"adragon@yahoo.com", "adminId"=>"adragon", "telephone2"=>"1-800-445-2588", "subscriber"=>"CornerStore", "lastName"=>"Dragon", "password"=>"p3333"}, {"objectName"=>"AdministratorDO", "OID"=>"4", "telephone1"=>"1-617-789-1890", "email"=>"mrodman@yahoo.com", "adminId"=>"mrodman", "telephone2"=>"1-800-445-2588", "subscriber"=>"Cyberdyne", "lastName"=>"Rodman", "password"=>"p4444"}, {"objectName"=>"AdministratorDO", "OID"=>"5", "telephone1"=>"1-617-890-7897", "email"=>"mjordan@yahoo.com", "adminId"=>"mjordan", "telephone2"=>"1-800-445-2588", "subscriber"=>"StarSports", "lastName"=>"Jordan", "password"=>"p5555"}, {"objectName"=>"AdministratorDO", "OID"=>"6", "telephone1"=>"1-781-789-9876", "email"=>"gpippen@yahoo.com", "adminId"=>"gpippen", "telephone2"=>"1-800-445-2588", "subscriber"=>"GreatBooks", "lastName"=>"Pippen", "password"=>"p6666"}, {"objectName"=>"AdministratorDO", "OID"=>"7", "telephone1"=>"1-781-678-8970", "email"=>"aandrew@yahoo.com", "adminId"=>"aandrew", "telephone2"=>"1-800-445-2588", "subscriber"=>"AxisChemicals", "lastName"=>"Andhrew", "password"=>"p7777"}, {"objectName"=>"AdministratorDO", "OID"=>"8", "telephone1"=>"1-786-897-8908", "email"=>"tvincent@yahoo.com", "adminId"=>"tvincent", "telephone2"=>"1-800-445-2588", "subscriber"=>"MediaShop", "lastName"=>"Vincent", "password"=>"p8888"}, {"objectName"=>"AdministratorDO", "OID"=>"9", "telephone1"=>"1-508-789-6789", "email"=>"krichard@yahoo.com", "adminId"=>"krichard", "telephone2"=>"1-800-445-2588", "subscriber"=>"SmartShop", "lastName"=>"Richard", "password"=>"p9999"}, {"objectName"=>"AdministratorDO", "OID"=>"10", "telephone1"=>"1-617-789-8979", "email"=>"gconell@yahoo.com", "adminId"=>"gcornell", "telephone2"=>"1-800-445-2588", "subscriber"=>"HomeNeeds", "lastName"=>"Cornell", "password"=>"paaaa"}, {"objectName"=>"AdministratorDO", "OID"=>"11", "telephone1"=>"1-508-791-1267", "email"=>"shorstmann@yahoo.com", "adminId"=>"shorstmann", "telephone2"=>"1-800-445-2588", "subscriber"=>"MegaCorp", "lastName"=>"HorstMann", "password"=>"p1111"}, {"objectName"=>"AdministratorDO", "OID"=>"13", "telephone1"=>"1-781-789-9089", "email"=>"rbob@yahoo.com", "adminId"=>"rbob", "telephone2"=>"1-800-445-2588", "subscriber"=>"CornerStore", "lastName"=>"Bob", "password"=>"p3333"}, {"objectName"=>"AdministratorDO", "OID"=>"14", "telephone1"=>"1-617-789-1890", "email"=>"speter@yahoo.com", "adminId"=>"speter", "telephone2"=>"1-800-445-2588", "subscriber"=>"Cyberdyne", "lastName"=>"Peter", "password"=>"p4444"}, {"objectName"=>"AdministratorDO", "OID"=>"15", "telephone1"=>"1-617-890-7897", "email"=>"pnovak@yahoo.com", "adminId"=>"pnovak", "telephone2"=>"1-800-445-2588", "subscriber"=>"StarSports", "lastName"=>"Novak", "password"=>"p5555"}, {"objectName"=>"AdministratorDO", "OID"=>"16", "telephone1"=>"1-781-789-9876", "email"=>"pnancy@yahoo.com", "adminId"=>"pnancy", "telephone2"=>"1-800-445-2588", "subscriber"=>"GreatBooks", "lastName"=>"Nancy", "password"=>"p6666"}, {"objectName"=>"AdministratorDO", "OID"=>"17", "telephone1"=>"1-781-678-8970", "email"=>"hmichel@yahoo.com", "adminId"=>"hmichel", "telephone2"=>"1-800-445-2588", "subscriber"=>"AxisChemicals", "lastName"=>"Michel", "password"=>"p7777"}, {"objectName"=>"AdministratorDO", "OID"=>"18", "telephone1"=>"1-786-897-8908", "email"=>"kdavid@yahoo.com", "adminId"=>"kdavid", "telephone2"=>"1-800-445-2588", "subscriber"=>"MediaShop", "lastName"=>"David", "password"=>"p8888"}, {"objectName"=>"AdministratorDO", "OID"=>"19", "telephone1"=>"1-508-789-6789", "email"=>"pvalnoor@yahoo.com", "adminId"=>"pvalnoor", "telephone2"=>"1-800-445-2588", "subscriber"=>"SmartShop", "lastName"=>"Valnoor", "password"=>"p9999"}, {"objectName"=>"AdministratorDO", "OID"=>"20", "telephone1"=>"1-617-789-8979", "email"=>"wsmith@yahoo.com", "adminId"=>"wsmith", "telephone2"=>"1-800-445-2588", "subscriber"=>"HomeNeeds", "lastName"=>"Smith", "password"=>"paaaa"}, {"objectName"=>"AdministratorDO", "OID"=>"21", "telephone1"=>"1-781-789-9876", "email"=>"gcaral@yahoo.com", "adminId"=>"gcaral", "telephone2"=>"1-800-445-2588", "subscriber"=>"MegaCorp", "lastName"=>"Caral", "password"=>"p6666"}, {"objectName"=>"AdministratorDO", "OID"=>"23", "telephone1"=>"1-786-897-8908", "email"=>"phillary@yahoo.com", "adminId"=>"phillary", "telephone2"=>"1-800-445-2588", "subscriber"=>"CornerStore", "lastName"=>"Hillary", "password"=>"p8888"}, {"objectName"=>"AdministratorDO", "OID"=>"24", "telephone1"=>"1-508-789-6789", "email"=>"bphilip@yahoo.com", "adminId"=>"bphilip", "telephone2"=>"1-800-445-2588", "subscriber"=>"Cyberdyne", "lastName"=>"Philip", "password"=>"p9999"}, {"objectName"=>"AdministratorDO", "OID"=>"25", "telephone1"=>"1-617-789-8979", "email"=>"sandrea@yahoo.com", "adminId"=>"sandrea", "telephone2"=>"1-800-445-2588", "subscriber"=>"StarSports", "lastName"=>"Andrea", "password"=>"paaaa"}, {"objectName"=>"AdministratorDO", "OID"=>"26", "telephone1"=>"null", "email"=>"null", "adminId"=>"s4", "telephone2"=>"null", "subscriber"=>"s4", "lastName"=>"null", "password"=>"s4"}, {"objectName"=>"AdministratorDO", "OID"=>"82", "telephone1"=>"", "email"=>"", "adminId"=>"admin", "telephone2"=>"", "subscriber"=>"BigBank", "lastName"=>"administrator", "password"=>"admin"}]]xmlrpc4r-1_7_7/test/files/xml1.xml100644 1750 0 34066 7311170372 16075 0ustar michaelwheelobjectNameAdministratorDOadminIdhbakeremailhbaker@yahoo.comtelephone21-800-445-2588telephone11-508-791-1267OID1passwordp1111lastNameBakersubscriberMegaCorpobjectNameAdministratorDOadminIdadragonemailadragon@yahoo.comtelephone21-800-445-2588telephone11-781-789-9089OID3passwordp3333lastNameDragonsubscriberCornerStoreobjectNameAdministratorDOadminIdmrodmanemailmrodman@yahoo.comtelephone21-800-445-2588telephone11-617-789-1890OID4passwordp4444lastNameRodmansubscriberCyberdyneobjectNameAdministratorDOadminIdmjordanemailmjordan@yahoo.comtelephone21-800-445-2588telephone11-617-890-7897OID5passwordp5555lastNameJordansubscriberStarSportsobjectNameAdministratorDOadminIdgpippenemailgpippen@yahoo.comtelephone21-800-445-2588telephone11-781-789-9876OID6passwordp6666lastNamePippensubscriberGreatBooksobjectNameAdministratorDOadminIdaandrewemailaandrew@yahoo.comtelephone21-800-445-2588telephone11-781-678-8970OID7passwordp7777lastNameAndhrewsubscriberAxisChemicalsobjectNameAdministratorDOadminIdtvincentemailtvincent@yahoo.comtelephone21-800-445-2588telephone11-786-897-8908OID8passwordp8888lastNameVincentsubscriberMediaShopobjectNameAdministratorDOadminIdkrichardemailkrichard@yahoo.comtelephone21-800-445-2588telephone11-508-789-6789OID9passwordp9999lastNameRichardsubscriberSmartShopobjectNameAdministratorDOadminIdgcornellemailgconell@yahoo.comtelephone21-800-445-2588telephone11-617-789-8979OID10passwordpaaaalastNameCornellsubscriberHomeNeedsobjectNameAdministratorDOadminIdshorstmannemailshorstmann@yahoo.comtelephone21-800-445-2588telephone11-508-791-1267OID11passwordp1111lastNameHorstMannsubscriberMegaCorpobjectNameAdministratorDOadminIdrbobemailrbob@yahoo.comtelephone21-800-445-2588telephone11-781-789-9089OID13passwordp3333lastNameBobsubscriberCornerStoreobjectNameAdministratorDOadminIdspeteremailspeter@yahoo.comtelephone21-800-445-2588telephone11-617-789-1890OID14passwordp4444lastNamePetersubscriberCyberdyneobjectNameAdministratorDOadminIdpnovakemailpnovak@yahoo.comtelephone21-800-445-2588telephone11-617-890-7897OID15passwordp5555lastNameNovaksubscriberStarSportsobjectNameAdministratorDOadminIdpnancyemailpnancy@yahoo.comtelephone21-800-445-2588telephone11-781-789-9876OID16passwordp6666lastNameNancysubscriberGreatBooksobjectNameAdministratorDOadminIdhmichelemailhmichel@yahoo.comtelephone21-800-445-2588telephone11-781-678-8970OID17passwordp7777lastNameMichelsubscriberAxisChemicalsobjectNameAdministratorDOadminIdkdavidemailkdavid@yahoo.comtelephone21-800-445-2588telephone11-786-897-8908OID18passwordp8888lastNameDavidsubscriberMediaShopobjectNameAdministratorDOadminIdpvalnooremailpvalnoor@yahoo.comtelephone21-800-445-2588telephone11-508-789-6789OID19passwordp9999lastNameValnoorsubscriberSmartShopobjectNameAdministratorDOadminIdwsmithemailwsmith@yahoo.comtelephone21-800-445-2588telephone11-617-789-8979OID20passwordpaaaalastNameSmithsubscriberHomeNeedsobjectNameAdministratorDOadminIdgcaralemailgcaral@yahoo.comtelephone21-800-445-2588telephone11-781-789-9876OID21passwordp6666lastNameCaralsubscriberMegaCorpobjectNameAdministratorDOadminIdphillaryemailphillary@yahoo.comtelephone21-800-445-2588telephone11-786-897-8908OID23passwordp8888lastNameHillarysubscriberCornerStoreobjectNameAdministratorDOadminIdbphilipemailbphilip@yahoo.comtelephone21-800-445-2588telephone11-508-789-6789OID24passwordp9999lastNamePhilipsubscriberCyberdyneobjectNameAdministratorDOadminIdsandreaemailsandrea@yahoo.comtelephone21-800-445-2588telephone11-617-789-8979OID25passwordpaaaalastNameAndreasubscriberStarSportsobjectNameAdministratorDOadminIds4emailnulltelephone2nulltelephone1nullOID26passwords4lastNamenullsubscribers4objectNameAdministratorDOadminIdadminemailtelephone2telephone1OID82passwordadminlastNameadministratorsubscriberBigBank