# Copyright (c) 2001 LOGILAB S.A. (Paris, FRANCE). # http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307 # USA. __revision__ = "$Id: xmlrpc.py,v 1.5 2002/09/20 14:12:34 syt Exp $" import xmlrpclib import BaseHTTPServer from narval.communication.RPCFactory import ServerInterface from narval.services.BaseService import BaseSocketService class XMLRPCServer(ServerInterface, BaseSocketService): def __init__(self, port, method_handler) : _XMLRPCRequestHandler.call = self.call self.handler = method_handler BaseSocketService.__init__(self, port, _XMLRPCRequestHandler, 'XML-RPC RpcService') def call(self, method, params) : try: #print 'Server call', method, self.handler.EXPORTED_METHODS[method] object = getattr(self.handler, self.handler.EXPORTED_METHODS[method]) if object : func = getattr(object,method) result = apply(func, params) if result != None : return (result,) else : print 'RpcService error: No',object,'to call' except KeyError, e : import traceback traceback.print_exc() print '*-'*20 print 'RPC call to undefined/forbidden method',method,params except Exception, e : print 'Error: %s in %s when calling method %s with params %s' \ % (str(e), self.__class__, method, str(params)) import traceback traceback.print_exc() return ('',) class XMLRPCProxy: def __init__(self, uri): # delegate self.server = xmlrpclib.Server(uri, transport=None, encoding=None, verbose=0) def __request(self, methodname, params): response = self.server._ServerProxy__request(methodname, tuple(map(wrap_argument, params))) ## if type(response) in SUSPECT_TYPES or len(response) == 1: if isinstance(response, xmlrpclib.Binary) or len(response) == 1: return unwrap_argument(response) else: return tuple(map(unwrap_argument, response)) def __getattr__(self, name): return xmlrpclib._Method(self.__request, name) class _XMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): """ class for request handling on XMLRPC servers.""" def dumps(self, method, response) : return xmlrpclib.dumps(response, methodresponse=1) def loads(self, data) : params, method = xmlrpclib.loads(data) return method, params def log_message(self,format,*args): pass def do_POST(self): try: # get arguments data = self.rfile.read(int(self.headers["content-length"])) method, params = self.loads(data) # generate response try: response = self.call(method, tuple(map(unwrap_argument,params))) if type(response) != type(()): response = (wrap_argument(response),) except: # report exception back to server import sys response = xmlrpclib.dumps(xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))) status = 500 import traceback traceback.print_exc() else: response = self.dumps(method, tuple(map(wrap_argument,response))) status = 200 except: import sys print 'internal error', sys.exc_type, sys.exc_value # internal error, report as HTTP server error self.send_response(500) self.end_headers() else: # got a valid response self.send_response(status) self.send_header("Content-type", "text/xml") self.send_header("Content-length", str(len(response))) self.end_headers() self.wfile.write(response) # shut down the connection (from Skip Montanaro) self.wfile.flush() self.connection.shutdown(1) from types import StringType,UnicodeType try: SUSPECT_TYPES = [StringType,UnicodeType] SUSPECT_TYPES.append(UnicodeType) except: SUSPECT_TYPES = [StringType,] import re ASCII_RE = re.compile('[^\\s\x20-\x7E]') def wrap_argument(arg): if type(arg) in SUSPECT_TYPES and ASCII_RE.search(arg): return xmlrpclib.Binary(arg) return arg def unwrap_argument(arg): if isinstance(arg, xmlrpclib.Binary): return arg.data return arg