def dumps(self, obj): try: encoder = import_string(settings.MODERNRPC_JSON_ENCODER) return json.dumps(obj, cls=encoder) except Exception as e: raise RPCInternalError( 'Unable to serialize result as valid JSON: ' + str(e))
def process_request(self): encoding = self.request.encoding or 'utf-8' payload = self.loads(self.request.body.decode(encoding)) if isinstance(payload, dict): # Store current request id, or None if request is a notification self.request_id = payload.get('id') return self.process_single_request(payload) elif isinstance(payload, (list, tuple)): batch_result = JSONRPCBatchResult() for single_payload in payload: try: try: request_id = single_payload.get('id') except AttributeError: request_id = None raise RPCInvalidRequest( 'Single RPC call payload must be a struct') result = self.process_single_request(single_payload) # As stated in documentation: # "A Response object SHOULD exist for each Request object, except that there SHOULD NOT be any # Response objects for notifications." if request_id: batch_result.results.append( self.json_success_response(result, override_id=request_id)) except AuthenticationFailed as e: raise e except RPCException as e: logger.warning( 'RPC Exception raised in a JSON-RPC batch handling: {}' .format(e), exc_info=settings.MODERNRPC_LOG_EXCEPTIONS) batch_result.results.append( self.json_error_response(e, override_id=request_id)) except Exception as e: logger.warning( 'Exception raised in a JSON-RPC batch handling: {}'. format(e), exc_info=settings.MODERNRPC_LOG_EXCEPTIONS) rpc_exception = RPCInternalError(str(e)) batch_result.results.append( self.json_error_response(rpc_exception, override_id=request_id)) return batch_result else: raise RPCInvalidRequest('Bad JSON-RPC payload: {}'.format( str(payload)))
def post(self, request, *args, **kwargs): """ Handle a XML-RPC or JSON-RPC request. :param request: Incoming request :param args: Additional arguments :param kwargs: Additional named arguments :return: A HttpResponse containing XML-RPC or JSON-RPC response, depending on the incoming request """ logger.debug('RPC request received...') for handler_cls in self.get_handler_classes(): handler = handler_cls(request, self.entry_point) try: if not handler.can_handle(): continue logger.debug('Request will be handled by {}'.format( handler_cls.__name__)) result = handler.process_request() return handler.result_success(result) except AuthenticationFailed as e: # Customize HttpResponse instance used when AuthenticationFailed was raised logger.warning(e) return handler.result_error(e, HttpResponseForbidden) except RPCException as e: logger.warning('RPC exception: {}'.format(e), exc_info=settings.MODERNRPC_LOG_EXCEPTIONS) return handler.result_error(e) except Exception as e: logger.error( 'Exception raised from a RPC method: "{}"'.format(e), exc_info=settings.MODERNRPC_LOG_EXCEPTIONS) return handler.result_error(RPCInternalError(str(e))) logger.error('Unable to handle incoming request.') return HttpResponse( 'Unable to handle your request. Please ensure you called the right entry point. If not, ' 'this could be a server error.')
def process_request(self): encoding = self.request.encoding or 'utf-8' payload = self.loads(self.request.body.decode(encoding)) if isinstance(payload, dict): # Store current request id, or None if request is a notification self.request_id = payload.get('id') return self.process_single_request(payload) elif isinstance(payload, (list, tuple)): batch_result = JSONRPCBatchResult() for single_payload in payload: try: try: request_id = single_payload.get('id') except AttributeError: request_id = None raise RPCInvalidRequest() result = self.process_single_request(single_payload) if request_id: # As stated in documentation: # "A Response object SHOULD exist for each Request object, except that there SHOULD NOT be any # Response objects for notifications." batch_result.results.append( self.json_success_response(result, override_id=request_id)) except RPCException as e: batch_result.results.append( self.json_error_response(e, override_id=request_id)) except Exception as e: rpc_exception = RPCInternalError(str(e)) batch_result.results.append( self.json_error_response(rpc_exception, override_id=request_id)) return batch_result else: raise RPCInvalidRequest()
def login_custom(username, password, **kwargs): user = authenticate(username=username, password=password) request = kwargs.get(REQUEST_KEY) if user is None: raise RPCInternalError('Incorrect username or password.') login(request, user) if not request.session.exists(request.session.session_key): request.session.create() result = {"session": request.session.session_key} return result
def dumps(self, obj): try: # Marshaller has a specific handling of Fault instance. It is given without modification if isinstance(obj, xmlrpc_client.Fault): return self.marshaller.dumps(obj) # xmlrpc_client.Marshaller expects a list of objects to dumps. # It will output a '<params></params>' block and loops onto given objects to inject, for each one, # a '<param><value><type>X</type></value></param>' block. # This is not the return defined in XML-RPC standard, see http://xmlrpc.scripting.com/spec.html: # "The body of the response is a single XML structure, a <methodResponse>, which can contain # a single <params> which contains a single <param> which contains a single <value>." # # So, to make sure the return value always contain a single '<param><value><type>X</type></value></param>', # we dumps it as an array of a single value. return self.marshaller.dumps([obj]) except Exception: raise RPCInternalError('Unable to serialize result as valid XML')