* lib/xmlrpc.rb, lib/xmlrpc/*, test/xmlrpc: XMLRPC is bundled gem

on Ruby 2.4. [Feature #12160][ruby-core:74239]
* gems/bundled_gems: ditto.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@55013 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
hsbt 2016-05-16 02:41:11 +00:00
Родитель b14c93e6ca
Коммит e2bb529c8f
34 изменённых файлов: 8 добавлений и 4418 удалений

Просмотреть файл

@ -1,3 +1,10 @@
Mon May 16 11:39:02 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
* lib/xmlrpc.rb, lib/xmlrpc/*, test/xmlrpc: XMLRPC is bundled gem
on Ruby 2.4. It is extracted to https://github.com/ruby/xmlrpc
[Feature #12160][ruby-core:74239]
* gems/bundled_gems: ditto.
Mon May 16 06:06:21 2016 Eric Wong <e@80x24.org>
* proc.c: fix RDoc of Proc#===/call/yield/[]

Просмотреть файл

@ -4,3 +4,4 @@ minitest 5.8.4
rake 11.1.2
net-telnet 0.1.1
did_you_mean 1.0.0
xmlrpc 0.1.0

Просмотреть файл

@ -1,291 +0,0 @@
# frozen_string_literal: false
# == Author and Copyright
#
# Copyright (C) 2001-2004 by Michael Neumann (mailto:mneumann@ntecs.de)
#
# Released under the same term of license as Ruby.
#
# == Overview
#
# XMLRPC is a lightweight protocol that enables remote procedure calls over
# HTTP. It is defined at http://www.xmlrpc.com.
#
# XMLRPC allows you to create simple distributed computing solutions that span
# computer languages. Its distinctive feature is its simplicity compared to
# other approaches like SOAP and CORBA.
#
# The Ruby standard library package 'xmlrpc' enables you to create a server that
# implements remote procedures and a client that calls them. Very little code
# is required to achieve either of these.
#
# == Example
#
# Try the following code. It calls a standard demonstration remote procedure.
#
# require 'xmlrpc/client'
# require 'pp'
#
# server = XMLRPC::Client.new2("http://xmlrpc-c.sourceforge.net/api/sample.php")
# result = server.call("sample.sumAndDifference", 5, 3)
# pp result
#
# == Documentation
#
# See http://www.ntecs.de/ruby/xmlrpc4r/. There is plenty of detail there to
# use the client and implement a server.
#
# == Features of XMLRPC for Ruby
#
# * Extensions
# * Introspection
# * multiCall
# * optionally nil values and integers larger than 32 Bit
#
# * Server
# * Standalone XML-RPC server
# * CGI-based (works with FastCGI)
# * Apache mod_ruby server
# * WEBrick servlet
#
# * Client
# * synchronous/asynchronous calls
# * Basic HTTP-401 Authentication
# * HTTPS protocol (SSL)
#
# * Parsers
# * REXML (XMLParser::REXMLStreamParser)
# * Not compiled (pure ruby)
# * See ruby standard library
# * libxml (LibXMLStreamParser)
# * Compiled
# * See https://rubygems.org/gems/libxml-ruby/
#
# * General
# * possible to choose between XMLParser module (Expat wrapper) and REXML (pure Ruby) parsers
# * Marshalling Ruby objects to Hashes and reconstruct them later from a Hash
# * SandStorm component architecture XMLRPC::Client interface
#
# == Howto
#
# === Client
#
# require "xmlrpc/client"
#
# # Make an object to represent the XML-RPC server.
# server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
#
# # Call the remote server and get our result
# result = server.call("sample.sumAndDifference", 5, 3)
#
# sum = result["sum"]
# difference = result["difference"]
#
# puts "Sum: #{sum}, Difference: #{difference}"
#
# === XMLRPC::Client with XML-RPC fault-structure handling
#
# There are two possible ways, of handling a fault-structure:
#
# ==== by catching a XMLRPC::FaultException exception
#
# require "xmlrpc/client"
#
# # Make an object to represent the XML-RPC server.
# server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
#
# begin
# # Call the remote server and get our result
# result = server.call("sample.sumAndDifference", 5, 3)
#
# sum = result["sum"]
# difference = result["difference"]
#
# puts "Sum: #{sum}, Difference: #{difference}"
#
# rescue XMLRPC::FaultException => e
# puts "Error: "
# puts e.faultCode
# puts e.faultString
# end
#
# ==== by calling "call2" which returns a boolean
#
# require "xmlrpc/client"
#
# # Make an object to represent the XML-RPC server.
# server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
#
# # Call the remote server and get our result
# ok, result = server.call2("sample.sumAndDifference", 5, 3)
#
# if ok
# sum = result["sum"]
# difference = result["difference"]
#
# puts "Sum: #{sum}, Difference: #{difference}"
# else
# puts "Error: "
# puts result.faultCode
# puts result.faultString
# end
#
# === Using XMLRPC::Client::Proxy
#
# You can create a Proxy object onto which you can call methods. This way it
# looks nicer. Both forms, _call_ and _call2_ are supported through _proxy_ and
# _proxy2_. You can additionally give arguments to the Proxy, which will be
# given to each XML-RPC call using that Proxy.
#
# require "xmlrpc/client"
#
# # Make an object to represent the XML-RPC server.
# server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
#
# # Create a Proxy object
# sample = server.proxy("sample")
#
# # Call the remote server and get our result
# result = sample.sumAndDifference(5,3)
#
# sum = result["sum"]
# difference = result["difference"]
#
# puts "Sum: #{sum}, Difference: #{difference}"
#
# === CGI-based server using XMLRPC::CGIServer
#
# There are also two ways to define handler, the first is
# like C/PHP, the second like Java, of course both ways
# can be mixed:
#
# ==== C/PHP-like (handler functions)
#
# require "xmlrpc/server"
#
# s = XMLRPC::CGIServer.new
#
# s.add_handler("sample.sumAndDifference") do |a,b|
# { "sum" => a + b, "difference" => a - b }
# end
#
# s.serve
#
# ==== Java-like (handler classes)
#
# require "xmlrpc/server"
#
# s = XMLRPC::CGIServer.new
#
# class MyHandler
# def sumAndDifference(a, b)
# { "sum" => a + b, "difference" => a - b }
# end
# end
#
# # NOTE: Security Hole (read below)!!!
# s.add_handler("sample", MyHandler.new)
# s.serve
#
#
# To return a fault-structure you have to raise an XMLRPC::FaultException e.g.:
#
# raise XMLRPC::FaultException.new(3, "division by Zero")
#
# ===== Security Note
#
# From Brian Candler:
#
# Above code sample has an extremely nasty security hole, in that you can now call
# any method of 'MyHandler' remotely, including methods inherited from Object
# and Kernel! For example, in the client code, you can use
#
# puts server.call("sample.send","`","ls")
#
# (backtick being the method name for running system processes). Needless to
# say, 'ls' can be replaced with something else.
#
# The version which binds proc objects (or the version presented below in the next section)
# doesn't have this problem, but people may be tempted to use the second version because it's
# so nice and 'Rubyesque'. I think it needs a big red disclaimer.
#
#
# From Michael:
#
# A solution is to undef insecure methods or to use
# XMLRPC::Service::PublicInstanceMethodsInterface as shown below:
#
# class MyHandler
# def sumAndDifference(a, b)
# { "sum" => a + b, "difference" => a - b }
# end
# end
#
# # ... server initialization ...
#
# s.add_handler(XMLRPC::iPIMethods("sample"), MyHandler.new)
#
# # ...
#
# This adds only public instance methods explicitly declared in class MyHandler
# (and not those inherited from any other class).
#
# ==== With interface declarations
#
# Code sample from the book Ruby Developer's Guide:
#
# require "xmlrpc/server"
#
# class Num
# INTERFACE = XMLRPC::interface("num") {
# meth 'int add(int, int)', 'Add two numbers', 'add'
# meth 'int div(int, int)', 'Divide two numbers'
# }
#
# def add(a, b) a + b end
# def div(a, b) a / b end
# end
#
#
# s = XMLRPC::CGIServer.new
# s.add_handler(Num::INTERFACE, Num.new)
# s.serve
#
# === Standalone XMLRPC::Server
#
# Same as CGI-based server, the only difference being
#
# server = XMLRPC::CGIServer.new
#
# must be changed to
#
# server = XMLRPC::Server.new(8080)
#
# if you want a server listening on port 8080.
# The rest is the same.
#
# === Choosing a different XMLParser or XMLWriter
#
# The examples above all use the default parser (which is now since 1.8
# XMLParser::REXMLStreamParser) and a default XMLRPC::XMLWriter.
# If you want to use a different XMLParser, then you have to call the
# ParserWriterChooseMixin#set_parser method of XMLRPC::Client instances
# or instances of subclasses of XMLRPC::BasicServer or by editing
# xmlrpc/config.rb.
#
# XMLRPC::Client Example:
#
# # ...
# server = XMLRPC::Client.new( "xmlrpc-c.sourceforge.net", "/api/sample.php")
# server.set_parser(XMLRPC::XMLParser::XMLParser.new)
# # ...
#
# XMLRPC::Server Example:
#
# # ...
# s = XMLRPC::CGIServer.new
# s.set_parser(XMLRPC::XMLParser::XMLParser.new)
# # ...
#
#
# You can change the XML-writer by calling method ParserWriterChooseMixin#set_writer.
module XMLRPC; end

Просмотреть файл

@ -1,63 +0,0 @@
# frozen_string_literal: false
#
# xmlrpc/base64.rb
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# Released under the same term of license as Ruby.
module XMLRPC # :nodoc:
# This class is necessary for 'xmlrpc4r' to determine that a string should
# be transmitted base64-encoded and not as a raw-string.
#
# You can use XMLRPC::Base64 on the client and server-side as a
# parameter and/or return-value.
class Base64
# Creates a new XMLRPC::Base64 instance with string +str+ as the
# internal string. When +state+ is +:dec+ it assumes that the
# string +str+ is not in base64 format (perhaps already decoded),
# otherwise if +state+ is +:enc+ it decodes +str+
# and stores it as the internal string.
def initialize(str, state = :dec)
case state
when :enc
@str = Base64.decode(str)
when :dec
@str = str
else
raise ArgumentError, "wrong argument; either :enc or :dec"
end
end
# Returns the decoded internal string.
def decoded
@str
end
# Returns the base64 encoded internal string.
def encoded
Base64.encode(@str)
end
# Decodes string +str+ with base64 and returns that value.
def Base64.decode(str)
str.gsub(/\s+/, "").unpack("m")[0]
end
# Encodes string +str+ with base64 and returns that value.
def Base64.encode(str)
[str].pack("m")
end
end
end # module XMLRPC
=begin
= History
$Id$
=end

Просмотреть файл

@ -1,629 +0,0 @@
# frozen_string_literal: false
# xmlrpc/client.rb
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# Released under the same term of license as Ruby.
#
# History
# $Id$
#
require "xmlrpc/parser"
require "xmlrpc/create"
require "xmlrpc/config"
require "xmlrpc/utils" # ParserWriterChooseMixin
require "net/http"
require "uri"
module XMLRPC # :nodoc:
# Provides remote procedure calls to a XML-RPC server.
#
# After setting the connection-parameters with XMLRPC::Client.new which
# creates a new XMLRPC::Client instance, you can execute a remote procedure
# by sending the XMLRPC::Client#call or XMLRPC::Client#call2
# message to this new instance.
#
# The given parameters indicate which method to call on the remote-side and
# of course the parameters for the remote procedure.
#
# require "xmlrpc/client"
#
# server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
# begin
# param = server.call("michael.add", 4, 5)
# puts "4 + 5 = #{param}"
# rescue XMLRPC::FaultException => e
# puts "Error:"
# puts e.faultCode
# puts e.faultString
# end
#
# or
#
# require "xmlrpc/client"
#
# server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
# ok, param = server.call2("michael.add", 4, 5)
# if ok then
# puts "4 + 5 = #{param}"
# else
# puts "Error:"
# puts param.faultCode
# puts param.faultString
# end
class Client
USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})"
include ParserWriterChooseMixin
include ParseContentType
# Creates an object which represents the remote XML-RPC server on the
# given +host+. If the server is CGI-based, +path+ is the
# path to the CGI-script, which will be called, otherwise (in the
# case of a standalone server) +path+ should be <tt>"/RPC2"</tt>.
# +port+ is the port on which the XML-RPC server listens.
#
# If +proxy_host+ is given, then a proxy server listening at
# +proxy_host+ is used. +proxy_port+ is the port of the
# proxy server.
#
# Default values for +host+, +path+ and +port+ are 'localhost', '/RPC2' and
# '80' respectively using SSL '443'.
#
# If +user+ and +password+ are given, each time a request is sent,
# an Authorization header is sent. Currently only Basic Authentication is
# implemented, no Digest.
#
# If +use_ssl+ is set to +true+, communication over SSL is enabled.
#
# Parameter +timeout+ is the time to wait for a XML-RPC response, defaults to 30.
def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil,
user=nil, password=nil, use_ssl=nil, timeout=nil)
@http_header_extra = nil
@http_last_response = nil
@cookie = 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
@http = net_http(@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
class << self
# Creates an object which represents the remote XML-RPC server at the
# given +uri+. The URI should have a host, port, path, user and password.
# Example: https://user:password@host:port/path
#
# Raises an ArgumentError if the +uri+ is invalid,
# or if the protocol isn't http or https.
#
# If a +proxy+ is given it should be in the form of "host:port".
#
# The optional +timeout+ defaults to 30 seconds.
def new2(uri, proxy=nil, timeout=nil)
begin
url = URI(uri)
rescue URI::InvalidURIError => e
raise ArgumentError, e.message, e.backtrace
end
unless URI::HTTP === url
raise ArgumentError, "Wrong protocol specified. Only http or https allowed!"
end
proto = url.scheme
user = url.user
passwd = url.password
host = url.host
port = url.port
path = url.path.empty? ? nil : url.request_uri
proxy_host, proxy_port = (proxy || "").split(":")
proxy_port = proxy_port.to_i if proxy_port
self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout)
end
alias new_from_uri new2
# Receives a Hash and calls XMLRPC::Client.new
# with the corresponding values.
#
# The +hash+ parameter has following case-insensitive keys:
# * host
# * path
# * port
# * proxy_host
# * proxy_port
# * user
# * password
# * use_ssl
# * timeout
def new3(hash={})
# convert all keys into lowercase strings
h = {}
hash.each { |k,v| h[k.to_s.downcase] = v }
self.new(h['host'], h['path'], h['port'], h['proxy_host'], h['proxy_port'], h['user'], h['password'],
h['use_ssl'], h['timeout'])
end
alias new_from_hash new3
end
# Returns the Net::HTTP object for the client. If you want to
# change HTTP client options except header, cookie, timeout,
# user and password, use Net::HTTP directly.
#
# Since 2.1.0.
attr_reader :http
# Add additional HTTP headers to the request
attr_accessor :http_header_extra
# Returns the Net::HTTPResponse object of the last RPC.
attr_reader :http_last_response
# Get and set the HTTP Cookie header.
attr_accessor :cookie
# Return the corresponding attributes.
attr_reader :timeout, :user, :password
# Sets the Net::HTTP#read_timeout and Net::HTTP#open_timeout to
# +new_timeout+
def timeout=(new_timeout)
@timeout = new_timeout
@http.read_timeout = @timeout
@http.open_timeout = @timeout
end
# Changes the user for the Basic Authentication header to +new_user+
def user=(new_user)
@user = new_user
set_auth
end
# Changes the password for the Basic Authentication header to
# +new_password+
def password=(new_password)
@password = new_password
set_auth
end
# Invokes the method named +method+ with the parameters given by
# +args+ on the XML-RPC server.
#
# The +method+ parameter is converted into a String and should
# be a valid XML-RPC method-name.
#
# Each parameter of +args+ must be of one of the following types,
# where Hash, Struct and Array can contain any of these listed _types_:
#
# * Fixnum, Bignum
# * TrueClass, FalseClass, +true+, +false+
# * String, Symbol
# * Float
# * Hash, Struct
# * Array
# * Date, Time, XMLRPC::DateTime
# * XMLRPC::Base64
# * A Ruby object which class includes XMLRPC::Marshallable
# (only if Config::ENABLE_MARSHALLING is +true+).
# That object is converted into a hash, with one additional key/value
# pair <code>___class___</code> which contains the class name
# for restoring that object later.
#
# The method returns the return-value from the Remote Procedure Call.
#
# The type of the return-value is one of the types shown above.
#
# A Bignum is only allowed when it fits in 32-bit. A XML-RPC
# +dateTime.iso8601+ type is always returned as a XMLRPC::DateTime object.
# Struct is never returned, only a Hash, the same for a Symbol, where as a
# String is always returned. XMLRPC::Base64 is returned as a String from
# xmlrpc4r version 1.6.1 on.
#
# If the remote procedure returned a fault-structure, then a
# XMLRPC::FaultException exception is raised, which has two accessor-methods
# +faultCode+ an Integer, and +faultString+ a String.
def call(method, *args)
ok, param = call2(method, *args)
if ok
param
else
raise param
end
end
# The difference between this method and XMLRPC::Client#call is, that
# this method will <b>NOT</b> raise a XMLRPC::FaultException exception.
#
# The method returns an array of two values. The first value indicates if
# the second value is +true+ or an XMLRPC::FaultException.
#
# Both are explained in XMLRPC::Client#call.
#
# Simple to remember: The "2" in "call2" denotes the number of values it returns.
def call2(method, *args)
request = create().methodCall(method, *args)
data = do_rpc(request, false)
parser().parseMethodResponse(data)
end
# Similar to XMLRPC::Client#call, however can be called concurrently and
# use a new connection for each request. In contrast to the corresponding
# method without the +_async+ suffix, which use connect-alive (one
# connection for all requests).
#
# Note, that you have to use Thread to call these methods concurrently.
# The following example calls two methods concurrently:
#
# Thread.new {
# p client.call_async("michael.add", 4, 5)
# }
#
# Thread.new {
# p client.call_async("michael.div", 7, 9)
# }
#
def call_async(method, *args)
ok, param = call2_async(method, *args)
if ok
param
else
raise param
end
end
# Same as XMLRPC::Client#call2, but can be called concurrently.
#
# See also XMLRPC::Client#call_async
def call2_async(method, *args)
request = create().methodCall(method, *args)
data = do_rpc(request, true)
parser().parseMethodResponse(data)
end
# You can use this method to execute several methods on a XMLRPC server
# which support the multi-call extension.
#
# s.multicall(
# ['michael.add', 3, 4],
# ['michael.sub', 4, 5]
# )
# # => [7, -1]
def multicall(*methods)
ok, params = multicall2(*methods)
if ok
params
else
raise params
end
end
# Same as XMLRPC::Client#multicall, but returns two parameters instead of
# raising an XMLRPC::FaultException.
#
# See XMLRPC::Client#call2
def multicall2(*methods)
gen_multicall(methods, false)
end
# Similar to XMLRPC::Client#multicall, however can be called concurrently and
# use a new connection for each request. In contrast to the corresponding
# method without the +_async+ suffix, which use connect-alive (one
# connection for all requests).
#
# Note, that you have to use Thread to call these methods concurrently.
# The following example calls two methods concurrently:
#
# Thread.new {
# p client.multicall_async("michael.add", 4, 5)
# }
#
# Thread.new {
# p client.multicall_async("michael.div", 7, 9)
# }
#
def multicall_async(*methods)
ok, params = multicall2_async(*methods)
if ok
params
else
raise params
end
end
# Same as XMLRPC::Client#multicall2, but can be called concurrently.
#
# See also XMLRPC::Client#multicall_async
def multicall2_async(*methods)
gen_multicall(methods, true)
end
# Returns an object of class XMLRPC::Client::Proxy, initialized with
# +prefix+ and +args+.
#
# A proxy object returned by this method behaves like XMLRPC::Client#call,
# i.e. a call on that object will raise a XMLRPC::FaultException when a
# fault-structure is returned by that call.
def proxy(prefix=nil, *args)
Proxy.new(self, prefix, args, :call)
end
# Almost the same like XMLRPC::Client#proxy only that a call on the returned
# XMLRPC::Client::Proxy object will return two parameters.
#
# See XMLRPC::Client#call2
def proxy2(prefix=nil, *args)
Proxy.new(self, prefix, args, :call2)
end
# Similar to XMLRPC::Client#proxy, however can be called concurrently and
# use a new connection for each request. In contrast to the corresponding
# method without the +_async+ suffix, which use connect-alive (one
# connection for all requests).
#
# Note, that you have to use Thread to call these methods concurrently.
# The following example calls two methods concurrently:
#
# Thread.new {
# p client.proxy_async("michael.add", 4, 5)
# }
#
# Thread.new {
# p client.proxy_async("michael.div", 7, 9)
# }
#
def proxy_async(prefix=nil, *args)
Proxy.new(self, prefix, args, :call_async)
end
# Same as XMLRPC::Client#proxy2, but can be called concurrently.
#
# See also XMLRPC::Client#proxy_async
def proxy2_async(prefix=nil, *args)
Proxy.new(self, prefix, args, :call2_async)
end
private
def net_http(host, port, proxy_host, proxy_port)
Net::HTTP.new host, port, proxy_host, proxy_port
end
def dup_net_http
http = net_http(@http.address,
@http.port,
@http.proxy_address,
@http.proxy_port)
http.proxy_user = @http.proxy_user
http.proxy_pass = @http.proxy_pass
if @http.use_ssl?
http.use_ssl = true
Net::HTTP::SSL_ATTRIBUTES.each do |attribute|
http.__send__("#{attribute}=", @http.__send__(attribute))
end
end
http.read_timeout = @http.read_timeout
http.open_timeout = @http.open_timeout
http
end
def set_auth
if @user.nil?
@auth = nil
else
a = "#@user"
a << ":#@password" if @password != nil
@auth = "Basic " + [a].pack("m0")
end
end
def do_rpc(request, async=false)
header = {
"User-Agent" => USER_AGENT,
"Content-Type" => "text/xml; charset=utf-8",
"Content-Length" => request.bytesize.to_s,
"Connection" => (async ? "close" : "keep-alive")
}
header["Cookie"] = @cookie if @cookie
header.update(@http_header_extra) if @http_header_extra
if @auth != nil
# add authorization header
header["Authorization"] = @auth
end
resp = nil
@http_last_response = nil
if async
# use a new HTTP object for each call
http = dup_net_http
# post request
http.start {
resp = http.request_post(@path, request, header)
}
else
# reuse the HTTP object for each call => connection alive is possible
# we must start connection explicitly first time so that http.request
# does not assume that we don't want keepalive
@http.start if not @http.started?
# post request
resp = @http.request_post(@path, request, header)
end
@http_last_response = resp
data = resp.body
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
# assume text/xml on instances where Content-Type header is not set
ct_expected = resp["Content-Type"] || 'text/xml'
ct = parse_content_type(ct_expected).first
if ct != "text/xml"
if ct == "text/html"
raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}"
else
raise "Wrong content-type (received '#{ct}' but expected 'text/xml')"
end
end
expected = resp["Content-Length"] || "<unknown>"
if data.nil? or data.bytesize == 0
raise "Wrong size. Was #{data.bytesize}, should be #{expected}"
end
parse_set_cookies(resp.get_fields("Set-Cookie"))
return data
end
def parse_set_cookies(set_cookies)
return if set_cookies.nil?
return if set_cookies.empty?
require 'webrick/cookie'
pairs = {}
set_cookies.each do |set_cookie|
cookie = WEBrick::Cookie.parse_set_cookie(set_cookie)
pairs.delete(cookie.name)
pairs[cookie.name] = cookie.value
end
cookies = pairs.collect do |name, value|
WEBrick::Cookie.new(name, value).to_s
end
@cookie = cookies.join("; ")
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
# XML-RPC calls look nicer!
#
# You can call any method onto objects of that class - the object handles
# XMLRPC::Client::Proxy#method_missing and will forward the method call to
# a XML-RPC server.
#
# Don't use this class directly, instead use the public instance method
# XMLRPC::Client#proxy or XMLRPC::Client#proxy2.
#
# require "xmlrpc/client"
#
# server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
#
# michael = server.proxy("michael")
# michael2 = server.proxy("michael", 4)
#
# # both calls should return the same value '9'.
# p michael.add(4,5)
# p michael2.add(5)
class Proxy
# Creates an object which provides XMLRPC::Client::Proxy#method_missing.
#
# The given +server+ must be an instance of XMLRPC::Client, which is the
# XML-RPC server to be used for a XML-RPC call.
#
# +prefix+ and +delim+ will be prepended to the method name called onto this object.
#
# An optional parameter +meth+ is the method to use for a RPC.
# It can be either, call, call2, call_async, call2_async
#
# +args+ are arguments which are automatically given to every XML-RPC
# call before being provided through +method_missing+.
def initialize(server, prefix, args=[], meth=:call, delim=".")
@server = server
@prefix = prefix ? prefix + delim : ""
@args = args
@meth = meth
end
# Every method call is forwarded to the XML-RPC server defined in
# XMLRPC::Client::Proxy#new.
#
# Note: Inherited methods from class Object cannot be used as XML-RPC
# names, because they get around +method_missing+.
def method_missing(mid, *args)
pre = @prefix + mid.to_s
arg = @args + args
@server.send(@meth, pre, *arg)
end
end # class Proxy
end # class Client
end # module XMLRPC

Просмотреть файл

@ -1,39 +0,0 @@
# frozen_string_literal: false
#
# $Id$
# Configuration file for XML-RPC for Ruby
#
module XMLRPC # :nodoc:
module Config
# or XMLWriter::XMLParser
DEFAULT_WRITER = XMLWriter::Simple
# === Available parsers
#
# * XMLParser::REXMLStreamParser
# * XMLParser::LibXMLStreamParser
DEFAULT_PARSER = XMLParser::REXMLStreamParser
# enable <code><nil/></code> 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

Просмотреть файл

@ -1,287 +0,0 @@
# frozen_string_literal: false
#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# $Id$
#
require "date"
require "xmlrpc/base64"
module XMLRPC # :nodoc:
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)
"<?#{name} " + params.join(" ") + " ?>"
end
def element(name, attrs, *children)
raise "attributes not yet implemented" unless attrs.nil?
if children.empty?
"<#{name}/>"
else
"<#{name}>" + children.join("") + "</#{name}>"
end
end
def text(txt)
cleaned = txt.dup
cleaned.gsub!(/&/, '&amp;')
cleaned.gsub!(/</, '&lt;')
cleaned.gsub!(/>/, '&gt;')
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
Classes = [Simple, XMLParser]
# yields an instance of each installed XML writer
def self.each_installed_writer
XMLRPC::XMLWriter::Classes.each do |klass|
begin
yield klass.new
rescue LoadError
end
end
end
end # module XMLWriter
# Creates XML-RPC call/response documents
#
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
tree = @writer.document(
@writer.pi("xml", 'version="1.0"'),
@writer.ele("methodCall",
@writer.tag("methodName", name),
@writer.ele("params", *parameter)
)
)
@writer.document_to_str(tree) + "\n"
end
#
# Generates a XML-RPC methodResponse document
#
# When +is_ret+ is +false+ then the +params+ array must
# contain only one element, which is a structure
# of a fault return-value.
#
# When +is_ret+ is +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 <code><value></code> tag
#
def conv2value(param) # :doc:
val = case param
when Fixnum, Bignum
# XML-RPC's int is 32bit int, and Fixnum also may be beyond 32bit
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 Symbol
@writer.tag("string", param.to_s)
when String
@writer.tag("string", param)
when NilClass
if Config::ENABLE_NIL_CREATE
@writer.ele("nil")
else
raise "Wrong type NilClass. Not allowed!"
end
when Float
raise "Wrong value #{param}. Not allowed!" unless param.finite?
@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 Time, Date, ::DateTime
@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.instance_variables.each {|v|
name = v[1..-1]
val = param.instance_variable_get(v)
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

Просмотреть файл

@ -1,130 +0,0 @@
# frozen_string_literal: false
#
# xmlrpc/datetime.rb
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# Released under the same term of license as Ruby.
#
require "date"
module XMLRPC # :nodoc:
# This class is important to handle XMLRPC +dateTime.iso8601+ values,
# correctly, because normal UNIX-dates, ie: Date, only handle dates
# from year 1970 on, and ruby's native Time class handles dates without the
# time component.
#
# XMLRPC::DateTime is able to store a XMLRPC +dateTime.iso8601+ value correctly.
class DateTime
# Return the value of the specified date/time component.
attr_reader :year, :month, :day, :hour, :min, :sec
# Set +value+ as the new date/time component.
#
# Raises ArgumentError if the given +value+ is out of range, or in the case
# of XMLRPC::DateTime#year= if +value+ is not of type Integer.
def year= (value)
raise ArgumentError, "date/time out of range" unless value.is_a? Integer
@year = value
end
# Set +value+ as the new date/time component.
#
# Raises an ArgumentError if the given +value+ isn't between 1 and 12.
def month= (value)
raise ArgumentError, "date/time out of range" unless (1..12).include? value
@month = value
end
# Set +value+ as the new date/time component.
#
# Raises an ArgumentError if the given +value+ isn't between 1 and 31.
def day= (value)
raise ArgumentError, "date/time out of range" unless (1..31).include? value
@day = value
end
# Set +value+ as the new date/time component.
#
# Raises an ArgumentError if the given +value+ isn't between 0 and 24.
def hour= (value)
raise ArgumentError, "date/time out of range" unless (0..24).include? value
@hour = value
end
# Set +value+ as the new date/time component.
#
# Raises an ArgumentError if the given +value+ isn't between 0 and 59.
def min= (value)
raise ArgumentError, "date/time out of range" unless (0..59).include? value
@min = value
end
# Set +value+ as the new date/time component.
#
# Raises an ArgumentError if the given +value+ isn't between 0 and 59.
def sec= (value)
raise ArgumentError, "date/time out of range" unless (0..59).include? value
@sec = value
end
# Alias for XMLRPC::DateTime#month.
alias mon month
# Alias for XMLRPC::DateTime#month=.
alias mon= month=
# Creates a new XMLRPC::DateTime instance with the
# parameters +year+, +month+, +day+ as date and
# +hour+, +min+, +sec+ as time.
#
# Raises an ArgumentError if a parameter is out of range,
# or if +year+ is not of the Integer type.
def initialize(year, month, day, hour, min, sec)
self.year, self.month, self.day = year, month, day
self.hour, self.min, self.sec = hour, min, sec
end
# Return a Time object of the date/time which represents +self+.
# If the <code>@year</code> is below 1970, this method returns +nil+,
# because Time cannot handle years below 1970.
#
# The timezone used is GMT.
def to_time
if @year >= 1970
Time.gm(*to_a)
else
nil
end
end
# Return a Date object of the date which represents +self+.
#
# The Date object do _not_ contain the time component (only date).
def to_date
Date.new(*to_a[0,3])
end
# Returns all date/time components in an array.
#
# Returns +[year, month, day, hour, min, sec]+.
def to_a
[@year, @month, @day, @hour, @min, @sec]
end
# Returns whether or not all date/time components are an array.
def ==(o)
self.to_a == Array(o) rescue false
end
end
end # module XMLRPC
=begin
= History
$Id$
=end

Просмотреть файл

@ -1,67 +0,0 @@
# frozen_string_literal: false
#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# $Id$
#
require "xmlrpc/parser"
require "xmlrpc/create"
require "xmlrpc/config"
require "xmlrpc/utils"
module XMLRPC # :nodoc:
# Marshalling of XMLRPC::Create#methodCall and XMLRPC::Create#methodResponse
class Marshal
include ParserWriterChooseMixin
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
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 <code>[ methodname, params ]</code>
def load_call( stringOrReadable )
parser.parseMethodCall( stringOrReadable )
end
# Returns +paramOrFault+
def load_response( stringOrReadable )
parser.parseMethodResponse( stringOrReadable )[1]
end
end # class Marshal
end

Просмотреть файл

@ -1,642 +0,0 @@
# frozen_string_literal: false
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# $Id$
#
require "date"
require "xmlrpc/base64"
require "xmlrpc/datetime"
module XMLRPC # :nodoc:
# Raised when the remote procedure returns a fault-structure, which has two
# accessor-methods +faultCode+ an Integer, and +faultString+ a String.
class FaultException < StandardError
attr_reader :faultCode, :faultString
# Creates a new XMLRPC::FaultException instance.
#
# +faultString+ is passed to StandardError as the +msg+ of the Exception.
def initialize(faultCode, faultString)
@faultCode = faultCode
@faultString = faultString
super(@faultString)
end
# The +faultCode+ and +faultString+ of the exception in a Hash.
def to_h
{"faultCode" => @faultCode, "faultString" => @faultString}
end
end
# Helper class used to convert types.
module Convert
# Converts a String to an Integer
#
# See also String.to_i
def self.int(str)
str.to_i
end
# Converts a String to +true+ or +false+
#
# Raises an exception if +str+ is not +0+ or +1+
def self.boolean(str)
case str
when "0" then false
when "1" then true
else
raise "RPC-value of type boolean is wrong"
end
end
# Converts a String to a Float
#
# See also String.to_f
def self.double(str)
str.to_f
end
# Converts a the given +str+ to a +dateTime.iso8601+ formatted date.
#
# Raises an exception if the String isn't in +dateTime.iso8601+ format.
#
# See also, XMLRPC::DateTime
def self.dateTime(str)
case str
when /^(-?\d\d\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(?:Z|([+-])(\d\d):?(\d\d))?$/
a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i}
if $7
ofs = $8.to_i*3600 + $9.to_i*60
ofs = -ofs if $7=='+'
utc = Time.utc(*a) + ofs
a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ]
end
XMLRPC::DateTime.new(*a)
when /^(-?\d\d)-?(\d\d)-?(\d\d)T(\d\d):(\d\d):(\d\d)(Z|([+-]\d\d):(\d\d))?$/
a = [$1, $2, $3, $4, $5, $6].collect{|i| i.to_i}
if a[0] < 70
a[0] += 2000
else
a[0] += 1900
end
if $7
ofs = $8.to_i*3600 + $9.to_i*60
ofs = -ofs if $7=='+'
utc = Time.utc(*a) + ofs
a = [ utc.year, utc.month, utc.day, utc.hour, utc.min, utc.sec ]
end
XMLRPC::DateTime.new(*a)
else
raise "wrong dateTime.iso8601 format " + str
end
end
# Decodes the given +str+ using XMLRPC::Base64.decode
def self.base64(str)
XMLRPC::Base64.decode(str)
end
# Converts the given +hash+ to a marshalled object.
#
# Returns the given +hash+ if an exception occurs.
def self.struct(hash)
# convert to marshalled 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)}
obj = mod.allocate
hash.delete "___class___"
hash.each {|key, value|
obj.instance_variable_set("@#{ key }", value) if key =~ /^([a-zA-Z_]\w*)$/
}
obj
rescue
hash
end
end
end
# Converts the given +hash+ to an XMLRPC::FaultException object by passing
# the +faultCode+ and +faultString+ attributes of the Hash to
# XMLRPC::FaultException.new
#
# Raises an Exception if the given +hash+ doesn't meet the requirements.
# Those requirements being:
# * 2 keys
# * <code>'faultCode'</code> key is an Integer
# * <code>'faultString'</code> key is a String
def self.fault(hash)
if hash.kind_of? Hash and hash.size == 2 and
hash.has_key? "faultCode" and hash.has_key? "faultString" and
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
# Parser for XML-RPC call and response
module XMLParser
class AbstractTreeParser
def parseMethodResponse(str)
methodResponse_document(createCleanedTree(str))
end
def parseMethodCall(str)
methodCall_document(createCleanedTree(str))
end
private
# Removes all whitespaces but in the tags i4, i8, 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 i8 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 i8 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", "i8", "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 "Too 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", "i8", "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 = Convert.struct(@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 REXMLStreamParser < AbstractStreamParser
def initialize
require "rexml/document"
@parser_class = StreamListener
end
class StreamListener
include StreamParserMixin
alias :tag_start :startElement
alias :tag_end :endElement
alias :text :character
alias :cdata :character
def method_missing(*a)
# ignore
end
def parse(str)
REXML::Document.parse_stream(str, self)
end
end
end
class LibXMLStreamParser < AbstractStreamParser
def initialize
require 'libxml'
@parser_class = LibXMLStreamListener
end
class LibXMLStreamListener
include StreamParserMixin
def on_start_element_ns(name, attributes, prefix, uri, namespaces)
startElement(name)
end
def on_end_element_ns(name, prefix, uri)
endElement(name)
end
alias :on_characters :character
alias :on_cdata_block :character
def method_missing(*a)
end
def parse(str)
parser = LibXML::XML::SaxParser.string(str)
parser.callbacks = self
parser.parse()
end
end
end
Classes = [REXMLStreamParser, LibXMLStreamParser]
# yields an instance of each installed parser
def self.each_installed_parser
XMLRPC::XMLParser::Classes.each do |klass|
begin
yield klass.new
rescue LoadError
end
end
end
end # module XMLParser
end # module XMLRPC

Просмотреть файл

@ -1,708 +0,0 @@
# frozen_string_literal: false
# xmlrpc/server.rb
# Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de)
#
# Released under the same term of license as Ruby.
require "xmlrpc/parser"
require "xmlrpc/create"
require "xmlrpc/config"
require "xmlrpc/utils" # ParserWriterChooseMixin
module XMLRPC # :nodoc:
# This is the base class for all XML-RPC server-types (CGI, standalone).
# You can add handler and set a default handler.
# Do not use this server, as this is/should be an abstract class.
#
# === How the method to call is found
# The arity (number of accepted arguments) of a handler (method or Proc
# object) is compared to the given arguments submitted by the client for a
# RPC, or Remote Procedure Call.
#
# A handler is only called if it accepts the number of arguments, otherwise
# the search for another handler will go on. When at the end no handler was
# found, the default_handler, XMLRPC::BasicServer#set_default_handler will be
# called.
#
# With this technique it is possible to do overloading by number of parameters, but
# only for Proc handler, because you cannot define two methods of the same name in
# the same class.
class BasicServer
include ParserWriterChooseMixin
include ParseContentType
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
# Creates a new XMLRPC::BasicServer instance, which should not be
# done, because XMLRPC::BasicServer is an abstract class. This
# method should be called from a subclass indirectly by a +super+ call
# in the initialize method.
#
# The parameter +class_delim+ is used by add_handler, see
# XMLRPC::BasicServer#add_handler, when an object is added as a handler, to
# delimit the object-prefix and the method-name.
def initialize(class_delim=".")
@handler = []
@default_handler = nil
@service_hook = nil
@class_delim = class_delim
@create = nil
@parser = nil
add_multicall if Config::ENABLE_MULTICALL
add_introspection if Config::ENABLE_INTROSPECTION
end
# Adds +aBlock+ to the list of handlers, with +name+ as the name of
# the method.
#
# Parameters +signature+ and +help+ are used by the Introspection method if
# specified, where +signature+ is either an Array containing strings each
# representing a type of it's signature (the first is the return value) or
# an Array of Arrays if the method has multiple signatures.
#
# Value type-names are "int, boolean, double, string, dateTime.iso8601,
# base64, array, struct".
#
# Parameter +help+ is a String with information about how to call this method etc.
#
# When a method fails, it can tell the client by throwing an
# XMLRPC::FaultException like in this example:
#
# s.add_handler("michael.div") do |a,b|
# if b == 0
# raise XMLRPC::FaultException.new(1, "division by zero")
# else
# a / b
# end
# end
#
# In the case of <code>b==0</code> the client gets an object back of type
# XMLRPC::FaultException that has a +faultCode+ and +faultString+ field.
#
# This is the second form of ((<add_handler|XMLRPC::BasicServer#add_handler>)).
# To add an object write:
#
# server.add_handler("michael", MyHandlerClass.new)
#
# All public methods of MyHandlerClass are accessible to
# the XML-RPC clients by <code>michael."name of method"</code>. This is
# where the +class_delim+ in XMLRPC::BasicServer.new plays it's role, a
# XML-RPC method-name is defined by +prefix+ + +class_delim+ + <code>"name
# of method"</code>.
#
# The third form of +add_handler is to use XMLRPC::Service::Interface to
# generate an object, which represents an interface (with signature and
# help text) for a handler class.
#
# The +interface+ parameter must be an instance of XMLRPC::Service::Interface.
# Adds all methods of +obj+ which are defined in the +interface+ to the server.
#
# This is the recommended way of adding services to a server!
def add_handler(prefix, obj_or_signature=nil, help=nil, &block)
if block_given?
# proc-handler
@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
# Returns the service-hook, which is called on each service request (RPC)
# unless it's +nil+.
def get_service_hook
@service_hook
end
# A service-hook is called for each service request (RPC).
#
# You can use a service-hook for example to wrap existing methods and catch
# exceptions of them or convert values to values recognized by XMLRPC.
#
# You can disable it by passing +nil+ as the +handler+ parameter.
#
# The service-hook is called with a Proc object along with any parameters.
#
# An example:
#
# server.set_service_hook {|obj, *args|
# begin
# ret = obj.call(*args) # call the original service-method
# # could convert the return value
# rescue
# # rescue exceptions
# end
# }
#
def set_service_hook(&handler)
@service_hook = handler
self
end
# Returns the default-handler, which is called when no handler for
# a method-name is found.
#
# It is either a Proc object or +nil+.
def get_default_handler
@default_handler
end
# Sets +handler+ as the default-handler, which is called when
# no handler for a method-name is found.
#
# +handler+ is a code-block.
#
# The default-handler is called with the (XML-RPC) method-name as first
# argument, and the other arguments are the parameters given by the
# client-call.
#
# If no block is specified the default of XMLRPC::BasicServer is
# used, which raises a XMLRPC::FaultException saying "method missing".
def set_default_handler(&handler)
@default_handler = handler
self
end
# Adds the multi-call handler <code>"system.multicall"</code>.
def add_multicall
add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs|
unless arrStructs.is_a? Array
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
# Adds the introspection handlers <code>"system.listMethods"</code>,
# <code>"system.methodSignature"</code> and
# <code>"system.methodHelp"</code>, where only the first one works.
def add_introspection
add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do
methods = []
@handler.each do |name, obj|
if obj.kind_of? Proc
methods << name
else
obj.class.public_instance_methods(false).each do |meth|
methods << "#{name}#{meth}"
end
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
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 +n_args+
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
# Implements a CGI-based XML-RPC server.
#
# require "xmlrpc/server"
#
# s = XMLRPC::CGIServer.new
#
# s.add_handler("michael.add") do |a,b|
# a + b
# end
#
# s.add_handler("michael.div") do |a,b|
# if b == 0
# raise XMLRPC::FaultException.new(1, "division by zero")
# else
# a / b
# end
# end
#
# s.set_default_handler do |name, *args|
# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
# " or wrong number of parameters!")
# end
#
# s.serve
#
#
# <b>Note:</b> Make sure that you don't write to standard-output in a
# handler, or in any other part of your program, this would cause a CGI-based
# server to fail!
class CGIServer < BasicServer
@@obj = nil
# Creates a new XMLRPC::CGIServer instance.
#
# All parameters given are by-passed to XMLRPC::BasicServer.new.
#
# You can only create <b>one</b> XMLRPC::CGIServer instance, because more
# than one makes no sense.
def CGIServer.new(*a)
@@obj = super(*a) if @@obj.nil?
@@obj
end
def initialize(*a)
super(*a)
end
# Call this after you have added all you handlers to the server.
#
# This method processes a XML-RPC method call and sends the answer
# back to the client.
def serve
catch(:exit_serve) {
length = ENV['CONTENT_LENGTH'].to_i
http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST"
http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "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.bytesize != length
http_write(process(data), "Content-type" => "text/xml; charset=utf-8")
}
end
private
def http_error(status, message)
err = "#{status} #{message}"
msg = <<-"MSGEND"
<html>
<head>
<title>#{err}</title>
</head>
<body>
<h1>#{err}</h1>
<p>Unexpected error occurred while processing XML-RPC request!</p>
</body>
</html>
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.bytesize.to_s
str = ""
h.each {|key, value| str << "#{key}: #{value}\r\n"}
str << "\r\n#{body}"
print str
end
end
# Implements a XML-RPC server, which works with Apache mod_ruby.
#
# Use it in the same way as XMLRPC::CGIServer!
class ModRubyServer < BasicServer
# Creates a new XMLRPC::ModRubyServer instance.
#
# All parameters given are by-passed to XMLRPC::BasicServer.new.
def initialize(*a)
@ap = Apache::request
super(*a)
end
# Call this after you have added all you handlers to the server.
#
# This method processes a XML-RPC method call and sends the answer
# back to the client.
def serve
catch(:exit_serve) {
header = {}
@ap.headers_in.each {|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 parse_content_type(header['Content-type']).first == "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.bytesize != length
http_write(process(data), 200, "Content-type" => "text/xml; charset=utf-8")
}
end
private
def http_error(status, message)
err = "#{status} #{message}"
msg = <<-"MSGEND"
<html>
<head>
<title>#{err}</title>
</head>
<body>
<h1>#{err}</h1>
<p>Unexpected error occurred while processing XML-RPC request!</p>
</body>
</html>
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.bytesize.to_s
h.each {|key, value| @ap.headers_out[key] = value }
@ap.content_type = h["Content-type"]
@ap.status = status.to_i
@ap.send_http_header
@ap.print body
end
end
class WEBrickServlet < BasicServer; end # forward declaration
# Implements a standalone XML-RPC server. The method XMLRPC::Server#serve is
# left if a SIGHUP is sent to the program.
#
# require "xmlrpc/server"
#
# s = XMLRPC::Server.new(8080)
#
# s.add_handler("michael.add") do |a,b|
# a + b
# end
#
# s.add_handler("michael.div") do |a,b|
# if b == 0
# raise XMLRPC::FaultException.new(1, "division by zero")
# else
# a / b
# end
# end
#
# s.set_default_handler do |name, *args|
# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
# " or wrong number of parameters!")
# end
#
# s.serve
class Server < WEBrickServlet
# Creates a new XMLRPC::Server instance, which is a XML-RPC server
# listening on the given +port+ and accepts requests for the given +host+,
# which is +localhost+ by default.
#
# The server is not started, to start it you have to call
# XMLRPC::Server#serve.
#
# The optional +audit+ and +debug+ parameters are obsolete!
#
# All additionally provided parameters in <code>*a</code> are by-passed to
# XMLRPC::BasicServer.new.
def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a)
super(*a)
require 'webrick'
@server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections,
:Logger => WEBrick::Log.new(stdlog))
@server.mount("/", self)
end
# Call this after you have added all you handlers to the server.
# This method starts the server to listen for XML-RPC requests and answer them.
def serve
signals = %w[INT TERM HUP] & Signal.list.keys
signals.each { |signal| trap(signal) { @server.shutdown } }
@server.start
end
# Stops and shuts the server down.
def shutdown
@server.shutdown
end
end
# Implements a servlet for use with WEBrick, a pure Ruby (HTTP) server
# framework.
#
# require "webrick"
# require "xmlrpc/server"
#
# s = XMLRPC::WEBrickServlet.new
# s.add_handler("michael.add") do |a,b|
# a + b
# end
#
# s.add_handler("michael.div") do |a,b|
# if b == 0
# raise XMLRPC::FaultException.new(1, "division by zero")
# else
# a / b
# end
# end
#
# s.set_default_handler do |name, *args|
# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
# " or wrong number of parameters!")
# end
#
# httpserver = WEBrick::HTTPServer.new(:Port => 8080)
# httpserver.mount("/RPC2", s)
# trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows
# httpserver.start
class WEBrickServlet < BasicServer
def initialize(*a)
super
require "webrick/httpstatus"
@valid_ip = nil
end
# Deprecated from WEBrick/1.2.2, but does not break anything.
def require_path_info?
false
end
def get_instance(config, *options)
# TODO: set config & options
self
end
# Specifies the valid IP addresses that are allowed to connect to the server.
#
# Each IP is either a String or a Regexp.
def set_valid_ip(*ip_addr)
if ip_addr.size == 1 and ip_addr[0].nil?
@valid_ip = nil
else
@valid_ip = ip_addr
end
end
# Return the valid IP addresses that are allowed to connect to the server.
#
# See also, XMLRPC::Server#set_valid_ip
def get_valid_ip
@valid_ip
end
def service(request, response)
if @valid_ip
raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
end
if request.request_method != "POST"
raise WEBrick::HTTPStatus::MethodNotAllowed,
"unsupported method `#{request.request_method}'."
end
if parse_content_type(request['Content-type']).first != "text/xml"
raise WEBrick::HTTPStatus::BadRequest
end
length = (request['Content-length'] || 0).to_i
raise WEBrick::HTTPStatus::LengthRequired unless length > 0
data = request.body
if data.nil? or data.bytesize != length
raise WEBrick::HTTPStatus::BadRequest
end
resp = process(data)
if resp.nil? or resp.bytesize <= 0
raise WEBrick::HTTPStatus::InternalServerError
end
response.status = 200
response['Content-Length'] = resp.bytesize
response['Content-Type'] = "text/xml; charset=utf-8"
response.body = resp
end
end
end # module XMLRPC
=begin
= History
$Id$
=end

Просмотреть файл

@ -1,172 +0,0 @@
# frozen_string_literal: false
#
# Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
#
# $Id$
#
module XMLRPC # :nodoc:
# This module enables a user-class to be marshalled
# by XML-RPC for Ruby into a Hash, with one additional
# key/value pair <code>___class___ => ClassName</code>
#
module Marshallable
end
# Defines ParserWriterChooseMixin, which makes it possible to choose a
# different XMLWriter and/or XMLParser then the default one.
#
# The Mixin is used in client.rb (class XMLRPC::Client)
# and server.rb (class XMLRPC::BasicServer)
module ParserWriterChooseMixin
# Sets the XMLWriter to use for generating XML output.
#
# Should be an instance of a class from module XMLRPC::XMLWriter.
#
# If this method is not called, then XMLRPC::Config::DEFAULT_WRITER is used.
def set_writer(writer)
@create = Create.new(writer)
self
end
# Sets the XMLParser to use for parsing XML documents.
#
# Should be an instance of a class from module XMLRPC::XMLParser.
#
# If this method is not called, then XMLRPC::Config::DEFAULT_PARSER is used.
def set_parser(parser)
@parser = parser
self
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 XMLRPC::Service::Interface definitions, used
# by XMLRPC::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 XMLRPC::Service::Interface definition, used
# by XMLRPC::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.to_s, 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(false).collect { |name|
[prefix + name.to_s, obj.method(name).to_proc, nil, nil]
}
end
end
end # module Service
#
# Short-form to create a XMLRPC::Service::Interface
#
def self.interface(prefix, &p)
Service::Interface.new(prefix, &p)
end
# Short-cut for creating a XMLRPC::Service::PublicInstanceMethodsInterface
def self.iPIMethods(prefix)
Service::PublicInstanceMethodsInterface.new(prefix)
end
module ParseContentType
def parse_content_type(str)
a, *b = str.split(";")
return a.strip.downcase, *b
end
end
end # module XMLRPC

Просмотреть файл

@ -1,18 +0,0 @@
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<array><data>
<value><struct>
<member><name>isAdmin</name><value><boolean>1</boolean></value></member>
<member><name>url</name><value><string>http://tenderlovemaking.com/</string></value></member>
<member><name>blogid</name><value><string>1</string></value></member>
<member><name>blogName</name><value><string>Tender Lovemaking</string></value></member>
<member><name>xmlrpc</name><value><string>http://tenderlovemaking.com/xmlrpc.php</string></value></member>
</struct></value>
</data></array>
</value>
</param>
</params>
</methodResponse>

Просмотреть файл

@ -1,3 +0,0 @@
---
- true
- false

Просмотреть файл

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><boolean>0</boolean></value>
</param>
</params>
</methodResponse>

Просмотреть файл

@ -1,3 +0,0 @@
---
- true
- test

Просмотреть файл

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><string><![CDATA[test]]></string></value>
</param>
</params>
</methodResponse>

Просмотреть файл

@ -1,10 +0,0 @@
---
- true
- >
Site,SANs,Array
Configured Capacity,Array Reserved Capacity,Array Ava
ilable Capacity,Array % Reserved,Host Allocated,Host Used,Host Free,Host %
Used

Просмотреть файл

@ -1,6 +0,0 @@
<?xml version="1.0"
encoding="ISO-8859-1"?><methodResponse><params><param><value>Site,SANs,Array
Configured Capacity,Array Reserved Capacity,Array Ava
ilable Capacity,Array % Reserved,Host Allocated,Host Used,Host Free,Host %
Used
</value></param></params></methodResponse>

Просмотреть файл

@ -1,8 +0,0 @@
<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value><dateTime.iso8601>20041105T01:15:23Z</dateTime.iso8601></value>
</param>
</params>
</methodResponse>

Просмотреть файл

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<methodResponse>
<fault>
<value><struct>
<member>
<name>faultCode</name>
<value><int>4</int></value>
</member>
<member>
<name>faultString</name>
<value>an error message</value>
</member>
</struct></value>
</fault>
</methodResponse>

Просмотреть файл

@ -1,7 +0,0 @@
---
- Test
-
- Hallo Leute
- " Hallo "
- ''
- " "

Просмотреть файл

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<methodCall>
<methodName>Test</methodName>
<params>
<param>
<value>Hallo Leute</value>
</param>
<param>
<value> Hallo </value>
</param>
<param>
<value></value>
</param>
<param>
<value> </value>
</param>
</params>
</methodCall>

Просмотреть файл

@ -1,243 +0,0 @@
---
- true
-
-
subscriber: MegaCorp
lastName: Baker
telephone1: 1-508-791-1267
telephone2: 1-800-445-2588
password: p1111
OID: "1"
email: hbaker@yahoo.com
adminId: hbaker
objectName: AdministratorDO
-
subscriber: CornerStore
lastName: Dragon
telephone1: 1-781-789-9089
telephone2: 1-800-445-2588
password: p3333
OID: "3"
email: adragon@yahoo.com
adminId: adragon
objectName: AdministratorDO
-
subscriber: Cyberdyne
lastName: Rodman
telephone1: 1-617-789-1890
telephone2: 1-800-445-2588
password: p4444
OID: "4"
email: mrodman@yahoo.com
adminId: mrodman
objectName: AdministratorDO
-
subscriber: StarSports
lastName: Jordan
telephone1: 1-617-890-7897
telephone2: 1-800-445-2588
password: p5555
OID: "5"
email: mjordan@yahoo.com
adminId: mjordan
objectName: AdministratorDO
-
subscriber: GreatBooks
lastName: Pippen
telephone1: 1-781-789-9876
telephone2: 1-800-445-2588
password: p6666
OID: "6"
email: gpippen@yahoo.com
adminId: gpippen
objectName: AdministratorDO
-
subscriber: AxisChemicals
lastName: Andhrew
telephone1: 1-781-678-8970
telephone2: 1-800-445-2588
password: p7777
OID: "7"
email: aandrew@yahoo.com
adminId: aandrew
objectName: AdministratorDO
-
subscriber: MediaShop
lastName: Vincent
telephone1: 1-786-897-8908
telephone2: 1-800-445-2588
password: p8888
OID: "8"
email: tvincent@yahoo.com
adminId: tvincent
objectName: AdministratorDO
-
subscriber: SmartShop
lastName: Richard
telephone1: 1-508-789-6789
telephone2: 1-800-445-2588
password: p9999
OID: "9"
email: krichard@yahoo.com
adminId: krichard
objectName: AdministratorDO
-
subscriber: HomeNeeds
lastName: Cornell
telephone1: 1-617-789-8979
telephone2: 1-800-445-2588
password: paaaa
OID: "10"
email: gconell@yahoo.com
adminId: gcornell
objectName: AdministratorDO
-
subscriber: MegaCorp
lastName: HorstMann
telephone1: 1-508-791-1267
telephone2: 1-800-445-2588
password: p1111
OID: "11"
email: shorstmann@yahoo.com
adminId: shorstmann
objectName: AdministratorDO
-
subscriber: CornerStore
lastName: Bob
telephone1: 1-781-789-9089
telephone2: 1-800-445-2588
password: p3333
OID: "13"
email: rbob@yahoo.com
adminId: rbob
objectName: AdministratorDO
-
subscriber: Cyberdyne
lastName: Peter
telephone1: 1-617-789-1890
telephone2: 1-800-445-2588
password: p4444
OID: "14"
email: speter@yahoo.com
adminId: speter
objectName: AdministratorDO
-
subscriber: StarSports
lastName: Novak
telephone1: 1-617-890-7897
telephone2: 1-800-445-2588
password: p5555
OID: "15"
email: pnovak@yahoo.com
adminId: pnovak
objectName: AdministratorDO
-
subscriber: GreatBooks
lastName: Nancy
telephone1: 1-781-789-9876
telephone2: 1-800-445-2588
password: p6666
OID: "16"
email: pnancy@yahoo.com
adminId: pnancy
objectName: AdministratorDO
-
subscriber: AxisChemicals
lastName: Michel
telephone1: 1-781-678-8970
telephone2: 1-800-445-2588
password: p7777
OID: "17"
email: hmichel@yahoo.com
adminId: hmichel
objectName: AdministratorDO
-
subscriber: MediaShop
lastName: David
telephone1: 1-786-897-8908
telephone2: 1-800-445-2588
password: p8888
OID: "18"
email: kdavid@yahoo.com
adminId: kdavid
objectName: AdministratorDO
-
subscriber: SmartShop
lastName: Valnoor
telephone1: 1-508-789-6789
telephone2: 1-800-445-2588
password: p9999
OID: "19"
email: pvalnoor@yahoo.com
adminId: pvalnoor
objectName: AdministratorDO
-
subscriber: HomeNeeds
lastName: Smith
telephone1: 1-617-789-8979
telephone2: 1-800-445-2588
password: paaaa
OID: "20"
email: wsmith@yahoo.com
adminId: wsmith
objectName: AdministratorDO
-
subscriber: MegaCorp
lastName: Caral
telephone1: 1-781-789-9876
telephone2: 1-800-445-2588
password: p6666
OID: "21"
email: gcaral@yahoo.com
adminId: gcaral
objectName: AdministratorDO
-
subscriber: CornerStore
lastName: Hillary
telephone1: 1-786-897-8908
telephone2: 1-800-445-2588
password: p8888
OID: "23"
email: phillary@yahoo.com
adminId: phillary
objectName: AdministratorDO
-
subscriber: Cyberdyne
lastName: Philip
telephone1: 1-508-789-6789
telephone2: 1-800-445-2588
password: p9999
OID: "24"
email: bphilip@yahoo.com
adminId: bphilip
objectName: AdministratorDO
-
subscriber: StarSports
lastName: Andrea
telephone1: 1-617-789-8979
telephone2: 1-800-445-2588
password: paaaa
OID: "25"
email: sandrea@yahoo.com
adminId: sandrea
objectName: AdministratorDO
-
subscriber: s4
lastName: "null"
telephone1: "null"
telephone2: "null"
password: s4
OID: "26"
email: "null"
adminId: s4
objectName: AdministratorDO
-
subscriber: BigBank
lastName: administrator
telephone1: ''
telephone2: ''
password: admin
OID: "82"
email: ''
adminId: admin
objectName: AdministratorDO

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,2 +0,0 @@
admin:Qg266hq/YYKe2
01234567890123456789012345678901234567890123456789012345678901234567890123456789:Yl.SJmoFETpS2

Просмотреть файл

@ -1,323 +0,0 @@
# frozen_string_literal: false
require 'test/unit'
require 'xmlrpc/client'
require 'net/http'
begin
require 'openssl'
rescue LoadError
end
module XMLRPC
class ClientTest < Test::Unit::TestCase
module Fake
class HTTP < Net::HTTP
class << self
def new(*args, &block)
Class.method(:new).unbind.bind(self).call(*args, &block)
end
end
def initialize responses = {}
super("127.0.0.1")
@started = false
@responses = responses
end
def started?
@started
end
def start
@started = true
if block_given?
begin
return yield(self)
ensure
@started = false
end
end
self
end
def request_post path, request, headers
@responses[path].shift
end
end
class Client < XMLRPC::Client
attr_reader :args, :http
def initialize(*args)
@args = args
super
end
private
def net_http host, port, proxy_host, proxy_port
HTTP.new
end
end
class Response
def self.new body, fields = [], status = '200'
klass = Class.new(Net::HTTPResponse::CODE_TO_OBJ[status]) {
def initialize(*args)
super
@read = true
end
}
resp = klass.new '1.1', status, 'OK'
resp.body = body
fields.each do |k,v|
resp.add_field k, v
end
resp
end
end
end
def test_new2_host_path_port
client = Fake::Client.new2 'http://example.org/foo'
host, path, port, *rest = client.args
assert_equal 'example.org', host
assert_equal '/foo', path
assert_equal 80, port
rest.each { |x| refute x }
end
def test_new2_custom_port
client = Fake::Client.new2 'http://example.org:1234/foo'
host, path, port, *rest = client.args
assert_equal 'example.org', host
assert_equal '/foo', path
assert_equal 1234, port
rest.each { |x| refute x }
end
def test_new2_ssl
client = Fake::Client.new2 'https://example.org/foo'
host, path, port, proxy_host, proxy_port, user, password, use_ssl, timeout = client.args
assert_equal 'example.org', host
assert_equal '/foo', path
assert_equal 443, port
assert use_ssl
refute proxy_host
refute proxy_port
refute user
refute password
refute timeout
end if defined?(OpenSSL)
def test_new2_ssl_custom_port
client = Fake::Client.new2 'https://example.org:1234/foo'
host, path, port, proxy_host, proxy_port, user, password, use_ssl, timeout = client.args
assert_equal 'example.org', host
assert_equal '/foo', path
assert_equal 1234, port
assert use_ssl
refute proxy_host
refute proxy_port
refute user
refute password
refute timeout
end if defined?(OpenSSL)
def test_new2_user_password
client = Fake::Client.new2 'http://aaron:tenderlove@example.org/foo'
host, path, port, proxy_host, proxy_port, user, password, use_ssl, timeout = client.args
[ host, path, port ].each { |x| assert x }
assert_equal 'aaron', user
assert_equal 'tenderlove', password
[ proxy_host, proxy_port, use_ssl, timeout ].each { |x| refute x }
end
def test_new2_proxy_host
client = Fake::Client.new2 'http://example.org/foo', 'example.com'
host, path, port, proxy_host, proxy_port, user, password, use_ssl, timeout = client.args
[ host, path, port ].each { |x| assert x }
assert_equal 'example.com', proxy_host
[ user, password, proxy_port, use_ssl, timeout ].each { |x| refute x }
end
def test_new2_proxy_port
client = Fake::Client.new2 'http://example.org/foo', 'example.com:1234'
host, path, port, proxy_host, proxy_port, user, password, use_ssl, timeout = client.args
[ host, path, port ].each { |x| assert x }
assert_equal 'example.com', proxy_host
assert_equal 1234, proxy_port
[ user, password, use_ssl, timeout ].each { |x| refute x }
end
def test_new2_no_path
client = Fake::Client.new2 'http://example.org'
host, path, port, *rest = client.args
assert_equal 'example.org', host
assert_nil path
assert port
rest.each { |x| refute x }
end
def test_new2_slash_path
client = Fake::Client.new2 'http://example.org/'
host, path, port, *rest = client.args
assert_equal 'example.org', host
assert_equal '/', path
assert port
rest.each { |x| refute x }
end
def test_new2_bad_protocol
assert_raise(ArgumentError) do
XMLRPC::Client.new2 'ftp://example.org'
end
end
def test_new2_bad_uri
assert_raise(ArgumentError) do
XMLRPC::Client.new2 ':::::'
end
end
def test_new2_path_with_query
client = Fake::Client.new2 'http://example.org/foo?bar=baz'
host, path, port, *rest = client.args
assert_equal 'example.org', host
assert_equal '/foo?bar=baz', path
assert port
rest.each { |x| refute x }
end
def test_request
fh = read 'blog.xml'
responses = {
'/foo' => [ Fake::Response.new(fh, [['Content-Type', 'text/xml']]) ]
}
client = fake_client(responses).new2 'http://example.org/foo'
resp = client.call('wp.getUsersBlogs', 'tlo', 'omg')
expected = [{
"isAdmin" => true,
"url" => "http://tenderlovemaking.com/",
"blogid" => "1",
"blogName" => "Tender Lovemaking",
"xmlrpc" => "http://tenderlovemaking.com/xmlrpc.php"
}]
assert_equal expected, resp
end
def test_async_request
fh = read 'blog.xml'
responses = {
'/foo' => [ Fake::Response.new(fh, [['Content-Type', 'text/xml']]) ]
}
client = fake_client(responses).new2 'http://example.org/foo'
resp = client.call_async('wp.getUsersBlogs', 'tlo', 'omg')
expected = [{
"isAdmin" => true,
"url" => "http://tenderlovemaking.com/",
"blogid" => "1",
"blogName" => "Tender Lovemaking",
"xmlrpc" => "http://tenderlovemaking.com/xmlrpc.php"
}]
assert_equal expected, resp
end
# make a request without content-type header
def test_bad_content_type
fh = read 'blog.xml'
responses = {
'/foo' => [ Fake::Response.new(fh) ]
}
client = fake_client(responses).new2 'http://example.org/foo'
resp = client.call('wp.getUsersBlogs', 'tlo', 'omg')
expected = [{
"isAdmin" => true,
"url" => "http://tenderlovemaking.com/",
"blogid" => "1",
"blogName" => "Tender Lovemaking",
"xmlrpc" => "http://tenderlovemaking.com/xmlrpc.php"
}]
assert_equal expected, resp
end
def test_i8_tag
fh = read('blog.xml').gsub(/string/, 'i8')
responses = {
'/foo' => [ Fake::Response.new(fh) ]
}
client = fake_client(responses).new2 'http://example.org/foo'
resp = client.call('wp.getUsersBlogs', 'tlo', 'omg')
assert_equal 1, resp.first['blogid']
end
def test_cookie_simple
client = Fake::Client.new2('http://example.org/cookie')
assert_nil(client.cookie)
client.send(:parse_set_cookies, ["param1=value1", "param2=value2"])
assert_equal("param1=value1; param2=value2", client.cookie)
end
def test_cookie_override
client = Fake::Client.new2('http://example.org/cookie')
client.send(:parse_set_cookies,
[
"param1=value1",
"param2=value2",
"param1=value3",
])
assert_equal("param2=value2; param1=value3", client.cookie)
end
private
def read filename
File.read File.expand_path(File.join(__FILE__, '..', 'data', filename))
end
def fake_client responses
Class.new(Fake::Client) {
define_method(:net_http) { |*_| Fake::HTTP.new(responses) }
}
end
end
end

Просмотреть файл

@ -1,97 +0,0 @@
# frozen_string_literal: false
require 'test/unit'
require 'time'
require 'webrick'
require_relative 'webrick_testing'
require "xmlrpc/server"
require 'xmlrpc/client'
module TestXMLRPC
class TestCookie < Test::Unit::TestCase
include WEBrick_Testing
def create_servlet
s = XMLRPC::WEBrickServlet.new
def s.logged_in_users
@logged_in_users ||= {}
end
def s.request
@request
end
def s.response
@response
end
def s.service(request, response)
@request = request
@response = response
super
ensure
@request = nil
@response = nil
end
key = Time.now.to_i.to_s
valid_user = "valid-user"
s.add_handler("test.login") do |user, password|
ok = (user == valid_user and password == "secret")
if ok
s.logged_in_users[key] = user
expires = (Time.now + 60 * 60).httpdate
cookies = s.response.cookies
cookies << "key=\"#{key}\"; path=\"/RPC2\"; expires=#{expires}"
cookies << "user=\"#{user}\"; path=\"/RPC2\""
end
ok
end
s.add_handler("test.require_authenticate_echo") do |string|
cookies = {}
s.request.cookies.each do |cookie|
cookies[cookie.name] = cookie.value
end
if cookies == {"key" => key, "user" => valid_user}
string
else
raise XMLRPC::FaultException.new(29, "Authentication required")
end
end
s.set_default_handler do |name, *args|
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
" or wrong number of parameters!")
end
s.add_introspection
s
end
def setup_http_server_option
option = {:Port => 0}
end
def test_cookie
option = setup_http_server_option
with_server(option, create_servlet) {|addr|
begin
@s = XMLRPC::Client.new3(:host => addr.ip_address, :port => addr.ip_port)
do_test
ensure
@s.http.finish
end
}
end
def do_test
assert(!@s.call("test.login", "invalid-user", "invalid-password"))
exception = assert_raise(XMLRPC::FaultException) do
@s.call("test.require_authenticate_echo", "Hello")
end
assert_equal(29, exception.faultCode)
assert(@s.call("test.login", "valid-user", "secret"))
assert_equal("Hello", @s.call("test.require_authenticate_echo", "Hello"))
end
end
end

Просмотреть файл

@ -1,162 +0,0 @@
# frozen_string_literal: false
require 'test/unit'
require "xmlrpc/datetime"
module TestXMLRPC
class Test_DateTime < Test::Unit::TestCase
def test_new
dt = createDateTime()
assert_instance_of(XMLRPC::DateTime, dt)
end
def test_new_exception
assert_raise(ArgumentError) { XMLRPC::DateTime.new(4.5, 13, 32, 25, 60, 60) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 32, 25, 60, 60) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 25, 60, 60) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 60, 60) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 59, 60) }
assert_nothing_raised(ArgumentError) { XMLRPC::DateTime.new(2001, 12, 31, 24, 59, 59) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 0, 0, -1, -1, -1) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 0, -1, -1, -1) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, -1, -1, -1) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, -1, -1) }
assert_raise(ArgumentError) { XMLRPC::DateTime.new(2001, 1, 1, 0, 0, -1) }
assert_nothing_raised(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_raise(ArgumentError) { dt.year = 4.5 }
assert_nothing_raised(ArgumentError) { dt.year = -2000 }
assert_raise(ArgumentError) { dt.month = 0 }
assert_raise(ArgumentError) { dt.month = 13 }
assert_nothing_raised(ArgumentError) { dt.month = 7 }
assert_raise(ArgumentError) { dt.mon = 0 }
assert_raise(ArgumentError) { dt.mon = 13 }
assert_nothing_raised(ArgumentError) { dt.mon = 7 }
assert_raise(ArgumentError) { dt.day = 0 }
assert_raise(ArgumentError) { dt.day = 32 }
assert_nothing_raised(ArgumentError) { dt.day = 16 }
assert_raise(ArgumentError) { dt.hour = -1 }
assert_raise(ArgumentError) { dt.hour = 25 }
assert_nothing_raised(ArgumentError) { dt.hour = 12 }
assert_raise(ArgumentError) { dt.min = -1 }
assert_raise(ArgumentError) { dt.min = 60 }
assert_nothing_raised(ArgumentError) { dt.min = 30 }
assert_raise(ArgumentError) { dt.sec = -1 }
assert_raise(ArgumentError) { dt.sec = 60 }
assert_nothing_raised(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
end

Просмотреть файл

@ -1,51 +0,0 @@
# frozen_string_literal: false
require 'test/unit'
require "xmlrpc/create"
require "xmlrpc/parser"
require "xmlrpc/config"
module TestXMLRPC
class Test_Features < Test::Unit::TestCase
def setup
@params = [nil, {"test" => nil}, [nil, 1, nil]]
end
def test_nil_create
XMLRPC::XMLWriter.each_installed_writer do |writer|
c = XMLRPC::Create.new(writer)
XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)}
XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, false)
assert_raise(RuntimeError) { c.methodCall("test", *@params) }
XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)}
XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, true)
assert_nothing_raised { c.methodCall("test", *@params) }
end
end
def test_nil_parse
XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_CREATE)}
XMLRPC::Config.const_set(:ENABLE_NIL_CREATE, true)
XMLRPC::XMLWriter.each_installed_writer do |writer|
c = XMLRPC::Create.new(writer)
str = c.methodCall("test", *@params)
XMLRPC::XMLParser.each_installed_parser do |parser|
para = nil
XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_PARSER)}
XMLRPC::Config.const_set(:ENABLE_NIL_PARSER, false)
assert_raise(RuntimeError) { para = parser.parseMethodCall(str) }
XMLRPC::Config.module_eval {remove_const(:ENABLE_NIL_PARSER)}
XMLRPC::Config.const_set(:ENABLE_NIL_PARSER, true)
assert_nothing_raised { para = parser.parseMethodCall(str) }
assert_equal(para[1], @params)
end
end
end
end
end

Просмотреть файл

@ -1,111 +0,0 @@
# frozen_string_literal: false
require 'test/unit'
require "xmlrpc/marshal"
module TestXMLRPC
class Test_Marshal < Test::Unit::TestCase
# for test_parser_values
class Person
include XMLRPC::Marshallable
attr_reader :name
def initialize(name)
@name = name
end
end
def test1_dump_response
assert_nothing_raised(NameError) {
XMLRPC::Marshal.dump_response('arg')
}
end
def test1_dump_call
assert_nothing_raised(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
v1 = [
1, -7778, -(2**31), 2**31-1, # 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"
]
person = Person.new("Michael")
XMLRPC::XMLParser.each_installed_parser do |parser|
m = XMLRPC::Marshal.new(parser)
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)) )
pers = m.load_response(m.dump_response(person))
assert( pers.is_a?(Person) )
assert( person.name == pers.name )
end
# missing, Date, Time, DateTime
# Struct
end
def test_parser_invalid_values
values = [
-1-(2**31), 2**31,
Float::INFINITY, -Float::INFINITY, Float::NAN
]
XMLRPC::XMLParser.each_installed_parser do |parser|
m = XMLRPC::Marshal.new(parser)
values.each do |v|
assert_raise(RuntimeError, "#{v} shouldn't be dumped, but dumped") \
{ m.dump_response(v) }
end
end
end
def test_no_params_tag
# bug found by Idan Sofer
expect = %{<?xml version="1.0" ?><methodCall><methodName>myMethod</methodName><params/></methodCall>\n}
str = XMLRPC::Marshal.dump_call("myMethod")
assert_equal(expect, str)
end
end
end

Просмотреть файл

@ -1,94 +0,0 @@
# frozen_string_literal: false
require 'test/unit'
require 'xmlrpc/datetime'
require "xmlrpc/parser"
require 'yaml'
module TestXMLRPC
module GenericParserTest
def datafile(base)
File.join(File.dirname(__FILE__), "data", base)
end
def load_data(name)
[File.read(datafile(name) + ".xml"), YAML.load(File.read(datafile(name) + ".expected"))]
end
def setup
@xml1, @expected1 = load_data('xml1')
@xml2, @expected2 = load_data('bug_covert')
@xml3, @expected3 = load_data('bug_bool')
@xml4, @expected4 = load_data('value')
@cdata_xml, @cdata_expected = load_data('bug_cdata')
@datetime_xml = File.read(datafile('datetime_iso8601.xml'))
@datetime_expected = XMLRPC::DateTime.new(2004, 11, 5, 1, 15, 23)
@fault_doc = File.read(datafile('fault.xml'))
end
# test parseMethodResponse --------------------------------------------------
def test_parseMethodResponse1
assert_equal(@expected1, @p.parseMethodResponse(@xml1))
end
def test_parseMethodResponse2
assert_equal(@expected2, @p.parseMethodResponse(@xml2))
end
def test_parseMethodResponse3
assert_equal(@expected3, @p.parseMethodResponse(@xml3))
end
def test_cdata
assert_equal(@cdata_expected, @p.parseMethodResponse(@cdata_xml))
end
def test_dateTime
assert_equal(@datetime_expected, @p.parseMethodResponse(@datetime_xml)[1])
end
# test parseMethodCall ------------------------------------------------------
def test_parseMethodCall
assert_equal(@expected4, @p.parseMethodCall(@xml4))
end
# test fault ----------------------------------------------------------------
def test_fault
flag, fault = @p.parseMethodResponse(@fault_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
def test_fault_message
fault = XMLRPC::FaultException.new(1234, 'an error message')
assert_equal('an error message', fault.to_s)
assert_equal('#<XMLRPC::FaultException: an error message>', fault.inspect)
end
end
# create test class for each installed parser
XMLRPC::XMLParser.each_installed_parser do |parser|
klass = parser.class
name = klass.to_s.split("::").last
eval %{
class Test_#{name} < Test::Unit::TestCase
include GenericParserTest
def setup
super
@p = #{klass}.new
end
end
}
end
end

Просмотреть файл

@ -1,136 +0,0 @@
# coding: utf-8
# frozen_string_literal: false
require 'test/unit'
require 'webrick'
require_relative 'webrick_testing'
require "xmlrpc/server"
require 'xmlrpc/client'
require 'logger'
module TestXMLRPC
class Test_Webrick < Test::Unit::TestCase
include WEBrick_Testing
def create_servlet(server)
s = XMLRPC::WEBrickServlet.new
basic_auth = WEBrick::HTTPAuth::BasicAuth.new(
:Realm => 'auth',
:UserDB => WEBrick::HTTPAuth::Htpasswd.new(File.expand_path('./htpasswd', File.dirname(__FILE__))),
:Logger => server.logger,
)
class << s; self end.send(:define_method, :service) {|req, res|
basic_auth.authenticate(req, res)
super(req, res)
}
s.add_handler("test.add") do |a,b|
a + b
end
s.add_handler("test.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.add_introspection
return s
end
def setup_http_server_option(use_ssl)
option = {
:BindAddress => "localhost",
:Port => 0,
:SSLEnable => use_ssl,
}
if use_ssl
require 'webrick/https'
option.update(
:SSLVerifyClient => ::OpenSSL::SSL::VERIFY_NONE,
:SSLCertName => []
)
end
option
end
def test_client_server
# NOTE: I don't enable SSL testing as this hangs
[false].each do |use_ssl|
option = setup_http_server_option(use_ssl)
with_server(option, method(:create_servlet)) {|addr|
@s = XMLRPC::Client.new3(:host => addr.ip_address, :port => addr.ip_port, :use_ssl => use_ssl)
@s.user = 'admin'
@s.password = 'admin'
silent do
do_test
end
@s.http.finish
@s = XMLRPC::Client.new3(:host => addr.ip_address, :port => addr.ip_port, :use_ssl => use_ssl)
@s.user = '01234567890123456789012345678901234567890123456789012345678901234567890123456789'
@s.password = 'guest'
silent do
do_test
end
@s.http.finish
}
end
end
def silent
begin
back, $VERBOSE = $VERBOSE, nil
yield
ensure
$VERBOSE = back
end
end
def do_test
# simple call
assert_equal 9, @s.call('test.add', 4, 5)
# fault exception
assert_raise(XMLRPC::FaultException) { @s.call('test.div', 1, 0) }
# fault exception via call2
ok, param = @s.call2('test.div', 1, 0)
assert_equal false, ok
assert_instance_of XMLRPC::FaultException, param
assert_equal 1, param.faultCode
assert_equal 'division by zero', param.faultString
# call2 without fault exception
ok, param = @s.call2('test.div', 10, 5)
assert_equal true, ok
assert_equal param, 2
# introspection
assert_equal ["test.add", "test.div", "system.listMethods", "system.methodSignature", "system.methodHelp"], @s.call("system.listMethods")
# default handler (missing handler)
ok, param = @s.call2('test.nonexisting')
assert_equal false, ok
assert_equal(-99, param.faultCode)
# default handler (wrong number of arguments)
ok, param = @s.call2('test.add', 1, 2, 3)
assert_equal false, ok
assert_equal(-99, param.faultCode)
# multibyte characters
assert_equal "あいうえおかきくけこ", @s.call('test.add', "あいうえお", "かきくけこ")
end
end
end

Просмотреть файл

@ -1,61 +0,0 @@
# frozen_string_literal: false
require 'timeout'
module TestXMLRPC
module WEBrick_Testing
def teardown
WEBrick::Utils::TimeoutHandler.terminate
super
end
def start_server(logger, config={})
raise "already started" if defined?(@__server) && @__server
@__started = false
@__server = WEBrick::HTTPServer.new(
{
:BindAddress => "localhost",
:Logger => logger,
:AccessLog => [],
}.update(config))
yield @__server
@__started = true
addr = @__server.listeners.first.connect_address
@__server_thread = Thread.new {
begin
@__server.start
rescue IOError => e
assert_match(/closed/, e.message)
ensure
@__started = false
end
}
addr
end
def with_server(config, servlet)
log = []
logger = WEBrick::Log.new(log, WEBrick::BasicLog::WARN)
addr = start_server(logger, config) {|w|
servlet = servlet.call(w) if servlet.respond_to? :call
w.mount('/RPC2', servlet)
}
client_thread = Thread.new {
begin
yield addr
ensure
@__server.shutdown
end
}
server_thread = Thread.new {
@__server_thread.join
@__server = nil
assert_equal([], log)
}
assert_join_threads([client_thread, server_thread])
end
end
end