Mercurial > hg > AuthRPC
changeset 2:c7a236de5214
-
author | Ben Croston <ben@croston.org> |
---|---|
date | Tue, 30 Aug 2011 23:37:53 +0100 |
parents | 317e6f82c733 |
children | 43595981978d |
files | client/ServerProxy.py client/ServerProxy2.py client/__init__.py client/thing.py server/JsonRpcApp.py server/__init__.py wibble/__init__.py wibble/client/ServerProxy.py wibble/client/ServerProxy2.py wibble/client/__init__.py wibble/client/thing.py wibble/server/JsonRpcApp.py wibble/server/__init__.py |
diffstat | 8 files changed, 475 insertions(+), 475 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/ServerProxy.py Tue Aug 30 23:37:53 2011 +0100 @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +from uuid import uuid4 +from urllib.parse import urlparse +import json +import http.client +import copy +import socket +import hashlib + +class _Method(object): + def __init__(self, call, name, username=None, password=None): + self.call = call + self.name = name + self._username = username + self._password = password + + def __call__(self, *args, **kwargs): + request = {} + request['id'] = str(uuid4()) + request['method'] = self.name + + if len(kwargs) is not 0: + params = copy.copy(kwargs) + index = 0 + for arg in args: + params[str(index)] = arg + index = index + 1 + elif len(args) is not 0: + params = copy.copy(args) + else: + params = None + request['params'] = params + + if self._username is not None: + request['username'] = self._username + if self._password is not None: + request['password'] = hashlib.md5(self._password.encode()).hexdigest() + + resp = self.call(json.dumps(request)) + if resp is not None and resp['error'] is None and resp['id'] == request['id']: + return resp['result'] + else: + raise Exception('This is not supposed to happen -- btc') ######## + + def __getattr__(self, name): + return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password) + +class _JSONRPCTransport(object): + headers = {'Content-Type':'application/json', + 'Accept':'application/json'} + + def __init__(self, uri, proxy_uri=None, user_agent=None): + self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib' + if proxy_uri is not None: + self.connection_url = urlparse(proxy_uri) + self.request_path = uri + else: + self.connection_url = urlparse(uri) + self.request_path = self.connection_url.path + + def request(self, request_body): + if self.connection_url.scheme == 'http': + if self.connection_url.port is None: + port = 80 + else: + port = self.connection_url.port + connection = http.client.HTTPConnection(self.connection_url.hostname+':'+str(port)) + elif self.connection_url.scheme == 'https': + if self.connection_url.port is None: + port = 443 + else: + port = self.connection_url.port + connection = http.client.HTTPSConnection(self.connection_url.hostname+':'+str(port)) + else: + raise Exception('unsupported transport') + + connection.request('POST', self.request_path, body=request_body, headers=self.headers) + return connection.getresponse() + +class BadRequestException(Exception): + """HTTP 400 - Bad Request""" + def __init__(self): + Exception.__init__(self,'HTTP 400 - Bad Request') + +class UnauthorisedException(Exception): + """HTTP 401 - Unauthorised""" + def __init__(self): + Exception.__init__(self,'HTTP 401 - Unauthorised') + +class ForbiddenException(Exception): + """HTTP 403 - Forbidden""" + def __init__(self): + Exception.__init__(self,'HTTP 403 - Forbidden') + +class NotFoundException(Exception): + """HTTP 404 - Not Found""" + def __init__(self): + Exception.__init__(self,'HTTP 404 - Not Found') + +class NetworkSocketException(Exception): + def __init__(self): + Exception.__init__(self,'Network socket exception') + +class BadGatewayException(Exception): + """HTTP 502 - Bad Gateway""" + def __init__(self): + Exception.__init__(self,'HTTP 502 - Bad Gateway') + +class ServerProxy(object): + def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None): + if uri is None and transport is None: + raise Exception('either uri or transport needs to be specified') + + if transport is None: + transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent) + self.__transport = transport + self._username = username + self._password = password + + def __request(self, request): + # call a method on the remote server + try: + response = self.__transport.request(request) + except socket.error: + raise NetworkSocketException + if response.status == 200: + return json.loads(response.read().decode()) + elif response.status == 400: + raise BadRequestException + elif response.status == 401: + raise UnauthorisedException + elif response.status == 403: + raise ForbiddenException + elif response.status == 404: + raise NotFoundException + elif response.status == 500: + msg = json.loads(response.read().decode()) + raise Exception('JSONRPCError\n%s'%msg['error']['error']) + elif response.status == 502: + raise BadGatewayException + else: + raise Exception('HTTP Status %s'%response.status) + + def __repr__(self): + return ( + "<ServerProxy for %s%s>" % + (self.__host, self.__handler) + ) + + __str__ = __repr__ + + def __getattr__(self, name): + # magic method dispatcher + return _Method(self.__request, name, self._username, self._password) + +if __name__ == '__main__': + #### btc fixme + jsonrpc_client = ServerProxy('http://localhost:1337/', username='testuser', password='', user_agent='Py3NotInternetExploiter') + #jsonrpc_client = ServerProxy('https://www.croston.org/test/index.py', + # username='testuser', + # password='', + # user_agent='Py3NotInternetExploiter') + assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod() + try: + print(jsonrpc_client.wibble('this should fail')) + except BadRequestException: + pass # test passed + else: + raise Exception('Test failed (calling unknown method)') + + print('All tests passed') +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/ServerProxy2.py Tue Aug 30 23:37:53 2011 +0100 @@ -0,0 +1,174 @@ +#!/usr/bin/env python2.7 +from uuid import uuid4 +from urlparse import urlparse +try: + import json +except: + import simplejson as json +import httplib +import copy +import socket +import hashlib + +class _Method(object): + def __init__(self, call, name, username=None, password=None): + self.call = call + self.name = name + self._username = username + self._password = password + + def __call__(self, *args, **kwargs): + request = {} + request['id'] = str(uuid4()) + request['method'] = self.name + + if len(kwargs) is not 0: + params = copy.copy(kwargs) + index = 0 + for arg in args: + params[str(index)] = arg + index = index + 1 + elif len(args) is not 0: + params = copy.copy(args) + else: + params = None + request['params'] = params + + if self._username is not None: + request['username'] = self._username + if self._password is not None: + request['password'] = hashlib.md5(self._password).hexdigest() + + resp = self.call(json.dumps(request)) + if resp is not None and resp['error'] is None and resp['id'] == request['id']: + return resp['result'] + else: + raise Exception('This is not supposed to happen -- btc') ######## + + def __getattr__(self, name): + return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password) + +class _JSONRPCTransport(object): + headers = {'Content-Type':'application/json', + 'Accept':'application/json'} + + def __init__(self, uri, proxy_uri=None, user_agent=None): + self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib' + if proxy_uri is not None: + self.connection_url = urlparse(proxy_uri) + self.request_path = uri + else: + self.connection_url = urlparse(uri) + self.request_path = self.connection_url.path + + def request(self, request_body): + if self.connection_url.scheme == 'http': + if self.connection_url.port is None: + port = 80 + else: + port = self.connection_url.port + connection = httplib.HTTPConnection(self.connection_url.hostname+':'+str(port)) + elif self.connection_url.scheme == 'https': + if self.connection_url.port is None: + port = 443 + else: + port = self.connection_url.port + connection = httplib.HTTPSConnection(self.connection_url.hostname+':'+str(port)) + else: + raise Exception('unsupported transport') + connection.request('POST', self.request_path, body=request_body, headers=self.headers) + return connection.getresponse() + +class BadRequestException(Exception): + """HTTP 400 - Bad Request""" + def __init__(self): + Exception.__init__(self,'HTTP 400 - Bad Request') + +class UnauthorisedException(Exception): + """HTTP 401 - Unauthorised""" + def __init__(self): + Exception.__init__(self,'HTTP 401 - Unauthorised') + +class ForbiddenException(Exception): + """HTTP 403 - Forbidden""" + def __init__(self): + Exception.__init__(self,'HTTP 403 - Forbidden') + +class NotFoundException(Exception): + """HTTP 404 - Not Found""" + def __init__(self): + Exception.__init__(self,'HTTP 404 - Not Found') + +class NetworkSocketException(Exception): + def __init__(self): + Exception.__init__(self,'Network socket exception') + +class BadGatewayException(Exception): + """HTTP 502 - Bad Gateway""" + def __init__(self): + Exception.__init__(self,'HTTP 502 - Bad Gateway') + +class ServerProxy2(object): + def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None): + if uri is None and transport is None: + raise Exception('either uri or transport needs to be specified') + + if transport is None: + transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent) + self.__transport = transport + self._username = username + self._password = password + + def __request(self, request): + # call a method on the remote server + try: + response = self.__transport.request(request) + except socket.error: + raise NetworkSocketException + if response.status == 200: + return json.loads(response.read()) + elif response.status == 400: + raise BadRequestException + elif response.status == 401: + raise UnauthorisedException + elif response.status == 403: + raise ForbiddenException + elif response.status == 404: + raise NotFoundException + elif response.status == 500: + msg = json.loads(response.read()) + raise Exception('JSONRPCError\n%s'%msg['error']['error']) + elif response.status == 502: + raise BadGatewayException + else: + raise Exception('HTTP Status %s'%response.status) + + def __repr__(self): + return ( + "<ServerProxy for %s%s>" % + (self.__host, self.__handler) + ) + + __str__ = __repr__ + + def __getattr__(self, name): + # magic method dispatcher + return _Method(self.__request, name, self._username, self._password) + +if __name__ == '__main__': + ##### btc fixme + jsonrpc_client = ServerProxy2('http://localhost:1337/', username='testuser', password='', user_agent='Py2NotInternetExploiter') + #jsonrpc_client = ServerProxy2('https://www.croston.org/test/index.py', + # username='testuser', + # password='', + # user_agent='Py2NotInternetExploiter') + assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod() + try: + print(jsonrpc_client.wibble('this should fail')) + except BadRequestException: + pass # test passed + else: + raise Exception('Test failed (calling unknown method)') + + print 'All tests passed' +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/thing.py Tue Aug 30 23:37:53 2011 +0100 @@ -0,0 +1,3 @@ +#!/usr/bin/python +print 'thing' +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/server/JsonRpcApp.py Tue Aug 30 23:37:53 2011 +0100 @@ -0,0 +1,126 @@ +from webob import Request, Response, exc +try: + from json import loads, dumps +except: + from simplejson import loads, dumps +import traceback +import sys + +class JsonRpcApp(object): + """ + Serve the given object via json-rpc (http://json-rpc.org/) + """ + + def __init__(self, obj, auth=None): + """ + obj - a class of functions available using jsonrpc + auth - an authentication function (optional) + """ + self.obj = obj + self.auth = auth + + def __call__(self, environ, start_response): + req = Request(environ) + try: + resp = self.process(req) + except ValueError, e: + resp = exc.HTTPBadRequest(str(e)) + except exc.HTTPException, e: + resp = e + return resp(environ, start_response) + + def process(self, req): + if not req.method == 'POST': + raise exc.HTTPMethodNotAllowed("Only POST allowed").exception + + try: + json = loads(req.body) + except ValueError, e: + raise ValueError('Bad JSON: %s' % e) + + try: + method = json['method'] + params = json['params'] + id = json['id'] + username = json['username'] if 'username' in json else None + password = json['password'] if 'password' in json else None + except KeyError, e: + raise ValueError("JSON body missing parameter: %s" % e) + + if params is None: + params = [] + if not isinstance(params, list): + raise ValueError("Bad params %r: must be a list" % params) + text = traceback.format_exc() + exc_value = sys.exc_info()[1] + error_value = dict( + name='JSONRPCError', + code=100, + message=str(exc_value), + error=text) + return Response( + status=500, + content_type='application/json', + body=dumps(dict(result=None, + error=error_value, + id=id))) + + obj = self.obj + if isinstance(self.obj,tuple) or isinstance(self.obj,list): + for x in self.obj: + if method.startswith('%s.'%x.__class__.__name__): + obj = x + method = method.replace('%s.'%obj.__class__.__name__,'',1) + break + elif method.startswith('%s.'%self.obj.__class__.__name__): + method = method.replace('%s.'%self.obj.__class__.__name__,'',1) + if method.startswith('_'): + raise exc.HTTPForbidden("Bad method name %s: must not start with _" % method).exception + try: + method = getattr(obj, method) + except AttributeError: + raise ValueError("No such method %s" % method) + + if self.auth is not None: + try: + auth_result = self.auth(username, password, req.user_agent) + except: + text = traceback.format_exc() + exc_value = sys.exc_info()[1] + error_value = dict( + name='JSONRPCError', + code=100, + message=str(exc_value), + error=text) + return Response( + status=500, + content_type='application/json', + body=dumps(dict(result=None, + error=error_value, + id=id))) + if not auth_result: + raise exc.HTTPUnauthorized().exception + + try: + result = method(*params) + except: + text = traceback.format_exc() + exc_value = sys.exc_info()[1] + error_value = dict( + name='JSONRPCError', + code=100, + message=str(exc_value), + error=text) + return Response( + status=500, + content_type='application/json', + body=dumps(dict(result=None, + error=error_value, + id=id))) + + return Response( + content_type='application/json', + body=dumps(dict(result=result, + error=None, + id=id))) +
--- a/wibble/client/ServerProxy.py Tue Aug 30 22:47:02 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,172 +0,0 @@ -#!/usr/bin/env python3 -from uuid import uuid4 -from urllib.parse import urlparse -import json -import http.client -import copy -import socket -import hashlib - -class _Method(object): - def __init__(self, call, name, username=None, password=None): - self.call = call - self.name = name - self._username = username - self._password = password - - def __call__(self, *args, **kwargs): - request = {} - request['id'] = str(uuid4()) - request['method'] = self.name - - if len(kwargs) is not 0: - params = copy.copy(kwargs) - index = 0 - for arg in args: - params[str(index)] = arg - index = index + 1 - elif len(args) is not 0: - params = copy.copy(args) - else: - params = None - request['params'] = params - - if self._username is not None: - request['username'] = self._username - if self._password is not None: - request['password'] = hashlib.md5(self._password.encode()).hexdigest() - - resp = self.call(json.dumps(request)) - if resp is not None and resp['error'] is None and resp['id'] == request['id']: - return resp['result'] - else: - raise Exception('This is not supposed to happen -- btc') ######## - - def __getattr__(self, name): - return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password) - -class _JSONRPCTransport(object): - headers = {'Content-Type':'application/json', - 'Accept':'application/json'} - - def __init__(self, uri, proxy_uri=None, user_agent=None): - self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib' - if proxy_uri is not None: - self.connection_url = urlparse(proxy_uri) - self.request_path = uri - else: - self.connection_url = urlparse(uri) - self.request_path = self.connection_url.path - - def request(self, request_body): - if self.connection_url.scheme == 'http': - if self.connection_url.port is None: - port = 80 - else: - port = self.connection_url.port - connection = http.client.HTTPConnection(self.connection_url.hostname+':'+str(port)) - elif self.connection_url.scheme == 'https': - if self.connection_url.port is None: - port = 443 - else: - port = self.connection_url.port - connection = http.client.HTTPSConnection(self.connection_url.hostname+':'+str(port)) - else: - raise Exception('unsupported transport') - - connection.request('POST', self.request_path, body=request_body, headers=self.headers) - return connection.getresponse() - -class BadRequestException(Exception): - """HTTP 400 - Bad Request""" - def __init__(self): - Exception.__init__(self,'HTTP 400 - Bad Request') - -class UnauthorisedException(Exception): - """HTTP 401 - Unauthorised""" - def __init__(self): - Exception.__init__(self,'HTTP 401 - Unauthorised') - -class ForbiddenException(Exception): - """HTTP 403 - Forbidden""" - def __init__(self): - Exception.__init__(self,'HTTP 403 - Forbidden') - -class NotFoundException(Exception): - """HTTP 404 - Not Found""" - def __init__(self): - Exception.__init__(self,'HTTP 404 - Not Found') - -class NetworkSocketException(Exception): - def __init__(self): - Exception.__init__(self,'Network socket exception') - -class BadGatewayException(Exception): - """HTTP 502 - Bad Gateway""" - def __init__(self): - Exception.__init__(self,'HTTP 502 - Bad Gateway') - -class ServerProxy(object): - def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None): - if uri is None and transport is None: - raise Exception('either uri or transport needs to be specified') - - if transport is None: - transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent) - self.__transport = transport - self._username = username - self._password = password - - def __request(self, request): - # call a method on the remote server - try: - response = self.__transport.request(request) - except socket.error: - raise NetworkSocketException - if response.status == 200: - return json.loads(response.read().decode()) - elif response.status == 400: - raise BadRequestException - elif response.status == 401: - raise UnauthorisedException - elif response.status == 403: - raise ForbiddenException - elif response.status == 404: - raise NotFoundException - elif response.status == 500: - msg = json.loads(response.read().decode()) - raise Exception('JSONRPCError\n%s'%msg['error']['error']) - elif response.status == 502: - raise BadGatewayException - else: - raise Exception('HTTP Status %s'%response.status) - - def __repr__(self): - return ( - "<ServerProxy for %s%s>" % - (self.__host, self.__handler) - ) - - __str__ = __repr__ - - def __getattr__(self, name): - # magic method dispatcher - return _Method(self.__request, name, self._username, self._password) - -if __name__ == '__main__': - #### btc fixme - jsonrpc_client = ServerProxy('http://localhost:1337/', username='testuser', password='', user_agent='Py3NotInternetExploiter') - #jsonrpc_client = ServerProxy('https://www.croston.org/test/index.py', - # username='testuser', - # password='', - # user_agent='Py3NotInternetExploiter') - assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod() - try: - print(jsonrpc_client.wibble('this should fail')) - except BadRequestException: - pass # test passed - else: - raise Exception('Test failed (calling unknown method)') - - print('All tests passed') -
--- a/wibble/client/ServerProxy2.py Tue Aug 30 22:47:02 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -#!/usr/bin/env python2.7 -from uuid import uuid4 -from urlparse import urlparse -try: - import json -except: - import simplejson as json -import httplib -import copy -import socket -import hashlib - -class _Method(object): - def __init__(self, call, name, username=None, password=None): - self.call = call - self.name = name - self._username = username - self._password = password - - def __call__(self, *args, **kwargs): - request = {} - request['id'] = str(uuid4()) - request['method'] = self.name - - if len(kwargs) is not 0: - params = copy.copy(kwargs) - index = 0 - for arg in args: - params[str(index)] = arg - index = index + 1 - elif len(args) is not 0: - params = copy.copy(args) - else: - params = None - request['params'] = params - - if self._username is not None: - request['username'] = self._username - if self._password is not None: - request['password'] = hashlib.md5(self._password).hexdigest() - - resp = self.call(json.dumps(request)) - if resp is not None and resp['error'] is None and resp['id'] == request['id']: - return resp['result'] - else: - raise Exception('This is not supposed to happen -- btc') ######## - - def __getattr__(self, name): - return _Method(self.call, "%s.%s" % (self.name, name), self._username, self._password) - -class _JSONRPCTransport(object): - headers = {'Content-Type':'application/json', - 'Accept':'application/json'} - - def __init__(self, uri, proxy_uri=None, user_agent=None): - self.headers['User-Agent'] = user_agent if user_agent is not None else 'jsonrpclib' - if proxy_uri is not None: - self.connection_url = urlparse(proxy_uri) - self.request_path = uri - else: - self.connection_url = urlparse(uri) - self.request_path = self.connection_url.path - - def request(self, request_body): - if self.connection_url.scheme == 'http': - if self.connection_url.port is None: - port = 80 - else: - port = self.connection_url.port - connection = httplib.HTTPConnection(self.connection_url.hostname+':'+str(port)) - elif self.connection_url.scheme == 'https': - if self.connection_url.port is None: - port = 443 - else: - port = self.connection_url.port - connection = httplib.HTTPSConnection(self.connection_url.hostname+':'+str(port)) - else: - raise Exception('unsupported transport') - connection.request('POST', self.request_path, body=request_body, headers=self.headers) - return connection.getresponse() - -class BadRequestException(Exception): - """HTTP 400 - Bad Request""" - def __init__(self): - Exception.__init__(self,'HTTP 400 - Bad Request') - -class UnauthorisedException(Exception): - """HTTP 401 - Unauthorised""" - def __init__(self): - Exception.__init__(self,'HTTP 401 - Unauthorised') - -class ForbiddenException(Exception): - """HTTP 403 - Forbidden""" - def __init__(self): - Exception.__init__(self,'HTTP 403 - Forbidden') - -class NotFoundException(Exception): - """HTTP 404 - Not Found""" - def __init__(self): - Exception.__init__(self,'HTTP 404 - Not Found') - -class NetworkSocketException(Exception): - def __init__(self): - Exception.__init__(self,'Network socket exception') - -class BadGatewayException(Exception): - """HTTP 502 - Bad Gateway""" - def __init__(self): - Exception.__init__(self,'HTTP 502 - Bad Gateway') - -class ServerProxy2(object): - def __init__(self, uri=None, transport=None, proxy_uri=None, user_agent=None, username=None, password=None): - if uri is None and transport is None: - raise Exception('either uri or transport needs to be specified') - - if transport is None: - transport = _JSONRPCTransport(uri, proxy_uri=proxy_uri, user_agent=user_agent) - self.__transport = transport - self._username = username - self._password = password - - def __request(self, request): - # call a method on the remote server - try: - response = self.__transport.request(request) - except socket.error: - raise NetworkSocketException - if response.status == 200: - return json.loads(response.read()) - elif response.status == 400: - raise BadRequestException - elif response.status == 401: - raise UnauthorisedException - elif response.status == 403: - raise ForbiddenException - elif response.status == 404: - raise NotFoundException - elif response.status == 500: - msg = json.loads(response.read()) - raise Exception('JSONRPCError\n%s'%msg['error']['error']) - elif response.status == 502: - raise BadGatewayException - else: - raise Exception('HTTP Status %s'%response.status) - - def __repr__(self): - return ( - "<ServerProxy for %s%s>" % - (self.__host, self.__handler) - ) - - __str__ = __repr__ - - def __getattr__(self, name): - # magic method dispatcher - return _Method(self.__request, name, self._username, self._password) - -if __name__ == '__main__': - ##### btc fixme - jsonrpc_client = ServerProxy2('http://localhost:1337/', username='testuser', password='', user_agent='Py2NotInternetExploiter') - #jsonrpc_client = ServerProxy2('https://www.croston.org/test/index.py', - # username='testuser', - # password='', - # user_agent='Py2NotInternetExploiter') - assert jsonrpc_client.api.mymethod() == jsonrpc_client.mymethod() - try: - print(jsonrpc_client.wibble('this should fail')) - except BadRequestException: - pass # test passed - else: - raise Exception('Test failed (calling unknown method)') - - print 'All tests passed' -
--- a/wibble/client/thing.py Tue Aug 30 22:47:02 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -#!/usr/bin/python -print 'thing' -
--- a/wibble/server/JsonRpcApp.py Tue Aug 30 22:47:02 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -from webob import Request, Response, exc -try: - from json import loads, dumps -except: - from simplejson import loads, dumps -import traceback -import sys - -class JsonRpcApp(object): - """ - Serve the given object via json-rpc (http://json-rpc.org/) - """ - - def __init__(self, obj, auth=None): - """ - obj - a class of functions available using jsonrpc - auth - an authentication function (optional) - """ - self.obj = obj - self.auth = auth - - def __call__(self, environ, start_response): - req = Request(environ) - try: - resp = self.process(req) - except ValueError, e: - resp = exc.HTTPBadRequest(str(e)) - except exc.HTTPException, e: - resp = e - return resp(environ, start_response) - - def process(self, req): - if not req.method == 'POST': - raise exc.HTTPMethodNotAllowed("Only POST allowed").exception - - try: - json = loads(req.body) - except ValueError, e: - raise ValueError('Bad JSON: %s' % e) - - try: - method = json['method'] - params = json['params'] - id = json['id'] - username = json['username'] if 'username' in json else None - password = json['password'] if 'password' in json else None - except KeyError, e: - raise ValueError("JSON body missing parameter: %s" % e) - - if params is None: - params = [] - if not isinstance(params, list): - raise ValueError("Bad params %r: must be a list" % params) - text = traceback.format_exc() - exc_value = sys.exc_info()[1] - error_value = dict( - name='JSONRPCError', - code=100, - message=str(exc_value), - error=text) - return Response( - status=500, - content_type='application/json', - body=dumps(dict(result=None, - error=error_value, - id=id))) - - obj = self.obj - if isinstance(self.obj,tuple) or isinstance(self.obj,list): - for x in self.obj: - if method.startswith('%s.'%x.__class__.__name__): - obj = x - method = method.replace('%s.'%obj.__class__.__name__,'',1) - break - elif method.startswith('%s.'%self.obj.__class__.__name__): - method = method.replace('%s.'%self.obj.__class__.__name__,'',1) - if method.startswith('_'): - raise exc.HTTPForbidden("Bad method name %s: must not start with _" % method).exception - try: - method = getattr(obj, method) - except AttributeError: - raise ValueError("No such method %s" % method) - - if self.auth is not None: - try: - auth_result = self.auth(username, password, req.user_agent) - except: - text = traceback.format_exc() - exc_value = sys.exc_info()[1] - error_value = dict( - name='JSONRPCError', - code=100, - message=str(exc_value), - error=text) - return Response( - status=500, - content_type='application/json', - body=dumps(dict(result=None, - error=error_value, - id=id))) - if not auth_result: - raise exc.HTTPUnauthorized().exception - - try: - result = method(*params) - except: - text = traceback.format_exc() - exc_value = sys.exc_info()[1] - error_value = dict( - name='JSONRPCError', - code=100, - message=str(exc_value), - error=text) - return Response( - status=500, - content_type='application/json', - body=dumps(dict(result=None, - error=error_value, - id=id))) - - return Response( - content_type='application/json', - body=dumps(dict(result=result, - error=None, - id=id))) -