def __asynccall(self, asyncresult, args, kwargs): try: # use a copy of the proxy otherwise calls would be serialized, # and use contextmanager to close the proxy after we're done with self.__proxy.__copy__() as proxy: value = proxy._pyroInvoke(self.__name, args, kwargs) asyncresult.value = value except Exception: # ignore any exceptions here, return them as part of the async result instead asyncresult.value = futures._ExceptionWrapper(sys.exc_info()[1])
def _pyro_remote_call(self, msg): log = logger.debug result = [] # Deserialize request_flags = msg.flags request_seq = msg.seq serializer = util.get_serializer_by_id(msg.serializer_id) objId, method, vargs, kwargs = serializer.deserializeCall(msg.data, compressed=msg.flags & Pyro4.message.FLAGS_COMPRESSED) del msg # invite GC to collect the object, don't wait for out-of-scope # Individual or batch log("Searching for object %s" % str(objId)) obj = self.factory.objectsById.get(objId) log("Found object with type %s" % str(type(obj))) if obj is not None: # Sanitize kwargs if kwargs and sys.version_info < (2, 6, 5) and os.name != "java": # Python before 2.6.5 doesn't accept unicode keyword arguments kwargs = dict((str(k), kwargs[k]) for k in kwargs) if request_flags & Pyro4.message.FLAGS_BATCH: for method, vargs, kwargs in vargs: log("Running call %s with vargs %s and kwargs %s agasint object %s" % (str(method), str(vargs), str(kwargs), str(obj))) response = yield self._pyro_run_call(obj, method, vargs, kwargs) if isinstance(response, Exception): response = _ExceptionWrapper(response) result.append(response) # Return the final value else: log("Running call %s with vargs %s and kwargs %s agasint object %s" % (str(method), str(vargs), str(kwargs), str(obj))) if method == "__getattr__": # special case for direct attribute access (only exposed @properties are accessible) result = util.get_exposed_property_value(obj, vargs[0], only_exposed=Pyro4.config.REQUIRE_EXPOSE) elif method == "__setattr__": # special case for direct attribute access (only exposed @properties are accessible) result = util.set_exposed_property_value(obj, vargs[0], vargs[1], only_exposed=Pyro4.config.REQUIRE_EXPOSE) else: result = yield self._pyro_run_call(obj, method, vargs, kwargs) if isinstance(result, Failure): exception = result.type(result.value) exception._pyroTraceback = result.tb result = exception log("Returning result %s from _remote_call" % pformat(result)) defer.returnValue(result) else: log("unknown object requested: %s", objId) raise Pyro4.core.errors.DaemonError("unknown object")
def dict_to_class(cls, data): """ Recreate an object out of a dict containing the class name and the attributes. Only a fixed set of classes are recognized. Not used for the pickle serializer. """ from Pyro4 import core, futures # XXX circular classname = data.get("__class__", "<unknown>") if isinstance(classname, bytes): classname = classname.decode("utf-8") if classname in cls.__custom_dict_to_class_registry: converter = cls.__custom_dict_to_class_registry[classname] return converter(classname, data) if "__" in classname: raise errors.SecurityError("refused to deserialize types with double underscores in their name: " + classname) # for performance, the constructors below are hardcoded here instead of added on a per-class basis to the dict-to-class registry if classname.startswith("Pyro4.core."): if classname == "Pyro4.core.URI": uri = core.URI.__new__(core.URI) uri.__setstate_from_dict__(data["state"]) return uri elif classname == "Pyro4.core.Proxy": proxy = core.Proxy.__new__(core.Proxy) proxy.__setstate_from_dict__(data["state"]) return proxy elif classname == "Pyro4.core.Daemon": daemon = core.Daemon.__new__(core.Daemon) daemon.__setstate_from_dict__(data["state"]) return daemon elif classname.startswith("Pyro4.util."): if classname == "Pyro4.util.SerpentSerializer": return SerpentSerializer() elif classname == "Pyro4.util.PickleSerializer": return PickleSerializer() elif classname == "Pyro4.util.MarshalSerializer": return MarshalSerializer() elif classname == "Pyro4.util.JsonSerializer": return JsonSerializer() elif classname == "Pyro4.util.MsgpackSerializer": return MsgpackSerializer() elif classname == "Pyro4.util.CloudpickleSerializer": return CloudpickleSerializer() elif classname == "Pyro4.util.DillSerializer": return DillSerializer() elif classname.startswith("Pyro4.errors."): errortype = getattr(errors, classname.split('.', 2)[2]) if issubclass(errortype, errors.PyroError): return SerializerBase.make_exception(errortype, data) elif classname == "Pyro4.futures._ExceptionWrapper": ex = data["exception"] if isinstance(ex, dict) and "__class__" in ex: ex = SerializerBase.dict_to_class(ex) return futures._ExceptionWrapper(ex) elif data.get("__exception__", False): if classname in all_exceptions: return SerializerBase.make_exception(all_exceptions[classname], data) # python 2.x: exceptions.ValueError # python 3.x: builtins.ValueError # translate to the appropriate namespace... namespace, short_classname = classname.split('.', 1) if namespace in ("builtins", "exceptions"): if sys.version_info < (3, 0): exceptiontype = getattr(exceptions, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) else: exceptiontype = getattr(builtins, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) elif namespace == "sqlite3" and short_classname.endswith("Error"): import sqlite3 exceptiontype = getattr(sqlite3, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) log.warning("unsupported serialized class: " + classname) raise errors.SerializeError("unsupported serialized class: " + classname)
def dict_to_class(cls, data): """ Recreate an object out of a dict containing the class name and the attributes. Only a fixed set of classes are recognized. Not used for the pickle serializer. """ from Pyro4 import core, futures # XXX circular classname = data.get("__class__", "<unknown>") if isinstance(classname, bytes): classname = classname.decode("utf-8") if classname in cls.__custom_dict_to_class_registry: converter = cls.__custom_dict_to_class_registry[classname] return converter(classname, data) if "__" in classname: raise errors.SecurityError("refused to deserialize types with double underscores in their name: " + classname) # for performance, the constructors below are hardcoded here instead of added on a per-class basis to the dict-to-class registry if classname.startswith("Pyro4.core."): if classname == "Pyro4.core.URI": uri = core.URI.__new__(core.URI) uri.__setstate_from_dict__(data["state"]) return uri elif classname == "Pyro4.core.Proxy": proxy = core.Proxy.__new__(core.Proxy) proxy.__setstate_from_dict__(data["state"]) return proxy elif classname == "Pyro4.core.Daemon": daemon = core.Daemon.__new__(core.Daemon) daemon.__setstate_from_dict__(data["state"]) return daemon elif classname.startswith("Pyro4.util."): if classname == "Pyro4.util.SerpentSerializer": return SerpentSerializer() elif classname == "Pyro4.util.PickleSerializer": return PickleSerializer() elif classname == "Pyro4.util.MarshalSerializer": return MarshalSerializer() elif classname == "Pyro4.util.JsonSerializer": return JsonSerializer() elif classname == "Pyro4.util.MsgpackSerializer": return MsgpackSerializer() elif classname == "Pyro4.util.CloudpickleSerializer": return CloudpickleSerializer() elif classname == "Pyro4.util.DillSerializer": return DillSerializer() elif classname.startswith("Pyro4.errors."): errortype = getattr(errors, classname.split('.', 2)[2]) if issubclass(errortype, errors.PyroError): return SerializerBase.make_exception(errortype, data) elif classname == "Pyro4.futures._ExceptionWrapper": ex = data["exception"] if isinstance(ex, dict) and "__class__" in ex: ex = SerializerBase.dict_to_class(ex) return futures._ExceptionWrapper(ex) elif data.get("__exception__", False): if classname in all_exceptions: return SerializerBase.make_exception(all_exceptions[classname], data) # python 2.x: exceptions.ValueError # python 3.x: builtins.ValueError # translate to the appropriate namespace... namespace, short_classname = classname.split('.', 1) if namespace in ("builtins", "exceptions"): if sys.version_info < (3, 0): exceptiontype = getattr(exceptions, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) else: exceptiontype = getattr(builtins, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) elif namespace == "sqlite3" and short_classname.endswith("Error"): import sqlite3 exceptiontype = getattr(sqlite3, short_classname) if issubclass(exceptiontype, BaseException): return SerializerBase.make_exception(exceptiontype, data) log.warning("unsupported serialized class: " + classname) raise errors.SerializeError("unsupported serialized class: " + classname)
def handleRequest(self, conn): """ Handle incoming Pyro request. Catches any exception that may occur and wraps it in a reply to the calling side, as to not make this server side loop terminate due to exceptions caused by remote invocations. """ request_flags = 0 request_seq = 0 request_serializer_id = util.MarshalSerializer.serializer_id wasBatched = False isCallback = False try: msg = Message.recv( conn, [Pyro4.message.MSG_INVOKE, Pyro4.message.MSG_PING]) request_flags = msg.flags request_seq = msg.seq request_serializer_id = msg.serializer_id if Pyro4.config.LOGWIRE: log.debug( "daemon wiredata received: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" % (msg.type, msg.flags, msg.serializer_id, msg.seq, msg.data)) if msg.type == Pyro4.message.MSG_PING: # return same seq, but ignore any data (it's a ping, not an echo). Nothing is deserialized. msg = Message(Pyro4.message.MSG_PING, b"pong", msg.serializer_id, 0, msg.seq) if Pyro4.config.LOGWIRE: log.debug( "daemon wiredata sending: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" % (msg.type, msg.flags, msg.serializer_id, msg.seq, msg.data)) conn.send(msg.to_bytes()) return if msg.serializer_id not in self.__serializer_ids: raise errors.ProtocolError( "message used serializer that is not accepted: %d" % msg.serializer_id) serializer = util.get_serializer_by_id(msg.serializer_id) objId, method, vargs, kwargs = serializer.deserializeCall( msg.data, compressed=msg.flags & Pyro4.message.FLAGS_COMPRESSED) del msg # invite GC to collect the object, don't wait for out-of-scope obj = self.objectsById.get(objId) if obj is not None: if kwargs and sys.version_info < (2, 6, 5) and os.name != "java": # Python before 2.6.5 doesn't accept unicode keyword arguments kwargs = dict((str(k), kwargs[k]) for k in kwargs) if request_flags & Pyro4.message.FLAGS_BATCH: # batched method calls, loop over them all and collect all results data = [] for method, vargs, kwargs in vargs: method = util.resolveDottedAttribute( obj, method, Pyro4.config.DOTTEDNAMES) try: result = method( *vargs, **kwargs ) # this is the actual method call to the Pyro object except Exception: xt, xv = sys.exc_info()[0:2] log.debug( "Exception occurred while handling batched request: %s", xv) xv._pyroTraceback = util.formatTraceback( detailed=Pyro4.config.DETAILED_TRACEBACK) if sys.platform == "cli": util.fixIronPythonExceptionForPickle( xv, True) # piggyback attributes data.append(futures._ExceptionWrapper(xv)) break # stop processing the rest of the batch else: data.append(result) wasBatched = True else: # normal single method call method = util.resolveDottedAttribute( obj, method, Pyro4.config.DOTTEDNAMES) if request_flags & Pyro4.message.FLAGS_ONEWAY and Pyro4.config.ONEWAY_THREADED: # oneway call to be run inside its own thread thread = threadutil.Thread(target=method, args=vargs, kwargs=kwargs) thread.setDaemon(True) thread.start() else: isCallback = getattr(method, "_pyroCallback", False) data = method( *vargs, **kwargs ) # this is the actual method call to the Pyro object else: log.debug("unknown object requested: %s", objId) raise errors.DaemonError("unknown object") if request_flags & Pyro4.message.FLAGS_ONEWAY: return # oneway call, don't send a response else: data, compressed = serializer.serializeData( data, compress=Pyro4.config.COMPRESSION) response_flags = 0 if compressed: response_flags |= Pyro4.message.FLAGS_COMPRESSED if wasBatched: response_flags |= Pyro4.message.FLAGS_BATCH if Pyro4.config.LOGWIRE: log.debug( "daemon wiredata sending: msgtype=%d flags=0x%x ser=%d seq=%d data=%r" % (Pyro4.message.MSG_RESULT, response_flags, serializer.serializer_id, request_seq, data)) msg = Message(Pyro4.message.MSG_RESULT, data, serializer.serializer_id, response_flags, request_seq) conn.send(msg.to_bytes()) except Exception: xt, xv = sys.exc_info()[0:2] if xt is not errors.ConnectionClosedError: log.debug("Exception occurred while handling request: %r", xv) if not request_flags & Pyro4.message.FLAGS_ONEWAY: # only return the error to the client if it wasn't a oneway call tblines = util.formatTraceback( detailed=Pyro4.config.DETAILED_TRACEBACK) self._sendExceptionResponse(conn, request_seq, request_serializer_id, xv, tblines) if isCallback or isinstance( xv, (errors.CommunicationError, errors.SecurityError)): raise # re-raise if flagged as callback, communication or security error.
def handleRequest(self, conn): """ Handle incoming Pyro request. Catches any exception that may occur and wraps it in a reply to the calling side, as to not make this server side loop terminate due to exceptions caused by remote invocations. """ flags=0 seq=0 wasBatched=False isCallback=False client_future = None try: msgType, flags, seq, data = MessageFactory.getMessage(conn, MessageFactory.MSG_INVOKE) objId, method, vargs, kwargs=self.serializer.deserialize( data, compressed=flags & MessageFactory.FLAGS_COMPRESSED) del data # invite GC to collect the object, don't wait for out-of-scope obj=self.objectsById.get(objId) if flags & MessageFactory.FLAGS_ASYNC: client_future = vargs[0] client_future._pyroOneway.update(["set_cancelled", "set_result", "set_exception", "set_progress"]) vargs = vargs[1:] elif flags & MessageFactory.FLAGS_ASYNC_CANCEL: client_future_uri = vargs[0] if obj is not None: if kwargs and sys.version_info<(2, 6, 5) and os.name!="java": # Python before 2.6.5 doesn't accept unicode keyword arguments kwargs = dict((str(k), kwargs[k]) for k in kwargs) if flags & MessageFactory.FLAGS_BATCH: # batched method calls, loop over them all and collect all results data=[] for method,vargs,kwargs in vargs: method=util.resolveDottedAttribute(obj, method, Pyro4.config.DOTTEDNAMES) try: result=method(*vargs, **kwargs) # this is the actual method call to the Pyro object except Exception: xt,xv=sys.exc_info()[0:2] log.debug("Exception occurred while handling batched request: %s", xv) xv._pyroTraceback=util.formatTraceback(detailed=Pyro4.config.DETAILED_TRACEBACK) if sys.platform=="cli": util.fixIronPythonExceptionForPickle(xv, True) # piggyback attributes data.append(futures._ExceptionWrapper(xv)) break # stop processing the rest of the batch else: data.append(result) wasBatched=True elif flags & MessageFactory.FLAGS_ASYNC_CANCEL: data=self._cancelFuture(client_future_uri) else: # normal single method call method=util.resolveDottedAttribute(obj, method, Pyro4.config.DOTTEDNAMES) if flags & MessageFactory.FLAGS_ONEWAY and Pyro4.config.ONEWAY_THREADED: # oneway call to be run inside its own thread thread=threadutil.Thread(target=method, args=vargs, kwargs=kwargs) thread.setDaemon(True) thread.start() elif flags & MessageFactory.FLAGS_ASYNC: future=method(*vargs, **kwargs) self._followFuture(future, client_future) else: isCallback=getattr(method, "_pyroCallback", False) data=method(*vargs, **kwargs) # this is the actual method call to the Pyro object else: log.debug("unknown object requested: %s", objId) raise errors.DaemonError("unknown object") if flags & MessageFactory.FLAGS_ONEWAY: return # oneway call, don't send a response elif flags & MessageFactory.FLAGS_ASYNC: return # async call, don't send a response yet else: data, compressed=self.serializer.serialize(data, compress=Pyro4.config.COMPRESSION) flags=0 if compressed: flags |= MessageFactory.FLAGS_COMPRESSED if wasBatched: flags |= MessageFactory.FLAGS_BATCH msg=MessageFactory.createMessage(MessageFactory.MSG_RESULT, data, flags, seq) del data conn.send(msg) except Exception as ex: xt,xv=sys.exc_info()[0:2] if xt is not errors.ConnectionClosedError: log.debug("Exception occurred while handling request: %r", xv) if client_future is not None: # send exception to the client future client_future.set_exception(ex) elif not flags & MessageFactory.FLAGS_ONEWAY: # only return the error to the client if it wasn't a oneway call tblines=util.formatTraceback(detailed=Pyro4.config.DETAILED_TRACEBACK) self._sendExceptionResponse(conn, seq, xv, tblines) if isCallback or isinstance(xv, (errors.CommunicationError, errors.SecurityError)): raise # re-raise if flagged as callback, communication or security error.