diff --git a/areion/core/exceptions.py b/areion/core/exceptions.py new file mode 100644 index 0000000..ead92df --- /dev/null +++ b/areion/core/exceptions.py @@ -0,0 +1,62 @@ +""" +Custom exceptions for Areion. + +These are globally handled in the core server. +""" + + +class HttpError(Exception): + """Base class for HTTP errors.""" + + status_code: int = 500 + message: str = "Internal Server Error" + + def __init__(self, message: str = None): + if message: + self.message = message + super().__init__(self.message) + + def __str__(self): + return str(self.status_code) + " " + self.message + + +class BadRequestError(HttpError): + """400 Bad Request.""" + + status_code = 400 + message = "Bad Request" + + +class UnauthorizedError(HttpError): + """401 Unauthorized.""" + + status_code = 401 + message = "Unauthorized" + + +class ForbiddenError(HttpError): + """403 Forbidden.""" + + status_code = 403 + message = "Forbidden" + + +class NotFoundError(HttpError): + """404 Not Found.""" + + status_code = 404 + message = "Not Found" + + +class MethodNotAllowedError(HttpError): + """405 Method Not Allowed.""" + + status_code = 405 + message = "Method Not Allowed" + + +class InternalServerError(HttpError): + """500 Internal Server Error.""" + + status_code = 500 + message = "Internal Server Error" diff --git a/areion/core/server.py b/areion/core/server.py index 97ae220..844d1c2 100644 --- a/areion/core/server.py +++ b/areion/core/server.py @@ -1,4 +1,6 @@ import asyncio + +from .exceptions import HttpError, NotFoundError from .response import HttpResponse from .request import HttpRequest @@ -72,23 +74,22 @@ async def _handle_request_logic(self, reader, writer): headers = await self._parse_headers(reader) request = self.request_factory.create(method, path, headers) + handler, path_params = self.router.get_handler(method, path) + try: - handler, path_params = self.router.get_handler(method, path) - - # Change this to raise 404 exception after thats built if not handler: - response = HttpResponse(status_code=404, body="Not Found") - - if not path_params: - path_params = {} - + raise NotFoundError() + # TODO: Move this to router get handler dict so dont have to do this at runtime - # TODO: Simplify - if handler and asyncio.iscoroutinefunction(handler): + if asyncio.iscoroutinefunction(handler): response = await handler(request, **path_params) - elif handler: + else: response = handler(request, **path_params) - except Exception: + except HttpError as e: + # Handles web exceptions raised by the handler + response = HttpResponse(status_code=e.status_code, body=e) + except Exception as e: + # Handles all other exceptions response = HttpResponse(status_code=500, body="Internal Server Error") await self._send_response(writer, response) @@ -104,11 +105,10 @@ async def _parse_headers(self, reader): return headers async def _send_response(self, writer, response): - # TODO: Move Response assertion here # TODO: Add optional response logging if not isinstance(response, HttpResponse): response = HttpResponse(body=response) - + buffer = response.format_response() chunk_size = self.buffer_size