From 12b1543b2182073626e3f1dc67ea575c60af5493 Mon Sep 17 00:00:00 2001 From: Leonid Vinogradov Date: Tue, 29 Oct 2024 15:40:06 +0300 Subject: [PATCH] HH-235907 small fixes --- examples/example_app/pages/example.py | 5 ++++- frontik/app.py | 7 ++++--- frontik/auth.py | 8 ++++---- frontik/config_parser.py | 6 ++---- frontik/debug.py | 23 ++++++++++++++--------- frontik/handler_asgi.py | 11 ++++------- frontik/loggers/__init__.py | 6 +++--- frontik/request_context.py | 4 ++-- frontik/routing.py | 7 +++---- frontik/service_discovery.py | 3 +-- tests/test_no_debug_mode.py | 8 +++----- 11 files changed, 44 insertions(+), 44 deletions(-) diff --git a/examples/example_app/pages/example.py b/examples/example_app/pages/example.py index de4f26f21..a90bb224e 100644 --- a/examples/example_app/pages/example.py +++ b/examples/example_app/pages/example.py @@ -1,5 +1,8 @@ +from fastapi import APIRouter + from frontik.dependencies import HttpClient -from frontik.routing import router + +router = APIRouter() @router.get('/example') diff --git a/frontik/app.py b/frontik/app.py index 6927afbf3..4e7e63ac0 100644 --- a/frontik/app.py +++ b/frontik/app.py @@ -196,12 +196,13 @@ def __init__(self, frontik_app: FrontikApplication) -> None: super().__init__() self.router = router + for _router in routers: + if _router is not router: + self.include_router(_router) + if options.openapi_enabled: self.setup() - for _router in routers: - self.include_router(_router) - self.config = frontik_app.config self.get_current_status = frontik_app.get_current_status self.get_frontik_and_apps_versions = frontik_app.get_frontik_and_apps_versions diff --git a/frontik/auth.py b/frontik/auth.py index 5b5f6e1b3..ffee2f024 100644 --- a/frontik/auth.py +++ b/frontik/auth.py @@ -26,21 +26,21 @@ def passed_basic_auth(auth_header: Optional[str], login: Optional[str], passwd: def check_debug_auth_by_headers( headers: Union[Mapping, MutableMapping], login: Optional[str], password: Optional[str] -) -> Optional[str]: +) -> Optional[dict]: debug_auth_header = headers.get(DEBUG_AUTH_HEADER_NAME) if debug_auth_header is not None: debug_access = debug_auth_header == f'{login}:{password}' if not debug_access: - return f'{DEBUG_AUTH_HEADER_NAME}-Header realm="Secure Area"' + return {'WWW-Authenticate': f'{DEBUG_AUTH_HEADER_NAME}-Header realm="Secure Area"'} else: auth_header: Optional[str] = headers.get('Authorization') debug_access = passed_basic_auth(auth_header, login, password) if not debug_access: - return 'Basic realm="Secure Area"' + return {'WWW-Authenticate': 'Basic realm="Secure Area"'} return None def check_debug_auth( tornado_request: httputil.HTTPServerRequest, login: Optional[str], password: Optional[str] -) -> Optional[str]: +) -> Optional[dict]: return check_debug_auth_by_headers(tornado_request.headers, login, password) diff --git a/frontik/config_parser.py b/frontik/config_parser.py index ed0a4551b..f334df9fd 100644 --- a/frontik/config_parser.py +++ b/frontik/config_parser.py @@ -29,8 +29,7 @@ def parse_configs(config_files: Optional[str]) -> None: configs_to_read = options.config else: if config_files is None: - msg = 'Configs can not be None' - raise Exception(msg) + raise Exception('Configs can not be None') configs_to_read = config_files configs_to_read_filter = filter( @@ -86,5 +85,4 @@ def parse_command_line(options: Options, allowed_options: Iterable) -> None: elif option.type == str or get_args(option.type) == (str, type(None)): setattr(options, name, value) else: - msg = f'Complex types are not implemented {name!r}: {value!r} ({option.type})' - raise Exception(msg) + raise Exception(f'Complex types are not implemented {name!r}: {value!r} ({option.type})') diff --git a/frontik/debug.py b/frontik/debug.py index 47b74e516..042cdc8b5 100644 --- a/frontik/debug.py +++ b/frontik/debug.py @@ -402,7 +402,7 @@ def transform_chunk( start_time = time.time() handler_name = request_context.get_handler_name() - debug_log_data = request_context.get_log_handler().produce_all() # type: ignore + debug_log_data = request_context.get_debug_log_handler().produce_all() # type: ignore debug_log_data.set('code', str(int(response.status_code))) debug_log_data.set('handler-name', handler_name if handler_name else 'unknown handler') debug_log_data.set('started', _format_number(tornado_request._start_time)) @@ -477,8 +477,9 @@ def __init__(self, tornado_request: HTTPServerRequest) -> None: self.inherited = tornado_request.headers.get(DEBUG_HEADER_NAME, None) self.pass_debug = False self.enabled = False + self.debug_response = False self.profile_xslt = False - self.failed_auth_header: Optional[str] = None + self.failed_auth_headers: Optional[dict] = None self.need_auth = ( self.debug_value is not None or self.inherited @@ -486,32 +487,36 @@ def __init__(self, tornado_request: HTTPServerRequest) -> None: or self.notrl is not None or self.noxsl is not None ) + self.auth_failed: Optional[bool] = None if self.inherited: debug_log.debug('debug mode is inherited due to %s request header', DEBUG_HEADER_NAME) def require_debug_access(self, tornado_request: HTTPServerRequest, auth_failed: Optional[bool] = None) -> None: if auth_failed is True: - self.failed_auth_header = 'Basic realm="Secure Area"' + self.auth_failed = True return if options.debug or auth_failed is False: + self.auth_failed = False self.on_auth_ok() return - self.failed_auth_header = check_debug_auth(tornado_request, options.debug_login, options.debug_password) - if not self.failed_auth_header: + self.failed_auth_headers = check_debug_auth(tornado_request, options.debug_login, options.debug_password) + if self.failed_auth_headers is None: + self.auth_failed = False self.on_auth_ok() + return + + self.auth_failed = True def on_auth_ok(self) -> None: + self.debug_response = self.debug_value is not None or self.inherited self.enabled = True self.pass_debug = 'nopass' not in self.mode_values or bool(self.inherited) self.profile_xslt = 'xslt' in self.mode_values - request_context.set_log_handler(DebugBufferedHandler()) + request_context.set_debug_log_handler(DebugBufferedHandler()) if self.pass_debug: debug_log.debug('%s header will be passed to all requests', DEBUG_HEADER_NAME) - - def auth_failed(self) -> bool: - return self.failed_auth_header is not None diff --git a/frontik/handler_asgi.py b/frontik/handler_asgi.py index 96b58b2cb..eeb470634 100644 --- a/frontik/handler_asgi.py +++ b/frontik/handler_asgi.py @@ -71,11 +71,8 @@ async def process_request( return FrontikResponse(status_code=http.client.SERVICE_UNAVAILABLE) debug_mode = make_debug_mode(frontik_app, tornado_request) - if debug_mode.auth_failed(): - assert debug_mode.failed_auth_header is not None - return FrontikResponse( - status_code=http.client.UNAUTHORIZED, headers={'WWW-Authenticate': debug_mode.failed_auth_header} - ) + if debug_mode.auth_failed: + return FrontikResponse(status_code=http.client.UNAUTHORIZED, headers=debug_mode.failed_auth_headers) assert tornado_request.method is not None @@ -84,7 +81,7 @@ async def process_request( response = await execute_asgi_page(frontik_app, asgi_app, tornado_request, scope, debug_mode, integrations) - if debug_mode.enabled and not response.headers_written: + if debug_mode.debug_response and not response.headers_written: debug_transform = DebugTransform(frontik_app, debug_mode) response = debug_transform.transform_chunk(tornado_request, response) @@ -138,7 +135,7 @@ async def send(message): response.headers.add(h[0].decode(CHARSET), h[1].decode(CHARSET)) elif message['type'] == 'http.response.body': chunk = message['body'] - if debug_mode.enabled or not message.get('more_body'): + if debug_mode.debug_response or not message.get('more_body'): response.body += chunk elif not response.headers_written: for integration in integrations.values(): diff --git a/frontik/loggers/__init__.py b/frontik/loggers/__init__.py index 45684c7f1..4a3580786 100644 --- a/frontik/loggers/__init__.py +++ b/frontik/loggers/__init__.py @@ -57,9 +57,9 @@ def produce_all(self): raise NotImplementedError() # pragma: no cover -class GlobalLogHandler(Handler): +class DebugLogHandler(Handler): def handle(self, record): - handler = request_context.get_log_handler() + handler = request_context.get_debug_log_handler() if handler is not None: handler.handle(record) @@ -171,7 +171,7 @@ def bootstrap_logger( handler.setLevel(logger_level) logger.addHandler(handler) - logger.addHandler(GlobalLogHandler()) + logger.addHandler(DebugLogHandler()) logger.propagate = False return logger diff --git a/frontik/request_context.py b/frontik/request_context.py index 8802e31ce..c0f0bce61 100644 --- a/frontik/request_context.py +++ b/frontik/request_context.py @@ -45,9 +45,9 @@ def set_handler_name(route: APIRoute) -> None: _context.get().handler_name = f'{route.endpoint.__module__}.{route.endpoint.__name__}' -def get_log_handler() -> Optional[DebugBufferedHandler]: +def get_debug_log_handler() -> Optional[DebugBufferedHandler]: return _context.get().log_handler -def set_log_handler(log_handler: DebugBufferedHandler) -> None: +def set_debug_log_handler(log_handler: DebugBufferedHandler) -> None: _context.get().log_handler = log_handler diff --git a/frontik/routing.py b/frontik/routing.py index 57035d62a..fabc92dd4 100644 --- a/frontik/routing.py +++ b/frontik/routing.py @@ -25,10 +25,9 @@ def add_api_route(self, *args: Any, **kwargs: Any) -> None: class FastAPIRouter(APIRouter): - def __init__(self, include_in_app: bool = True, **kwargs: Any) -> None: + def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) - if include_in_app: - routers.append(self) + routers.append(self) async def __call__(self, scope, receive, send): assert scope['type'] == 'http' @@ -83,7 +82,7 @@ def import_all_pages(app_module: str) -> None: raise RuntimeError('failed on import page %s %s', full_name, ex) -router = FastAPIRouter(include_in_app=False) +router = FastAPIRouter() regex_router = FrontikRegexRouter() not_found_router = APIRouter() method_not_allowed_router = APIRouter() diff --git a/frontik/service_discovery.py b/frontik/service_discovery.py index 9faaf8307..0f9d3e653 100644 --- a/frontik/service_discovery.py +++ b/frontik/service_discovery.py @@ -65,8 +65,7 @@ def _get_weight_or_default(value: Optional[dict]) -> int: def _get_hostname_or_raise(node_name: str) -> str: if not node_name: - msg = 'options node_name must be defined' - raise RuntimeError(msg) + raise RuntimeError('options node_name must be defined') return node_name diff --git a/tests/test_no_debug_mode.py b/tests/test_no_debug_mode.py index 88a2429f0..2ace3aa66 100644 --- a/tests/test_no_debug_mode.py +++ b/tests/test_no_debug_mode.py @@ -24,11 +24,9 @@ def check_debug_auth_or_finish(login: str, password: str) -> None: return _login: Optional[str] = login or options.debug_login _password: Optional[str] = password or options.debug_password - fail_header = check_debug_auth_by_headers(request.headers, _login, _password) - if fail_header: - raise HTTPException( - status_code=http.client.UNAUTHORIZED, detail='Unauthorized', headers={'WWW-Authenticate': fail_header} - ) + fail_headers = check_debug_auth_by_headers(request.headers, _login, _password) + if fail_headers: + raise HTTPException(status_code=http.client.UNAUTHORIZED, detail='Unauthorized', headers=fail_headers) check_debug_auth_or_finish('user', 'god') return {'authenticated': True}