2 from jsonrpclib import Fault
3 import SimpleXMLRPCServer
10 def get_version(request):
11 if type(request) not in (types.ListType, types.DictType):
13 if type(request) is types.ListType:
16 if 'jsonrpc' not in request[0].keys():
20 if 'jsonrpc' in request.keys():
22 if 'id' in request.keys():
26 class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
28 def __init__(self, encoding=None):
29 SimpleXMLRPCServer.SimpleXMLRPCDispatcher.__init__(self,
33 def _marshaled_dispatch(self, data, dispatch_method = None):
36 request = jsonrpclib.loads(data)
38 fault = Fault(-32600, 'Request %s invalid.' % data)
39 response = fault.response()
41 version = get_version(request)
43 fault = Fault(-32600, 'Request %s invalid.' % data)
44 response = fault.response()
46 if type(request) is types.ListType:
47 # This SHOULD be a batch, by spec
49 for req_entry in request:
50 resp_entry = self._marshaled_single_dispatch(req_entry)
51 if resp_entry is not None:
52 responses.append(resp_entry)
53 response = '[%s]' % ','.join(responses)
55 response = self._marshaled_single_dispatch(request)
58 def _marshaled_single_dispatch(self, request):
59 # TODO - Use the multiprocessing and skip the response if
60 # it is a notification
61 method = request['method']
62 params = request['params']
63 # Put in support for custom dispatcher here
64 # (See SimpleXMLRPCServer._marshaled_dispatch)
66 response = self._dispatch(method, params)
68 exc_type, exc_value, exc_tb = sys.exc_info()
69 fault = Fault(-32603, '%s:%s' % (exc_type, exc_value))
70 return fault.response()
71 if 'id' not in request.keys() or request['id'] == None:
75 response = jsonrpclib.dumps(response,
81 exc_type, exc_value, exc_tb = sys.exc_info()
82 fault = Fault(-32603, '%s:%s' % (exc_type, exc_value))
83 return fault.response()
85 def _dispatch(self, method, params):
88 func = self.funcs[method]
90 if self.instance is not None:
91 if hasattr(self.instance, '_dispatch'):
92 return self.instance._dispatch(method, params)
95 func = SimpleXMLRPCServer.resolve_dotted_attribute(
100 except AttributeError:
104 if type(params) is types.ListType:
105 response = func(*params)
107 response = func(**params)
110 return Fault(-32602, 'Invalid parameters.')
112 err_lines = traceback.format_exc().splitlines()
113 trace_string = '%s | %s' % (err_lines[-3], err_lines[-1])
114 fault = jsonrpclib.Fault(-32603, 'Server error: %s' %
118 return Fault(-32601, 'Method %s not supported.' % method)
120 class SimpleJSONRPCRequestHandler(
121 SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
124 if not self.is_rpc_path_valid():
128 max_chunk_size = 10*1024*1024
129 size_remaining = int(self.headers["content-length"])
131 while size_remaining:
132 chunk_size = min(size_remaining, max_chunk_size)
133 L.append(self.rfile.read(chunk_size))
134 size_remaining -= len(L[-1])
136 response = self.server._marshaled_dispatch(data)
137 self.send_response(200)
139 self.send_response(500)
140 err_lines = traceback.format_exc().splitlines()
141 trace_string = '%s | %s' % (err_lines[-3], err_lines[-1])
142 fault = jsonrpclib.Fault(-32603, 'Server error: %s' % trace_string)
143 response = fault.response()
146 self.send_header("Content-type", "application/json-rpc")
147 self.send_header("Content-length", str(len(response)))
149 self.wfile.write(response)
151 self.connection.shutdown(1)
153 class SimpleJSONRPCServer(SocketServer.TCPServer,
154 SimpleJSONRPCDispatcher):
156 allow_reuse_address = True
158 def __init__(self, addr, requestHandler=SimpleJSONRPCRequestHandler,
159 logRequests=True, encoding=None, bind_and_activate=True):
160 self.logRequests = logRequests
161 SimpleJSONRPCDispatcher.__init__(self, encoding)
162 # TCPServer.__init__ has an extra parameter on 2.6+, so
163 # check Python version and decide on how to call it
164 vi = sys.version_info
165 # if python 2.5 and lower
166 if vi[0] < 3 and vi[1] < 6:
167 SocketServer.TCPServer.__init__(self, addr, requestHandler)
169 SocketServer.TCPServer.__init__(self, addr, requestHandler,
171 if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
172 flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
173 flags |= fcntl.FD_CLOEXEC
174 fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)
176 class CGIJSONRPCRequestHandler(SimpleJSONRPCDispatcher):
178 def __init__(self, encoding=None):
179 SimpleJSONRPCDispatcher.__init__(self, encoding)
181 def handle_jsonrpc(self, request_text):
182 response = self._marshaled_dispatch(request_text)
183 print 'Content-Type: application/json-rpc'
184 print 'Content-Length: %d' % len(response)
186 sys.stdout.write(response)
188 handle_xmlrpc = handle_jsonrpc
190 if __name__ == '__main__':
191 print 'Running JSON-RPC server on port 8000'
192 server = SimpleJSONRPCServer(("localhost", 8000))
193 server.register_function(pow)
194 server.register_function(lambda x,y: x+y, 'add')
195 server.serve_forever()