ยปCore Development>Code coverage>Lib/SimpleXMLRPCServer.py

Python code coverage for Lib/SimpleXMLRPCServer.py

#countcontent
1n/a"""Simple XML-RPC Server.
2n/a
3n/aThis module can be used to create simple XML-RPC servers
4n/aby creating a server and either installing functions, a
5n/aclass instance, or by extending the SimpleXMLRPCServer
6n/aclass.
7n/a
8n/aIt can also be used to handle XML-RPC requests in a CGI
9n/aenvironment using CGIXMLRPCRequestHandler.
10n/a
11n/aA list of possible usage patterns follows:
12n/a
13n/a1. Install functions:
14n/a
15n/aserver = SimpleXMLRPCServer(("localhost", 8000))
16n/aserver.register_function(pow)
17n/aserver.register_function(lambda x,y: x+y, 'add')
18n/aserver.serve_forever()
19n/a
20n/a2. Install an instance:
21n/a
22n/aclass MyFuncs:
23n/a def __init__(self):
24n/a # make all of the string functions available through
25n/a # string.func_name
26n/a import string
27n/a self.string = string
28n/a def _listMethods(self):
29n/a # implement this method so that system.listMethods
30n/a # knows to advertise the strings methods
31n/a return list_public_methods(self) + \
32n/a ['string.' + method for method in list_public_methods(self.string)]
33n/a def pow(self, x, y): return pow(x, y)
34n/a def add(self, x, y) : return x + y
35n/a
36n/aserver = SimpleXMLRPCServer(("localhost", 8000))
37n/aserver.register_introspection_functions()
38n/aserver.register_instance(MyFuncs())
39n/aserver.serve_forever()
40n/a
41n/a3. Install an instance with custom dispatch method:
42n/a
43n/aclass Math:
44n/a def _listMethods(self):
45n/a # this method must be present for system.listMethods
46n/a # to work
47n/a return ['add', 'pow']
48n/a def _methodHelp(self, method):
49n/a # this method must be present for system.methodHelp
50n/a # to work
51n/a if method == 'add':
52n/a return "add(2,3) => 5"
53n/a elif method == 'pow':
54n/a return "pow(x, y[, z]) => number"
55n/a else:
56n/a # By convention, return empty
57n/a # string if no help is available
58n/a return ""
59n/a def _dispatch(self, method, params):
60n/a if method == 'pow':
61n/a return pow(*params)
62n/a elif method == 'add':
63n/a return params[0] + params[1]
64n/a else:
65n/a raise 'bad method'
66n/a
67n/aserver = SimpleXMLRPCServer(("localhost", 8000))
68n/aserver.register_introspection_functions()
69n/aserver.register_instance(Math())
70n/aserver.serve_forever()
71n/a
72n/a4. Subclass SimpleXMLRPCServer:
73n/a
74n/aclass MathServer(SimpleXMLRPCServer):
75n/a def _dispatch(self, method, params):
76n/a try:
77n/a # We are forcing the 'export_' prefix on methods that are
78n/a # callable through XML-RPC to prevent potential security
79n/a # problems
80n/a func = getattr(self, 'export_' + method)
81n/a except AttributeError:
82n/a raise Exception('method "%s" is not supported' % method)
83n/a else:
84n/a return func(*params)
85n/a
86n/a def export_add(self, x, y):
87n/a return x + y
88n/a
89n/aserver = MathServer(("localhost", 8000))
90n/aserver.serve_forever()
91n/a
92n/a5. CGI script:
93n/a
94n/aserver = CGIXMLRPCRequestHandler()
95n/aserver.register_function(pow)
96n/aserver.handle_request()
971"""
98n/a
99n/a# Written by Brian Quinlan (brian@sweetapp.com).
100n/a# Based on code written by Fredrik Lundh.
101n/a
1021import xmlrpclib
1031from xmlrpclib import Fault
1041import SocketServer
1051import BaseHTTPServer
1061import sys
1071import os
1081import traceback
1091import re
1101try:
1111 import fcntl
1120except ImportError:
1130 fcntl = None
114n/a
1151def resolve_dotted_attribute(obj, attr, allow_dotted_names=True):
116n/a """resolve_dotted_attribute(a, 'b.c.d') => a.b.c.d
117n/a
118n/a Resolves a dotted attribute name to an object. Raises
119n/a an AttributeError if any attribute in the chain starts with a '_'.
120n/a
121n/a If the optional allow_dotted_names argument is false, dots are not
122n/a supported and this function operates similar to getattr(obj, attr).
123n/a """
124n/a
1259 if allow_dotted_names:
1267 attrs = attr.split('.')
127n/a else:
1282 attrs = [attr]
129n/a
13016 for i in attrs:
1319 if i.startswith('_'):
1321 raise AttributeError(
1331 'attempt to access private attribute "%s"' % i
134n/a )
135n/a else:
1368 obj = getattr(obj,i)
1377 return obj
138n/a
1391def list_public_methods(obj):
140n/a """Returns a list of attribute strings, found in the specified
141n/a object, which represent callable attributes"""
142n/a
143105 return [member for member in dir(obj)
14499 if not member.startswith('_') and
1456 hasattr(getattr(obj, member), '__call__')]
146n/a
1471def remove_duplicates(lst):
148n/a """remove_duplicates([2,2,2,1,3,3]) => [3,1,2]
149n/a
150n/a Returns a copy of a list without duplicates. Every list
151n/a item must be hashable and the order of the items in the
152n/a resulting list is not defined.
153n/a """
1546 u = {}
15544 for x in lst:
15638 u[x] = 1
157n/a
1586 return u.keys()
159n/a
1602class SimpleXMLRPCDispatcher:
161n/a """Mix-in class that dispatches XML-RPC requests.
162n/a
163n/a This class is used to register XML-RPC method handlers
164n/a and then to dispatch them. This class doesn't need to be
165n/a instanced directly when used by SimpleXMLRPCServer but it
166n/a can be instanced when used by the MultiPathXMLRPCServer
1671 """
168n/a
1691 def __init__(self, allow_none=False, encoding=None):
17032 self.funcs = {}
17132 self.instance = None
17232 self.allow_none = allow_none
17332 self.encoding = encoding
174n/a
1751 def register_instance(self, instance, allow_dotted_names=False):
176n/a """Registers an instance to respond to XML-RPC requests.
177n/a
178n/a Only one instance can be installed at a time.
179n/a
180n/a If the registered instance has a _dispatch method then that
181n/a method will be called with the name of the XML-RPC method and
182n/a its parameters as a tuple
183n/a e.g. instance._dispatch('add',(2,3))
184n/a
185n/a If the registered instance does not have a _dispatch method
186n/a then the instance will be searched to find a matching method
187n/a and, if found, will be called. Methods beginning with an '_'
188n/a are considered private and will not be called by
189n/a SimpleXMLRPCServer.
190n/a
191n/a If a registered function matches a XML-RPC request, then it
192n/a will be called instead of the registered instance.
193n/a
194n/a If the optional allow_dotted_names argument is true and the
195n/a instance does not have a _dispatch method, method names
196n/a containing dots are supported and resolved, as long as none of
197n/a the name segments start with an '_'.
198n/a
199n/a *** SECURITY WARNING: ***
200n/a
201n/a Enabling the allow_dotted_names options allows intruders
202n/a to access your module's global variables and may allow
203n/a intruders to execute arbitrary code on your machine. Only
204n/a use this option on a secure, closed network.
205n/a
206n/a """
207n/a
20824 self.instance = instance
20924 self.allow_dotted_names = allow_dotted_names
210n/a
2111 def register_function(self, function, name = None):
212n/a """Registers a function to respond to XML-RPC requests.
213n/a
214n/a The optional name argument can be used to set a Unicode name
215n/a for the function.
216n/a """
217n/a
21870 if name is None:
21950 name = function.__name__
22070 self.funcs[name] = function
221n/a
2221 def register_introspection_functions(self):
223n/a """Registers the XML-RPC introspection methods in the system
224n/a namespace.
225n/a
226n/a see http://xmlrpc.usefulinc.com/doc/reserved.html
227n/a """
228n/a
22928 self.funcs.update({'system.listMethods' : self.system_listMethods,
23028 'system.methodSignature' : self.system_methodSignature,
23128 'system.methodHelp' : self.system_methodHelp})
232n/a
2331 def register_multicall_functions(self):
234n/a """Registers the XML-RPC multicall method in the system
235n/a namespace.
236n/a
237n/a see http://www.xmlrpc.com/discuss/msgReader$1208"""
238n/a
23922 self.funcs.update({'system.multicall' : self.system_multicall})
240n/a
2411 def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
242n/a """Dispatches an XML-RPC method from marshalled (XML) data.
243n/a
244n/a XML-RPC methods are dispatched from the marshalled (XML) data
245n/a using the _dispatch method and the result is returned as
246n/a marshalled data. For backwards compatibility, a dispatch
247n/a function can be provided as an argument (see comment in
248n/a SimpleXMLRPCRequestHandler.do_POST) but overriding the
249n/a existing method through subclassing is the prefered means
250n/a of changing method dispatch behavior.
251n/a """
252n/a
25330 try:
25430 params, method = xmlrpclib.loads(data)
255n/a
256n/a # generate response
25730 if dispatch_method is not None:
2580 response = dispatch_method(method, params)
259n/a else:
26030 response = self._dispatch(method, params)
261n/a # wrap response in a singleton tuple
26227 response = (response,)
26327 response = xmlrpclib.dumps(response, methodresponse=1,
26427 allow_none=self.allow_none, encoding=self.encoding)
2653 except Fault, fault:
2660 response = xmlrpclib.dumps(fault, allow_none=self.allow_none,
2670 encoding=self.encoding)
2683 except:
269n/a # report exception back to server
2703 exc_type, exc_value, exc_tb = sys.exc_info()
2713 response = xmlrpclib.dumps(
2723 xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)),
2733 encoding=self.encoding, allow_none=self.allow_none,
274n/a )
275n/a
27630 return response
277n/a
2781 def system_listMethods(self):
279n/a """system.listMethods() => ['add', 'subtract', 'multiple']
280n/a
281n/a Returns a list of the methods supported by the server."""
282n/a
2836 methods = self.funcs.keys()
2846 if self.instance is not None:
285n/a # Instance can implement _listMethod to return a list of
286n/a # methods
2876 if hasattr(self.instance, '_listMethods'):
2880 methods = remove_duplicates(
2890 methods + self.instance._listMethods()
290n/a )
291n/a # if the instance has a _dispatch method then we
292n/a # don't have enough information to provide a list
293n/a # of methods
2946 elif not hasattr(self.instance, '_dispatch'):
2956 methods = remove_duplicates(
2966 methods + list_public_methods(self.instance)
297n/a )
2986 methods.sort()
2996 return methods
300n/a
3011 def system_methodSignature(self, method_name):
302n/a """system.methodSignature('add') => [double, int, int]
303n/a
304n/a Returns a list describing the signature of the method. In the
305n/a above example, the add method takes two integers as arguments
306n/a and returns a double result.
307n/a
308n/a This server does NOT support system.methodSignature."""
309n/a
310n/a # See http://xmlrpc.usefulinc.com/doc/sysmethodsig.html
311n/a
3121 return 'signatures not supported'
313n/a
3141 def system_methodHelp(self, method_name):
315n/a """system.methodHelp('add') => "Adds two integers together"
316n/a
317n/a Returns a string containing documentation for the specified method."""
318n/a
3192 method = None
3202 if method_name in self.funcs:
3211 method = self.funcs[method_name]
3221 elif self.instance is not None:
323n/a # Instance can implement _methodHelp to return help for a method
3241 if hasattr(self.instance, '_methodHelp'):
3251 return self.instance._methodHelp(method_name)
326n/a # if the instance has a _dispatch method then we
327n/a # don't have enough information to provide help
3280 elif not hasattr(self.instance, '_dispatch'):
3290 try:
3300 method = resolve_dotted_attribute(
3310 self.instance,
3320 method_name,
3330 self.allow_dotted_names
334n/a )
3350 except AttributeError:
3360 pass
337n/a
338n/a # Note that we aren't checking that the method actually
339n/a # be a callable object of some kind
3401 if method is None:
3410 return ""
342n/a else:
3431 import pydoc
3441 return pydoc.getdoc(method)
345n/a
3461 def system_multicall(self, call_list):
347n/a """system.multicall([{'methodName': 'add', 'params': [2, 2]}, ...]) => \
348n/a[[4], ...]
349n/a
350n/a Allows the caller to package multiple XML-RPC calls into a single
351n/a request.
352n/a
353n/a See http://www.xmlrpc.com/discuss/msgReader$1208
354n/a """
355n/a
3562 results = []
3576 for call in call_list:
3584 method_name = call['methodName']
3594 params = call['params']
360n/a
3614 try:
362n/a # XXX A marshalling error in any response will fail the entire
363n/a # multicall. If someone cares they should fix this.
3644 results.append([self._dispatch(method_name, params)])
3651 except Fault, fault:
3660 results.append(
3670 {'faultCode' : fault.faultCode,
3680 'faultString' : fault.faultString}
369n/a )
3701 except:
3711 exc_type, exc_value, exc_tb = sys.exc_info()
3721 results.append(
3731 {'faultCode' : 1,
3741 'faultString' : "%s:%s" % (exc_type, exc_value)}
375n/a )
3762 return results
377n/a
3781 def _dispatch(self, method, params):
379n/a """Dispatches the XML-RPC method.
380n/a
381n/a XML-RPC calls are forwarded to a registered function that
382n/a matches the called XML-RPC method name. If no such function
383n/a exists then the call is forwarded to the registered instance,
384n/a if available.
385n/a
386n/a If the registered instance has a _dispatch method then that
387n/a method will be called with the name of the XML-RPC method and
388n/a its parameters as a tuple
389n/a e.g. instance._dispatch('add',(2,3))
390n/a
391n/a If the registered instance does not have a _dispatch method
392n/a then the instance will be searched to find a matching method
393n/a and, if found, will be called.
394n/a
395n/a Methods beginning with an '_' are considered private and will
396n/a not be called.
397n/a """
398n/a
39934 func = None
40034 try:
401n/a # check to see if a matching function has been registered
40234 func = self.funcs[method]
4035 except KeyError:
4045 if self.instance is not None:
405n/a # check for a _dispatch method
4062 if hasattr(self.instance, '_dispatch'):
4070 return self.instance._dispatch(method, params)
408n/a else:
409n/a # call instance method directly
4102 try:
4112 func = resolve_dotted_attribute(
4122 self.instance,
4132 method,
4142 self.allow_dotted_names
4150 )
4161 except AttributeError:
4171 pass
418n/a
41934 if func is not None:
42030 return func(*params)
421n/a else:
4224 raise Exception('method "%s" is not supported' % method)
423n/a
4242class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
425n/a """Simple XML-RPC request handler class.
426n/a
427n/a Handles all HTTP POST requests and attempts to decode them as
428n/a XML-RPC requests.
4291 """
430n/a
431n/a # Class attribute listing the accessible path components;
432n/a # paths not on this list will result in a 404 error.
4331 rpc_paths = ('/', '/RPC2')
434n/a
435n/a #if not None, encode responses larger than this, if possible
4361 encode_threshold = 1400 #a common MTU
437n/a
438n/a #Override form StreamRequestHandler: full buffering of output
439n/a #and no Nagle.
4401 wbufsize = -1
4411 disable_nagle_algorithm = True
442n/a
443n/a # a re to match a gzip Accept-Encoding
4441 aepattern = re.compile(r"""
445n/a \s* ([^\s;]+) \s* #content-coding
446n/a (;\s* q \s*=\s* ([0-9\.]+))? #q
4471 """, re.VERBOSE | re.IGNORECASE)
448n/a
4491 def accept_encodings(self):
4501 r = {}
4511 ae = self.headers.get("Accept-Encoding", "")
4522 for e in ae.split(","):
4531 match = self.aepattern.match(e)
4541 if match:
4551 v = match.group(3)
4561 v = float(v) if v else 1.0
4571 r[match.group(1)] = v
4581 return r
459n/a
4601 def is_rpc_path_valid(self):
46138 if self.rpc_paths:
46234 return self.path in self.rpc_paths
463n/a else:
464n/a # If .rpc_paths is empty, just assume all paths are legal
4654 return True
466n/a
4671 def do_POST(self):
468n/a """Handles the HTTP POST request.
469n/a
470n/a Attempts to interpret all HTTP POST requests as XML-RPC calls,
471n/a which are forwarded to the server's _dispatch method for handling.
472n/a """
473n/a
474n/a # Check that the path is legal
47532 if not self.is_rpc_path_valid():
4760 self.report_404()
4770 return
478n/a
47932 try:
480n/a # Get arguments by reading body of request.
481n/a # We read this in chunks to avoid straining
482n/a # socket.read(); around the 10 or 15Mb mark, some platforms
483n/a # begin to have problems (bug #792570).
48432 max_chunk_size = 10*1024*1024
48532 size_remaining = int(self.headers["content-length"])
48630 L = []
48760 while size_remaining:
48830 chunk_size = min(size_remaining, max_chunk_size)
48930 L.append(self.rfile.read(chunk_size))
49030 size_remaining -= len(L[-1])
49130 data = ''.join(L)
492n/a
49330 data = self.decode_request_content(data)
49430 if data is None:
4951 return #response has been sent
496n/a
497n/a # In previous versions of SimpleXMLRPCServer, _dispatch
498n/a # could be overridden in this class, instead of in
499n/a # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
500n/a # check to see if a subclass implements _dispatch and dispatch
501n/a # using that method if present.
50229 response = self.server._marshaled_dispatch(
50329 data, getattr(self, '_dispatch', None), self.path
504n/a )
5052 except Exception, e: # This should only happen if the module is buggy
506n/a # internal error, report as HTTP server error
5072 self.send_response(500)
508n/a
509n/a # Send information about the exception if requested
5102 if hasattr(self.server, '_send_traceback_header') and \
5112 self.server._send_traceback_header:
5121 self.send_header("X-exception", str(e))
5131 self.send_header("X-traceback", traceback.format_exc())
514n/a
5152 self.send_header("Content-length", "0")
5162 self.end_headers()
517n/a else:
518n/a # got a valid XML RPC response
51929 self.send_response(200)
52029 self.send_header("Content-type", "text/xml")
52129 if self.encode_threshold is not None:
52228 if len(response) > self.encode_threshold:
5231 q = self.accept_encodings().get("gzip", 0)
5241 if q:
5251 try:
5261 response = xmlrpclib.gzip_encode(response)
5271 self.send_header("Content-Encoding", "gzip")
5280 except NotImplementedError:
5290 pass
53029 self.send_header("Content-length", str(len(response)))
53129 self.end_headers()
53229 self.wfile.write(response)
533n/a
5341 def decode_request_content(self, data):
535n/a #support gzip encoding of request
53630 encoding = self.headers.get("content-encoding", "identity").lower()
53730 if encoding == "identity":
53828 return data
5392 if encoding == "gzip":
5402 try:
5412 return xmlrpclib.gzip_decode(data)
5421 except NotImplementedError:
5430 self.send_response(501, "encoding %r not supported" % encoding)
5441 except ValueError:
5451 self.send_response(400, "error decoding gzip content")
546n/a else:
5470 self.send_response(501, "encoding %r not supported" % encoding)
5481 self.send_header("Content-length", "0")
5491 self.end_headers()
550n/a
5511 def report_404 (self):
552n/a # Report a 404 error
5531 self.send_response(404)
5541 response = 'No such page'
5551 self.send_header("Content-type", "text/plain")
5561 self.send_header("Content-length", str(len(response)))
5571 self.end_headers()
5581 self.wfile.write(response)
559n/a
5601 def log_request(self, code='-', size='-'):
561n/a """Selectively log an accepted request."""
562n/a
56338 if self.server.logRequests:
5640 BaseHTTPServer.BaseHTTPRequestHandler.log_request(self, code, size)
565n/a
5662class SimpleXMLRPCServer(SocketServer.TCPServer,
5671 SimpleXMLRPCDispatcher):
568n/a """Simple XML-RPC server.
569n/a
570n/a Simple XML-RPC server that allows functions and a single instance
571n/a to be installed to handle requests. The default implementation
572n/a attempts to dispatch XML-RPC calls to the functions or instance
573n/a installed in the server. Override the _dispatch method inhereted
574n/a from SimpleXMLRPCDispatcher to change this behavior.
5751 """
576n/a
5771 allow_reuse_address = True
578n/a
579n/a # Warning: this is for debugging purposes only! Never set this to True in
580n/a # production code, as will be sending out sensitive information (exception
581n/a # and stack trace details) when exceptions are raised inside
582n/a # SimpleXMLRPCRequestHandler.do_POST
5831 _send_traceback_header = False
584n/a
5851 def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
5861 logRequests=True, allow_none=False, encoding=None, bind_and_activate=True):
58726 self.logRequests = logRequests
588n/a
58926 SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
59026 SocketServer.TCPServer.__init__(self, addr, requestHandler, bind_and_activate)
591n/a
592n/a # [Bug #1222790] If possible, set close-on-exec flag; if a
593n/a # method spawns a subprocess, the subprocess shouldn't have
594n/a # the listening socket open.
59526 if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
59626 flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
59726 flags |= fcntl.FD_CLOEXEC
59826 fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
599n/a
6002class MultiPathXMLRPCServer(SimpleXMLRPCServer):
601n/a """Multipath XML-RPC Server
602n/a This specialization of SimpleXMLRPCServer allows the user to create
603n/a multiple Dispatcher instances and assign them to different
604n/a HTTP request paths. This makes it possible to run two or more
605n/a 'virtual XML-RPC servers' at the same port.
606n/a Make sure that the requestHandler accepts the paths in question.
6071 """
6081 def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler,
6091 logRequests=True, allow_none=False, encoding=None, bind_and_activate=True):
610n/a
6112 SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests, allow_none,
6122 encoding, bind_and_activate)
6132 self.dispatchers = {}
6142 self.allow_none = allow_none
6152 self.encoding = encoding
616n/a
6171 def add_dispatcher(self, path, dispatcher):
6184 self.dispatchers[path] = dispatcher
6194 return dispatcher
620n/a
6211 def get_dispatcher(self, path):
6224 return self.dispatchers[path]
623n/a
6241 def _marshaled_dispatch(self, data, dispatch_method = None, path = None):
6254 try:
6264 response = self.dispatchers[path]._marshaled_dispatch(
6274 data, dispatch_method, path)
6280 except:
629n/a # report low level exception back to server
630n/a # (each dispatcher should have handled their own
631n/a # exceptions)
6320 exc_type, exc_value = sys.exc_info()[:2]
6330 response = xmlrpclib.dumps(
6340 xmlrpclib.Fault(1, "%s:%s" % (exc_type, exc_value)),
6350 encoding=self.encoding, allow_none=self.allow_none)
6364 return response
637n/a
6382class CGIXMLRPCRequestHandler(SimpleXMLRPCDispatcher):
6391 """Simple handler for XML-RPC data passed through CGI."""
640n/a
6411 def __init__(self, allow_none=False, encoding=None):
6422 SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding)
643n/a
6441 def handle_xmlrpc(self, request_text):
645n/a """Handle a single XML-RPC request"""
646n/a
6471 response = self._marshaled_dispatch(request_text)
648n/a
6491 print 'Content-Type: text/xml'
6501 print 'Content-Length: %d' % len(response)
6511 print
6521 sys.stdout.write(response)
653n/a
6541 def handle_get(self):
655n/a """Handle a single HTTP GET request.
656n/a
657n/a Default implementation indicates an error because
658n/a XML-RPC uses the POST method.
659n/a """
660n/a
6611 code = 400
662n/a message, explain = \
6631 BaseHTTPServer.BaseHTTPRequestHandler.responses[code]
664n/a
6651 response = BaseHTTPServer.DEFAULT_ERROR_MESSAGE % \
6661 {
6671 'code' : code,
6681 'message' : message,
6691 'explain' : explain
670n/a }
6711 print 'Status: %d %s' % (code, message)
6721 print 'Content-Type: %s' % BaseHTTPServer.DEFAULT_ERROR_CONTENT_TYPE
6731 print 'Content-Length: %d' % len(response)
6741 print
6751 sys.stdout.write(response)
676n/a
6771 def handle_request(self, request_text = None):
678n/a """Handle a single XML-RPC request passed through a CGI post method.
679n/a
680n/a If no XML data is given then it is read from stdin. The resulting
681n/a XML-RPC response is printed to stdout along with the correct HTTP
682n/a headers.
683n/a """
684n/a
6852 if request_text is None and \
6862 os.environ.get('REQUEST_METHOD', None) == 'GET':
6871 self.handle_get()
688n/a else:
689n/a # POST data is normally available through stdin
6901 try:
6911 length = int(os.environ.get('CONTENT_LENGTH', None))
6920 except (TypeError, ValueError):
6930 length = -1
6941 if request_text is None:
6951 request_text = sys.stdin.read(length)
696n/a
6971 self.handle_xmlrpc(request_text)
698n/a
6991if __name__ == '__main__':
7000 print 'Running XML-RPC server on port 8000'
7010 server = SimpleXMLRPCServer(("localhost", 8000))
7020 server.register_function(pow)
7030 server.register_function(lambda x,y: x+y, 'add')
7040 server.serve_forever()