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.
- checksums.yaml +14 -6
- data/.travis.yml +5 -6
- data/lib/rubysl/xmlrpc.rb +1 -0
- data/lib/rubysl/xmlrpc/version.rb +1 -1
- data/lib/rubysl/xmlrpc/xmlrpc.rb +301 -0
- data/lib/xmlrpc.rb +1 -0
- data/lib/xmlrpc/.document +1 -0
- data/lib/xmlrpc/README.rdoc +300 -0
- data/lib/xmlrpc/base64.rb +27 -46
- data/lib/xmlrpc/client.rb +320 -343
- data/lib/xmlrpc/config.rb +18 -16
- data/lib/xmlrpc/create.rb +108 -112
- data/lib/xmlrpc/datetime.rb +59 -72
- data/lib/xmlrpc/httpserver.rb +38 -43
- data/lib/xmlrpc/marshal.rb +6 -16
- data/lib/xmlrpc/parser.rb +267 -242
- data/lib/xmlrpc/server.rb +297 -372
- data/lib/xmlrpc/utils.rb +40 -34
- data/rubysl-xmlrpc.gemspec +0 -1
- metadata +16 -24
data/lib/xmlrpc/server.rb
CHANGED
@@ -1,146 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
Released under the same term of license as Ruby.
|
6
|
-
|
7
|
-
= Classes
|
8
|
-
* ((<XMLRPC::BasicServer>))
|
9
|
-
* ((<XMLRPC::CGIServer>))
|
10
|
-
* ((<XMLRPC::ModRubyServer>))
|
11
|
-
* ((<XMLRPC::Server>))
|
12
|
-
* ((<XMLRPC::WEBrickServlet>))
|
13
|
-
|
14
|
-
= XMLRPC::BasicServer
|
15
|
-
== Description
|
16
|
-
Is the base class for all XML-RPC server-types (CGI, standalone).
|
17
|
-
You can add handler and set a default handler.
|
18
|
-
Do not use this server, as this is/should be an abstract class.
|
19
|
-
|
20
|
-
=== How the method to call is found
|
21
|
-
The arity (number of accepted arguments) of a handler (method or (({Proc})) object) is
|
22
|
-
compared to the given arguments submitted by the client for a RPC ((-Remote Procedure Call-)).
|
23
|
-
A handler is only called if it accepts the number of arguments, otherwise the search
|
24
|
-
for another handler will go on. When at the end no handler was found,
|
25
|
-
the ((<default_handler|XMLRPC::BasicServer#set_default_handler>)) will be called.
|
26
|
-
With this technique it is possible to do overloading by number of parameters, but
|
27
|
-
only for (({Proc})) handler, because you cannot define two methods of the same name in
|
28
|
-
the same class.
|
29
|
-
|
30
|
-
|
31
|
-
== Class Methods
|
32
|
-
--- XMLRPC::BasicServer.new( class_delim="." )
|
33
|
-
Creates a new (({XMLRPC::BasicServer})) instance, which should not be
|
34
|
-
done, because (({XMLRPC::BasicServer})) is an abstract class. This
|
35
|
-
method should be called from a subclass indirectly by a (({super})) call
|
36
|
-
in the method (({initialize})). The paramter ((|class_delim|)) is used
|
37
|
-
in ((<add_handler|XMLRPC::BasicServer#add_handler>)) when an object is
|
38
|
-
added as handler, to delimit the object-prefix and the method-name.
|
39
|
-
|
40
|
-
== Instance Methods
|
41
|
-
--- XMLRPC::BasicServer#add_handler( name, signature=nil, help=nil ) { aBlock }
|
42
|
-
Adds ((|aBlock|)) to the list of handlers, with ((|name|)) as the name of the method.
|
43
|
-
Parameters ((|signature|)) and ((|help|)) are used by the Introspection method if specified,
|
44
|
-
where ((|signature|)) is either an Array containing strings each representing a type of it's
|
45
|
-
signature (the first is the return value) or an Array of Arrays if the method has multiple
|
46
|
-
signatures. Value type-names are "int, boolean, double, string, dateTime.iso8601, base64, array, struct".
|
47
|
-
|
48
|
-
Parameter ((|help|)) is a String with informations about how to call this method etc.
|
49
|
-
|
50
|
-
A handler method or code-block can return the types listed at
|
51
|
-
((<XMLRPC::Client#call|URL:client.html#index:0>)).
|
52
|
-
When a method fails, it can tell it the client by throwing an
|
53
|
-
(({XMLRPC::FaultException})) like in this example:
|
54
|
-
s.add_handler("michael.div") do |a,b|
|
55
|
-
if b == 0
|
56
|
-
raise XMLRPC::FaultException.new(1, "division by zero")
|
57
|
-
else
|
58
|
-
a / b
|
59
|
-
end
|
60
|
-
end
|
61
|
-
The client gets in the case of (({b==0})) an object back of type
|
62
|
-
(({XMLRPC::FaultException})) that has a ((|faultCode|)) and ((|faultString|))
|
63
|
-
field.
|
64
|
-
|
65
|
-
--- XMLRPC::BasicServer#add_handler( prefix, obj )
|
66
|
-
This is the second form of ((<add_handler|XMLRPC::BasicServer#add_handler>)).
|
67
|
-
To add an object write:
|
68
|
-
server.add_handler("michael", MyHandlerClass.new)
|
69
|
-
All public methods of (({MyHandlerClass})) are accessible to
|
70
|
-
the XML-RPC clients by (('michael."name of method"')). This is
|
71
|
-
where the ((|class_delim|)) in ((<new|XMLRPC::BasicServer.new>))
|
72
|
-
has it's role, a XML-RPC method-name is defined by
|
73
|
-
((|prefix|)) + ((|class_delim|)) + (('"name of method"')).
|
74
|
-
|
75
|
-
--- XMLRPC::BasicServer#add_handler( interface, obj )
|
76
|
-
This is the third form of ((<add_handler|XMLRPC::BasicServer#add_handler>)).
|
77
|
-
|
78
|
-
Use (({XMLRPC::interface})) to generate an ServiceInterface object, which
|
79
|
-
represents an interface (with signature and help text) for a handler class.
|
80
|
-
|
81
|
-
Parameter ((|interface|)) must be of type (({XMLRPC::ServiceInterface})).
|
82
|
-
Adds all methods of ((|obj|)) which are defined in ((|interface|)) to the
|
83
|
-
server.
|
84
|
-
|
85
|
-
This is the recommended way of adding services to a server!
|
86
|
-
|
87
|
-
|
88
|
-
--- XMLRPC::BasicServer#get_default_handler
|
89
|
-
Returns the default-handler, which is called when no handler for
|
90
|
-
a method-name is found.
|
91
|
-
It is a (({Proc})) object or (({nil})).
|
92
|
-
|
93
|
-
--- XMLRPC::BasicServer#set_default_handler ( &handler )
|
94
|
-
Sets ((|handler|)) as the default-handler, which is called when
|
95
|
-
no handler for a method-name is found. ((|handler|)) is a code-block.
|
96
|
-
The default-handler is called with the (XML-RPC) method-name as first argument, and
|
97
|
-
the other arguments are the parameters given by the client-call.
|
98
|
-
|
99
|
-
If no block is specified the default of (({XMLRPC::BasicServer})) is used, which raises a
|
100
|
-
XMLRPC::FaultException saying "method missing".
|
101
|
-
|
102
|
-
|
103
|
-
--- XMLRPC::BasicServer#set_writer( writer )
|
104
|
-
Sets the XML writer to use for generating XML output.
|
105
|
-
Should be an instance of a class from module (({XMLRPC::XMLWriter})).
|
106
|
-
If this method is not called, then (({XMLRPC::Config::DEFAULT_WRITER})) is used.
|
107
|
-
|
108
|
-
--- XMLRPC::BasicServer#set_parser( parser )
|
109
|
-
Sets the XML parser to use for parsing XML documents.
|
110
|
-
Should be an instance of a class from module (({XMLRPC::XMLParser})).
|
111
|
-
If this method is not called, then (({XMLRPC::Config::DEFAULT_PARSER})) is used.
|
112
|
-
|
113
|
-
--- XMLRPC::BasicServer#add_introspection
|
114
|
-
Adds the introspection handlers "system.listMethods", "system.methodSignature" and "system.methodHelp",
|
115
|
-
where only the first one works.
|
116
|
-
|
117
|
-
--- XMLRPC::BasicServer#add_multicall
|
118
|
-
Adds the multi-call handler "system.multicall".
|
119
|
-
|
120
|
-
--- XMLRPC::BasicServer#get_service_hook
|
121
|
-
Returns the service-hook, which is called on each service request (RPC) unless it's (({nil})).
|
122
|
-
|
123
|
-
--- XMLRPC::BasicServer#set_service_hook ( &handler )
|
124
|
-
A service-hook is called for each service request (RPC).
|
125
|
-
You can use a service-hook for example to wrap existing methods and catch exceptions of them or
|
126
|
-
convert values to values recognized by XMLRPC. You can disable it by passing (({nil})) as parameter
|
127
|
-
((|handler|)) .
|
128
|
-
|
129
|
-
The service-hook is called with a (({Proc})) object and with the parameters for this (({Proc})).
|
130
|
-
An example:
|
131
|
-
|
132
|
-
server.set_service_hook {|obj, *args|
|
133
|
-
begin
|
134
|
-
ret = obj.call(*args) # call the original service-method
|
135
|
-
# could convert the return value
|
136
|
-
resuce
|
137
|
-
# rescue exceptions
|
138
|
-
end
|
139
|
-
}
|
140
|
-
|
141
|
-
=end
|
142
|
-
|
143
|
-
|
1
|
+
# xmlrpc/server.rb
|
2
|
+
# Copyright (C) 2001, 2002, 2003, 2005 by Michael Neumann (mneumann@ntecs.de)
|
3
|
+
#
|
4
|
+
# Released under the same term of license as Ruby.
|
144
5
|
|
145
6
|
require "xmlrpc/parser"
|
146
7
|
require "xmlrpc/create"
|
@@ -149,15 +10,32 @@ require "xmlrpc/utils" # ParserWriterChooseMixin
|
|
149
10
|
|
150
11
|
|
151
12
|
|
152
|
-
module XMLRPC
|
13
|
+
module XMLRPC # :nodoc:
|
153
14
|
|
154
15
|
|
16
|
+
# This is the base class for all XML-RPC server-types (CGI, standalone).
|
17
|
+
# You can add handler and set a default handler.
|
18
|
+
# Do not use this server, as this is/should be an abstract class.
|
19
|
+
#
|
20
|
+
# === How the method to call is found
|
21
|
+
# The arity (number of accepted arguments) of a handler (method or Proc
|
22
|
+
# object) is compared to the given arguments submitted by the client for a
|
23
|
+
# RPC, or Remote Procedure Call.
|
24
|
+
#
|
25
|
+
# A handler is only called if it accepts the number of arguments, otherwise
|
26
|
+
# the search for another handler will go on. When at the end no handler was
|
27
|
+
# found, the default_handler, XMLRPC::BasicServer#set_default_handler will be
|
28
|
+
# called.
|
29
|
+
#
|
30
|
+
# With this technique it is possible to do overloading by number of parameters, but
|
31
|
+
# only for Proc handler, because you cannot define two methods of the same name in
|
32
|
+
# the same class.
|
155
33
|
class BasicServer
|
156
34
|
|
157
35
|
include ParserWriterChooseMixin
|
158
36
|
include ParseContentType
|
159
37
|
|
160
|
-
ERR_METHOD_MISSING = 1
|
38
|
+
ERR_METHOD_MISSING = 1
|
161
39
|
ERR_UNCAUGHT_EXCEPTION = 2
|
162
40
|
ERR_MC_WRONG_PARAM = 3
|
163
41
|
ERR_MC_MISSING_PARAMS = 4
|
@@ -167,9 +45,17 @@ class BasicServer
|
|
167
45
|
ERR_MC_EXPECTED_STRUCT = 8
|
168
46
|
|
169
47
|
|
48
|
+
# Creates a new XMLRPC::BasicServer instance, which should not be
|
49
|
+
# done, because XMLRPC::BasicServer is an abstract class. This
|
50
|
+
# method should be called from a subclass indirectly by a +super+ call
|
51
|
+
# in the initialize method.
|
52
|
+
#
|
53
|
+
# The paramter +class_delim+ is used by add_handler, see
|
54
|
+
# XMLRPC::BasicServer#add_handler, when an object is added as a handler, to
|
55
|
+
# delimit the object-prefix and the method-name.
|
170
56
|
def initialize(class_delim=".")
|
171
57
|
@handler = []
|
172
|
-
@default_handler = nil
|
58
|
+
@default_handler = nil
|
173
59
|
@service_hook = nil
|
174
60
|
|
175
61
|
@class_delim = class_delim
|
@@ -180,10 +66,56 @@ class BasicServer
|
|
180
66
|
add_introspection if Config::ENABLE_INTROSPECTION
|
181
67
|
end
|
182
68
|
|
69
|
+
# Adds +aBlock+ to the list of handlers, with +name+ as the name of
|
70
|
+
# the method.
|
71
|
+
#
|
72
|
+
# Parameters +signature+ and +help+ are used by the Introspection method if
|
73
|
+
# specified, where +signature+ is either an Array containing strings each
|
74
|
+
# representing a type of it's signature (the first is the return value) or
|
75
|
+
# an Array of Arrays if the method has multiple signatures.
|
76
|
+
#
|
77
|
+
# Value type-names are "int, boolean, double, string, dateTime.iso8601,
|
78
|
+
# base64, array, struct".
|
79
|
+
#
|
80
|
+
# Parameter +help+ is a String with information about how to call this method etc.
|
81
|
+
#
|
82
|
+
# When a method fails, it can tell the client by throwing an
|
83
|
+
# XMLRPC::FaultException like in this example:
|
84
|
+
#
|
85
|
+
# s.add_handler("michael.div") do |a,b|
|
86
|
+
# if b == 0
|
87
|
+
# raise XMLRPC::FaultException.new(1, "division by zero")
|
88
|
+
# else
|
89
|
+
# a / b
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# In the case of <code>b==0</code> the client gets an object back of type
|
94
|
+
# XMLRPC::FaultException that has a +faultCode+ and +faultString+ field.
|
95
|
+
#
|
96
|
+
# This is the second form of ((<add_handler|XMLRPC::BasicServer#add_handler>)).
|
97
|
+
# To add an object write:
|
98
|
+
#
|
99
|
+
# server.add_handler("michael", MyHandlerClass.new)
|
100
|
+
#
|
101
|
+
# All public methods of MyHandlerClass are accessible to
|
102
|
+
# the XML-RPC clients by <code>michael."name of method"</code>. This is
|
103
|
+
# where the +class_delim+ in XMLRPC::BasicServer.new plays it's role, a
|
104
|
+
# XML-RPC method-name is defined by +prefix+ + +class_delim+ + <code>"name
|
105
|
+
# of method"</code>.
|
106
|
+
#
|
107
|
+
# The third form of +add_handler is to use XMLRPC::Service::Interface to
|
108
|
+
# generate an object, which represents an interface (with signature and
|
109
|
+
# help text) for a handler class.
|
110
|
+
#
|
111
|
+
# The +interface+ parameter must be an instance of XMLRPC::Service::Interface.
|
112
|
+
# Adds all methods of +obj+ which are defined in the +interface+ to the server.
|
113
|
+
#
|
114
|
+
# This is the recommended way of adding services to a server!
|
183
115
|
def add_handler(prefix, obj_or_signature=nil, help=nil, &block)
|
184
116
|
if block_given?
|
185
117
|
# proc-handler
|
186
|
-
@handler << [prefix, block, obj_or_signature, help]
|
118
|
+
@handler << [prefix, block, obj_or_signature, help]
|
187
119
|
else
|
188
120
|
if prefix.kind_of? String
|
189
121
|
# class-handler
|
@@ -200,34 +132,72 @@ class BasicServer
|
|
200
132
|
self
|
201
133
|
end
|
202
134
|
|
135
|
+
# Returns the service-hook, which is called on each service request (RPC)
|
136
|
+
# unless it's +nil+.
|
203
137
|
def get_service_hook
|
204
138
|
@service_hook
|
205
139
|
end
|
206
140
|
|
141
|
+
# A service-hook is called for each service request (RPC).
|
142
|
+
#
|
143
|
+
# You can use a service-hook for example to wrap existing methods and catch
|
144
|
+
# exceptions of them or convert values to values recognized by XMLRPC.
|
145
|
+
#
|
146
|
+
# You can disable it by passing +nil+ as the +handler+ parameter.
|
147
|
+
#
|
148
|
+
# The service-hook is called with a Proc object along with any parameters.
|
149
|
+
#
|
150
|
+
# An example:
|
151
|
+
#
|
152
|
+
# server.set_service_hook {|obj, *args|
|
153
|
+
# begin
|
154
|
+
# ret = obj.call(*args) # call the original service-method
|
155
|
+
# # could convert the return value
|
156
|
+
# rescue
|
157
|
+
# # rescue exceptions
|
158
|
+
# end
|
159
|
+
# }
|
160
|
+
#
|
207
161
|
def set_service_hook(&handler)
|
208
162
|
@service_hook = handler
|
209
163
|
self
|
210
164
|
end
|
211
|
-
|
165
|
+
|
166
|
+
# Returns the default-handler, which is called when no handler for
|
167
|
+
# a method-name is found.
|
168
|
+
#
|
169
|
+
# It is either a Proc object or +nil+.
|
212
170
|
def get_default_handler
|
213
171
|
@default_handler
|
214
172
|
end
|
215
173
|
|
216
|
-
|
174
|
+
# Sets +handler+ as the default-handler, which is called when
|
175
|
+
# no handler for a method-name is found.
|
176
|
+
#
|
177
|
+
# +handler+ is a code-block.
|
178
|
+
#
|
179
|
+
# The default-handler is called with the (XML-RPC) method-name as first
|
180
|
+
# argument, and the other arguments are the parameters given by the
|
181
|
+
# client-call.
|
182
|
+
#
|
183
|
+
# If no block is specified the default of XMLRPC::BasicServer is
|
184
|
+
# used, which raises a XMLRPC::FaultException saying "method missing".
|
185
|
+
def set_default_handler(&handler)
|
217
186
|
@default_handler = handler
|
218
187
|
self
|
219
|
-
end
|
188
|
+
end
|
220
189
|
|
190
|
+
# Adds the multi-call handler <code>"system.multicall"</code>.
|
221
191
|
def add_multicall
|
222
192
|
add_handler("system.multicall", %w(array array), "Multicall Extension") do |arrStructs|
|
223
|
-
unless arrStructs.is_a? Array
|
193
|
+
unless arrStructs.is_a? Array
|
224
194
|
raise XMLRPC::FaultException.new(ERR_MC_WRONG_PARAM, "system.multicall expects an array")
|
225
195
|
end
|
226
196
|
|
227
197
|
arrStructs.collect {|call|
|
228
198
|
if call.is_a? Hash
|
229
199
|
methodName = call["methodName"]
|
230
|
-
params = call["params"]
|
200
|
+
params = call["params"]
|
231
201
|
|
232
202
|
if params.nil?
|
233
203
|
multicall_fault(ERR_MC_MISSING_PARAMS, "Missing params")
|
@@ -246,20 +216,23 @@ class BasicServer
|
|
246
216
|
[val]
|
247
217
|
else
|
248
218
|
# exception
|
249
|
-
multicall_fault(val.faultCode, val.faultString)
|
219
|
+
multicall_fault(val.faultCode, val.faultString)
|
250
220
|
end
|
251
221
|
end
|
252
222
|
end
|
253
|
-
end
|
254
|
-
|
223
|
+
end
|
224
|
+
|
255
225
|
else
|
256
226
|
multicall_fault(ERR_MC_EXPECTED_STRUCT, "system.multicall expected struct")
|
257
227
|
end
|
258
|
-
}
|
228
|
+
}
|
259
229
|
end # end add_handler
|
260
230
|
self
|
261
231
|
end
|
262
232
|
|
233
|
+
# Adds the introspection handlers <code>"system.listMethods"</code>,
|
234
|
+
# <code>"system.methodSignature"</code> and
|
235
|
+
# <code>"system.methodHelp"</code>, where only the first one works.
|
263
236
|
def add_introspection
|
264
237
|
add_handler("system.listMethods",%w(array), "List methods available on this XML-RPC server") do
|
265
238
|
methods = []
|
@@ -284,7 +257,7 @@ class BasicServer
|
|
284
257
|
sig.each {|s| sigs << s}
|
285
258
|
else
|
286
259
|
# sig is a single signature, e.g. ["array"]
|
287
|
-
sigs << sig
|
260
|
+
sigs << sig
|
288
261
|
end
|
289
262
|
end
|
290
263
|
end
|
@@ -292,11 +265,11 @@ class BasicServer
|
|
292
265
|
end
|
293
266
|
|
294
267
|
add_handler("system.methodHelp", %w(string string), "Returns help on using this method") do |meth|
|
295
|
-
help = nil
|
268
|
+
help = nil
|
296
269
|
@handler.each do |name, obj, sig, hlp|
|
297
|
-
if obj.kind_of? Proc and name == meth
|
270
|
+
if obj.kind_of? Proc and name == meth
|
298
271
|
help = hlp
|
299
|
-
break
|
272
|
+
break
|
300
273
|
end
|
301
274
|
end
|
302
275
|
help || ""
|
@@ -306,21 +279,18 @@ class BasicServer
|
|
306
279
|
end
|
307
280
|
|
308
281
|
|
309
|
-
|
282
|
+
|
310
283
|
def process(data)
|
311
|
-
method, params = parser().parseMethodCall(data)
|
284
|
+
method, params = parser().parseMethodCall(data)
|
312
285
|
handle(method, *params)
|
313
286
|
end
|
314
|
-
|
315
|
-
private
|
287
|
+
|
288
|
+
private
|
316
289
|
|
317
290
|
def multicall_fault(nr, str)
|
318
291
|
{"faultCode" => nr, "faultString" => str}
|
319
292
|
end
|
320
|
-
|
321
|
-
#
|
322
|
-
# method dispatch
|
323
|
-
#
|
293
|
+
|
324
294
|
def dispatch(methodname, *args)
|
325
295
|
for name, obj in @handler
|
326
296
|
if obj.kind_of? Proc
|
@@ -333,31 +303,29 @@ class BasicServer
|
|
333
303
|
|
334
304
|
if check_arity(obj, args.size)
|
335
305
|
if @service_hook.nil?
|
336
|
-
return obj.call(*args)
|
306
|
+
return obj.call(*args)
|
337
307
|
else
|
338
308
|
return @service_hook.call(obj, *args)
|
339
309
|
end
|
340
310
|
end
|
341
|
-
end
|
342
|
-
|
311
|
+
end
|
312
|
+
|
343
313
|
if @default_handler.nil?
|
344
314
|
raise XMLRPC::FaultException.new(ERR_METHOD_MISSING, "Method #{methodname} missing or wrong number of parameters!")
|
345
315
|
else
|
346
|
-
@default_handler.call(methodname, *args)
|
316
|
+
@default_handler.call(methodname, *args)
|
347
317
|
end
|
348
318
|
end
|
349
319
|
|
350
320
|
|
351
|
-
#
|
352
|
-
# returns true, if the arity of "obj" matches
|
353
|
-
#
|
321
|
+
# Returns +true+, if the arity of +obj+ matches +n_args+
|
354
322
|
def check_arity(obj, n_args)
|
355
323
|
ary = obj.arity
|
356
324
|
|
357
325
|
if ary >= 0
|
358
326
|
n_args == ary
|
359
327
|
else
|
360
|
-
n_args >= (ary+1).abs
|
328
|
+
n_args >= (ary+1).abs
|
361
329
|
end
|
362
330
|
end
|
363
331
|
|
@@ -366,16 +334,13 @@ class BasicServer
|
|
366
334
|
def call_method(methodname, *args)
|
367
335
|
begin
|
368
336
|
[true, dispatch(methodname, *args)]
|
369
|
-
rescue XMLRPC::FaultException => e
|
370
|
-
[false, e]
|
337
|
+
rescue XMLRPC::FaultException => e
|
338
|
+
[false, e]
|
371
339
|
rescue Exception => e
|
372
340
|
[false, XMLRPC::FaultException.new(ERR_UNCAUGHT_EXCEPTION, "Uncaught exception #{e.message} in method #{methodname}")]
|
373
341
|
end
|
374
342
|
end
|
375
343
|
|
376
|
-
#
|
377
|
-
#
|
378
|
-
#
|
379
344
|
def handle(methodname, *args)
|
380
345
|
create().methodResponse(*call_method(methodname, *args))
|
381
346
|
end
|
@@ -384,57 +349,44 @@ class BasicServer
|
|
384
349
|
end
|
385
350
|
|
386
351
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
== Superclass
|
417
|
-
((<XMLRPC::BasicServer>))
|
418
|
-
|
419
|
-
== Class Methods
|
420
|
-
--- XMLRPC::CGIServer.new( *a )
|
421
|
-
Creates a new (({XMLRPC::CGIServer})) instance. All parameters given
|
422
|
-
are by-passed to ((<XMLRPC::BasicServer.new>)). You can only create
|
423
|
-
((*one*)) (({XMLRPC::CGIServer})) instance, because more than one makes
|
424
|
-
no sense.
|
425
|
-
|
426
|
-
== Instance Methods
|
427
|
-
--- XMLRPC::CGIServer#serve
|
428
|
-
Call this after you have added all you handlers to the server.
|
429
|
-
This method processes a XML-RPC methodCall and sends the answer
|
430
|
-
back to the client.
|
431
|
-
Make sure that you don't write to standard-output in a handler, or in
|
432
|
-
any other part of your program, this would case a CGI-based server to fail!
|
433
|
-
=end
|
434
|
-
|
352
|
+
# Implements a CGI-based XML-RPC server.
|
353
|
+
#
|
354
|
+
# require "xmlrpc/server"
|
355
|
+
#
|
356
|
+
# s = XMLRPC::CGIServer.new
|
357
|
+
#
|
358
|
+
# s.add_handler("michael.add") do |a,b|
|
359
|
+
# a + b
|
360
|
+
# end
|
361
|
+
#
|
362
|
+
# s.add_handler("michael.div") do |a,b|
|
363
|
+
# if b == 0
|
364
|
+
# raise XMLRPC::FaultException.new(1, "division by zero")
|
365
|
+
# else
|
366
|
+
# a / b
|
367
|
+
# end
|
368
|
+
# end
|
369
|
+
#
|
370
|
+
# s.set_default_handler do |name, *args|
|
371
|
+
# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
|
372
|
+
# " or wrong number of parameters!")
|
373
|
+
# end
|
374
|
+
#
|
375
|
+
# s.serve
|
376
|
+
#
|
377
|
+
#
|
378
|
+
# <b>Note:</b> Make sure that you don't write to standard-output in a
|
379
|
+
# handler, or in any other part of your program, this would cause a CGI-based
|
380
|
+
# server to fail!
|
435
381
|
class CGIServer < BasicServer
|
436
382
|
@@obj = nil
|
437
383
|
|
384
|
+
# Creates a new XMLRPC::CGIServer instance.
|
385
|
+
#
|
386
|
+
# All parameters given are by-passed to XMLRPC::BasicServer.new.
|
387
|
+
#
|
388
|
+
# You can only create <b>one</b> XMLRPC::CGIServer instance, because more
|
389
|
+
# than one makes no sense.
|
438
390
|
def CGIServer.new(*a)
|
439
391
|
@@obj = super(*a) if @@obj.nil?
|
440
392
|
@@obj
|
@@ -443,20 +395,24 @@ class CGIServer < BasicServer
|
|
443
395
|
def initialize(*a)
|
444
396
|
super(*a)
|
445
397
|
end
|
446
|
-
|
398
|
+
|
399
|
+
# Call this after you have added all you handlers to the server.
|
400
|
+
#
|
401
|
+
# This method processes a XML-RPC method call and sends the answer
|
402
|
+
# back to the client.
|
447
403
|
def serve
|
448
404
|
catch(:exit_serve) {
|
449
405
|
length = ENV['CONTENT_LENGTH'].to_i
|
450
406
|
|
451
|
-
http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST"
|
407
|
+
http_error(405, "Method Not Allowed") unless ENV['REQUEST_METHOD'] == "POST"
|
452
408
|
http_error(400, "Bad Request") unless parse_content_type(ENV['CONTENT_TYPE']).first == "text/xml"
|
453
|
-
http_error(411, "Length Required") unless length > 0
|
409
|
+
http_error(411, "Length Required") unless length > 0
|
454
410
|
|
455
411
|
# TODO: do we need a call to binmode?
|
456
412
|
$stdin.binmode if $stdin.respond_to? :binmode
|
457
413
|
data = $stdin.read(length)
|
458
414
|
|
459
|
-
http_error(400, "Bad Request") if data.nil? or data.
|
415
|
+
http_error(400, "Bad Request") if data.nil? or data.bytesize != length
|
460
416
|
|
461
417
|
http_write(process(data), "Content-type" => "text/xml; charset=utf-8")
|
462
418
|
}
|
@@ -467,7 +423,7 @@ class CGIServer < BasicServer
|
|
467
423
|
|
468
424
|
def http_error(status, message)
|
469
425
|
err = "#{status} #{message}"
|
470
|
-
msg = <<-"MSGEND"
|
426
|
+
msg = <<-"MSGEND"
|
471
427
|
<html>
|
472
428
|
<head>
|
473
429
|
<title>#{err}</title>
|
@@ -487,7 +443,7 @@ class CGIServer < BasicServer
|
|
487
443
|
h = {}
|
488
444
|
header.each {|key, value| h[key.to_s.capitalize] = value}
|
489
445
|
h['Status'] ||= "200 OK"
|
490
|
-
h['Content-length'] ||= body.
|
446
|
+
h['Content-length'] ||= body.bytesize.to_s
|
491
447
|
|
492
448
|
str = ""
|
493
449
|
h.each {|key, value| str << "#{key}: #{value}\r\n"}
|
@@ -498,24 +454,24 @@ class CGIServer < BasicServer
|
|
498
454
|
|
499
455
|
end
|
500
456
|
|
501
|
-
=begin
|
502
|
-
= XMLRPC::ModRubyServer
|
503
|
-
== Description
|
504
|
-
Implements a XML-RPC server, which works with Apache mod_ruby.
|
505
|
-
|
506
|
-
Use it in the same way as CGIServer!
|
507
|
-
|
508
|
-
== Superclass
|
509
|
-
((<XMLRPC::BasicServer>))
|
510
|
-
=end
|
511
457
|
|
458
|
+
# Implements a XML-RPC server, which works with Apache mod_ruby.
|
459
|
+
#
|
460
|
+
# Use it in the same way as XMLRPC::CGIServer!
|
512
461
|
class ModRubyServer < BasicServer
|
513
462
|
|
463
|
+
# Creates a new XMLRPC::ModRubyServer instance.
|
464
|
+
#
|
465
|
+
# All parameters given are by-passed to XMLRPC::BasicServer.new.
|
514
466
|
def initialize(*a)
|
515
467
|
@ap = Apache::request
|
516
468
|
super(*a)
|
517
469
|
end
|
518
470
|
|
471
|
+
# Call this after you have added all you handlers to the server.
|
472
|
+
#
|
473
|
+
# This method processes a XML-RPC method call and sends the answer
|
474
|
+
# back to the client.
|
519
475
|
def serve
|
520
476
|
catch(:exit_serve) {
|
521
477
|
header = {}
|
@@ -523,15 +479,15 @@ class ModRubyServer < BasicServer
|
|
523
479
|
|
524
480
|
length = header['Content-length'].to_i
|
525
481
|
|
526
|
-
http_error(405, "Method Not Allowed") unless @ap.request_method == "POST"
|
482
|
+
http_error(405, "Method Not Allowed") unless @ap.request_method == "POST"
|
527
483
|
http_error(400, "Bad Request") unless parse_content_type(header['Content-type']).first == "text/xml"
|
528
|
-
http_error(411, "Length Required") unless length > 0
|
484
|
+
http_error(411, "Length Required") unless length > 0
|
529
485
|
|
530
486
|
# TODO: do we need a call to binmode?
|
531
487
|
@ap.binmode
|
532
488
|
data = @ap.read(length)
|
533
489
|
|
534
|
-
http_error(400, "Bad Request") if data.nil? or data.
|
490
|
+
http_error(400, "Bad Request") if data.nil? or data.bytesize != length
|
535
491
|
|
536
492
|
http_write(process(data), 200, "Content-type" => "text/xml; charset=utf-8")
|
537
493
|
}
|
@@ -542,7 +498,7 @@ class ModRubyServer < BasicServer
|
|
542
498
|
|
543
499
|
def http_error(status, message)
|
544
500
|
err = "#{status} #{message}"
|
545
|
-
msg = <<-"MSGEND"
|
501
|
+
msg = <<-"MSGEND"
|
546
502
|
<html>
|
547
503
|
<head>
|
548
504
|
<title>#{err}</title>
|
@@ -562,148 +518,112 @@ class ModRubyServer < BasicServer
|
|
562
518
|
h = {}
|
563
519
|
header.each {|key, value| h[key.to_s.capitalize] = value}
|
564
520
|
h['Status'] ||= "200 OK"
|
565
|
-
h['Content-length'] ||= body.
|
521
|
+
h['Content-length'] ||= body.bytesize.to_s
|
566
522
|
|
567
523
|
h.each {|key, value| @ap.headers_out[key] = value }
|
568
|
-
@ap.content_type = h["Content-type"]
|
569
|
-
@ap.status = status.to_i
|
570
|
-
@ap.send_http_header
|
524
|
+
@ap.content_type = h["Content-type"]
|
525
|
+
@ap.status = status.to_i
|
526
|
+
@ap.send_http_header
|
571
527
|
|
572
528
|
@ap.print body
|
573
529
|
end
|
574
530
|
|
575
531
|
end
|
576
532
|
|
577
|
-
=begin
|
578
|
-
= XMLRPC::Server
|
579
|
-
== Synopsis
|
580
|
-
require "xmlrpc/server"
|
581
|
-
|
582
|
-
s = XMLRPC::Server.new(8080)
|
583
|
-
|
584
|
-
s.add_handler("michael.add") do |a,b|
|
585
|
-
a + b
|
586
|
-
end
|
587
|
-
|
588
|
-
s.add_handler("michael.div") do |a,b|
|
589
|
-
if b == 0
|
590
|
-
raise XMLRPC::FaultException.new(1, "division by zero")
|
591
|
-
else
|
592
|
-
a / b
|
593
|
-
end
|
594
|
-
end
|
595
|
-
|
596
|
-
s.set_default_handler do |name, *args|
|
597
|
-
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
|
598
|
-
" or wrong number of parameters!")
|
599
|
-
end
|
600
|
-
|
601
|
-
s.serve
|
602
|
-
|
603
|
-
== Description
|
604
|
-
Implements a standalone XML-RPC server. The method (({serve}))) is left if a SIGHUP is sent to the
|
605
|
-
program.
|
606
|
-
|
607
|
-
== Superclass
|
608
|
-
((<XMLRPC::WEBrickServlet>))
|
609
|
-
|
610
|
-
== Class Methods
|
611
|
-
--- XMLRPC::Server.new( port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a )
|
612
|
-
Creates a new (({XMLRPC::Server})) instance, which is a XML-RPC server listening on
|
613
|
-
port ((|port|)) and accepts requests for the host ((|host|)), which is by default only the localhost.
|
614
|
-
The server is not started, to start it you have to call ((<serve|XMLRPC::Server#serve>)).
|
615
|
-
|
616
|
-
Parameters ((|audit|)) and ((|debug|)) are obsolete!
|
617
|
-
|
618
|
-
All additionally given parameters in ((|*a|)) are by-passed to ((<XMLRPC::BasicServer.new>)).
|
619
|
-
|
620
|
-
== Instance Methods
|
621
|
-
--- XMLRPC::Server#serve
|
622
|
-
Call this after you have added all you handlers to the server.
|
623
|
-
This method starts the server to listen for XML-RPC requests and answer them.
|
624
|
-
|
625
|
-
--- XMLRPC::Server#shutdown
|
626
|
-
Stops and shuts the server down.
|
627
|
-
|
628
|
-
=end
|
629
533
|
|
630
534
|
class WEBrickServlet < BasicServer; end # forward declaration
|
631
535
|
|
536
|
+
# Implements a standalone XML-RPC server. The method XMLRPC::Server#serve is
|
537
|
+
# left if a SIGHUP is sent to the program.
|
538
|
+
#
|
539
|
+
# require "xmlrpc/server"
|
540
|
+
#
|
541
|
+
# s = XMLRPC::Server.new(8080)
|
542
|
+
#
|
543
|
+
# s.add_handler("michael.add") do |a,b|
|
544
|
+
# a + b
|
545
|
+
# end
|
546
|
+
#
|
547
|
+
# s.add_handler("michael.div") do |a,b|
|
548
|
+
# if b == 0
|
549
|
+
# raise XMLRPC::FaultException.new(1, "division by zero")
|
550
|
+
# else
|
551
|
+
# a / b
|
552
|
+
# end
|
553
|
+
# end
|
554
|
+
#
|
555
|
+
# s.set_default_handler do |name, *args|
|
556
|
+
# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
|
557
|
+
# " or wrong number of parameters!")
|
558
|
+
# end
|
559
|
+
#
|
560
|
+
# s.serve
|
632
561
|
class Server < WEBrickServlet
|
633
562
|
|
563
|
+
# Creates a new XMLRPC::Server instance, which is a XML-RPC server
|
564
|
+
# listening on the given +port+ and accepts requests for the given +host+,
|
565
|
+
# which is +localhost+ by default.
|
566
|
+
#
|
567
|
+
# The server is not started, to start it you have to call
|
568
|
+
# XMLRPC::Server#serve.
|
569
|
+
#
|
570
|
+
# The optional +audit+ and +debug+ parameters are obsolete!
|
571
|
+
#
|
572
|
+
# All additionally provided parameters in <code>*a</code> are by-passed to
|
573
|
+
# XMLRPC::BasicServer.new.
|
634
574
|
def initialize(port=8080, host="127.0.0.1", maxConnections=4, stdlog=$stdout, audit=true, debug=true, *a)
|
635
575
|
super(*a)
|
636
576
|
require 'webrick'
|
637
|
-
@server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections,
|
577
|
+
@server = WEBrick::HTTPServer.new(:Port => port, :BindAddress => host, :MaxClients => maxConnections,
|
638
578
|
:Logger => WEBrick::Log.new(stdlog))
|
639
579
|
@server.mount("/", self)
|
640
580
|
end
|
641
|
-
|
581
|
+
|
582
|
+
# Call this after you have added all you handlers to the server.
|
583
|
+
# This method starts the server to listen for XML-RPC requests and answer them.
|
642
584
|
def serve
|
643
|
-
|
644
|
-
signals = [1]
|
645
|
-
else
|
646
|
-
signals = %w[INT TERM HUP]
|
647
|
-
end
|
585
|
+
signals = %w[INT TERM HUP] & Signal.list.keys
|
648
586
|
signals.each { |signal| trap(signal) { @server.shutdown } }
|
649
587
|
|
650
588
|
@server.start
|
651
589
|
end
|
652
|
-
|
590
|
+
|
591
|
+
# Stops and shuts the server down.
|
653
592
|
def shutdown
|
654
593
|
@server.shutdown
|
655
594
|
end
|
656
|
-
|
657
|
-
end
|
658
595
|
|
659
|
-
|
660
|
-
= XMLRPC::WEBrickServlet
|
661
|
-
== Synopsis
|
662
|
-
|
663
|
-
require "webrick"
|
664
|
-
require "xmlrpc/server"
|
665
|
-
|
666
|
-
s = XMLRPC::WEBrickServlet.new
|
667
|
-
s.add_handler("michael.add") do |a,b|
|
668
|
-
a + b
|
669
|
-
end
|
670
|
-
|
671
|
-
s.add_handler("michael.div") do |a,b|
|
672
|
-
if b == 0
|
673
|
-
raise XMLRPC::FaultException.new(1, "division by zero")
|
674
|
-
else
|
675
|
-
a / b
|
676
|
-
end
|
677
|
-
end
|
678
|
-
|
679
|
-
s.set_default_handler do |name, *args|
|
680
|
-
raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
|
681
|
-
" or wrong number of parameters!")
|
682
|
-
end
|
683
|
-
|
684
|
-
httpserver = WEBrick::HTTPServer.new(:Port => 8080)
|
685
|
-
httpserver.mount("/RPC2", s)
|
686
|
-
trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows
|
687
|
-
httpserver.start
|
688
|
-
|
689
|
-
== Instance Methods
|
690
|
-
|
691
|
-
--- XMLRPC::WEBrickServlet#set_valid_ip( *ip_addr )
|
692
|
-
Specifies the valid IP addresses that are allowed to connect to the server.
|
693
|
-
Each IP is either a (({String})) or a (({Regexp})).
|
694
|
-
|
695
|
-
--- XMLRPC::WEBrickServlet#get_valid_ip
|
696
|
-
Return the via method ((<set_valid_ip|XMLRPC::Server#set_valid_ip>)) specified
|
697
|
-
valid IP addresses.
|
698
|
-
|
699
|
-
== Description
|
700
|
-
Implements a servlet for use with WEBrick, a pure Ruby (HTTP-) server framework.
|
701
|
-
|
702
|
-
== Superclass
|
703
|
-
((<XMLRPC::BasicServer>))
|
596
|
+
end
|
704
597
|
|
705
|
-
=end
|
706
598
|
|
599
|
+
# Implements a servlet for use with WEBrick, a pure Ruby (HTTP) server
|
600
|
+
# framework.
|
601
|
+
#
|
602
|
+
# require "webrick"
|
603
|
+
# require "xmlrpc/server"
|
604
|
+
#
|
605
|
+
# s = XMLRPC::WEBrickServlet.new
|
606
|
+
# s.add_handler("michael.add") do |a,b|
|
607
|
+
# a + b
|
608
|
+
# end
|
609
|
+
#
|
610
|
+
# s.add_handler("michael.div") do |a,b|
|
611
|
+
# if b == 0
|
612
|
+
# raise XMLRPC::FaultException.new(1, "division by zero")
|
613
|
+
# else
|
614
|
+
# a / b
|
615
|
+
# end
|
616
|
+
# end
|
617
|
+
#
|
618
|
+
# s.set_default_handler do |name, *args|
|
619
|
+
# raise XMLRPC::FaultException.new(-99, "Method #{name} missing" +
|
620
|
+
# " or wrong number of parameters!")
|
621
|
+
# end
|
622
|
+
#
|
623
|
+
# httpserver = WEBrick::HTTPServer.new(:Port => 8080)
|
624
|
+
# httpserver.mount("/RPC2", s)
|
625
|
+
# trap("HUP") { httpserver.shutdown } # use 1 instead of "HUP" on Windows
|
626
|
+
# httpserver.start
|
707
627
|
class WEBrickServlet < BasicServer
|
708
628
|
def initialize(*a)
|
709
629
|
super
|
@@ -711,10 +631,9 @@ class WEBrickServlet < BasicServer
|
|
711
631
|
@valid_ip = nil
|
712
632
|
end
|
713
633
|
|
714
|
-
#
|
715
|
-
# but does not break anything.
|
634
|
+
# Deprecated from WEBrick/1.2.2, but does not break anything.
|
716
635
|
def require_path_info?
|
717
|
-
false
|
636
|
+
false
|
718
637
|
end
|
719
638
|
|
720
639
|
def get_instance(config, *options)
|
@@ -722,6 +641,9 @@ class WEBrickServlet < BasicServer
|
|
722
641
|
self
|
723
642
|
end
|
724
643
|
|
644
|
+
# Specifies the valid IP addresses that are allowed to connect to the server.
|
645
|
+
#
|
646
|
+
# Each IP is either a String or a Regexp.
|
725
647
|
def set_valid_ip(*ip_addr)
|
726
648
|
if ip_addr.size == 1 and ip_addr[0].nil?
|
727
649
|
@valid_ip = nil
|
@@ -730,13 +652,16 @@ class WEBrickServlet < BasicServer
|
|
730
652
|
end
|
731
653
|
end
|
732
654
|
|
655
|
+
# Return the valid IP addresses that are allowed to connect to the server.
|
656
|
+
#
|
657
|
+
# See also, XMLRPC::Server#set_valid_ip
|
733
658
|
def get_valid_ip
|
734
659
|
@valid_ip
|
735
660
|
end
|
736
661
|
|
737
662
|
def service(request, response)
|
738
663
|
|
739
|
-
if @valid_ip
|
664
|
+
if @valid_ip
|
740
665
|
raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
|
741
666
|
end
|
742
667
|
|
@@ -745,9 +670,9 @@ class WEBrickServlet < BasicServer
|
|
745
670
|
"unsupported method `#{request.request_method}'."
|
746
671
|
end
|
747
672
|
|
748
|
-
if parse_content_type(request['Content-type']).first != "text/xml"
|
673
|
+
if parse_content_type(request['Content-type']).first != "text/xml"
|
749
674
|
raise WEBrick::HTTPStatus::BadRequest
|
750
|
-
end
|
675
|
+
end
|
751
676
|
|
752
677
|
length = (request['Content-length'] || 0).to_i
|
753
678
|
|
@@ -755,19 +680,19 @@ class WEBrickServlet < BasicServer
|
|
755
680
|
|
756
681
|
data = request.body
|
757
682
|
|
758
|
-
if data.nil? or data.
|
683
|
+
if data.nil? or data.bytesize != length
|
759
684
|
raise WEBrick::HTTPStatus::BadRequest
|
760
685
|
end
|
761
686
|
|
762
687
|
resp = process(data)
|
763
|
-
if resp.nil? or resp.
|
688
|
+
if resp.nil? or resp.bytesize <= 0
|
764
689
|
raise WEBrick::HTTPStatus::InternalServerError
|
765
690
|
end
|
766
691
|
|
767
692
|
response.status = 200
|
768
|
-
response['Content-Length'] = resp.
|
693
|
+
response['Content-Length'] = resp.bytesize
|
769
694
|
response['Content-Type'] = "text/xml; charset=utf-8"
|
770
|
-
response.body = resp
|
695
|
+
response.body = resp
|
771
696
|
end
|
772
697
|
end
|
773
698
|
|
@@ -777,6 +702,6 @@ end # module XMLRPC
|
|
777
702
|
|
778
703
|
=begin
|
779
704
|
= History
|
780
|
-
$Id
|
705
|
+
$Id$
|
781
706
|
=end
|
782
707
|
|