| # | 
 | # XML-RPC SERVER | 
 | # $Id$ | 
 | # | 
 | # an asynchronous XML-RPC server for Medusa | 
 | # | 
 | # written by Sam Rushing | 
 | # | 
 | # Based on "xmlrpcserver.py" by Fredrik Lundh (fredrik@pythonware.com) | 
 | # | 
 |  | 
 | import http_server | 
 | import xmlrpclib | 
 |  | 
 | import sys | 
 |  | 
 | class xmlrpc_handler: | 
 |  | 
 |     def match (self, request): | 
 |         # Note: /RPC2 is not required by the spec, so you may override this method. | 
 |         if request.uri[:5] == '/RPC2': | 
 |             return 1 | 
 |         else: | 
 |             return 0 | 
 |  | 
 |     def handle_request (self, request): | 
 |         [path, params, query, fragment] = request.split_uri() | 
 |  | 
 |         if request.command in ('post', 'put'): | 
 |             request.collector = collector (self, request) | 
 |         else: | 
 |             request.error (400) | 
 |  | 
 |     def continue_request (self, data, request): | 
 |         params, method = xmlrpclib.loads (data) | 
 |         try: | 
 |             # generate response | 
 |             try: | 
 |                 response = self.call (method, params) | 
 |                 response = (response,) | 
 |             except: | 
 |                 # report exception back to server | 
 |                 response = xmlrpclib.dumps ( | 
 |                     xmlrpclib.Fault (1, "%s:%s" % sys.exc_info()[:2]) | 
 |                     ) | 
 |             else: | 
 |                 response = xmlrpclib.dumps (response, methodresponse=1) | 
 |         except: | 
 |             # internal error, report as HTTP server error | 
 |             request.error (500) | 
 |         else: | 
 |             # got a valid XML RPC response | 
 |             request['Content-Type'] = 'text/xml' | 
 |             request.push (response) | 
 |             request.done() | 
 |  | 
 |     def call (self, method, params): | 
 |         # override this method to implement RPC methods | 
 |         raise "NotYetImplemented" | 
 |  | 
 | class collector: | 
 |  | 
 |     "gathers input for POST and PUT requests" | 
 |  | 
 |     def __init__ (self, handler, request): | 
 |  | 
 |         self.handler = handler | 
 |         self.request = request | 
 |         self.data = '' | 
 |  | 
 |         # make sure there's a content-length header | 
 |         cl = request.get_header ('content-length') | 
 |  | 
 |         if not cl: | 
 |             request.error (411) | 
 |         else: | 
 |             cl = int (cl) | 
 |             # using a 'numeric' terminator | 
 |             self.request.channel.set_terminator (cl) | 
 |  | 
 |     def collect_incoming_data (self, data): | 
 |         self.data = self.data + data | 
 |  | 
 |     def found_terminator (self): | 
 |         # set the terminator back to the default | 
 |         self.request.channel.set_terminator ('\r\n\r\n') | 
 |         self.handler.continue_request (self.data, self.request) | 
 |  | 
 | if __name__ == '__main__': | 
 |  | 
 |     class rpc_demo (xmlrpc_handler): | 
 |  | 
 |         def call (self, method, params): | 
 |             print 'method="%s" params=%s' % (method, params) | 
 |             return "Sure, that works" | 
 |  | 
 |     import asyncore | 
 |     import http_server | 
 |  | 
 |     hs = http_server.http_server ('', 8000) | 
 |     rpc = rpc_demo() | 
 |     hs.install_handler (rpc) | 
 |  | 
 |     asyncore.loop() |