def test_invalid_error(): """ This test tries to decode an error message with an invalid error code """ from aiohttp_json_rpc import RpcInvalidRequestError from aiohttp_json_rpc.protocol import decode_msg raw_msg = ''' { "jsonrpc": "2.0", "id": 1, "error": { "code": -32101, "message": "Invalid request", "data": null } } ''' with pytest.raises(RpcInvalidRequestError): decode_msg(raw_msg)
def test_valid_notification(): from aiohttp_json_rpc.protocol import JsonRpcMsgTyp, decode_msg # id is Null raw_msg = ''' { "jsonrpc": "2.0", "id": null, "method": "foo", "params": "bar" } ''' msg = decode_msg(raw_msg) assert msg.type == JsonRpcMsgTyp.NOTIFICATION assert msg.data['jsonrpc'] == '2.0' assert msg.data['id'] is None assert msg.data['method'] == 'foo' assert msg.data['params'] == 'bar' # without id raw_msg = ''' { "jsonrpc": "2.0", "method": "foo", "params": "bar" } ''' msg = decode_msg(raw_msg) assert msg.type == JsonRpcMsgTyp.NOTIFICATION assert msg.data['jsonrpc'] == '2.0' assert msg.data['id'] is None assert msg.data['method'] == 'foo' assert msg.data['params'] == 'bar'
def test_valid_error(): from aiohttp_json_rpc.protocol import JsonRpcMsgTyp, decode_msg raw_msg = ''' { "jsonrpc": "2.0", "id": 1, "error": { "code": -32600, "message": "Invalid request", "data": null } } ''' msg = decode_msg(raw_msg) assert msg.type == JsonRpcMsgTyp.ERROR
async def _handle_rpc_msg(self, http_request, raw_msg): # This is duplicated code from super but there is no way how to do it # to be able handle server->client requests host = http_request.host if host in self.waiting_requests: try: _raw_message = raw_msg.data msg = decode_msg(_raw_message) except RpcError as error: await self._ws_send_str(http_request, encode_error(error)) return if msg.type in (JsonRpcMsgTyp.RESULT, JsonRpcMsgTyp.ERROR): msg_data = json.loads(_raw_message) if msg_data.get("id") in self.waiting_requests[host]: self.responses[host].append(msg_data) return return await super()._handle_rpc_msg(http_request, raw_msg)
def test_valid_message(): from aiohttp_json_rpc.protocol import JsonRpcMsgTyp, decode_msg raw_msg = ''' { "jsonrpc": "2.0", "id": 0, "method": "foo", "params": "bar" } ''' msg = decode_msg(raw_msg) assert msg.type == JsonRpcMsgTyp.REQUEST assert msg.data['jsonrpc'] == '2.0' assert msg.data['id'] == 0 assert msg.data['method'] == 'foo' assert msg.data['params'] == 'bar'
async def handle_http_request(self, http_request): raw_msg = await http_request.read() try: msg = decode_msg(raw_msg) self.logger.debug('message decoded: %s', msg) except RpcError as error: return self._http_send_str(http_request, encode_error(error)) # handle requests if msg.type == JsonRpcMsgTyp.REQUEST: self.logger.debug('msg gets handled as request') # check if method is available if msg.data['method'] not in http_request.methods: self.logger.debug('method %s is unknown or restricted', msg.data['method']) if msg.data['method'] in self.rpc_methods: err_msg = 'Method is disabled by the node administrator' else: err_msg = 'Method not found' return self._http_send_str( http_request, encode_error( RpcMethodNotFoundError(msg_id=msg.data.get('id', None), message=err_msg))) # call method raw_response = getattr( http_request.methods[msg.data['method']].method, 'raw_response', False, ) try: result = await http_request.methods[msg.data['method']]( http_request=http_request, rpc=self, msg=msg, ) if not raw_response: result = encode_result(msg.data['id'], result) return self._http_send_str(http_request, result) except (RpcGenericServerDefinedError, RpcInvalidRequestError, RpcInvalidParamsError, RemmeRpcError) as error: return self._http_send_str( http_request, encode_error(error, id=msg.data.get('id', None))) except Exception as error: logging.error(error, exc_info=True) return self._http_send_str( http_request, encode_error( RpcInternalError(msg_id=msg.data.get('id', None)))) # handle result elif msg.type == JsonRpcMsgTyp.RESULT: self.logger.debug('msg gets handled as result') result = encode_result(msg.data['id'], msg.data['result']) return self._http_send_str(http_request, result) else: self.logger.debug('unsupported msg type (%s)', msg.type) return self._http_send_str( http_request, encode_error( RpcInvalidRequestError(msg_id=msg.data.get('id', None))))
async def _handle_rpc_msg(self, http_request, data=None): if not data: raw_msg = await http_request.read() else: raw_msg = data.data try: msg = decode_msg(raw_msg) self.logger.debug(f'message decoded: {msg}') except RpcError as error: return await self._send_str(http_request, encode_error(error)) # handle requests if msg.type == JsonRpcMsgTyp.REQUEST: self.logger.debug('msg gets handled as request') method = msg.data['method'] # check if method is available if method not in http_request.methods: self.logger.debug(f'method {method} is unknown or restricted') if method in self.rpc_methods: err_msg = 'Method is disabled by the node administrator' else: err_msg = 'Method not found' return await self._send_str( http_request, encode_error( RpcMethodNotFoundError(msg_id=msg.data.get('id', None), message=err_msg))) measurement = METRICS_SENDER.get_time_measurement( f'rpc_api.{method}') # call method raw_response = getattr( http_request.methods[method].method, 'raw_response', False, ) try: result = await http_request.methods[method]( http_request=http_request, rpc=self, msg=msg, ) if not raw_response: result = encode_result(msg.data['id'], result) except (RpcGenericServerDefinedError, RpcInvalidRequestError, RpcInvalidParamsError, RemmeRpcError) as error: result = encode_error(error, id=msg.data.get('id', None)) except Exception as error: logging.error(error, exc_info=True) result = encode_error( RpcInternalError(msg_id=msg.data.get('id', None))) measurement.done() return await self._send_str(http_request, result) # handle result elif msg.type == JsonRpcMsgTyp.RESULT: self.logger.debug('msg gets handled as result') result = encode_result(msg.data['id'], msg.data['result']) return await self._send_str(http_request, result) else: self.logger.debug(f'unsupported msg type ({msg.type})') return await self._send_str( http_request, encode_error( RpcInvalidRequestError(msg_id=msg.data.get('id', None))))