From f034f6ae16e71e0d65779578d8ed66f3be6db03b Mon Sep 17 00:00:00 2001 From: Roberto Prevato Date: Wed, 17 Jan 2024 20:49:48 +0100 Subject: [PATCH] Fix #470 --- CHANGELOG.md | 4 +++- blacksheep/server/application.py | 3 ++- blacksheep/server/routing.py | 33 +++++++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f493268..2e54c89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [2.0.6] - 2024-01-16 :kr: :heart: +## [2.0.6] - 2024-01-17 :kr: :heart: - Adds built-in support for [Server-Sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). - Adds a function to detect when the server process is terminating because it @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Adds support for request handler normalization for methods defined as asynchronous generators. This feature is enabled by default only for ServerSentEvents, but can be configured for user defined types. +- Raises exception when the default router is used to register routes, but not + associated to an application object. Fixes [#470](https://github.com/Neoteroi/BlackSheep/issues/470). Refer to the [BlackSheep documentation](https://www.neoteroi.dev/blacksheep/server-sent-events/) and to the [examples repository](https://github.com/Neoteroi/BlackSheep-Examples/tree/main/server-sent-events) for more information on server-sent events support. diff --git a/blacksheep/server/application.py b/blacksheep/server/application.py index 8ac2847..c52756c 100644 --- a/blacksheep/server/application.py +++ b/blacksheep/server/application.py @@ -64,7 +64,7 @@ RoutesRegistry, ) from blacksheep.server.routing import router as default_router -from blacksheep.server.routing import validate_router +from blacksheep.server.routing import validate_default_router, validate_router from blacksheep.server.websocket import WebSocket, format_reason from blacksheep.sessions import SessionMiddleware, SessionSerializer from blacksheep.settings.di import di_settings @@ -706,6 +706,7 @@ async def start(self): if self.on_start: await self.on_start.fire() + validate_default_router() self.use_controllers() self.normalize_handlers() self.configure_middlewares() diff --git a/blacksheep/server/routing.py b/blacksheep/server/routing.py index aa3aa35..b6c0a72 100644 --- a/blacksheep/server/routing.py +++ b/blacksheep/server/routing.py @@ -66,6 +66,21 @@ class InvalidRouterConfigurationError(RouteException): """Base class for router configuration errors""" +class OrphanDefaultRouterError(InvalidRouterConfigurationError): + """ + Error raised when the default router was configured with routes, but it is not + associated to any application. + """ + + def __init__(self) -> None: + super().__init__( + "Invalid router configuration: the default router was used to register " + "routes, but it is not associated to any application object. To resolve, " + "ensure that the router bound to your application is used to register " + "routes. Do not use routing methods imported from the library." + ) + + class SharedRouterError(InvalidRouterConfigurationError): """ Error raised when the more than one application is using the same router. @@ -941,13 +956,29 @@ def validate_router(app): # by uvicorn reload feature, when uvicorn is started programmatically. # See https://github.com/Neoteroi/BlackSheep/issues/438 logging.getLogger("blacksheep.server").warning( - "[BlackSheep] The application was reloaded, resetting its router." + "The application was reloaded, resetting its router." ) app_router.reset() return raise SharedRouterError() +def validate_default_router(): + """ + This method ensures that the default router is associated to an application, if it + defines any route. + """ + if set(router): + # The default router has routes defined, ensure that it is bound to an + # application + # verify that + try: + _apps_by_router_id[id(router)] + except KeyError: + # Not good + raise OrphanDefaultRouterError() from None + + # Singleton router used to store initial configuration, # before the application starts # this is used as *default* router, but it can be overridden;