Skip to content

Commit

Permalink
HH-221505 small fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
712u3 committed Jul 18, 2024
1 parent cd9bfd3 commit a9c1234
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 52 deletions.
28 changes: 17 additions & 11 deletions frontik/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from frontik.json_builder import FrontikJsonDecodeError, json_decode
from frontik.loggers import CUSTOM_JSON_EXTRA, JSON_REQUESTS_LOGGER
from frontik.loggers.stages import StagesLogger
from frontik.options import options
from frontik.timeout_tracking import get_timeout_checker
from frontik.util import gather_dict, make_url
from frontik.validator import BaseValidationModel, Validators
Expand All @@ -53,6 +54,10 @@ def __init__(self, wait_finish_group: bool = False) -> None:
self.wait_finish_group = wait_finish_group


class RedirectSignal(Exception):
pass


class HTTPErrorWithPostprocessors(tornado.web.HTTPError):
pass

Expand Down Expand Up @@ -109,6 +114,9 @@ def __init__(
self.route = route
self.debug_mode = debug_mode
self.path_params = path_params
for _name, _value in path_params.items():
if _value:
request.arguments.setdefault(_name, []).append(_value)

super().__init__(application, request) # type: ignore

Expand Down Expand Up @@ -314,7 +322,8 @@ def redirect(self, url: str, *args: Any, allow_protocol_relative: bool = False,
# This is only reachable under certain configurations.
raise tornado.web.HTTPError(403, 'cannot redirect path with two initial slashes')
self.log.info('redirecting to: %s', url)
return super().redirect(url, *args, **kwargs)
super().redirect(url, *args, **kwargs)
raise RedirectSignal()

@property
def json_body(self):
Expand Down Expand Up @@ -346,8 +355,14 @@ def add_future(cls, future: Future, callback: Callable) -> None:

# Requests handling

async def my_execute(self) -> tuple[int, str, HTTPHeaders, bytes]:
async def execute(self) -> tuple[int, str, HTTPHeaders, bytes]:
try:
if self.request.method not in (
"GET",
"HEAD",
"OPTIONS",
) and options.xsrf_cookies:
self.check_xsrf_cookie()
await super()._execute([], b'', b'')
except Exception as ex:
self._handle_request_exception(ex)
Expand All @@ -368,9 +383,6 @@ async def delete(self, *args, **kwargs):
async def head(self, *args, **kwargs):
await self._execute_page()

def options(self, *args, **kwargs):
self.return_405()

async def _execute_page(self) -> None:
self.stages_logger.commit_stage('prepare')

Expand Down Expand Up @@ -398,12 +410,6 @@ async def _execute_page(self) -> None:
if render_result is not None:
self.write(render_result)

def return_405(self) -> None:
allowed_methods = [name for name in ('get', 'post', 'put', 'delete') if f'{name}_page' in vars(self.__class__)]
self.set_header('Allow', ', '.join(allowed_methods))
self.set_status(405)
self.finish()

def get_page_fail_fast(self, request_result: RequestResult) -> None:
self.__return_error(request_result.status_code, error_info={'is_fail_fast': True})

Expand Down
21 changes: 12 additions & 9 deletions frontik/handler_asgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ async def execute_page(
assert debug_mode.failed_auth_header is not None
status, reason, headers, data = make_debug_auth_failed_response(debug_mode.failed_auth_header)
elif route is None:
status, reason, headers, data = make_not_found_response(frontik_app, tornado_request.path)
status, reason, headers, data = await make_not_found_response(frontik_app, tornado_request)
else:
request_context.set_handler_name(f'{route.endpoint.__module__}.{route.endpoint.__name__}')

Expand Down Expand Up @@ -78,19 +78,23 @@ async def execute_page(
return status, reason, headers, data


def make_not_found_response(frontik_app: FrontikApplication, path: str) -> tuple[int, str, HTTPHeaders, bytes]:
allowed_methods = get_allowed_methods(path)
async def make_not_found_response(
frontik_app: FrontikApplication, tornado_request: httputil.HTTPServerRequest
) -> tuple[int, str, HTTPHeaders, bytes]:
allowed_methods = get_allowed_methods(tornado_request.path)
default_headers = get_default_headers()

if allowed_methods:
status = 405
headers = get_default_headers()
headers['Allow'] = ', '.join(allowed_methods)
headers = {'Allow': ', '.join(allowed_methods)}
data = b''
elif hasattr(frontik_app, 'application_404_handler'):
status, headers, data = frontik_app.application_404_handler()
status, headers, data = await frontik_app.application_404_handler(tornado_request)
else:
status, headers, data = build_error_data(404, 'Not Found')

default_headers.update(headers)

reason = httputil.responses.get(status, 'Unknown')
return status, reason, HTTPHeaders(headers), data

Expand All @@ -114,8 +118,7 @@ def make_not_accepted_response() -> tuple[int, str, HTTPHeaders, bytes]:
def build_error_data(
status_code: int = 500, message: Optional[str] = 'Internal Server Error'
) -> tuple[int, dict, bytes]:
headers = get_default_headers()
headers['Content-Type'] = media_types.TEXT_HTML
headers = {'Content-Type': media_types.TEXT_HTML}
data = f'<html><title>{status_code}: {message}</title><body>{status_code}: {message}</body></html>'.encode()
return status_code, headers, data

Expand All @@ -129,7 +132,7 @@ async def legacy_process_request(
debug_mode: DebugMode,
) -> tuple[int, str, HTTPHeaders, bytes]:
handler: PageHandler = page_cls(frontik_app, tornado_request, route, debug_mode, path_params)
return await handler.my_execute()
return await handler.execute()


def convert_tornado_request_to_asgi(
Expand Down
2 changes: 1 addition & 1 deletion frontik/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@
@dataclass
class Options:
app: Optional[str] = None
app_class: Optional[str] = None
workers: int = 1
init_workers_timeout_sec: int = 60
tornado_settings: Optional[dict] = None
max_active_handlers: int = 100
reuse_port: bool = True
xheaders: bool = False
validate_request_id: bool = False
xsrf_cookies: bool = False

config: Optional[str] = None
host: str = '0.0.0.0'
Expand Down
57 changes: 28 additions & 29 deletions frontik/routing.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,77 +22,77 @@


class FrontikRouter(APIRouter):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
def __init__(self, *, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> None:
super().__init__(**kwargs)
routers.append(self)
self._cls: Optional[Type[PageHandler]] = None
self._path: Optional[str] = None
self._base_cls: Optional[Type[PageHandler]] = cls

def get(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().get(path, **kwargs)

def post(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().post(path, **kwargs)

def put(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().put(path, **kwargs)

def delete(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().delete(path, **kwargs)

def head(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().head(path, **kwargs)

def add_api_route(self, *args, **kwargs):
super().add_api_route(*args, **kwargs)
route: APIRoute = self.routes[-1] # type: ignore
method = next(iter(route.methods), None)
path = route.path.strip('/')

if _plain_routes.get((self._path, method), None) is not None:
raise RuntimeError(f'route for {method} {self._path} exists')
if _plain_routes.get((path, method), None) is not None:
raise RuntimeError(f'route for {method} {path} already exists')

_plain_routes[(self._path, method)] = (route, self._cls) # we need our routing, for get route object
self._cls, self._path = None, None
_plain_routes[(path, method)] = (route, self._cls) # we need our routing, for get route object


class FrontikRegexRouter(APIRouter):
def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)
def __init__(self, *, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> None:
super().__init__(**kwargs)
routers.append(self)
self._cls: Optional[Type[PageHandler]] = None
self._path: Optional[str] = None
self._base_cls: Optional[Type[PageHandler]] = cls

def get(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().get(path, **kwargs)

def post(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().post(path, **kwargs)

def put(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().put(path, **kwargs)

def delete(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().delete(path, **kwargs)

def head(self, path: str, cls: Optional[Type[PageHandler]] = None, **kwargs: Any) -> Callable:
self._path, self._cls = path, cls
self._cls = self._base_cls or cls
return super().head(path, **kwargs)

def add_api_route(self, *args, **kwargs):
def add_api_route(self, *args, cls: Optional[Type[PageHandler]] = None, **kwargs):
super().add_api_route(*args, **kwargs)
self._cls = self._base_cls or cls
route = self.routes[-1]

_regex_mapping.append((re.compile(self._path), self.routes[-1], self._cls)) # type: ignore

self._cls, self._path = None, None
_regex_mapping.append((re.compile(route.path), route, self._cls)) # type: ignore


def _iter_submodules(path: MutableSequence[str], prefix: str = '') -> Generator:
Expand Down Expand Up @@ -125,8 +125,7 @@ def import_all_pages(app_module: Optional[str]) -> None:
except ModuleNotFoundError:
continue
except Exception as ex:
routing_logger.error('failed on import page %s %s', full_name, ex)
continue
raise RuntimeError('failed on import page %s %s', full_name, ex)


router = FrontikRouter()
Expand All @@ -147,11 +146,11 @@ def _find_regex_route(

def find_route(path: str, method: str) -> tuple[APIRoute, type, dict]:
route: APIRoute
route, page_cls = _plain_routes.get((path, method), (None, None))
path_params: dict = {}
route, page_cls, path_params = _find_regex_route(path, method)

if route is None:
route, page_cls, path_params = _find_regex_route(path, method)
route, page_cls = _plain_routes.get((path.strip('/'), method), (None, None))
path_params: dict = {}

if route is None:
routing_logger.error('match for request url %s "%s" not found', method, path)
Expand Down
8 changes: 6 additions & 2 deletions frontik/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from threading import Lock
from typing import Any, Callable, Optional, Union

import anyio
import tornado.autoreload
from http_client.balancing import Upstream
from tornado.httpserver import HTTPServer
Expand Down Expand Up @@ -48,7 +49,7 @@ def main(config_file: Optional[str] = None) -> None:
sys.exit(1)

if app_class_name is not None and not hasattr(app_module, app_class_name):
log.exception('application class "%s" not found', options.app_class)
log.exception('application class "%s" not found', app_class_name)
sys.exit(1)

application = getattr(app_module, app_class_name) if app_class_name is not None else FrontikApplication
Expand Down Expand Up @@ -207,4 +208,7 @@ async def message_poller(_sentinel: Any, _handler_task: Any) -> Any:


def anyio_noop(*_args, **_kwargs):
raise RuntimeError(f'trying to use {_args[0]}')
raise RuntimeError(f'trying to use non async {_args[0]}')


anyio.to_thread.run_sync = anyio_noop

0 comments on commit a9c1234

Please sign in to comment.