Mercurial > hg > AuthRPC
comparison wibble/server/__init__.py @ 4:ad5a8748afcf
Add test framework
author | Ben Croston <ben@croston.org> |
---|---|
date | Wed, 31 Aug 2011 21:35:14 +0100 |
parents | server/JsonRpcApp.py@c7a236de5214 |
children |
comparison
equal
deleted
inserted
replaced
3:43595981978d | 4:ad5a8748afcf |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 # Copyright (c) 2011 Ben Croston | |
4 # | |
5 # Permission is hereby granted, free of charge, to any person obtaining a copy of | |
6 # this software and associated documentation files (the "Software"), to deal in | |
7 # the Software without restriction, including without limitation the rights to | |
8 # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies | |
9 # of the Software, and to permit persons to whom the Software is furnished to do | |
10 # so, subject to the following conditions: | |
11 # | |
12 # The above copyright notice and this permission notice shall be included in all | |
13 # copies or substantial portions of the Software. | |
14 # | |
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
21 # SOFTWARE. | |
22 | |
23 from json import loads, dumps | |
24 import traceback | |
25 import sys | |
26 from webob import Request, Response, exc | |
27 | |
28 class JsonRpcApp(object): | |
29 """ | |
30 Serve the given object via json-rpc (http://json-rpc.org/) | |
31 """ | |
32 | |
33 def __init__(self, obj, auth=None): | |
34 """ | |
35 obj - a class containing functions available using jsonrpc | |
36 auth - an authentication function (optional) | |
37 """ | |
38 self.obj = obj | |
39 self.auth = auth | |
40 | |
41 def __call__(self, environ, start_response): | |
42 req = Request(environ) | |
43 try: | |
44 resp = self._process(req) | |
45 except ValueError, e: | |
46 resp = exc.HTTPBadRequest(str(e)) | |
47 except exc.HTTPException, e: | |
48 resp = e | |
49 return resp(environ, start_response) | |
50 | |
51 def _process(self, req): | |
52 """ | |
53 Process the JSONRPC request. | |
54 req - a webob Request object | |
55 """ | |
56 if not req.method == 'POST': | |
57 raise exc.HTTPMethodNotAllowed("Only POST allowed").exception | |
58 | |
59 try: | |
60 json = loads(req.body) | |
61 except ValueError, e: | |
62 raise ValueError('Bad JSON: %s' % e) | |
63 | |
64 try: | |
65 method = json['method'] | |
66 params = json['params'] | |
67 id = json['id'] | |
68 username = json['username'] if 'username' in json else None | |
69 password = json['password'] if 'password' in json else None | |
70 except KeyError, e: | |
71 raise ValueError("JSON body missing parameter: %s" % e) | |
72 | |
73 if params is None: | |
74 params = [] | |
75 if not isinstance(params, list): | |
76 raise ValueError("Bad params %r: must be a list" % params) | |
77 text = traceback.format_exc() | |
78 exc_value = sys.exc_info()[1] | |
79 error_value = dict( | |
80 name='JSONRPCError', | |
81 code=100, | |
82 message=str(exc_value), | |
83 error=text) | |
84 return Response( | |
85 status=500, | |
86 content_type='application/json', | |
87 body=dumps(dict(result=None, | |
88 error=error_value, | |
89 id=id))) | |
90 | |
91 obj = self.obj | |
92 if isinstance(self.obj,tuple) or isinstance(self.obj,list): | |
93 for x in self.obj: | |
94 if method.startswith('%s.'%x.__class__.__name__): | |
95 obj = x | |
96 method = method.replace('%s.'%obj.__class__.__name__,'',1) | |
97 break | |
98 elif method.startswith('%s.'%self.obj.__class__.__name__): | |
99 method = method.replace('%s.'%self.obj.__class__.__name__,'',1) | |
100 if method.startswith('_'): | |
101 raise exc.HTTPForbidden("Bad method name %s: must not start with _" % method).exception | |
102 try: | |
103 method = getattr(obj, method) | |
104 except AttributeError: | |
105 raise ValueError("No such method %s" % method) | |
106 | |
107 if self.auth is not None: | |
108 try: | |
109 auth_result = self.auth(username, password, req.user_agent) | |
110 except: | |
111 text = traceback.format_exc() | |
112 exc_value = sys.exc_info()[1] | |
113 error_value = dict( | |
114 name='JSONRPCError', | |
115 code=100, | |
116 message=str(exc_value), | |
117 error=text) | |
118 return Response( | |
119 status=500, | |
120 content_type='application/json', | |
121 body=dumps(dict(result=None, | |
122 error=error_value, | |
123 id=id))) | |
124 if not auth_result: | |
125 raise exc.HTTPUnauthorized().exception | |
126 | |
127 try: | |
128 result = method(*params) | |
129 except: | |
130 text = traceback.format_exc() | |
131 exc_value = sys.exc_info()[1] | |
132 error_value = dict( | |
133 name='JSONRPCError', | |
134 code=100, | |
135 message=str(exc_value), | |
136 error=text) | |
137 return Response( | |
138 status=500, | |
139 content_type='application/json', | |
140 body=dumps(dict(result=None, | |
141 error=error_value, | |
142 id=id))) | |
143 | |
144 return Response( | |
145 content_type='application/json', | |
146 body=dumps(dict(result=result, | |
147 error=None, | |
148 id=id))) | |
149 |