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

Unified 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: Created 6 years 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 side-by-side diff with in-line comments
Download patch
Index: remoting/tools/remote_test_helper/jsonrpclib.py
diff --git a/remoting/tools/remote_test_helper/jsonrpclib.py b/remoting/tools/remote_test_helper/jsonrpclib.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb9abf52ddda9dbaafd151477ee9b7e9a39f32ac
--- /dev/null
+++ b/remoting/tools/remote_test_helper/jsonrpclib.py
@@ -0,0 +1,347 @@
+# Copyright (c) 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Module to implement the JSON-RPC protocol.
+
+This module uses xmlrpclib as the base and only overrides those
+portions that implement the XML-RPC protocol. These portions are rewritten
+to use the JSON-RPC protocol instead.
+
+When large portions of code need to be rewritten the original code and
+comments are preserved. The intention here is to keep the amount of code
+change to a minimum.
+
+This module only depends on default Python modules. No third party code is
+required to use this module.
+"""
+import json
+import urllib
+import xmlrpclib as _base
+
+gzip_encode = _base.gzip_encode
+
+
+class Error(Exception):
+
+ def __str__(self):
+ return repr(self)
+
+
+class ProtocolError(Error):
+ """Indicates a JSON protocol error."""
+
+ def __init__(self, url, errcode, errmsg, headers):
+ Error.__init__(self)
+ self.url = url
+ self.errcode = errcode
+ self.errmsg = errmsg
+ self.headers = headers
+
+ def __repr__(self):
+ return (
+ '<ProtocolError for %s: %s %s>' %
+ (self.url, self.errcode, self.errmsg))
+
+
+class ResponseError(Error):
+ """Indicates a broken response package."""
+ pass
+
+
+class Fault(Error):
+ """Indicates an JSON-RPC fault package."""
+
+ def __init__(self, code, message):
+ Error.__init__(self)
+ if not isinstance(code, int):
+ raise ProtocolError('Fault code must be an integer.')
+ self.code = code
+ self.message = message
+
+ def __repr__(self):
+ return (
+ '<Fault %s: %s>' %
+ (self.code, repr(self.message))
+ )
+
+
+def CreateRequest(methodname, params, ident=''):
+ """Create a valid JSON-RPC request.
+
+ Args:
+ methodname: The name of the remote method to invoke.
+ params: The parameters to pass to the remote method. This should be a
+ list or tuple and able to be encoded by the default JSON parser.
+
+ Returns:
+ A valid JSON-RPC request object.
+ """
+ request = {
+ 'jsonrpc': '2.0',
+ 'method': methodname,
+ 'params': params,
+ 'id': ident
+ }
+
+ return request
+
+
+def CreateRequestString(methodname, params, ident=''):
+ """Create a valid JSON-RPC request string.
+
+ Args:
+ methodname: The name of the remote method to invoke.
+ params: The parameters to pass to the remote method.
+ These parameters need to be encode-able by the default JSON parser.
+ ident: The request identifier.
+
+ Returns:
+ A valid JSON-RPC request string.
+ """
+ return json.dumps(CreateRequest(methodname, params, ident))
+
+def CreateResponse(data, ident):
+ """Create a JSON-RPC response.
+
+ Args:
+ data: The data to return.
+ ident: The response identifier.
+
+ Returns:
+ A valid JSON-RPC response object.
+ """
+ if isinstance(data, Fault):
+ response = {
+ 'jsonrpc': '2.0',
+ 'error': {
+ 'code': data.code,
+ 'message': data.message},
+ 'id': ident
+ }
+ else:
+ response = {
+ 'jsonrpc': '2.0',
+ 'response': data,
+ 'id': ident
+ }
+
+ return response
+
+
+def CreateResponseString(data, ident):
+ """Create a JSON-RPC response string.
+
+ Args:
+ data: The data to return.
+ ident: The response identifier.
+
+ Returns:
+ A valid JSON-RPC response object.
+ """
+ return json.dumps(CreateResponse(data, ident))
+
+
+def ParseHTTPResponse(response):
+ """Parse an HTTP response object and return the JSON object.
+
+ Args:
+ response: An HTTP response object.
+
+ Returns:
+ The returned JSON-RPC object.
+
+ Raises:
+ ProtocolError: if the object format is not correct.
+ Fault: If a Fault error is returned from the server.
+ """
+ # Check for new http response object, else it is a file object
+ if hasattr(response, 'getheader'):
+ if response.getheader('Content-Encoding', '') == 'gzip':
+ stream = _base.GzipDecodedResponse(response)
+ else:
+ stream = response
+ else:
+ stream = response
+
+ data = ''
+ while 1:
+ chunk = stream.read(1024)
+ if not chunk:
+ break
+ data += chunk
+
+ response = json.loads(data)
+ ValidateBasicJSONRPCData(response)
+
+ if 'response' in response:
+ ValidateResponse(response)
+ return response['response']
+ elif 'error' in response:
+ ValidateError(response)
+ code = response['error']['code']
+ message = response['error']['message']
+ raise Fault(code, message)
+ else:
+ raise ProtocolError('No valid JSON returned')
+
+
+def ValidateRequest(data):
+ """Validate a JSON-RPC request object.
+
+ Args:
+ data: The JSON-RPC object (dict).
+
+ Raises:
+ ProtocolError: if the object format is not correct.
+ """
+ ValidateBasicJSONRPCData(data)
+ if 'method' not in data or 'params' not in data:
+ raise ProtocolError('JSON is not a valid request')
+
+
+def ValidateResponse(data):
+ """Validate a JSON-RPC response object.
+
+ Args:
+ data: The JSON-RPC object (dict).
+
+ Raises:
+ ProtocolError: if the object format is not correct.
+ """
+ ValidateBasicJSONRPCData(data)
+ if 'response' not in data:
+ raise ProtocolError('JSON is not a valid response')
+
+
+def ValidateError(data):
+ """Validate a JSON-RPC error object.
+
+ Args:
+ data: The JSON-RPC object (dict).
+
+ Raises:
+ ProtocolError: if the object format is not correct.
+ """
+ ValidateBasicJSONRPCData(data)
+ if ('error' not in data or
+ 'code' not in data['error'] or
+ 'message' not in data['error']):
+ raise ProtocolError('JSON is not a valid error response')
+
+
+def ValidateBasicJSONRPCData(data):
+ """Validate a basic JSON-RPC object.
+
+ Args:
+ data: The JSON-RPC object (dict).
+
+ Raises:
+ ProtocolError: if the object format is not correct.
+ """
+ error = None
+ if not isinstance(data, dict):
+ error = 'JSON data is not a dictionary'
+ elif 'jsonrpc' not in data or data['jsonrpc'] != '2.0':
+ error = 'JSON is not a valid JSON RPC 2.0 message'
+ elif 'id' not in data:
+ error = 'JSON data missing required id entry'
+ if error:
+ raise ProtocolError(error)
+
+
+class Transport(_base.Transport):
+ """RPC transport class.
+
+ This class extends the functionality of xmlrpclib.Transport and only
+ overrides the operations needed to change the protocol from XML-RPC to
+ JSON-RPC.
+ """
+
+ def single_request(self, host, handler, request_body, verbose=0):
+ """Issue a single JSON-RPC request."""
+
+ h = self.make_connection(host)
+ if verbose:
+ h.set_debuglevel(1)
+ try:
+ self.send_request(h, handler, request_body)
+ self.send_host(h, host)
+ self.send_user_agent(h)
+ self.send_content(h, request_body)
+
+ response = h.getresponse(buffering=True)
+ if response.status == 200:
+ self.verbose = verbose
+
+ return self.parse_response(response)
+
+ except Fault:
+ raise
+ except Exception:
+ # All unexpected errors leave connection in
+ # a strange state, so we clear it.
+ self.close()
+ raise
+
+ # discard any response data and raise exception
+ if response.getheader('content-length', 0):
+ response.read()
+ raise ProtocolError(
+ host + handler,
+ response.status, response.reason,
+ response.msg,
+ )
+
+ def parse_response(self, response):
+ """Parse the HTTP resoponse from the server."""
+ return ParseHTTPResponse(response)
+
+
+class SafeTransport(_base.SafeTransport):
+ """Transport class for HTTPS servers.
+
+ This class extends the functionality of xmlrpclib.SafeTransport and only
+ overrides the operations needed to change the protocol from XML-RPC to
+ JSON-RPC.
+ """
+
+ def parse_response(self, response):
+ return ParseHTTPResponse(response)
+
+
+class ServerProxy(_base.ServerProxy):
+ """Proxy class to the RPC server.
+
+ This class extends the functionality of xmlrpclib.ServerProxy and only
+ overrides the operations needed to change the protocol from XML-RPC to
+ JSON-RPC.
+ """
+
+ def __init__(self, uri, transport=None, encoding=None, verbose=0,
+ allow_none=0, use_datetime=0):
+ urltype, _ = urllib.splittype(uri)
+ if urltype not in ('http', 'https'):
+ raise IOError('unsupported JSON-RPC protocol')
+
+ _base.ServerProxy.__init__(self, uri, transport, encoding, verbose,
+ allow_none, use_datetime)
+
+ if transport is None:
+ if type == 'https':
+ transport = SafeTransport(use_datetime=use_datetime)
+ else:
+ transport = Transport(use_datetime=use_datetime)
+ self.__transport = transport
+
+ def __request(self, methodname, params):
+ """Call a method on the remote server."""
+ request = CreateRequestString(methodname, params)
+
+ response = self.__transport.request(
+ self.__host,
+ self.__handler,
+ request,
+ verbose=self.__verbose
+ )
+
+ return response

Powered by Google App Engine
This is Rietveld 408576698