def return_html_error( f: failure.Failure, request: Request, error_template: Union[str, jinja2.Template], ) -> None: """Sends an HTML error page corresponding to the given failure. Handles RedirectException and other CodeMessageExceptions (such as SynapseError) Args: f: the error to report request: the failing request error_template: the HTML template. Can be either a string (with `{code}`, `{msg}` placeholders), or a jinja2 template """ if f.check(CodeMessageException): # mypy doesn't understand that f.check asserts the type. cme: CodeMessageException = f.value # type: ignore code = cme.code msg = cme.msg if isinstance(cme, RedirectException): logger.info("%s redirect to %s", request, cme.location) request.setHeader(b"location", cme.location) request.cookies.extend(cme.cookies) elif isinstance(cme, SynapseError): logger.info("%s SynapseError: %s - %s", request, code, msg) else: logger.error( "Failed handle request %r", request, exc_info=(f.type, f.value, f.getTracebackObject()), # type: ignore[arg-type] ) elif f.check(CancelledError): code = HTTP_STATUS_REQUEST_CANCELLED msg = "Request cancelled" if not request._disconnected: logger.error( "Got cancellation before client disconnection when handling request %r", request, exc_info=(f.type, f.value, f.getTracebackObject()), # type: ignore[arg-type] ) else: code = HTTPStatus.INTERNAL_SERVER_ERROR msg = "Internal server error" logger.error( "Failed handle request %r", request, exc_info=(f.type, f.value, f.getTracebackObject()), # type: ignore[arg-type] ) if isinstance(error_template, str): body = error_template.format(code=code, msg=html.escape(msg)) else: body = error_template.render(code=code, msg=msg) respond_with_html(request, code, body)
def return_html_error( f: failure.Failure, request: Request, error_template: Union[str, jinja2.Template], ) -> None: """Sends an HTML error page corresponding to the given failure. Handles RedirectException and other CodeMessageExceptions (such as SynapseError) Args: f: the error to report request: the failing request error_template: the HTML template. Can be either a string (with `{code}`, `{msg}` placeholders), or a jinja2 template """ if f.check(CodeMessageException): cme = f.value code = cme.code msg = cme.msg if isinstance(cme, RedirectException): logger.info("%s redirect to %s", request, cme.location) request.setHeader(b"location", cme.location) request.cookies.extend(cme.cookies) elif isinstance(cme, SynapseError): logger.info("%s SynapseError: %s - %s", request, code, msg) else: logger.error( "Failed handle request %r", request, exc_info=(f.type, f.value, f.getTracebackObject()), ) else: code = http.HTTPStatus.INTERNAL_SERVER_ERROR msg = "Internal server error" logger.error( "Failed handle request %r", request, exc_info=(f.type, f.value, f.getTracebackObject()), ) if isinstance(error_template, str): body = error_template.format(code=code, msg=html.escape(msg)) else: body = error_template.render(code=code, msg=msg) body_bytes = body.encode("utf-8") request.setResponseCode(code) request.setHeader(b"Content-Type", b"text/html; charset=utf-8") request.setHeader(b"Content-Length", b"%i" % (len(body_bytes), )) request.write(body_bytes) finish_request(request)
def return_json_error(f: failure.Failure, request: SynapseRequest) -> None: """Sends a JSON error response to clients.""" if f.check(SynapseError): # mypy doesn't understand that f.check asserts the type. exc: SynapseError = f.value # type: ignore error_code = exc.code error_dict = exc.error_dict() logger.info("%s SynapseError: %s - %s", request, error_code, exc.msg) elif f.check(CancelledError): error_code = HTTP_STATUS_REQUEST_CANCELLED error_dict = {"error": "Request cancelled", "errcode": Codes.UNKNOWN} if not request._disconnected: logger.error( "Got cancellation before client disconnection from %r: %r", request.request_metrics.name, request, exc_info=(f.type, f.value, f.getTracebackObject()), # type: ignore[arg-type] ) else: error_code = 500 error_dict = { "error": "Internal server error", "errcode": Codes.UNKNOWN } logger.error( "Failed handle request via %r: %r", request.request_metrics.name, request, exc_info=(f.type, f.value, f.getTracebackObject()), # type: ignore[arg-type] ) # Only respond with an error response if we haven't already started writing, # otherwise lets just kill the connection if request.startedWriting: if request.transport: try: request.transport.abortConnection() except Exception: # abortConnection throws if the connection is already closed pass else: respond_with_json( request, error_code, error_dict, send_cors=True, )
async def _purge_history( self, purge_id: str, room_id: str, token: str, delete_local_events: bool ) -> None: """Carry out a history purge on a room. Args: purge_id: The id for this purge room_id: The room to purge from token: topological token to delete events before delete_local_events: True to delete local events as well as remote ones """ self._purges_in_progress_by_room.add(room_id) try: with await self.pagination_lock.write(room_id): await self.storage.purge_events.purge_history( room_id, token, delete_local_events ) logger.info("[purge] complete") self._purges_by_id[purge_id].status = PurgeStatus.STATUS_COMPLETE except Exception: f = Failure() logger.error( "[purge] failed", exc_info=(f.type, f.value, f.getTracebackObject()) ) self._purges_by_id[purge_id].status = PurgeStatus.STATUS_FAILED finally: self._purges_in_progress_by_room.discard(room_id) # remove the purge from the list 24 hours after it completes def clear_purge(): del self._purges_by_id[purge_id] self.hs.get_reactor().callLater(24 * 3600, clear_purge)
def get_error_html(self, status_code, **kwargs): try: if 'exception' in kwargs: failure = kwargs.get('exception') if isinstance(failure, cyclone.web.HTTPError): failure = Failure(failure) logger.exception(failure) if os.environ.get('XDEBUG'): from mako import exceptions return exceptions.html_error_template().render( traceback=failure.getTracebackObject()) if self.request.headers.get( 'X-Requested-With') == 'XMLHttpRequest': return self.render_json(code=1, msg=u'%s:服务器处理失败,请联系管理员' % status_code) if status_code == 404: return self.render_error(msg=u'404:页面不存在') if status_code == 403: return self.render_error(msg=u'403:非法的请求') if status_code == 500: return self.render_error(msg=u'500:服务器处理失败,请联系管理员') return self.render_error(msg=u'%s:服务器处理失败,请联系管理员' % status_code) except Exception as err: logger.exception(err) return self.render_error(msg=u'%s:服务器处理失败,请联系管理员' % status_code)
def run(): with _bg_metrics_lock: count = _background_process_counts.get(desc, 0) _background_process_counts[desc] = count + 1 _background_process_start_count.labels(desc).inc() _background_process_in_flight_count.labels(desc).inc() with BackgroundProcessLoggingContext(desc) as context: context.request = "%s-%i" % (desc, count) try: result = func(*args, **kwargs) # We probably don't have an ensureDeferred in our call stack to handle # coroutine results, so we need to ensureDeferred here. # # But we need this check because ensureDeferred doesn't like being # called on immediate values (as opposed to Deferreds or coroutines). if iscoroutine(result): result = defer.ensureDeferred(result) return (yield result) except Exception: # failure.Failure() fishes the original Failure out of our stack, and # thus gives us a sensible stack trace. f = Failure() logger.error( "Background process '%s' threw an exception", desc, exc_info=(f.type, f.value, f.getTracebackObject()), ) finally: _background_process_in_flight_count.labels(desc).dec()
def log_failure(failure: Failure, msg: str, consumeErrors: bool = True) -> Optional[Failure]: """Creates a function suitable for passing to `Deferred.addErrback` that logs any failures that occur. Args: failure: The Failure to log msg: Message to log consumeErrors: If true consumes the failure, otherwise passes on down the callback chain Returns: The Failure if consumeErrors is false. None, otherwise. """ logger.error( msg, exc_info=(failure.type, failure.value, failure.getTracebackObject() ) # type: ignore[arg-type] ) if not consumeErrors: return failure return None
def return_json_error(f: failure.Failure, request: SynapseRequest) -> None: """Sends a JSON error response to clients. """ if f.check(SynapseError): error_code = f.value.code error_dict = f.value.error_dict() logger.info("%s SynapseError: %s - %s", request, error_code, f.value.msg) else: error_code = 500 error_dict = {"error": "Internal server error", "errcode": Codes.UNKNOWN} logger.error( "Failed handle request via %r: %r", request.request_metrics.name, request, exc_info=(f.type, f.value, f.getTracebackObject()), ) # Only respond with an error response if we haven't already started writing, # otherwise lets just kill the connection if request.startedWriting: if request.transport: try: request.transport.abortConnection() except Exception: # abortConnection throws if the connection is already closed pass else: respond_with_json( request, error_code, error_dict, send_cors=True, )
def _purge_history(self, purge_id, room_id, token, delete_local_events): """Carry out a history purge on a room. Args: purge_id (str): The id for this purge room_id (str): The room to purge from token (str): topological token to delete events before delete_local_events (bool): True to delete local events as well as remote ones Returns: Deferred """ self._purges_in_progress_by_room.add(room_id) try: with (yield self.pagination_lock.write(room_id)): yield self.store.purge_history( room_id, token, delete_local_events, ) logger.info("[purge] complete") self._purges_by_id[purge_id].status = PurgeStatus.STATUS_COMPLETE except Exception: f = Failure() logger.error( "[purge] failed", exc_info=(f.type, f.value, f.getTracebackObject()), ) self._purges_by_id[purge_id].status = PurgeStatus.STATUS_FAILED finally: self._purges_in_progress_by_room.discard(room_id) # remove the purge from the list 24 hours after it completes def clear_purge(): del self._purges_by_id[purge_id] self.hs.get_reactor().callLater(24 * 3600, clear_purge)
async def _shutdown_and_purge_room( self, delete_id: str, room_id: str, requester_user_id: str, new_room_user_id: Optional[str] = None, new_room_name: Optional[str] = None, message: Optional[str] = None, block: bool = False, purge: bool = True, force_purge: bool = False, ) -> None: """ Shuts down and purges a room. See `RoomShutdownHandler.shutdown_room` for details of creation of the new room Args: delete_id: The ID for this delete. room_id: The ID of the room to shut down. requester_user_id: User who requested the action. Will be recorded as putting the room on the blocking list. new_room_user_id: If set, a new room will be created with this user ID as the creator and admin, and all users in the old room will be moved into that room. If not set, no new room will be created and the users will just be removed from the old room. new_room_name: A string representing the name of the room that new users will be invited to. Defaults to `Content Violation Notification` message: A string containing the first message that will be sent as `new_room_user_id` in the new room. Ideally this will clearly convey why the original room was shut down. Defaults to `Sharing illegal content on this server is not permitted and rooms in violation will be blocked.` block: If set to `true`, this room will be added to a blocking list, preventing future attempts to join the room. Defaults to `false`. purge: If set to `true`, purge the given room from the database. force_purge: If set to `true`, the room will be purged from database also if it fails to remove some users from room. Saves a `RoomShutdownHandler.ShutdownRoomResponse` in `DeleteStatus`: """ self._purges_in_progress_by_room.add(room_id) try: with await self.pagination_lock.write(room_id): self._delete_by_id[ delete_id].status = DeleteStatus.STATUS_SHUTTING_DOWN self._delete_by_id[ delete_id].shutdown_room = await self._room_shutdown_handler.shutdown_room( room_id=room_id, requester_user_id=requester_user_id, new_room_user_id=new_room_user_id, new_room_name=new_room_name, message=message, block=block, ) self._delete_by_id[ delete_id].status = DeleteStatus.STATUS_PURGING if purge: logger.info("starting purge room_id %s", room_id) # first check that we have no users in this room if not force_purge: joined = await self.store.is_host_joined( room_id, self._server_name) if joined: raise SynapseError( 400, "Users are still joined to this room") await self.storage.purge_events.purge_room(room_id) logger.info("complete") self._delete_by_id[delete_id].status = DeleteStatus.STATUS_COMPLETE except Exception: f = Failure() logger.error( "failed", exc_info=(f.type, f.value, f.getTracebackObject()), # type: ignore ) self._delete_by_id[delete_id].status = DeleteStatus.STATUS_FAILED self._delete_by_id[delete_id].error = f.getErrorMessage() finally: self._purges_in_progress_by_room.discard(room_id) # remove the delete from the list 24 hours after it completes def clear_delete() -> None: del self._delete_by_id[delete_id] self._delete_by_room[room_id].remove(delete_id) if not self._delete_by_room[room_id]: del self._delete_by_room[room_id] self.hs.get_reactor().callLater( PaginationHandler.CLEAR_PURGE_AFTER_MS / 1000, clear_delete)