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

Unified Diff: remoting/tools/remote_test_helper/SimpleJSONRPCServer.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: Fixing comments and merge issues. 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 side-by-side diff with in-line comments
Download patch
Index: remoting/tools/remote_test_helper/SimpleJSONRPCServer.py
diff --git a/remoting/tools/remote_test_helper/SimpleJSONRPCServer.py b/remoting/tools/remote_test_helper/SimpleJSONRPCServer.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b8f3d70c0bad7ca28eae97f8b9c42683f613674
--- /dev/null
+++ b/remoting/tools/remote_test_helper/SimpleJSONRPCServer.py
@@ -0,0 +1,193 @@
+# Copyright 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 SimpleXMLRPCServer module using JSON-RPC.
+
+This module uses SimpleXMLRPCServer 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, as well as jsonrpclib
+which also uses only default modules. No third party code is required to
+use this module.
+"""
+import fcntl
+import json
+import SimpleXMLRPCServer as _base
+import SocketServer
+import sys
+import traceback
+import jsonrpclib
+try:
+ import gzip
+except ImportError:
+ gzip = None #python can be built without zlib/gzip support
+
+
+class SimpleJSONRPCRequestHandler(_base.SimpleXMLRPCRequestHandler):
+ """Request handler class for received requests.
+
+ This class extends the functionality of SimpleXMLRPCRequestHandler and only
+ overrides the operations needed to change the protocol from XML-RPC to
+ JSON-RPC.
+ """
+
+ def do_POST(self):
+ """Handles the HTTP POST request.
+
+ Attempts to interpret all HTTP POST requests as JSON-RPC calls,
+ which are forwarded to the server's _dispatch method for handling.
+ """
+ # Check that the path is legal
+ if not self.is_rpc_path_valid():
+ self.report_404()
+ return
+
+ try:
+ # Get arguments by reading body of request.
+ # We read this in chunks to avoid straining
+ # socket.read(); around the 10 or 15Mb mark, some platforms
+ # begin to have problems (bug #792570).
+ max_chunk_size = 10*1024*1024
+ size_remaining = int(self.headers['content-length'])
+ data = []
+ while size_remaining:
+ chunk_size = min(size_remaining, max_chunk_size)
+ chunk = self.rfile.read(chunk_size)
+ if not chunk:
+ break
+ data.append(chunk)
+ size_remaining -= len(data[-1])
+ data = ''.join(data)
+ data = self.decode_request_content(data)
+
+ if data is None:
+ return # response has been sent
+
+ # In previous versions of SimpleXMLRPCServer, _dispatch
+ # could be overridden in this class, instead of in
+ # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
+ # check to see if a subclass implements _dispatch and dispatch
+ # using that method if present.
+ response = self.server._marshaled_dispatch(
+ data, getattr(self, '_dispatch', None), self.path)
+
+ except Exception, e: # This should only happen if the module is buggy
+ # internal error, report as HTTP server error
+ self.send_response(500)
+ # Send information about the exception if requested
+ if (hasattr(self.server, '_send_traceback_header') and
+ self.server._send_traceback_header):
+ self.send_header('X-exception', str(e))
+ self.send_header('X-traceback', traceback.format_exc())
+
+ self.send_header('Content-length', '0')
+ self.end_headers()
+ else:
+ # got a valid JSON RPC response
+ self.send_response(200)
+ self.send_header('Content-type', 'application/json')
+
+ if self.encode_threshold is not None:
+ if len(response) > self.encode_threshold:
+ q = self.accept_encodings().get('gzip', 0)
+ if q:
+ try:
+ response = jsonrpclib.gzip_encode(response)
+ self.send_header('Content-Encoding', 'gzip')
+ except NotImplementedError:
+ pass
+
+ self.send_header('Content-length', str(len(response)))
+ self.end_headers()
+ self.wfile.write(response)
+
+
+class SimpleJSONRPCDispatcher(_base.SimpleXMLRPCDispatcher):
+ """Dispatcher for received JSON-RPC requests.
+
+ This class extends the functionality of SimpleXMLRPCDispatcher and only
+ overrides the operations needed to change the protocol from XML-RPC to
+ JSON-RPC.
+ """
+
+ def _marshaled_dispatch(self, data, dispatch_method=None, path=None):
+ """Dispatches an JSON-RPC method from marshalled (JSON) data.
+
+ JSON-RPC methods are dispatched from the marshalled (JSON) data
+ using the _dispatch method and the result is returned as
+ marshalled data. For backwards compatibility, a dispatch
+ function can be provided as an argument (see comment in
+ SimpleJSONRPCRequestHandler.do_POST) but overriding the
+ existing method through subclassing is the preferred means
+ of changing method dispatch behavior.
+
+ Returns:
+ The JSON-RPC string to return.
+ """
+ method = ''
+ params = []
+ ident = ''
+ try:
+ request = json.loads(data)
+ print 'request:', request
+ jsonrpclib.ValidateRequest(request)
+ method = request['method']
+ params = request['params']
+ ident = request['id']
+
+ # generate response
+ if dispatch_method is not None:
+ response = dispatch_method(method, params)
+ else:
+ response = self._dispatch(method, params)
+ response = jsonrpclib.CreateResponseString(response, ident)
+
+ except jsonrpclib.Fault as fault:
+ response = jsonrpclib.CreateResponseString(fault, ident)
+
+ except:
+ # report exception back to server
+ exc_type, exc_value, _ = sys.exc_info()
+ response = jsonrpclib.CreateResponseString(
+ jsonrpclib.Fault(1, '%s:%s' % (exc_type, exc_value)), ident)
+ print 'response:', response
+ return response
+
+
+class SimpleJSONRPCServer(SocketServer.TCPServer,
+ SimpleJSONRPCDispatcher):
+ """Simple JSON-RPC server.
+
+ This class mimics the functionality of SimpleXMLRPCServer and only
+ overrides the operations needed to change the protocol from XML-RPC to
+ JSON-RPC.
+ """
+
+ allow_reuse_address = True
+
+ # Warning: this is for debugging purposes only! Never set this to True in
+ # production code, as will be sending out sensitive information (exception
+ # and stack trace details) when exceptions are raised inside
+ # SimpleJSONRPCRequestHandler.do_POST
+ _send_traceback_header = False
+
+ def __init__(self, addr, requestHandler=SimpleJSONRPCRequestHandler,
+ logRequests=True, allow_none=False, encoding=None,
+ bind_and_activate=True):
+ self.logRequests = logRequests
+ SimpleJSONRPCDispatcher.__init__(self, allow_none, encoding)
+ SocketServer.TCPServer.__init__(self, addr, requestHandler,
+ bind_and_activate)
+
+ # [Bug #1222790] If possible, set close-on-exec flag; if a
+ # method spawns a subprocess, the subprocess shouldn't have
+ # the listening socket open.
+ if fcntl is not None and hasattr(fcntl, 'FD_CLOEXEC'):
+ flags = fcntl.fcntl(self.fileno(), fcntl.F_GETFD)
+ flags |= fcntl.FD_CLOEXEC
+ fcntl.fcntl(self.fileno(), fcntl.F_SETFD, flags)

Powered by Google App Engine
This is Rietveld 408576698