Repository: litestar-org/litestar

Issue:
`get_exception_handler()` util resolve ordering.
https://github.com/starlite-api/starlite/blob/da79c068c906740a4375d431953f1c74fdea8067/starlite/utils/exception.py#L10-L28

I've registered an exception handler to `500_INTERNAL_SERVER_ERROR` that logs the exception but it is also catching and logging `HTTPException` instances. Even if I register an exception handler to `HTTPException` to try to avoid that, because I also have a handler registered for `500` that conditional is always hit and the handler returned before it has the chance to do the walk MRO thing.

So I think the mro walk should be above the `500` fallback, and then I think we should think of whether we'd actually want the `HTTPException` subclasses to be pulled in with the `500` handler if there isn't a narrower mapping.

This is the registration mapping:

```python
    exception_handlers={
        HTTP_500_INTERNAL_SERVER_ERROR: logging_exception_handler,
        HTTPException: passthrough_exception_handler,  # type:ignore[dict-item]
    },
```

But `HTTPException` sub-classes are getting sucked up by this:

```python
     if HTTP_500_INTERNAL_SERVER_ERROR in exception_handlers: 
         return exception_handlers[HTTP_500_INTERNAL_SERVER_ERROR] 
```

... before the mro check can find the base class mapping.


Discussion:
By the way, to work around it is easy enough, just to register the logging handler to `Exception` instead of the `500`, so not massively urgent to fix.

```python
    exception_handlers={
        Exception: logging_exception_handler,
        InternalServerException: logging_exception_handler,
        HTTPException: passthrough_exception_handler,
    },
```
Aight, let's update the ordering

Resolving patch:
diff --git a/starlite/utils/exception.py b/starlite/utils/exception.py
--- a/starlite/utils/exception.py
+++ b/starlite/utils/exception.py
@@ -1,5 +1,5 @@
 from inspect import getmro
-from typing import Dict, Optional, Type, Union, cast
+from typing import Dict, Optional, Type, Union
 
 from starlette.exceptions import HTTPException
 from starlette.status import HTTP_500_INTERNAL_SERVER_ERROR
@@ -13,16 +13,33 @@ def get_exception_handler(
     """
     Given a dictionary that maps exceptions and status codes to handler functions,
     and an exception, returns the appropriate handler if existing.
+
+    Status codes are given preference over exception type.
+
+    If no status code match exists, each class in the MRO of the exception type is checked and
+    the first matching handler is returned.
+
+    Finally, if a `500` handler is registered, it will be returned for any exception that isn't a
+    subclass of `HTTPException`.
+
+    Parameters
+    ----------
+    exception_handlers : dict[int | type[Exception], ExceptionHandler]
+        Mapping of status codes and exception types to handlers.
+    exc : Exception
+        Instance to be resolved to a handler.
+
+    Returns
+    -------
+    Exception | None
     """
     if not exception_handlers:
         return None
     if isinstance(exc, HTTPException) and exc.status_code in exception_handlers:
         return exception_handlers[exc.status_code]
-    if type(exc) in exception_handlers:
-        return exception_handlers[type(exc)]
-    if HTTP_500_INTERNAL_SERVER_ERROR in exception_handlers:
-        return exception_handlers[HTTP_500_INTERNAL_SERVER_ERROR]
     for cls in getmro(type(exc)):
         if cls in exception_handlers:
-            return exception_handlers[cast(Type[Exception], cls)]
+            return exception_handlers[cls]
+    if not isinstance(exc, HTTPException) and HTTP_500_INTERNAL_SERVER_ERROR in exception_handlers:
+        return exception_handlers[HTTP_500_INTERNAL_SERVER_ERROR]
     return None


Test patch:
diff --git a/tests/utils/test_exceptions.py b/tests/utils/test_exceptions.py
--- a/tests/utils/test_exceptions.py
+++ b/tests/utils/test_exceptions.py
@@ -3,7 +3,7 @@
 import pytest
 from starlette.status import HTTP_400_BAD_REQUEST, HTTP_500_INTERNAL_SERVER_ERROR
 
-from starlite import InternalServerException, ValidationException
+from starlite import HTTPException, InternalServerException, ValidationException
 from starlite.types import ExceptionHandler
 from starlite.utils.exception import get_exception_handler
 
@@ -12,6 +12,10 @@ def handler(_: Any, __: Any) -> Any:
     return None
 
 
+def handler_2(_: Any, __: Any) -> Any:
+    return None
+
+
 @pytest.mark.parametrize(
     ["mapping", "exc", "expected"],
     [
@@ -23,6 +27,11 @@ def handler(_: Any, __: Any) -> Any:
         ({Exception: handler}, ValidationException(), handler),
         ({ValueError: handler}, ValidationException(), handler),
         ({ValidationException: handler}, Exception(), None),
+        ({HTTP_500_INTERNAL_SERVER_ERROR: handler}, ValidationException(), None),
+        ({HTTP_500_INTERNAL_SERVER_ERROR: handler, HTTPException: handler_2}, ValidationException(), handler_2),
+        ({HTTPException: handler, ValidationException: handler_2}, ValidationException(), handler_2),
+        ({HTTPException: handler, ValidationException: handler_2}, InternalServerException(), handler),
+        ({HTTP_500_INTERNAL_SERVER_ERROR: handler, HTTPException: handler_2}, InternalServerException(), handler),
     ],
 )
 def test_get_exception_handler(