Class: XMLRPC::Client
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
|
|
Inherits: | Object |
Defined in: | lib/xmlrpc/client.rb |
Overview
Provides remote procedure calls to a XML-RPC server.
After setting the connection-parameters with .new which creates a new Client
instance, you can execute a remote procedure by sending the #call or #call2 message to this new instance.
The given parameters indicate which method to call on the remote-side and of course the parameters for the remote procedure.
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
Constant Summary
-
USER_AGENT =
# File 'lib/xmlrpc/client.rb', line 56"XMLRPC::Client (Ruby #{RUBY_VERSION})"
Class Method Summary
-
.new(host = nil, path = nil, port = nil, proxy_host = nil, proxy_port = nil, user = nil, password = nil, use_ssl = nil, timeout = nil) ⇒ Client
constructor
Creates an object which represents the remote XML-RPC server on the given
host
. -
.new2(uri, proxy = nil, timeout = nil)
(also: .new_from_uri)
Creates an object which represents the remote XML-RPC server at the given
uri
. -
.new3(hash = {})
(also: .new_from_hash)
Receives a Hash and calls .new with the corresponding values.
-
.new_from_hash(hash = {})
Alias for .new3.
-
.new_from_uri(uri, proxy = nil, timeout = nil)
Alias for .new2.
Instance Attribute Summary
-
#cookie
rw
Get and set the HTTP Cookie header.
-
#http_header_extra
rw
Add additional HTTP headers to the request.
-
#password
rw
Return the corresponding attributes.
-
#password=(new_password)
rw
Changes the password for the Basic Authentication header to
new_password
-
#timeout
rw
Return the corresponding attributes.
-
#timeout=(new_timeout)
rw
Sets the
Net::HTTP#read_timeout
andNet::HTTP#open_timeout
tonew_timeout
-
#user
rw
Return the corresponding attributes.
-
#user=(new_user)
rw
Changes the user for the Basic Authentication header to
new_user
-
#http
readonly
Returns the
Net::HTTP
object for the client. -
#http_last_response
readonly
Returns the
Net::HTTPResponse
object of the last RPC.
Instance Method Summary
-
#call(method, *args)
Invokes the method named
method
with the parameters given byargs
on the XML-RPC server. -
#call2(method, *args)
The difference between this method and #call is, that this method will NOT raise a FaultException exception.
-
#call2_async(method, *args)
Same as #call2, but can be called concurrently.
-
#call_async(method, *args)
Similar to #call, however can be called concurrently and use a new connection for each request.
-
#multicall(*methods)
You can use this method to execute several methods on a ::XMLRPC server which support the multi-call extension.
-
#multicall2(*methods)
Same as #multicall, but returns two parameters instead of raising an FaultException.
-
#multicall2_async(*methods)
Same as #multicall2, but can be called concurrently.
-
#multicall_async(*methods)
Similar to #multicall, however can be called concurrently and use a new connection for each request.
-
#proxy(prefix = nil, *args)
Returns an object of class Proxy, initialized with
prefix
andargs
. - #proxy2(prefix = nil, *args)
-
#proxy2_async(prefix = nil, *args)
Same as #proxy2, but can be called concurrently.
-
#proxy_async(prefix = nil, *args)
Similar to #proxy, however can be called concurrently and use a new connection for each request.
- #do_rpc(request, async = false) private
- #dup_net_http private
- #gen_multicall(methods = [], async = false) private
- #net_http(host, port, proxy_host, proxy_port) private
- #parse_set_cookies(set_cookies) private
- #set_auth private
ParseContentType - Included
ParserWriterChooseMixin - Included
#set_parser | Sets the XMLParser to use for parsing XML documents. |
#set_writer | Sets the XMLWriter to use for generating XML output. |
#create, #parser |
Constructor Details
.new(host = nil, path = nil, port = nil, proxy_host = nil, proxy_port = nil, user = nil, password = nil, use_ssl = nil, timeout = nil) ⇒ Client
Creates an object which represents the remote XML-RPC server on the given host
. If the server is CGI-based, path
is the path to the CGI-script, which will be called, otherwise (in the case of a standalone server) path
should be "/RPC2"
. port
is the port on which the XML-RPC server listens.
If proxy_host
is given, then a proxy server listening at proxy_host
is used. proxy_port
is the port of the proxy server.
Default values for host
, path
and port
are 'localhost', '/RPC2' and '80' respectively using SSL '443'.
If #user and #password are given, each time a request is sent, an Authorization header is sent. Currently only Basic Authentication is implemented, no Digest.
If use_ssl
is set to true
, communication over SSL is enabled.
Parameter #timeout is the time to wait for a XML-RPC response, defaults to 30.
# File 'lib/xmlrpc/client.rb', line 82
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 Method Details
.new2(uri, proxy = nil, timeout = nil) Also known as: .new_from_uri
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: 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.
# File 'lib/xmlrpc/client.rb', line 136
def new2(uri, proxy=nil, timeout=nil) begin url = URI(uri) rescue URI::InvalidURIError => e raise ArgumentError, e., 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
.new3(hash = {}) Also known as: .new_from_hash
Receives a Hash and calls .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
# File 'lib/xmlrpc/client.rb', line 175
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
.new_from_hash(hash = {})
Alias for .new3.
# File 'lib/xmlrpc/client.rb', line 185
alias new_from_hash new3
.new_from_uri(uri, proxy = nil, timeout = nil)
Alias for .new2.
# File 'lib/xmlrpc/client.rb', line 160
alias new_from_uri new2
Instance Attribute Details
#cookie (rw)
Get and set the HTTP Cookie header.
# File 'lib/xmlrpc/client.rb', line 204
attr_accessor :
#http (readonly)
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.
# File 'lib/xmlrpc/client.rb', line 195
attr_reader :http
#http_header_extra (rw)
Add additional HTTP headers to the request
# File 'lib/xmlrpc/client.rb', line 198
attr_accessor :http_header_extra
#http_last_response (readonly)
Returns the Net::HTTPResponse
object of the last RPC.
# File 'lib/xmlrpc/client.rb', line 201
attr_reader :http_last_response
#password (rw)
Return the corresponding attributes.
#password=(new_password) (rw)
Changes the password for the Basic Authentication header to new_password
# File 'lib/xmlrpc/client.rb', line 226
def password=(new_password) @password = new_password set_auth end
#timeout (rw)
Return the corresponding attributes.
#timeout=(new_timeout) (rw)
Sets the Net::HTTP#read_timeout
and Net::HTTP#open_timeout
to new_timeout
# File 'lib/xmlrpc/client.rb', line 212
def timeout=(new_timeout) @timeout = new_timeout @http.read_timeout = @timeout @http.open_timeout = @timeout end
#user (rw)
Return the corresponding attributes.
#user=(new_user) (rw)
Changes the user for the Basic Authentication header to new_user
# File 'lib/xmlrpc/client.rb', line 219
def user=(new_user) @user = new_user set_auth end
Instance Method Details
#call(method, *args)
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, DateTime
-
A Ruby object which class includes Marshallable (only if Config::ENABLE_MARSHALLING is
true
). That object is converted into a hash, with one additional key/value pair_class___
which contains the class name for restoring that object later.
The method returns the return-value from the Remote Procedure Call.
The type of the return-value is one of the types shown above.
A Bignum is only allowed when it fits in 32-bit. A XML-RPC dateTime.iso8601
type is always returned as a DateTime object. Struct is never returned, only a Hash, the same for a Symbol, where as a String is always returned. Base64 is returned as a String from xmlrpc4r version 1.6.1 on.
If the remote procedure returned a fault-structure, then a FaultException exception is raised, which has two accessor-methods faultCode
an Integer, and faultString
a String.
# File 'lib/xmlrpc/client.rb', line 267
def call(method, *args) ok, param = call2(method, *args) if ok param else raise param end end
#call2(method, *args)
The difference between this method and #call is, that this method will NOT raise a FaultException exception.
The method returns an array of two values. The first value indicates if the second value is true
or an FaultException.
Both are explained in #call.
Simple to remember: The “2” in “call2” denotes the number of values it returns.
# File 'lib/xmlrpc/client.rb', line 285
def call2(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, false) parser().parseMethodResponse(data) end
#call2_async(method, *args)
Same as #call2, but can be called concurrently.
See also #call_async
# File 'lib/xmlrpc/client.rb', line 319
def call2_async(method, *args) request = create().methodCall(method, *args) data = do_rpc(request, true) parser().parseMethodResponse(data) end
#call_async(method, *args)
Similar to #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)
}
# File 'lib/xmlrpc/client.rb', line 307
def call_async(method, *args) ok, param = call2_async(method, *args) if ok param else raise param end end
#do_rpc(request, async = false) (private)
[ GitHub ]# File 'lib/xmlrpc/client.rb', line 464
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.}" elsif resp.code[0,1] != "2" raise "HTTP-Error: #{resp.code} #{resp.}" 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 (resp.get_fields("Set-Cookie")) return data end
#dup_net_http (private)
[ GitHub ]# File 'lib/xmlrpc/client.rb', line 436
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
#gen_multicall(methods = [], async = false) (private)
[ GitHub ]# File 'lib/xmlrpc/client.rb', line 549
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
#multicall(*methods)
You can use this method to execute several methods on a ::XMLRPC server which support the multi-call extension.
s.multicall(
['michael.add', 3, 4],
['michael.sub', 4, 5]
)
# => [7, -1]
# File 'lib/xmlrpc/client.rb', line 334
def multicall(*methods) ok, params = multicall2(*methods) if ok params else raise params end end
#multicall2(*methods)
Same as #multicall, but returns two parameters instead of raising an FaultException.
See #call2
# File 'lib/xmlrpc/client.rb', line 347
def multicall2(*methods) gen_multicall(methods, false) end
#multicall2_async(*methods)
Same as #multicall2, but can be called concurrently.
See also #multicall_async
# File 'lib/xmlrpc/client.rb', line 379
def multicall2_async(*methods) gen_multicall(methods, true) end
#multicall_async(*methods)
Similar to #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)
}
# File 'lib/xmlrpc/client.rb', line 367
def multicall_async(*methods) ok, params = multicall2_async(*methods) if ok params else raise params end end
#net_http(host, port, proxy_host, proxy_port) (private)
[ GitHub ]# File 'lib/xmlrpc/client.rb', line 432
def net_http(host, port, proxy_host, proxy_port) Net::HTTP.new host, port, proxy_host, proxy_port end
#parse_set_cookies(set_cookies) (private)
[ GitHub ]# File 'lib/xmlrpc/client.rb', line 533
def ( ) return if .nil? return if .empty? require 'webrick/cookie' pairs = {} .each do || = WEBrick::Cookie. ( ) pairs.delete( .name) pairs[ .name] = .value end = pairs.collect do |name, value| WEBrick::Cookie.new(name, value).to_s end @cookie = .join("; ") end
#proxy(prefix = nil, *args)
Returns an object of class Client::Proxy, initialized with prefix
and args
.
A proxy object returned by this method behaves like #call, i.e. a call on that object will raise a FaultException when a fault-structure is returned by that call.
#proxy2(prefix = nil, *args)
Almost the same like #proxy only that a call on the returned Client::Proxy object will return two parameters.
See #call2
#proxy2_async(prefix = nil, *args)
Same as #proxy2, but can be called concurrently.
See also #proxy_async
# File 'lib/xmlrpc/client.rb', line 425
def proxy2_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call2_async) end
#proxy_async(prefix = nil, *args)
Similar to #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)
}
# File 'lib/xmlrpc/client.rb', line 418
def proxy_async(prefix=nil, *args) Proxy.new(self, prefix, args, :call_async) end
#set_auth (private)
[ GitHub ]# File 'lib/xmlrpc/client.rb', line 454
def set_auth if @user.nil? @auth = nil else a = "#@user" a << ":#@password" if @password != nil @auth = "Basic " + [a].pack("m0") end end