rubysl-xmlrpc 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,46 +1,23 @@
1
- =begin
2
- = xmlrpc/base64.rb
3
- Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
4
-
5
- Released under the same term of license as Ruby.
6
-
7
- = Classes
8
- * ((<XMLRPC::Base64>))
9
-
10
- = XMLRPC::Base64
11
- == Description
12
- This class is necessary for (('xmlrpc4r')) to determine that a string should
13
- be transmitted base64-encoded and not as a raw-string.
14
- You can use (({XMLRPC::Base64})) on the client and server-side as a
15
- parameter and/or return-value.
16
-
17
- == Class Methods
18
- --- XMLRPC::Base64.new( str, state = :dec )
19
- Creates a new (({XMLRPC::Base64})) instance with string ((|str|)) as the
20
- internal string. When ((|state|)) is (({:dec})) it assumes that the
21
- string ((|str|)) is not in base64 format (perhaps already decoded),
22
- otherwise if ((|state|)) is (({:enc})) it decodes ((|str|))
23
- and stores it as the internal string.
24
-
25
- --- XMLRPC::Base64.decode( str )
26
- Decodes string ((|str|)) with base64 and returns that value.
27
-
28
- --- XMLRPC::Base64.encode( str )
29
- Encodes string ((|str|)) with base64 and returns that value.
30
-
31
- == Instance Methods
32
- --- XMLRPC::Base64#decoded
33
- Returns the internal string decoded.
34
-
35
- --- XMLRPC::Base64#encoded
36
- Returns the internal string encoded with base64.
37
-
38
- =end
39
-
40
- module XMLRPC
41
-
1
+ #
2
+ # xmlrpc/base64.rb
3
+ # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
4
+ #
5
+ # Released under the same term of license as Ruby.
6
+
7
+ module XMLRPC # :nodoc:
8
+
9
+ # This class is necessary for 'xmlrpc4r' to determine that a string should
10
+ # be transmitted base64-encoded and not as a raw-string.
11
+ #
12
+ # You can use XMLRPC::Base64 on the client and server-side as a
13
+ # parameter and/or return-value.
42
14
  class Base64
43
-
15
+
16
+ # Creates a new XMLRPC::Base64 instance with string +str+ as the
17
+ # internal string. When +state+ is +:dec+ it assumes that the
18
+ # string +str+ is not in base64 format (perhaps already decoded),
19
+ # otherwise if +state+ is +:enc+ it decodes +str+
20
+ # and stores it as the internal string.
44
21
  def initialize(str, state = :dec)
45
22
  case state
46
23
  when :enc
@@ -51,20 +28,24 @@ class Base64
51
28
  raise ArgumentError, "wrong argument; either :enc or :dec"
52
29
  end
53
30
  end
54
-
31
+
32
+ # Returns the decoded internal string.
55
33
  def decoded
56
- @str
34
+ @str
57
35
  end
58
-
36
+
37
+ # Returns the base64 encoded internal string.
59
38
  def encoded
60
39
  Base64.encode(@str)
61
40
  end
62
41
 
63
42
 
43
+ # Decodes string +str+ with base64 and returns that value.
64
44
  def Base64.decode(str)
65
45
  str.gsub(/\s+/, "").unpack("m")[0]
66
46
  end
67
47
 
48
+ # Encodes string +str+ with base64 and returns that value.
68
49
  def Base64.encode(str)
69
50
  [str].pack("m")
70
51
  end
@@ -77,5 +58,5 @@ end # module XMLRPC
77
58
 
78
59
  =begin
79
60
  = History
80
- $Id: base64.rb 11708 2007-02-12 23:01:19Z shyouhei $
61
+ $Id$
81
62
  =end
@@ -1,302 +1,90 @@
1
- =begin
2
- = xmlrpc/client.rb
3
- Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
4
-
5
- Released under the same term of license as Ruby.
6
-
7
- = Classes
8
- * ((<XMLRPC::Client>))
9
- * ((<XMLRPC::Client::Proxy>))
10
-
11
-
12
- = XMLRPC::Client
13
- == Synopsis
14
- require "xmlrpc/client"
15
-
16
- server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
17
- begin
18
- param = server.call("michael.add", 4, 5)
19
- puts "4 + 5 = #{param}"
20
- rescue XMLRPC::FaultException => e
21
- puts "Error:"
22
- puts e.faultCode
23
- puts e.faultString
24
- end
25
-
26
- or
27
-
28
- require "xmlrpc/client"
29
-
30
- server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
31
- ok, param = server.call2("michael.add", 4, 5)
32
- if ok then
33
- puts "4 + 5 = #{param}"
34
- else
35
- puts "Error:"
36
- puts param.faultCode
37
- puts param.faultString
38
- end
39
-
40
- == Description
41
- Class (({XMLRPC::Client})) provides remote procedure calls to a XML-RPC server.
42
- After setting the connection-parameters with ((<XMLRPC::Client.new>)) which
43
- creates a new (({XMLRPC::Client})) instance, you can execute a remote procedure
44
- by sending the ((<call|XMLRPC::Client#call>)) or ((<call2|XMLRPC::Client#call2>))
45
- message to this new instance. The given parameters indicate which method to
46
- call on the remote-side and of course the parameters for the remote procedure.
47
-
48
- == Class Methods
49
- --- XMLRPC::Client.new( host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil, user=nil, password=nil, use_ssl=false, timeout =nil)
50
- Creates an object which represents the remote XML-RPC server on the
51
- given host ((|host|)). If the server is CGI-based, ((|path|)) is the
52
- path to the CGI-script, which will be called, otherwise (in the
53
- case of a standalone server) ((|path|)) should be (({"/RPC2"})).
54
- ((|port|)) is the port on which the XML-RPC server listens.
55
- If ((|proxy_host|)) is given, then a proxy server listening at
56
- ((|proxy_host|)) is used. ((|proxy_port|)) is the port of the
57
- proxy server.
58
-
59
- Default values for ((|host|)), ((|path|)) and ((|port|)) are 'localhost', '/RPC2' and
60
- '80' respectively using SSL '443'.
61
-
62
- If ((|user|)) and ((|password|)) are given, each time a request is send,
63
- a Authorization header is send. Currently only Basic Authentification is
64
- implemented no Digest.
65
-
66
- If ((|use_ssl|)) is set to (({true})), comunication over SSL is enabled.
67
- Note, that you need the SSL package from RAA installed.
68
-
69
- Parameter ((|timeout|)) is the time to wait for a XML-RPC response, defaults to 30.
70
-
71
- --- XMLRPC::Client.new2( uri, proxy=nil, timeout=nil)
72
- --- XMLRPC::Client.new_from_uri( uri, proxy=nil, timeout=nil)
73
- : uri
74
- URI specifying protocol (http or https), host, port, path, user and password.
75
- Example: https://user:password@host:port/path
76
-
77
- : proxy
78
- Is of the form "host:port".
79
-
80
- : timeout
81
- Defaults to 30.
82
-
83
- --- XMLRPC::Client.new3( hash={} )
84
- --- XMLRPC::Client.new_from_hash( hash={} )
85
- Parameter ((|hash|)) has following case-insensitive keys:
86
- * host
87
- * path
88
- * port
89
- * proxy_host
90
- * proxy_port
91
- * user
92
- * password
93
- * use_ssl
94
- * timeout
95
-
96
- Calls ((<XMLRPC::Client.new>)) with the corresponding values.
97
-
98
- == Instance Methods
99
- --- XMLRPC::Client#call( method, *args )
100
- Invokes the method named ((|method|)) with the parameters given by
101
- ((|args|)) on the XML-RPC server.
102
- The parameter ((|method|)) is converted into a (({String})) and should
103
- be a valid XML-RPC method-name.
104
- Each parameter of ((|args|)) must be of one of the following types,
105
- where (({Hash})), (({Struct})) and (({Array})) can contain any of these listed ((:types:)):
106
- * (({Fixnum})), (({Bignum}))
107
- * (({TrueClass})), (({FalseClass})) ((({true})), (({false})))
108
- * (({String})), (({Symbol}))
109
- * (({Float}))
110
- * (({Hash})), (({Struct}))
111
- * (({Array}))
112
- * (({Date})), (({Time})), (({XMLRPC::DateTime}))
113
- * (({XMLRPC::Base64}))
114
- * A Ruby object which class includes XMLRPC::Marshallable (only if Config::ENABLE_MARSHALLABLE is (({true}))).
115
- That object is converted into a hash, with one additional key/value pair "___class___" which contains the class name
116
- for restoring later that object.
117
-
118
- The method returns the return-value from the RPC
119
- ((-stands for Remote Procedure Call-)).
120
- The type of the return-value is one of the above shown,
121
- only that a (({Bignum})) is only allowed when it fits in 32-bit and
122
- that a XML-RPC (('dateTime.iso8601')) type is always returned as
123
- a ((<(({XMLRPC::DateTime}))|URL:datetime.html>)) object and
124
- a (({Struct})) is never returned, only a (({Hash})), the same for a (({Symbol})), where
125
- always a (({String})) is returned.
126
- A (({XMLRPC::Base64})) is returned as a (({String})) from xmlrpc4r version 1.6.1 on.
127
-
128
- If the remote procedure returned a fault-structure, then a
129
- (({XMLRPC::FaultException})) exception is raised, which has two accessor-methods
130
- (({faultCode})) and (({faultString})) of type (({Integer})) and (({String})).
131
-
132
- --- XMLRPC::Client#call2( method, *args )
133
- The difference between this method and ((<call|XMLRPC::Client#call>)) is, that
134
- this method do ((*not*)) raise a (({XMLRPC::FaultException})) exception.
135
- The method returns an array of two values. The first value indicates if
136
- the second value is a return-value ((({true}))) or an object of type
137
- (({XMLRPC::FaultException})).
138
- Both are explained in ((<call|XMLRPC::Client#call>)).
139
-
140
- Simple to remember: The "2" in "call2" denotes the number of values it returns.
141
-
142
- --- XMLRPC::Client#multicall( *methods )
143
- You can use this method to execute several methods on a XMLRPC server which supports
144
- the multi-call extension.
145
- Example:
146
-
147
- s.multicall(
148
- ['michael.add', 3, 4],
149
- ['michael.sub', 4, 5]
150
- )
151
- # => [7, -1]
152
-
153
- --- XMLRPC::Client#multicall2( *methods )
154
- Same as ((<XMLRPC::Client#multicall>)), but returns like ((<XMLRPC::Client#call2>)) two parameters
155
- instead of raising an (({XMLRPC::FaultException})).
156
-
157
- --- XMLRPC::Client#proxy( prefix, *args )
158
- Returns an object of class (({XMLRPC::Client::Proxy})), initialized with
159
- ((|prefix|)) and ((|args|)). A proxy object returned by this method behaves
160
- like ((<XMLRPC::Client#call>)), i.e. a call on that object will raise a
161
- (({XMLRPC::FaultException})) when a fault-structure is returned by that call.
162
-
163
- --- XMLRPC::Client#proxy2( prefix, *args )
164
- Almost the same like ((<XMLRPC::Client#proxy>)) only that a call on the returned
165
- (({XMLRPC::Client::Proxy})) object behaves like ((<XMLRPC::Client#call2>)), i.e.
166
- a call on that object will return two parameters.
167
-
168
-
169
-
170
-
171
- --- XMLRPC::Client#call_async(...)
172
- --- XMLRPC::Client#call2_async(...)
173
- --- XMLRPC::Client#multicall_async(...)
174
- --- XMLRPC::Client#multicall2_async(...)
175
- --- XMLRPC::Client#proxy_async(...)
176
- --- XMLRPC::Client#proxy2_async(...)
177
- In contrast to corresponding methods without "_async", these can be
178
- called concurrently and use for each request a new connection, where the
179
- non-asynchronous counterparts use connection-alive (one connection for all requests)
180
- if possible.
181
-
182
- Note, that you have to use Threads to call these methods concurrently.
183
- The following example calls two methods concurrently:
184
-
185
- Thread.new {
186
- p client.call_async("michael.add", 4, 5)
187
- }
188
-
189
- Thread.new {
190
- p client.call_async("michael.div", 7, 9)
191
- }
192
-
193
-
194
- --- XMLRPC::Client#timeout
195
- --- XMLRPC::Client#user
196
- --- XMLRPC::Client#password
197
- Return the corresponding attributes.
198
-
199
- --- XMLRPC::Client#timeout= (new_timeout)
200
- --- XMLRPC::Client#user= (new_user)
201
- --- XMLRPC::Client#password= (new_password)
202
- Set the corresponding attributes.
203
-
204
-
205
- --- XMLRPC::Client#set_writer( writer )
206
- Sets the XML writer to use for generating XML output.
207
- Should be an instance of a class from module (({XMLRPC::XMLWriter})).
208
- If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used.
209
-
210
- --- XMLRPC::Client#set_parser( parser )
211
- Sets the XML parser to use for parsing XML documents.
212
- Should be an instance of a class from module (({XMLRPC::XMLParser})).
213
- If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used.
214
-
215
- --- XMLRPC::Client#cookie
216
- --- XMLRPC::Client#cookie= (cookieString)
217
- Get and set the HTTP Cookie header.
218
-
219
- --- XMLRPC::Client#http_header_extra= (additionalHeaders)
220
- Set extra HTTP headers that are included in the request.
221
-
222
- --- XMLRPC::Client#http_header_extra
223
- Access the via ((<XMLRPC::Client#http_header_extra=>)) assigned header.
224
-
225
- --- XMLRPC::Client#http_last_response
226
- Returns the (({Net::HTTPResponse})) object of the last RPC.
227
-
228
- = XMLRPC::Client::Proxy
229
- == Synopsis
230
- require "xmlrpc/client"
231
-
232
- server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
233
-
234
- michael = server.proxy("michael")
235
- michael2 = server.proxy("michael", 4)
236
-
237
- # both calls should return the same value '9'.
238
- p michael.add(4,5)
239
- p michael2.add(5)
240
-
241
- == Description
242
- Class (({XMLRPC::Client::Proxy})) makes XML-RPC calls look nicer!
243
- You can call any method onto objects of that class - the object handles
244
- (({method_missing})) and will forward the method call to a XML-RPC server.
245
- Don't use this class directly, but use instead method ((<XMLRPC::Client#proxy>)) or
246
- ((<XMLRPC::Client#proxy2>)).
247
-
248
- == Class Methods
249
- --- XMLRPC::Client::Proxy.new( server, prefix, args=[], meth=:call, delim="." )
250
- Creates an object which provides (({method_missing})).
251
-
252
- ((|server|)) must be of type (({XMLRPC::Client})), which is the XML-RPC server to be used
253
- for a XML-RPC call. ((|prefix|)) and ((|delim|)) will be prepended to the methodname
254
- called onto this object.
255
-
256
- Parameter ((|meth|)) is the method (call, call2, call_async, call2_async) to use for
257
- a RPC.
258
-
259
- ((|args|)) are arguments which are automatically given
260
- to every XML-RPC call before the arguments provides through (({method_missing})).
261
-
262
- == Instance Methods
263
- Every method call is forwarded to the XML-RPC server defined in ((<new|XMLRPC::Client::Proxy#new>)).
264
-
265
- Note: Inherited methods from class (({Object})) cannot be used as XML-RPC names, because they get around
266
- (({method_missing})).
267
-
268
-
269
-
270
- = History
271
- $Id: client.rb 18091 2008-07-16 17:07:44Z shyouhei $
272
-
273
- =end
274
-
275
-
276
-
1
+ # xmlrpc/client.rb
2
+ # Copyright (C) 2001, 2002, 2003 by Michael Neumann (mneumann@ntecs.de)
3
+ #
4
+ # Released under the same term of license as Ruby.
5
+ #
6
+ # History
7
+ # $Id$
8
+ #
277
9
  require "xmlrpc/parser"
278
10
  require "xmlrpc/create"
279
11
  require "xmlrpc/config"
280
12
  require "xmlrpc/utils" # ParserWriterChooseMixin
281
13
  require "net/http"
282
-
283
- module XMLRPC
284
-
14
+ require "uri"
15
+
16
+ module XMLRPC # :nodoc:
17
+
18
+ # Provides remote procedure calls to a XML-RPC server.
19
+ #
20
+ # After setting the connection-parameters with XMLRPC::Client.new which
21
+ # creates a new XMLRPC::Client instance, you can execute a remote procedure
22
+ # by sending the XMLRPC::Client#call or XMLRPC::Client#call2
23
+ # message to this new instance.
24
+ #
25
+ # The given parameters indicate which method to call on the remote-side and
26
+ # of course the parameters for the remote procedure.
27
+ #
28
+ # require "xmlrpc/client"
29
+ #
30
+ # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
31
+ # begin
32
+ # param = server.call("michael.add", 4, 5)
33
+ # puts "4 + 5 = #{param}"
34
+ # rescue XMLRPC::FaultException => e
35
+ # puts "Error:"
36
+ # puts e.faultCode
37
+ # puts e.faultString
38
+ # end
39
+ #
40
+ # or
41
+ #
42
+ # require "xmlrpc/client"
43
+ #
44
+ # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
45
+ # ok, param = server.call2("michael.add", 4, 5)
46
+ # if ok then
47
+ # puts "4 + 5 = #{param}"
48
+ # else
49
+ # puts "Error:"
50
+ # puts param.faultCode
51
+ # puts param.faultString
52
+ # end
285
53
  class Client
286
-
54
+
287
55
  USER_AGENT = "XMLRPC::Client (Ruby #{RUBY_VERSION})"
288
56
 
289
57
  include ParserWriterChooseMixin
290
58
  include ParseContentType
291
59
 
292
60
 
293
- # Constructors -------------------------------------------------------------------
294
-
295
- def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil,
61
+ # Creates an object which represents the remote XML-RPC server on the
62
+ # given +host+. If the server is CGI-based, +path+ is the
63
+ # path to the CGI-script, which will be called, otherwise (in the
64
+ # case of a standalone server) +path+ should be <tt>"/RPC2"</tt>.
65
+ # +port+ is the port on which the XML-RPC server listens.
66
+ #
67
+ # If +proxy_host+ is given, then a proxy server listening at
68
+ # +proxy_host+ is used. +proxy_port+ is the port of the
69
+ # proxy server.
70
+ #
71
+ # Default values for +host+, +path+ and +port+ are 'localhost', '/RPC2' and
72
+ # '80' respectively using SSL '443'.
73
+ #
74
+ # If +user+ and +password+ are given, each time a request is sent,
75
+ # an Authorization header is sent. Currently only Basic Authentication is
76
+ # implemented, no Digest.
77
+ #
78
+ # If +use_ssl+ is set to +true+, communication over SSL is enabled.
79
+ #
80
+ # Note, that you need the SSL package from RAA installed.
81
+ #
82
+ # Parameter +timeout+ is the time to wait for a XML-RPC response, defaults to 30.
83
+ def initialize(host=nil, path=nil, port=nil, proxy_host=nil, proxy_port=nil,
296
84
  user=nil, password=nil, use_ssl=nil, timeout=nil)
297
85
 
298
86
  @http_header_extra = nil
299
- @http_last_response = nil
87
+ @http_last_response = nil
300
88
  @cookie = nil
301
89
 
302
90
  @host = host || "localhost"
@@ -324,8 +112,7 @@ module XMLRPC
324
112
  @proxy_port = @proxy_port.to_i if @proxy_port != nil
325
113
 
326
114
  # HTTP object for synchronous calls
327
- Net::HTTP.version_1_2
328
- @http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
115
+ @http = net_http(@host, @port, @proxy_host, @proxy_port)
329
116
  @http.use_ssl = @use_ssl if @use_ssl
330
117
  @http.read_timeout = @timeout
331
118
  @http.open_timeout = @timeout
@@ -337,28 +124,55 @@ module XMLRPC
337
124
 
338
125
  class << self
339
126
 
127
+ # Creates an object which represents the remote XML-RPC server at the
128
+ # given +uri+. The URI should have a host, port, path, user and password.
129
+ # Example: https://user:password@host:port/path
130
+ #
131
+ # Raises an ArgumentError if the +uri+ is invalid,
132
+ # or if the protocol isn't http or https.
133
+ #
134
+ # If a +proxy+ is given it should be in the form of "host:port".
135
+ #
136
+ # The optional +timeout+ defaults to 30 seconds.
340
137
  def new2(uri, proxy=nil, timeout=nil)
341
- if match = /^([^:]+):\/\/(([^@]+)@)?([^\/]+)(\/.*)?$/.match(uri)
342
- proto = match[1]
343
- user, passwd = (match[3] || "").split(":")
344
- host, port = match[4].split(":")
345
- path = match[5]
346
-
347
- if proto != "http" and proto != "https"
348
- raise "Wrong protocol specified. Only http or https allowed!"
349
- end
138
+ begin
139
+ url = URI(uri)
140
+ rescue URI::InvalidURIError => e
141
+ raise ArgumentError, e.message, e.backtrace
142
+ end
350
143
 
351
- else
352
- raise "Wrong URI as parameter!"
144
+ unless URI::HTTP === url
145
+ raise ArgumentError, "Wrong protocol specified. Only http or https allowed!"
353
146
  end
354
-
147
+
148
+ proto = url.scheme
149
+ user = url.user
150
+ passwd = url.password
151
+ host = url.host
152
+ port = url.port
153
+ path = url.path.empty? ? nil : url.request_uri
154
+
355
155
  proxy_host, proxy_port = (proxy || "").split(":")
156
+ proxy_port = proxy_port.to_i if proxy_port
356
157
 
357
158
  self.new(host, path, port, proxy_host, proxy_port, user, passwd, (proto == "https"), timeout)
358
159
  end
359
160
 
360
161
  alias new_from_uri new2
361
162
 
163
+ # Receives a Hash and calls XMLRPC::Client.new
164
+ # with the corresponding values.
165
+ #
166
+ # The +hash+ parameter has following case-insensitive keys:
167
+ # * host
168
+ # * path
169
+ # * port
170
+ # * proxy_host
171
+ # * proxy_port
172
+ # * user
173
+ # * password
174
+ # * use_ssl
175
+ # * timeout
362
176
  def new3(hash={})
363
177
 
364
178
  # convert all keys into lowercase strings
@@ -374,62 +188,128 @@ module XMLRPC
374
188
  end
375
189
 
376
190
 
377
- # Attribute Accessors -------------------------------------------------------------------
378
-
379
- # add additional HTTP headers to the request
191
+ # Add additional HTTP headers to the request
380
192
  attr_accessor :http_header_extra
381
193
 
382
- # makes last HTTP response accessible
194
+ # Returns the Net::HTTPResponse object of the last RPC.
383
195
  attr_reader :http_last_response
384
196
 
385
- # Cookie support
197
+ # Get and set the HTTP Cookie header.
386
198
  attr_accessor :cookie
387
-
388
199
 
200
+
201
+ # Return the corresponding attributes.
389
202
  attr_reader :timeout, :user, :password
390
203
 
204
+ # Sets the Net::HTTP#read_timeout and Net::HTTP#open_timeout to
205
+ # +new_timeout+
391
206
  def timeout=(new_timeout)
392
207
  @timeout = new_timeout
393
208
  @http.read_timeout = @timeout
394
209
  @http.open_timeout = @timeout
395
210
  end
396
211
 
212
+ # Changes the user for the Basic Authentication header to +new_user+
397
213
  def user=(new_user)
398
214
  @user = new_user
399
215
  set_auth
400
216
  end
401
217
 
218
+ # Changes the password for the Basic Authentication header to
219
+ # +new_password+
402
220
  def password=(new_password)
403
221
  @password = new_password
404
222
  set_auth
405
223
  end
406
224
 
407
- # Call methods --------------------------------------------------------------
408
-
225
+ # Invokes the method named +method+ with the parameters given by
226
+ # +args+ on the XML-RPC server.
227
+ #
228
+ # The +method+ parameter is converted into a String and should
229
+ # be a valid XML-RPC method-name.
230
+ #
231
+ # Each parameter of +args+ must be of one of the following types,
232
+ # where Hash, Struct and Array can contain any of these listed _types_:
233
+ #
234
+ # * Fixnum, Bignum
235
+ # * TrueClass, FalseClass, +true+, +false+
236
+ # * String, Symbol
237
+ # * Float
238
+ # * Hash, Struct
239
+ # * Array
240
+ # * Date, Time, XMLRPC::DateTime
241
+ # * XMLRPC::Base64
242
+ # * A Ruby object which class includes XMLRPC::Marshallable
243
+ # (only if Config::ENABLE_MARSHALLABLE is +true+).
244
+ # That object is converted into a hash, with one additional key/value
245
+ # pair <code>___class___</code> which contains the class name
246
+ # for restoring that object later.
247
+ #
248
+ # The method returns the return-value from the Remote Procedure Call.
249
+ #
250
+ # The type of the return-value is one of the types shown above.
251
+ #
252
+ # A Bignum is only allowed when it fits in 32-bit. A XML-RPC
253
+ # +dateTime.iso8601+ type is always returned as a XMLRPC::DateTime object.
254
+ # Struct is never returned, only a Hash, the same for a Symbol, where as a
255
+ # String is always returned. XMLRPC::Base64 is returned as a String from
256
+ # xmlrpc4r version 1.6.1 on.
257
+ #
258
+ # If the remote procedure returned a fault-structure, then a
259
+ # XMLRPC::FaultException exception is raised, which has two accessor-methods
260
+ # +faultCode+ an Integer, and +faultString+ a String.
409
261
  def call(method, *args)
410
- ok, param = call2(method, *args)
262
+ ok, param = call2(method, *args)
411
263
  if ok
412
264
  param
413
265
  else
414
266
  raise param
415
267
  end
416
- end
268
+ end
417
269
 
270
+ # The difference between this method and XMLRPC::Client#call is, that
271
+ # this method will <b>NOT</b> raise a XMLRPC::FaultException exception.
272
+ #
273
+ # The method returns an array of two values. The first value indicates if
274
+ # the second value is +true+ or an XMLRPC::FaultException.
275
+ #
276
+ # Both are explained in XMLRPC::Client#call.
277
+ #
278
+ # Simple to remember: The "2" in "call2" denotes the number of values it returns.
418
279
  def call2(method, *args)
419
280
  request = create().methodCall(method, *args)
420
281
  data = do_rpc(request, false)
421
282
  parser().parseMethodResponse(data)
422
283
  end
423
284
 
285
+ # Similar to XMLRPC::Client#call, however can be called concurrently and
286
+ # use a new connection for each request. In contrast to the corresponding
287
+ # method without the +_async+ suffix, which use connect-alive (one
288
+ # connection for all requests).
289
+ #
290
+ # Note, that you have to use Thread to call these methods concurrently.
291
+ # The following example calls two methods concurrently:
292
+ #
293
+ # Thread.new {
294
+ # p client.call_async("michael.add", 4, 5)
295
+ # }
296
+ #
297
+ # Thread.new {
298
+ # p client.call_async("michael.div", 7, 9)
299
+ # }
300
+ #
424
301
  def call_async(method, *args)
425
- ok, param = call2_async(method, *args)
302
+ ok, param = call2_async(method, *args)
426
303
  if ok
427
304
  param
428
305
  else
429
306
  raise param
430
307
  end
431
- end
308
+ end
432
309
 
310
+ # Same as XMLRPC::Client#call2, but can be called concurrently.
311
+ #
312
+ # See also XMLRPC::Client#call_async
433
313
  def call2_async(method, *args)
434
314
  request = create().methodCall(method, *args)
435
315
  data = do_rpc(request, true)
@@ -437,8 +317,14 @@ module XMLRPC
437
317
  end
438
318
 
439
319
 
440
- # Multicall methods --------------------------------------------------------------
441
-
320
+ # You can use this method to execute several methods on a XMLRPC server
321
+ # which support the multi-call extension.
322
+ #
323
+ # s.multicall(
324
+ # ['michael.add', 3, 4],
325
+ # ['michael.sub', 4, 5]
326
+ # )
327
+ # # => [7, -1]
442
328
  def multicall(*methods)
443
329
  ok, params = multicall2(*methods)
444
330
  if ok
@@ -448,10 +334,30 @@ module XMLRPC
448
334
  end
449
335
  end
450
336
 
337
+ # Same as XMLRPC::Client#multicall, but returns two parameters instead of
338
+ # raising an XMLRPC::FaultException.
339
+ #
340
+ # See XMLRPC::Client#call2
451
341
  def multicall2(*methods)
452
342
  gen_multicall(methods, false)
453
343
  end
454
344
 
345
+ # Similar to XMLRPC::Client#multicall, however can be called concurrently and
346
+ # use a new connection for each request. In contrast to the corresponding
347
+ # method without the +_async+ suffix, which use connect-alive (one
348
+ # connection for all requests).
349
+ #
350
+ # Note, that you have to use Thread to call these methods concurrently.
351
+ # The following example calls two methods concurrently:
352
+ #
353
+ # Thread.new {
354
+ # p client.multicall_async("michael.add", 4, 5)
355
+ # }
356
+ #
357
+ # Thread.new {
358
+ # p client.multicall_async("michael.div", 7, 9)
359
+ # }
360
+ #
455
361
  def multicall_async(*methods)
456
362
  ok, params = multicall2_async(*methods)
457
363
  if ok
@@ -461,31 +367,65 @@ module XMLRPC
461
367
  end
462
368
  end
463
369
 
370
+ # Same as XMLRPC::Client#multicall2, but can be called concurrently.
371
+ #
372
+ # See also XMLRPC::Client#multicall_async
464
373
  def multicall2_async(*methods)
465
374
  gen_multicall(methods, true)
466
375
  end
467
376
 
468
377
 
469
- # Proxy generating methods ------------------------------------------
470
-
378
+ # Returns an object of class XMLRPC::Client::Proxy, initialized with
379
+ # +prefix+ and +args+.
380
+ #
381
+ # A proxy object returned by this method behaves like XMLRPC::Client#call,
382
+ # i.e. a call on that object will raise a XMLRPC::FaultException when a
383
+ # fault-structure is returned by that call.
471
384
  def proxy(prefix=nil, *args)
472
385
  Proxy.new(self, prefix, args, :call)
473
386
  end
474
387
 
388
+ # Almost the same like XMLRPC::Client#proxy only that a call on the returned
389
+ # XMLRPC::Client::Proxy object will return two parameters.
390
+ #
391
+ # See XMLRPC::Client#call2
475
392
  def proxy2(prefix=nil, *args)
476
393
  Proxy.new(self, prefix, args, :call2)
477
394
  end
478
395
 
396
+ # Similar to XMLRPC::Client#proxy, however can be called concurrently and
397
+ # use a new connection for each request. In contrast to the corresponding
398
+ # method without the +_async+ suffix, which use connect-alive (one
399
+ # connection for all requests).
400
+ #
401
+ # Note, that you have to use Thread to call these methods concurrently.
402
+ # The following example calls two methods concurrently:
403
+ #
404
+ # Thread.new {
405
+ # p client.proxy_async("michael.add", 4, 5)
406
+ # }
407
+ #
408
+ # Thread.new {
409
+ # p client.proxy_async("michael.div", 7, 9)
410
+ # }
411
+ #
479
412
  def proxy_async(prefix=nil, *args)
480
413
  Proxy.new(self, prefix, args, :call_async)
481
414
  end
482
415
 
416
+ # Same as XMLRPC::Client#proxy2, but can be called concurrently.
417
+ #
418
+ # See also XMLRPC::Client#proxy_async
483
419
  def proxy2_async(prefix=nil, *args)
484
420
  Proxy.new(self, prefix, args, :call2_async)
485
421
  end
486
422
 
487
423
 
488
- private # ----------------------------------------------------------
424
+ private
425
+
426
+ def net_http(host, port, proxy_host, proxy_port)
427
+ Net::HTTP.new host, port, proxy_host, proxy_port
428
+ end
489
429
 
490
430
  def set_auth
491
431
  if @user.nil?
@@ -493,15 +433,15 @@ module XMLRPC
493
433
  else
494
434
  a = "#@user"
495
435
  a << ":#@password" if @password != nil
496
- @auth = ("Basic " + [a].pack("m")).chomp
436
+ @auth = "Basic " + [a].pack("m0")
497
437
  end
498
438
  end
499
439
 
500
440
  def do_rpc(request, async=false)
501
- header = {
441
+ header = {
502
442
  "User-Agent" => USER_AGENT,
503
443
  "Content-Type" => "text/xml; charset=utf-8",
504
- "Content-Length" => request.size.to_s,
444
+ "Content-Length" => request.bytesize.to_s,
505
445
  "Connection" => (async ? "close" : "keep-alive")
506
446
  }
507
447
 
@@ -512,44 +452,45 @@ module XMLRPC
512
452
  # add authorization header
513
453
  header["Authorization"] = @auth
514
454
  end
515
-
455
+
516
456
  resp = nil
517
457
  @http_last_response = nil
518
458
 
519
459
  if async
520
- # use a new HTTP object for each call
521
- Net::HTTP.version_1_2
522
- http = Net::HTTP.new(@host, @port, @proxy_host, @proxy_port)
460
+ # use a new HTTP object for each call
461
+ http = net_http(@host, @port, @proxy_host, @proxy_port)
523
462
  http.use_ssl = @use_ssl if @use_ssl
524
463
  http.read_timeout = @timeout
525
464
  http.open_timeout = @timeout
526
-
465
+
527
466
  # post request
528
467
  http.start {
529
- resp = http.post2(@path, request, header)
468
+ resp = http.request_post(@path, request, header)
530
469
  }
531
470
  else
532
471
  # reuse the HTTP object for each call => connection alive is possible
533
472
  # we must start connection explicitely first time so that http.request
534
473
  # does not assume that we don't want keepalive
535
474
  @http.start if not @http.started?
536
-
475
+
537
476
  # post request
538
- resp = @http.post2(@path, request, header)
477
+ resp = @http.request_post(@path, request, header)
539
478
  end
540
-
479
+
541
480
  @http_last_response = resp
542
481
 
543
482
  data = resp.body
544
483
 
545
484
  if resp.code == "401"
546
485
  # Authorization Required
547
- raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}"
486
+ raise "Authorization failed.\nHTTP-Error: #{resp.code} #{resp.message}"
548
487
  elsif resp.code[0,1] != "2"
549
- raise "HTTP-Error: #{resp.code} #{resp.message}"
488
+ raise "HTTP-Error: #{resp.code} #{resp.message}"
550
489
  end
551
490
 
552
- ct = parse_content_type(resp["Content-Type"]).first
491
+ # assume text/xml on instances where Content-Type header is not set
492
+ ct_expected = resp["Content-Type"] || 'text/xml'
493
+ ct = parse_content_type(ct_expected).first
553
494
  if ct != "text/xml"
554
495
  if ct == "text/html"
555
496
  raise "Wrong content-type (received '#{ct}' but expected 'text/xml'): \n#{data}"
@@ -559,10 +500,10 @@ module XMLRPC
559
500
  end
560
501
 
561
502
  expected = resp["Content-Length"] || "<unknown>"
562
- if data.nil? or data.size == 0
563
- raise "Wrong size. Was #{data.size}, should be #{expected}"
564
- elsif expected != "<unknown>" and expected.to_i != data.size and resp["Transfer-Encoding"].nil?
565
- raise "Wrong size. Was #{data.size}, should be #{expected}"
503
+ if data.nil? or data.bytesize == 0
504
+ raise "Wrong size. Was #{data.bytesize}, should be #{expected}"
505
+ elsif expected != "<unknown>" and expected.to_i != data.bytesize and resp["Transfer-Encoding"].nil?
506
+ raise "Wrong size. Was #{data.bytesize}, should be #{expected}"
566
507
  end
567
508
 
568
509
  set_cookies = resp.get_fields("Set-Cookie")
@@ -581,11 +522,11 @@ module XMLRPC
581
522
  meth = :call2
582
523
  meth = :call2_async if async
583
524
 
584
- ok, params = self.send(meth, "system.multicall",
525
+ ok, params = self.send(meth, "system.multicall",
585
526
  methods.collect {|m| {'methodName' => m[0], 'params' => m[1..-1]} }
586
527
  )
587
528
 
588
- if ok
529
+ if ok
589
530
  params = params.collect do |param|
590
531
  if param.is_a? Array
591
532
  param[0]
@@ -593,7 +534,7 @@ module XMLRPC
593
534
  XMLRPC::FaultException.new(param["faultCode"], param["faultString"])
594
535
  else
595
536
  raise "Wrong multicall return value"
596
- end
537
+ end
597
538
  end
598
539
  end
599
540
 
@@ -602,19 +543,55 @@ module XMLRPC
602
543
 
603
544
 
604
545
 
546
+ # XML-RPC calls look nicer!
547
+ #
548
+ # You can call any method onto objects of that class - the object handles
549
+ # XMLRPC::Client::Proxy#method_missing and will forward the method call to
550
+ # a XML-RPC server.
551
+ #
552
+ # Don't use this class directly, instead use the public instance method
553
+ # XMLRPC::Client#proxy or XMLRPC::Client#proxy2.
554
+ #
555
+ # require "xmlrpc/client"
556
+ #
557
+ # server = XMLRPC::Client.new("www.ruby-lang.org", "/RPC2", 80)
558
+ #
559
+ # michael = server.proxy("michael")
560
+ # michael2 = server.proxy("michael", 4)
561
+ #
562
+ # # both calls should return the same value '9'.
563
+ # p michael.add(4,5)
564
+ # p michael2.add(5)
605
565
  class Proxy
606
566
 
567
+ # Creates an object which provides XMLRPC::Client::Proxy#method_missing.
568
+ #
569
+ # The given +server+ must be an instance of XMLRPC::Client, which is the
570
+ # XML-RPC server to be used for a XML-RPC call.
571
+ #
572
+ # +prefix+ and +delim+ will be prepended to the method name called onto this object.
573
+ #
574
+ # An optional parameter +meth+ is the method to use for a RPC.
575
+ # It can be either, call, call2, call_async, call2_async
576
+ #
577
+ # +args+ are arguments which are automatically given to every XML-RPC
578
+ # call before being provided through +method_missing+.
607
579
  def initialize(server, prefix, args=[], meth=:call, delim=".")
608
- @server = server
609
- @prefix = prefix ? prefix + delim : ""
610
- @args = args
580
+ @server = server
581
+ @prefix = prefix ? prefix + delim : ""
582
+ @args = args
611
583
  @meth = meth
612
584
  end
613
585
 
586
+ # Every method call is forwarded to the XML-RPC server defined in
587
+ # XMLRPC::Client::Proxy#new.
588
+ #
589
+ # Note: Inherited methods from class Object cannot be used as XML-RPC
590
+ # names, because they get around +method_missing+.
614
591
  def method_missing(mid, *args)
615
- pre = @prefix + mid.to_s
616
- arg = @args + args
617
- @server.send(@meth, pre, *arg)
592
+ pre = @prefix + mid.to_s
593
+ arg = @args + args
594
+ @server.send(@meth, pre, *arg)
618
595
  end
619
596
 
620
597
  end # class Proxy