示例#1
0
        def _wrapped(*args, **kwargs):
            # If we're passed a cache_context then we'll want to call its invalidate()
            # whenever we are invalidated
            invalidate_callback = kwargs.pop("on_invalidate", None)

            cache_key = get_cache_key(args, kwargs)

            # Add our own `cache_context` to argument list if the wrapped function
            # has asked for one
            if self.add_cache_context:
                kwargs["cache_context"] = _CacheContext.get_instance(cache, cache_key)

            try:
                cached_result_d = cache.get(cache_key, callback=invalidate_callback)

                if isinstance(cached_result_d, ObservableDeferred):
                    observer = cached_result_d.observe()
                else:
                    observer = defer.succeed(cached_result_d)

            except KeyError:
                ret = defer.maybeDeferred(
                    preserve_fn(self.function_to_call), obj, *args, **kwargs
                )

                def onErr(f):
                    cache.invalidate(cache_key)
                    return f

                ret.addErrback(onErr)

                result_d = cache.set(cache_key, ret, callback=invalidate_callback)
                observer = result_d.observe()

            return make_deferred_yieldable(observer)
示例#2
0
        def _wrapped(*args: Any, **kwargs: Any) -> Any:
            # If we're passed a cache_context then we'll want to call its invalidate()
            # whenever we are invalidated
            invalidate_callback = kwargs.pop("on_invalidate", None)

            cache_key = get_cache_key(args, kwargs)

            try:
                ret = cache.get(cache_key, callback=invalidate_callback)
            except KeyError:
                # Add our own `cache_context` to argument list if the wrapped function
                # has asked for one
                if self.add_cache_context:
                    kwargs["cache_context"] = _CacheContext.get_instance(
                        cache, cache_key)

                ret = defer.maybeDeferred(preserve_fn(self.orig), obj, *args,
                                          **kwargs)
                ret = cache.set(cache_key, ret, callback=invalidate_callback)

                # We started a new call to `self.orig`, so we must always wait for it to
                # complete. Otherwise we might mark our current logging context as
                # finished while `self.orig` is still using it in the background.
                ret = delay_cancellation(ret)

            return make_deferred_yieldable(ret)
示例#3
0
    def _verify_objects(
        self, verify_requests: Iterable[VerifyJsonRequest]
    ) -> List[defer.Deferred]:
        """Does the work of verify_json_[objects_]for_server


        Args:
            verify_requests: Iterable of verification requests.

        Returns:
            List<Deferred[None]>: for each input item, a deferred indicating success
                or failure to verify each json object's signature for the given
                server_name. The deferreds run their callbacks in the sentinel
                logcontext.
        """
        # a list of VerifyJsonRequests which are awaiting a key lookup
        key_lookups = []
        handle = preserve_fn(_handle_key_deferred)

        def process(verify_request: VerifyJsonRequest) -> defer.Deferred:
            """Process an entry in the request list

            Adds a key request to key_lookups, and returns a deferred which
            will complete or fail (in the sentinel context) when verification completes.
            """
            if not verify_request.key_ids:
                return defer.fail(
                    SynapseError(
                        400,
                        "Not signed by %s" % (verify_request.server_name,),
                        Codes.UNAUTHORIZED,
                    )
                )

            logger.debug(
                "Verifying %s for %s with key_ids %s, min_validity %i",
                verify_request.request_name,
                verify_request.server_name,
                verify_request.key_ids,
                verify_request.minimum_valid_until_ts,
            )

            # add the key request to the queue, but don't start it off yet.
            key_lookups.append(verify_request)

            # now run _handle_key_deferred, which will wait for the key request
            # to complete and then do the verification.
            #
            # We want _handle_key_request to log to the right context, so we
            # wrap it with preserve_fn (aka run_in_background)
            return handle(verify_request)

        results = [process(r) for r in verify_requests]

        if key_lookups:
            run_in_background(self._start_key_lookups, key_lookups)

        return results
示例#4
0
        def wrapped(*args, **kwargs):
            # If we're passed a cache_context then we'll want to call its invalidate()
            # whenever we are invalidated
            invalidate_callback = kwargs.pop("on_invalidate", None)

            cache_key = get_cache_key(args, kwargs)

            # Add our own `cache_context` to argument list if the wrapped function
            # has asked for one
            if self.add_cache_context:
                kwargs["cache_context"] = _CacheContext(cache, cache_key)

            try:
                cached_result_d = cache.get(cache_key,
                                            callback=invalidate_callback)

                if isinstance(cached_result_d, ObservableDeferred):
                    observer = cached_result_d.observe()
                else:
                    observer = cached_result_d

            except KeyError:
                ret = defer.maybeDeferred(preserve_fn(self.function_to_call),
                                          obj, *args, **kwargs)

                def onErr(f):
                    cache.invalidate(cache_key)
                    return f

                ret.addErrback(onErr)

                # If our cache_key is a string on py2, try to convert to ascii
                # to save a bit of space in large caches. Py3 does this
                # internally automatically.
                if six.PY2 and isinstance(cache_key, string_types):
                    cache_key = to_ascii(cache_key)

                result_d = ObservableDeferred(ret, consumeErrors=True)
                cache.set(cache_key, result_d, callback=invalidate_callback)
                observer = result_d.observe()

            if isinstance(observer, defer.Deferred):
                return make_deferred_yieldable(observer)
            else:
                return observer
示例#5
0
文件: server.py 项目: vfat0/synapse
def wrap_async_request_handler(h):
    """Wraps an async request handler so that it calls request.processing.

    This helps ensure that work done by the request handler after the request is completed
    is correctly recorded against the request metrics/logs.

    The handler method must have a signature of "handle_foo(self, request)",
    where "request" must be a SynapseRequest.

    The handler may return a deferred, in which case the completion of the request isn't
    logged until the deferred completes.
    """
    async def wrapped_async_request_handler(self, request):
        with request.processing():
            await h(self, request)

    # we need to preserve_fn here, because the synchronous render method won't yield for
    # us (obviously)
    return preserve_fn(wrapped_async_request_handler)
示例#6
0
        def _wrapped(*args, **kwargs):
            # If we're passed a cache_context then we'll want to call its invalidate()
            # whenever we are invalidated
            invalidate_callback = kwargs.pop("on_invalidate", None)

            cache_key = get_cache_key(args, kwargs)

            try:
                ret = cache.get(cache_key, callback=invalidate_callback)
            except KeyError:
                # Add our own `cache_context` to argument list if the wrapped function
                # has asked for one
                if self.add_cache_context:
                    kwargs["cache_context"] = _CacheContext.get_instance(
                        cache, cache_key)

                ret = defer.maybeDeferred(preserve_fn(self.orig), obj, *args,
                                          **kwargs)
                ret = cache.set(cache_key, ret, callback=invalidate_callback)

            return make_deferred_yieldable(ret)
示例#7
0
        def wrapped(*args, **kwargs):
            # If we're passed a cache_context then we'll want to call its
            # invalidate() whenever we are invalidated
            invalidate_callback = kwargs.pop("on_invalidate", None)

            arg_dict = inspect.getcallargs(self.orig, obj, *args, **kwargs)
            keyargs = [arg_dict[arg_nm] for arg_nm in self.arg_names]
            list_args = arg_dict[self.list_name]

            results = {}

            def update_results_dict(res, arg):
                results[arg] = res

            # list of deferreds to wait for
            cached_defers = []

            missing = set()

            # If the cache takes a single arg then that is used as the key,
            # otherwise a tuple is used.
            if num_args == 1:

                def arg_to_cache_key(arg):
                    return arg

            else:
                keylist = list(keyargs)

                def arg_to_cache_key(arg):
                    keylist[self.list_pos] = arg
                    return tuple(keylist)

            for arg in list_args:
                try:
                    res = cache.get(arg_to_cache_key(arg),
                                    callback=invalidate_callback)
                    if not isinstance(res, ObservableDeferred):
                        results[arg] = res
                    elif not res.has_succeeded():
                        res = res.observe()
                        res.addCallback(update_results_dict, arg)
                        cached_defers.append(res)
                    else:
                        results[arg] = res.get_result()
                except KeyError:
                    missing.add(arg)

            if missing:
                # we need a deferred for each entry in the list,
                # which we put in the cache. Each deferred resolves with the
                # relevant result for that key.
                deferreds_map = {}
                for arg in missing:
                    deferred = defer.Deferred()
                    deferreds_map[arg] = deferred
                    key = arg_to_cache_key(arg)
                    cache.set(key, deferred, callback=invalidate_callback)

                def complete_all(res):
                    # the wrapped function has completed. It returns a
                    # a dict. We can now resolve the observable deferreds in
                    # the cache and update our own result map.
                    for e in missing:
                        val = res.get(e, None)
                        deferreds_map[e].callback(val)
                        results[e] = val

                def errback(f):
                    # the wrapped function has failed. Invalidate any cache
                    # entries we're supposed to be populating, and fail
                    # their deferreds.
                    for e in missing:
                        key = arg_to_cache_key(e)
                        cache.invalidate(key)
                        deferreds_map[e].errback(f)

                    # return the failure, to propagate to our caller.
                    return f

                args_to_call = dict(arg_dict)
                args_to_call[self.list_name] = list(missing)

                cached_defers.append(
                    defer.maybeDeferred(preserve_fn(self.function_to_call),
                                        **args_to_call).addCallbacks(
                                            complete_all, errback))

            if cached_defers:
                d = defer.gatherResults(cached_defers,
                                        consumeErrors=True).addCallbacks(
                                            lambda _: results,
                                            unwrapFirstError)
                return make_deferred_yieldable(d)
            else:
                return defer.succeed(results)
示例#8
0
    def _check_sigs_and_hash_and_fetch(
        self, origin, pdus, room_version, outlier=False, include_none=False
    ):
        """Takes a list of PDUs and checks the signatures and hashs of each
        one. If a PDU fails its signature check then we check if we have it in
        the database and if not then request if from the originating server of
        that PDU.

        If a PDU fails its content hash check then it is redacted.

        The given list of PDUs are not modified, instead the function returns
        a new list.

        Args:
            origin (str)
            pdu (list)
            room_version (str)
            outlier (bool): Whether the events are outliers or not
            include_none (str): Whether to include None in the returned list
                for events that have failed their checks

        Returns:
            Deferred : A list of PDUs that have valid signatures and hashes.
        """
        deferreds = self._check_sigs_and_hashes(room_version, pdus)

        @defer.inlineCallbacks
        def handle_check_result(pdu, deferred):
            try:
                res = yield make_deferred_yieldable(deferred)
            except SynapseError:
                res = None

            if not res:
                # Check local db.
                res = yield self.store.get_event(
                    pdu.event_id, allow_rejected=True, allow_none=True
                )

            if not res and pdu.origin != origin:
                try:
                    res = yield self.get_pdu(
                        destinations=[pdu.origin],
                        event_id=pdu.event_id,
                        room_version=room_version,
                        outlier=outlier,
                        timeout=10000,
                    )
                except SynapseError:
                    pass

            if not res:
                logger.warning(
                    "Failed to find copy of %s with valid signature", pdu.event_id
                )

            return res

        handle = preserve_fn(handle_check_result)
        deferreds2 = [handle(pdu, deferred) for pdu, deferred in zip(pdus, deferreds)]

        valid_pdus = yield make_deferred_yieldable(
            defer.gatherResults(deferreds2, consumeErrors=True)
        ).addErrback(unwrapFirstError)

        if include_none:
            return valid_pdus
        else:
            return [p for p in valid_pdus if p]
示例#9
0
        def wrapped(*args: Any, **kwargs: Any) -> "defer.Deferred[Dict]":
            # If we're passed a cache_context then we'll want to call its
            # invalidate() whenever we are invalidated
            invalidate_callback = kwargs.pop("on_invalidate", None)

            arg_dict = inspect.getcallargs(self.orig, obj, *args, **kwargs)
            keyargs = [arg_dict[arg_nm] for arg_nm in self.arg_names]
            list_args = arg_dict[self.list_name]

            results = {}

            def update_results_dict(res: Any, arg: Hashable) -> None:
                results[arg] = res

            # list of deferreds to wait for
            cached_defers = []

            missing = set()

            # If the cache takes a single arg then that is used as the key,
            # otherwise a tuple is used.
            if num_args == 1:

                def arg_to_cache_key(arg: Hashable) -> Hashable:
                    return arg

            else:
                keylist = list(keyargs)

                def arg_to_cache_key(arg: Hashable) -> Hashable:
                    keylist[self.list_pos] = arg
                    return tuple(keylist)

            for arg in list_args:
                try:
                    res = cache.get(arg_to_cache_key(arg),
                                    callback=invalidate_callback)
                    if not res.called:
                        res.addCallback(update_results_dict, arg)
                        cached_defers.append(res)
                    else:
                        results[arg] = res.result
                except KeyError:
                    missing.add(arg)

            if missing:
                # we need a deferred for each entry in the list,
                # which we put in the cache. Each deferred resolves with the
                # relevant result for that key.
                deferreds_map = {}
                for arg in missing:
                    deferred: "defer.Deferred[Any]" = defer.Deferred()
                    deferreds_map[arg] = deferred
                    key = arg_to_cache_key(arg)
                    cached_defers.append(
                        cache.set(key, deferred, callback=invalidate_callback))

                def complete_all(res: Dict[Hashable, Any]) -> None:
                    # the wrapped function has completed. It returns a dict.
                    # We can now update our own result map, and then resolve the
                    # observable deferreds in the cache.
                    for e, d1 in deferreds_map.items():
                        val = res.get(e, None)
                        # make sure we update the results map before running the
                        # deferreds, because as soon as we run the last deferred, the
                        # gatherResults() below will complete and return the result
                        # dict to our caller.
                        results[e] = val
                        d1.callback(val)

                def errback_all(f: Failure) -> None:
                    # the wrapped function has failed. Propagate the failure into
                    # the cache, which will invalidate the entry, and cause the
                    # relevant cached_deferreds to fail, which will propagate the
                    # failure to our caller.
                    for d1 in deferreds_map.values():
                        d1.errback(f)

                args_to_call = dict(arg_dict)
                args_to_call[self.list_name] = missing

                # dispatch the call, and attach the two handlers
                defer.maybeDeferred(preserve_fn(self.orig),
                                    **args_to_call).addCallbacks(
                                        complete_all, errback_all)

            if cached_defers:
                d = defer.gatherResults(cached_defers,
                                        consumeErrors=True).addCallbacks(
                                            lambda _: results,
                                            unwrapFirstError)
                if missing:
                    # We started a new call to `self.orig`, so we must always wait for it to
                    # complete. Otherwise we might mark our current logging context as
                    # finished while `self.orig` is still using it in the background.
                    d = delay_cancellation(d)
                return make_deferred_yieldable(d)
            else:
                return defer.succeed(results)