X-Git-Url: http://xvm.mit.edu/gitweb/invirt/packages/python-jsonrpclib.git/blobdiff_plain/669c1369c82b5dec6fd7952dce27a41ac1690b11..58b2e395701c50acb1db488108aadb3a4066eb09:/jsonrpclib/SimpleJSONRPCServer.py diff --git a/jsonrpclib/SimpleJSONRPCServer.py b/jsonrpclib/SimpleJSONRPCServer.py index ae41f93..854697b 100644 --- a/jsonrpclib/SimpleJSONRPCServer.py +++ b/jsonrpclib/SimpleJSONRPCServer.py @@ -2,26 +2,47 @@ import jsonrpclib from jsonrpclib import Fault import SimpleXMLRPCServer import SocketServer +import socket +import os import types import traceback -import fcntl import sys +try: + import fcntl +except ImportError: + # For Windows + fcntl = None def get_version(request): - if type(request) not in (types.ListType, types.DictType): - return None - if type(request) is types.ListType: - if len(request) == 0: - return None - if 'jsonrpc' not in request[0].keys(): - return None - return '2.0' # must be a dict if 'jsonrpc' in request.keys(): return 2.0 if 'id' in request.keys(): return 1.0 return None + +def validate_request(request): + if type(request) is not types.DictType: + fault = Fault( + -32600, 'Request must be {}, not %s.' % type(request) + ) + return fault + rpcid = request.get('id', None) + version = get_version(request) + if not version: + fault = Fault(-32600, 'Request %s invalid.' % request, rpcid=rpcid) + return fault + request.setdefault('params', []) + method = request.get('method', None) + params = request.get('params') + param_types = (types.ListType, types.DictType, types.TupleType) + if not method or type(method) not in types.StringTypes or \ + type(params) not in param_types: + fault = Fault( + -32600, 'Invalid request parameters or method.', rpcid=rpcid + ) + return fault + return True class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): @@ -34,34 +55,42 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): response = None try: request = jsonrpclib.loads(data) - except: - fault = Fault(-32600, 'Request %s invalid.' % data) - response = fault.response() - return response - version = get_version(request) - if not version: - fault = Fault(-32600, 'Request %s invalid.' % data) + except Exception, e: + fault = Fault(-32700, 'Request %s invalid. (%s)' % (data, e)) response = fault.response() return response + if not request: + fault = Fault(-32600, 'Request invalid -- no request data.') + return fault.response() if type(request) is types.ListType: # This SHOULD be a batch, by spec responses = [] for req_entry in request: + result = validate_request(req_entry) + if type(result) is Fault: + responses.append(result.response()) + continue resp_entry = self._marshaled_single_dispatch(req_entry) if resp_entry is not None: responses.append(resp_entry) - response = '[%s]' % ','.join(responses) - else: + if len(responses) > 0: + response = '[%s]' % ','.join(responses) + else: + response = '' + else: + result = validate_request(request) + if type(result) is Fault: + return result.response() response = self._marshaled_single_dispatch(request) return response def _marshaled_single_dispatch(self, request): # TODO - Use the multiprocessing and skip the response if # it is a notification - method = request['method'] - params = request['params'] # Put in support for custom dispatcher here # (See SimpleXMLRPCServer._marshaled_dispatch) + method = request.get('method') + params = request.get('params') try: response = self._dispatch(method, params) except: @@ -92,7 +121,7 @@ class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher): return self.instance._dispatch(method, params) else: try: - func = resolve_dotted_attribute( + func = SimpleXMLRPCServer.resolve_dotted_attribute( self.instance, method, True @@ -150,17 +179,33 @@ class SimpleJSONRPCRequestHandler( self.wfile.flush() self.connection.shutdown(1) -class SimpleJSONRPCServer(SocketServer.TCPServer, - SimpleJSONRPCDispatcher): +class SimpleJSONRPCServer(SocketServer.TCPServer, SimpleJSONRPCDispatcher): allow_reuse_address = True def __init__(self, addr, requestHandler=SimpleJSONRPCRequestHandler, - logRequests=True, encoding=None, bind_and_activate=True): + logRequests=True, encoding=None, bind_and_activate=True, + address_family=socket.AF_INET): self.logRequests = logRequests SimpleJSONRPCDispatcher.__init__(self, encoding) - SocketServer.TCPServer.__init__(self, addr, requestHandler, - bind_and_activate) + # TCPServer.__init__ has an extra parameter on 2.6+, so + # check Python version and decide on how to call it + vi = sys.version_info + self.address_family = address_family + if address_family == socket.AF_UNIX: + # Unix sockets can't be bound if they already exist in the + # filesystem. The convention of e.g. X11 is to unlink + # before binding again. + try: + os.unlink(addr) + except OSError: + pass + # if python 2.5 and lower + if vi[0] < 3 and vi[1] < 6: + SocketServer.TCPServer.__init__(self, addr, requestHandler) + else: + SocketServer.TCPServer.__init__(self, addr, requestHandler, + bind_and_activate) if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'): flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD) flags |= fcntl.FD_CLOEXEC @@ -179,10 +224,3 @@ class CGIJSONRPCRequestHandler(SimpleJSONRPCDispatcher): sys.stdout.write(response) handle_xmlrpc = handle_jsonrpc - -if __name__ == '__main__': - print 'Running JSON-RPC server on port 8000' - server = SimpleJSONRPCServer(("localhost", 8000)) - server.register_function(pow) - server.register_function(lambda x,y: x+y, 'add') - server.serve_forever()