def parse_request(self, data): """ Attempts to load the request, validates it, and calls it. """ try: obj = json.loads(data) except ValueError: return json.dumps(ProtocolError(-32700).generate_error()) if not obj: return json.dumps(ProtocolError(-32600).generate_error()) batch = True if type(obj) is not list: batch = False obj = [obj,] responses = [] for req in obj: request_error = ProtocolError(-32600) if type(req) is not dict: responses.append(request_error.generate_error()) elif 'method' not in req.keys() or \ type(req['method']) not in types.StringTypes: responses.append(request_error.generate_error()) else: result = self.parse_call(req) if req.has_key('id'): response = generate_response(result, id=req.get('id')) responses.append(response) if not responses: # It's either a batch of notifications or a single # notification, so return nothing. return '' else: if not batch: # Single request responses = responses[0] return json.dumps(responses)
def _parse_response(self, response): if response == '': return None try: obj = json.loads(response) except ValueError: raise ProtocolError(-32700) if obj == dict() and 'error' in obj: raise ProtocolError( obj.get('error').get('code'), obj.get('error').get('message'), obj.get('error').get('data', None)) return obj
def _parse_response(self, response): if response == '': return None try: obj = json.loads(response) except ValueError: raise ProtocolError(-32700) if type(obj) is dict and obj.has_key('error'): raise ProtocolError( obj.get('error').get('code'), obj.get('error').get('message'), obj.get('error').get('data', None)) return obj
def process(self, sock, addr): """ Retrieves the data stream from the socket and validates it. """ self.socket = sock self.socket.settimeout(config.timeout) self.client_address = addr requestlines = [] while True: data = self.get_data() if not data: break if type(data) != type('data'): data = data.decode('utf-8') requestlines.append(data) if len(data) < config.buffer: break request = ''.join(requestlines) response = '' crypt_error = False if config.secret: crypt = config.crypt.new(config.secret) try: request = crypt.decrypt(request) except ValueError: crypt_error = True error = ProtocolError(-32700, 'Could not decrypt request.') response = json.dumps(error.generate_error()) history.request = request logger.debug('SERVER | REQUEST: %s' % request) if self.socket_error: self.socket.close() else: if not crypt_error: response = self.parse_request(request) history.response = response logger.debug('SERVER | RESPONSE: %s' % response) if config.secret: length = config.crypt_chunk_size pad_length = length - (len(response) % length) response = crypt.encrypt('%s%s' % (response, ' ' * pad_length)) if type(response) == type('response'): response = response.encode('utf-8') self.socket.send(response) self.socket.close()
def _send_and_receive(self, message, batch=False, notify=False): """ Handles the socket connection, sends the JSON request, and (if not a notification) retrieves the response and decodes the JSON text. """ # Starting with a clean history history.request = message logger.debug('CLIENT | REQUEST: %s' % message) if self._key: crypt = config.crypt.new(self._key) length = config.crypt_chunk_size pad_length = length - (len(message) % length) message = crypt.encrypt('%s%s' % (message, ' ' * pad_length)) print(message) if type(message) == type("message"): # encode message = message.encode("utf-8") sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(config.timeout) sock.connect(self._addr) sock.send(message) responselist = [] if notify: # single notification, we don't need a response. sock.close() else: while True: try: data = sock.recv(config.buffer) except socket.timeout: break if not data: break if type(data) != type("data"): data = data.decode("utf-8") responselist.append(data) if len(data) < config.buffer: break sock.close() response = ''.join(responselist) if self._key: try: response = crypt.decrypt(response) except ValueError: # What exactly is an intuitive response to a poorly- or # not-encrypted response to an encrypted request? raise ProtocolError(-32700, 'Response not encrypted properly.') # Should we do a preliminary json.loads here to verify that the # decryption succeeded? logger.debug('CLIENT | RESPONSE: %s' % response) history.response = response return response
def _parse_response(self, response): if response == '': self._close() raise ProtocolError(-32700) try: obj = json.loads(response) except ValueError: self._close() raise ProtocolError(-32700) if type(obj) is dict and ('error' in obj) and obj.get('error') != None: self._close() if isinstance(obj.get('error'), str): raise ProtocolError(-1, obj.get('error'), None) else: raise ProtocolError( obj.get('error').get('code'), obj.get('error').get('message'), obj.get('error').get('data', None)) return obj
def process(self, sock, addr): """ Retrieves the data stream from the socket and validates it. """ self.socket = sock self.socket.settimeout(config.timeout) self.client_address = addr requestlines = [] while True: data = self.get_data() if not data: break requestlines.append(data) if len(data) < config.buffer: break request = ''.join(requestlines) response = '' crypt_error = False if config.secret: crypt = config.crypt.new(config.secret) try: request = crypt.decrypt(request) except ValueError: crypt_error = True error = ProtocolError(-32700, 'Could not decrypt request.') response = json.dumps(error.generate_error()) history.request = request logger.debug('SERVER | REQUEST: %s' % request) if self.socket_error: self.socket.close() else: if not crypt_error: response = self.parse_request(request) history.response = response logger.debug('SERVER | RESPONSE: %s' % response) if config.secret: length = config.crypt_chunk_size pad_length = length - (len(response) % length) response = crypt.encrypt('%s%s' % (response, ' '*pad_length)) self.socket.send(response) self.socket.close()
def parse_call(self, obj): """ Parses a JSON request. """ # Get ID, Notification if None # This is actually incorrect, as IDs can be null by spec (rare) request_id = obj.get('id', None) # Check for required parameters jsonrpc = obj.get('jsonrpc', None) method = obj.get('method', None) if not jsonrpc or not method: return ProtocolError(-32600) # Validate parameters params = obj.get('params', []) if type(params) not in (list, dict): return ProtocolError(-32602) # Parse Request kwargs = {} if type(params) is dict: kwargs = params params = [] handler = self.json_request.get_handler(method) error_code = None message = None if handler: try: response = handler(*params, **kwargs) return response except Exception: logger.error('Error calling handler %s' % method) message = traceback.format_exc().splitlines()[-1] error_code = -32603 else: error_code = -32601 return ProtocolError(error_code, message=message)
def validate_response(response): """ Parses the returned JSON object, verifies that it follows the JSON-RPC spec, and checks for errors, raising exceptions as necessary. """ jsonrpc = response.has_key('jsonrpc') response_id = response.has_key('id') result = response.has_key('result') error = response.has_key('error') if not jsonrpc or not response_id or (not result and not error): raise Exception('Server returned invalid response.') if error: raise ProtocolError(response['error']['code'], response['error']['message'])
def validate_response(response): """ Parses the returned JSON object, verifies that it follows the JSON-RPC spec, and checks for errors, raising exceptions as necessary. """ jsonrpc = 'jsonrpc' in response response_id = 'id' in response result = 'result' in response error = 'error' in response and response.get('error') != None if not response_id or (not result and not error): raise Exception('Server returned invalid response.') if error: raise ProtocolError(response['error']['code'], response['error']['message'])