Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: remoting/tools/remote_test_helper/jsonrpclib.py

Issue 807343002: Adding the first set of remote test cases and associated framework. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changing enum naming format to eliminate name conflict. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4 """Module to implement the JSON-RPC protocol.
5
6 This module uses xmlrpclib as the base and only overrides those
7 portions that implement the XML-RPC protocol. These portions are rewritten
8 to use the JSON-RPC protocol instead.
9
10 When large portions of code need to be rewritten the original code and
11 comments are preserved. The intention here is to keep the amount of code
12 change to a minimum.
13
14 This module only depends on default Python modules. No third party code is
15 required to use this module.
16 """
17 import json
18 import urllib
19 import xmlrpclib as _base
20
21 __version__ = '1.0.0'
22 gzip_encode = _base.gzip_encode
23
24
25 class Error(Exception):
26
27 def __str__(self):
28 return repr(self)
29
30
31 class ProtocolError(Error):
32 """Indicates a JSON protocol error."""
33
34 def __init__(self, url, errcode, errmsg, headers):
35 Error.__init__(self)
36 self.url = url
37 self.errcode = errcode
38 self.errmsg = errmsg
39 self.headers = headers
40
41 def __repr__(self):
42 return (
43 '<ProtocolError for %s: %s %s>' %
44 (self.url, self.errcode, self.errmsg))
45
46
47 class ResponseError(Error):
48 """Indicates a broken response package."""
49 pass
50
51
52 class Fault(Error):
53 """Indicates an JSON-RPC fault package."""
54
55 def __init__(self, code, message):
56 Error.__init__(self)
57 if not isinstance(code, int):
58 raise ProtocolError('Fault code must be an integer.')
59 self.code = code
60 self.message = message
61
62 def __repr__(self):
63 return (
64 '<Fault %s: %s>' %
65 (self.code, repr(self.message))
66 )
67
68
69 def CreateRequest(methodname, params, ident=''):
70 """Create a valid JSON-RPC request.
71
72 Args:
73 methodname: The name of the remote method to invoke.
74 params: The parameters to pass to the remote method. This should be a
75 list or tuple and able to be encoded by the default JSON parser.
76
77 Returns:
78 A valid JSON-RPC request object.
79 """
80 request = {
81 'jsonrpc': '2.0',
82 'method': methodname,
83 'params': params,
84 'id': ident
85 }
86
87 return request
88
89
90 def CreateRequestString(methodname, params, ident=''):
91 """Create a valid JSON-RPC request string.
92
93 Args:
94 methodname: The name of the remote method to invoke.
95 params: The parameters to pass to the remote method.
96 These parameters need to be encode-able by the default JSON parser.
97 ident: The request identifier.
98
99 Returns:
100 A valid JSON-RPC request string.
101 """
102 return json.dumps(CreateRequest(methodname, params, ident))
103
104 def CreateResponse(data, ident):
105 """Create a JSON-RPC response.
106
107 Args:
108 data: The data to return.
109 ident: The response identifier.
110
111 Returns:
112 A valid JSON-RPC response object.
113 """
114 if isinstance(data, Fault):
115 response = {
116 'jsonrpc': '2.0',
117 'error': {
118 'code': data.code,
119 'message': data.message},
120 'id': ident
121 }
122 else:
123 response = {
124 'jsonrpc': '2.0',
125 'response': data,
126 'id': ident
127 }
128
129 return response
130
131
132 def CreateResponseString(data, ident):
133 """Create a JSON-RPC response string.
134
135 Args:
136 data: The data to return.
137 ident: The response identifier.
138
139 Returns:
140 A valid JSON-RPC response object.
141 """
142 return json.dumps(CreateResponse(data, ident))
143
144
145 def ParseHTTPResponse(response):
146 """Parse an HTTP response object and return the JSON object.
147
148 Args:
149 response: An HTTP response object.
150
151 Returns:
152 The returned JSON-RPC object.
153
154 Raises:
155 ProtocolError: if the object format is not correct.
156 Fault: If a Fault error is returned from the server.
157 """
158 # Check for new http response object, else it is a file object
159 if hasattr(response, 'getheader'):
160 if response.getheader('Content-Encoding', '') == 'gzip':
161 stream = _base.GzipDecodedResponse(response)
162 else:
163 stream = response
164 else:
165 stream = response
166
167 data = ''
168 while 1:
169 chunk = stream.read(1024)
170 if not chunk:
171 break
172 data += chunk
173
174 response = json.loads(data)
175 ValidateBasicJSONRPCData(response)
176
177 if 'response' in response:
178 ValidateResponse(response)
179 return response['response']
180 elif 'error' in response:
181 ValidateError(response)
182 code = response['error']['code']
183 message = response['error']['message']
184 raise Fault(code, message)
185 else:
186 raise ProtocolError('No valid JSON returned')
187
188
189 def ValidateRequest(data):
190 """Validate a JSON-RPC request object.
191
192 Args:
193 data: The JSON-RPC object (dict).
194
195 Raises:
196 ProtocolError: if the object format is not correct.
197 """
198 ValidateBasicJSONRPCData(data)
199 if 'method' not in data or 'params' not in data:
200 raise ProtocolError('JSON is not a valid request')
201
202
203 def ValidateResponse(data):
204 """Validate a JSON-RPC response object.
205
206 Args:
207 data: The JSON-RPC object (dict).
208
209 Raises:
210 ProtocolError: if the object format is not correct.
211 """
212 ValidateBasicJSONRPCData(data)
213 if 'response' not in data:
214 raise ProtocolError('JSON is not a valid response')
215
216
217 def ValidateError(data):
218 """Validate a JSON-RPC error object.
219
220 Args:
221 data: The JSON-RPC object (dict).
222
223 Raises:
224 ProtocolError: if the object format is not correct.
225 """
226 ValidateBasicJSONRPCData(data)
227 if ('error' not in data or
228 'code' not in data['error'] or
229 'message' not in data['error']):
230 raise ProtocolError('JSON is not a valid error response')
231
232
233 def ValidateBasicJSONRPCData(data):
234 """Validate a basic JSON-RPC object.
235
236 Args:
237 data: The JSON-RPC object (dict).
238
239 Raises:
240 ProtocolError: if the object format is not correct.
241 """
242 error = None
243 if not isinstance(data, dict):
244 error = 'JSON data is not a dictionary'
245 elif 'jsonrpc' not in data or data['jsonrpc'] != '2.0':
246 error = 'JSON is not a valid JSON RPC 2.0 message'
247 elif 'id' not in data:
248 error = 'JSON data missing required id entry'
249 if error:
250 raise ProtocolError(error)
251
252
253 class Transport(_base.Transport):
254 """RPC transport class.
255
256 This class extends the functionality of xmlrpclib.Transport and only
257 overrides the operations needed to change the protocol from XML-RPC to
258 JSON-RPC.
259 """
260
261 user_agent = 'jsonrpclib.py/' + __version__
262
263 def send_content(self, connection, request_body):
264 """Send the request."""
265 connection.putheader('Content-Type','application/json')
266
267 #optionally encode the request
268 if (self.encode_threshold is not None and
269 self.encode_threshold < len(request_body) and
270 gzip):
271 connection.putheader('Content-Encoding', 'gzip')
272 request_body = gzip_encode(request_body)
273
274 connection.putheader('Content-Length', str(len(request_body)))
275 connection.endheaders(request_body)
276
277 def single_request(self, host, handler, request_body, verbose=0):
278 """Issue a single JSON-RPC request."""
279
280 h = self.make_connection(host)
281 if verbose:
282 h.set_debuglevel(1)
283 try:
284 self.send_request(h, handler, request_body)
285 self.send_host(h, host)
286 self.send_user_agent(h)
287 self.send_content(h, request_body)
288
289 response = h.getresponse(buffering=True)
290 if response.status == 200:
291 self.verbose = verbose
292
293 return self.parse_response(response)
294
295 except Fault:
296 raise
297 except Exception:
298 # All unexpected errors leave connection in
299 # a strange state, so we clear it.
300 self.close()
301 raise
302
303 # discard any response data and raise exception
304 if response.getheader('content-length', 0):
305 response.read()
306 raise ProtocolError(
307 host + handler,
308 response.status, response.reason,
309 response.msg,
310 )
311
312 def parse_response(self, response):
313 """Parse the HTTP resoponse from the server."""
314 return ParseHTTPResponse(response)
315
316
317 class SafeTransport(_base.SafeTransport):
318 """Transport class for HTTPS servers.
319
320 This class extends the functionality of xmlrpclib.SafeTransport and only
321 overrides the operations needed to change the protocol from XML-RPC to
322 JSON-RPC.
323 """
324
325 def parse_response(self, response):
326 return ParseHTTPResponse(response)
327
328
329 class ServerProxy(_base.ServerProxy):
330 """Proxy class to the RPC server.
331
332 This class extends the functionality of xmlrpclib.ServerProxy and only
333 overrides the operations needed to change the protocol from XML-RPC to
334 JSON-RPC.
335 """
336
337 def __init__(self, uri, transport=None, encoding=None, verbose=0,
338 allow_none=0, use_datetime=0):
339 urltype, _ = urllib.splittype(uri)
340 if urltype not in ('http', 'https'):
341 raise IOError('unsupported JSON-RPC protocol')
342
343 _base.ServerProxy.__init__(self, uri, transport, encoding, verbose,
344 allow_none, use_datetime)
345
346 if transport is None:
347 if type == 'https':
348 transport = SafeTransport(use_datetime=use_datetime)
349 else:
350 transport = Transport(use_datetime=use_datetime)
351 self.__transport = transport
352
353 def __request(self, methodname, params):
354 """Call a method on the remote server."""
355 request = CreateRequestString(methodname, params)
356
357 response = self.__transport.request(
358 self.__host,
359 self.__handler,
360 request,
361 verbose=self.__verbose
362 )
363
364 return response
OLDNEW
« no previous file with comments | « remoting/tools/remote_test_helper/jsonrpc.js ('k') | remoting/tools/remote_test_helper/rth_server.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698