Standardize init of exceptions (#2545)
This commit is contained in:
parent
89188f5fc6
commit
71cd53b64e
|
@ -2,6 +2,22 @@ from sanic.__version__ import __version__
|
||||||
from sanic.app import Sanic
|
from sanic.app import Sanic
|
||||||
from sanic.blueprints import Blueprint
|
from sanic.blueprints import Blueprint
|
||||||
from sanic.constants import HTTPMethod
|
from sanic.constants import HTTPMethod
|
||||||
|
from sanic.exceptions import (
|
||||||
|
BadRequest,
|
||||||
|
ExpectationFailed,
|
||||||
|
FileNotFound,
|
||||||
|
Forbidden,
|
||||||
|
HeaderNotFound,
|
||||||
|
InternalServerError,
|
||||||
|
InvalidHeader,
|
||||||
|
MethodNotAllowed,
|
||||||
|
NotFound,
|
||||||
|
RangeNotSatisfiable,
|
||||||
|
SanicException,
|
||||||
|
ServerError,
|
||||||
|
ServiceUnavailable,
|
||||||
|
Unauthorized,
|
||||||
|
)
|
||||||
from sanic.request import Request
|
from sanic.request import Request
|
||||||
from sanic.response import (
|
from sanic.response import (
|
||||||
HTTPResponse,
|
HTTPResponse,
|
||||||
|
@ -9,6 +25,7 @@ from sanic.response import (
|
||||||
file,
|
file,
|
||||||
html,
|
html,
|
||||||
json,
|
json,
|
||||||
|
raw,
|
||||||
redirect,
|
redirect,
|
||||||
text,
|
text,
|
||||||
)
|
)
|
||||||
|
@ -17,16 +34,34 @@ from sanic.server.websockets.impl import WebsocketImplProtocol as Websocket
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
"__version__",
|
"__version__",
|
||||||
|
# Common objects
|
||||||
"Sanic",
|
"Sanic",
|
||||||
"Blueprint",
|
"Blueprint",
|
||||||
"HTTPMethod",
|
"HTTPMethod",
|
||||||
"HTTPResponse",
|
"HTTPResponse",
|
||||||
"Request",
|
"Request",
|
||||||
"Websocket",
|
"Websocket",
|
||||||
|
# Common exceptions
|
||||||
|
"BadRequest",
|
||||||
|
"ExpectationFailed",
|
||||||
|
"FileNotFound",
|
||||||
|
"Forbidden",
|
||||||
|
"HeaderNotFound",
|
||||||
|
"InternalServerError",
|
||||||
|
"InvalidHeader",
|
||||||
|
"MethodNotAllowed",
|
||||||
|
"NotFound",
|
||||||
|
"RangeNotSatisfiable",
|
||||||
|
"SanicException",
|
||||||
|
"ServerError",
|
||||||
|
"ServiceUnavailable",
|
||||||
|
"Unauthorized",
|
||||||
|
# Common response methods
|
||||||
"empty",
|
"empty",
|
||||||
"file",
|
"file",
|
||||||
"html",
|
"html",
|
||||||
"json",
|
"json",
|
||||||
|
"raw",
|
||||||
"redirect",
|
"redirect",
|
||||||
"text",
|
"text",
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from asyncio import CancelledError
|
from asyncio import CancelledError, Protocol
|
||||||
from typing import Any, Dict, Optional, Union
|
from os import PathLike
|
||||||
|
from typing import Any, Dict, Optional, Sequence, Union
|
||||||
|
|
||||||
from sanic.helpers import STATUS_CODES
|
from sanic.helpers import STATUS_CODES
|
||||||
|
|
||||||
|
@ -9,51 +10,158 @@ class RequestCancelled(CancelledError):
|
||||||
|
|
||||||
|
|
||||||
class ServerKilled(Exception):
|
class ServerKilled(Exception):
|
||||||
...
|
"""
|
||||||
|
Exception Sanic server uses when killing a server process for something
|
||||||
|
unexpected happening.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class SanicException(Exception):
|
class SanicException(Exception):
|
||||||
|
"""
|
||||||
|
Generic exception that will generate an HTTP response when raised
|
||||||
|
in the context of a request lifecycle.
|
||||||
|
|
||||||
|
Usually it is best practice to use one of the more specific exceptions
|
||||||
|
than this generic. Even when trying to raise a 500, it is generally
|
||||||
|
preferrable to use :class:`.ServerError`
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
raise SanicException(
|
||||||
|
"Something went wrong",
|
||||||
|
status_code=999,
|
||||||
|
context={
|
||||||
|
"info": "Some additional details",
|
||||||
|
},
|
||||||
|
headers={
|
||||||
|
"X-Foo": "bar"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the appropriate HTTP response status message will be used
|
||||||
|
instead, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param status_code: The HTTP response code to send, if applicable. If
|
||||||
|
``None``, then it will be 500, defaults to None
|
||||||
|
:type status_code: Optional[int], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
|
"""
|
||||||
|
|
||||||
|
status_code: int = 500
|
||||||
|
quiet: Optional[bool] = False
|
||||||
|
headers: Dict[str, str] = {}
|
||||||
message: str = ""
|
message: str = ""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
message: Optional[Union[str, bytes]] = None,
|
message: Optional[Union[str, bytes]] = None,
|
||||||
status_code: Optional[int] = None,
|
status_code: Optional[int] = None,
|
||||||
|
*,
|
||||||
quiet: Optional[bool] = None,
|
quiet: Optional[bool] = None,
|
||||||
context: Optional[Dict[str, Any]] = None,
|
context: Optional[Dict[str, Any]] = None,
|
||||||
extra: Optional[Dict[str, Any]] = None,
|
extra: Optional[Dict[str, Any]] = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.context = context
|
self.context = context
|
||||||
self.extra = extra
|
self.extra = extra
|
||||||
|
status_code = status_code or getattr(
|
||||||
|
self.__class__, "status_code", None
|
||||||
|
)
|
||||||
|
quiet = quiet or getattr(self.__class__, "quiet", None)
|
||||||
|
headers = headers or getattr(self.__class__, "headers", {})
|
||||||
if message is None:
|
if message is None:
|
||||||
if self.message:
|
if self.message:
|
||||||
message = self.message
|
message = self.message
|
||||||
elif status_code is not None:
|
elif status_code:
|
||||||
msg: bytes = STATUS_CODES.get(status_code, b"")
|
msg: bytes = STATUS_CODES.get(status_code, b"")
|
||||||
message = msg.decode("utf8")
|
message = msg.decode("utf8")
|
||||||
|
|
||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
|
|
||||||
if status_code is not None:
|
self.status_code = status_code
|
||||||
self.status_code = status_code
|
self.quiet = quiet
|
||||||
|
self.headers = headers
|
||||||
# quiet=None/False/True with None meaning choose by status
|
|
||||||
if quiet or quiet is None and status_code not in (None, 500):
|
|
||||||
self.quiet = True
|
|
||||||
|
|
||||||
|
|
||||||
class NotFound(SanicException):
|
class HTTPException(SanicException):
|
||||||
|
"""
|
||||||
|
A base class for other exceptions and should not be called directly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
message: Optional[Union[str, bytes]] = None,
|
||||||
|
*,
|
||||||
|
quiet: Optional[bool] = None,
|
||||||
|
context: Optional[Dict[str, Any]] = None,
|
||||||
|
extra: Optional[Dict[str, Any]] = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(
|
||||||
|
message,
|
||||||
|
quiet=quiet,
|
||||||
|
context=context,
|
||||||
|
extra=extra,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class NotFound(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 404 Not Found
|
**Status**: 404 Not Found
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Not Found' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 404
|
status_code = 404
|
||||||
quiet = True
|
quiet = True
|
||||||
|
|
||||||
|
|
||||||
class BadRequest(SanicException):
|
class BadRequest(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 400 Bad Request
|
**Status**: 400 Bad Request
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Bad Request' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 400
|
status_code = 400
|
||||||
|
@ -61,51 +169,133 @@ class BadRequest(SanicException):
|
||||||
|
|
||||||
|
|
||||||
InvalidUsage = BadRequest
|
InvalidUsage = BadRequest
|
||||||
|
BadURL = BadRequest
|
||||||
|
|
||||||
|
|
||||||
class BadURL(BadRequest):
|
class MethodNotAllowed(HTTPException):
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
class MethodNotAllowed(SanicException):
|
|
||||||
"""
|
"""
|
||||||
**Status**: 405 Method Not Allowed
|
**Status**: 405 Method Not Allowed
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Method Not Allowed' will be sent,
|
||||||
|
defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param method: The HTTP method that was used, defaults to an empty string
|
||||||
|
:type method: Optional[str], optional
|
||||||
|
:param allowed_methods: The HTTP methods that can be used instead of the
|
||||||
|
one that was attempted
|
||||||
|
:type allowed_methods: Optional[Sequence[str]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 405
|
status_code = 405
|
||||||
quiet = True
|
quiet = True
|
||||||
|
|
||||||
def __init__(self, message, method, allowed_methods):
|
def __init__(
|
||||||
super().__init__(message)
|
self,
|
||||||
self.headers = {"Allow": ", ".join(allowed_methods)}
|
message: Optional[Union[str, bytes]] = None,
|
||||||
|
method: str = "",
|
||||||
|
allowed_methods: Optional[Sequence[str]] = None,
|
||||||
|
*,
|
||||||
|
quiet: Optional[bool] = None,
|
||||||
|
context: Optional[Dict[str, Any]] = None,
|
||||||
|
extra: Optional[Dict[str, Any]] = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
message,
|
||||||
|
quiet=quiet,
|
||||||
|
context=context,
|
||||||
|
extra=extra,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
if allowed_methods:
|
||||||
|
self.headers = {
|
||||||
|
**self.headers,
|
||||||
|
"Allow": ", ".join(allowed_methods),
|
||||||
|
}
|
||||||
|
self.method = method
|
||||||
|
self.allowed_methods = allowed_methods
|
||||||
|
|
||||||
|
|
||||||
MethodNotSupported = MethodNotAllowed
|
MethodNotSupported = MethodNotAllowed
|
||||||
|
|
||||||
|
|
||||||
class ServerError(SanicException):
|
class ServerError(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 500 Internal Server Error
|
**Status**: 500 Internal Server Error
|
||||||
|
|
||||||
|
A general server-side error has occurred. If no other HTTP exception is
|
||||||
|
appropriate, then this should be used
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Internal Server Error' will be sent,
|
||||||
|
defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 500
|
status_code = 500
|
||||||
|
|
||||||
|
|
||||||
class ServiceUnavailable(SanicException):
|
InternalServerError = ServerError
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceUnavailable(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 503 Service Unavailable
|
**Status**: 503 Service Unavailable
|
||||||
|
|
||||||
The server is currently unavailable (because it is overloaded or
|
The server is currently unavailable (because it is overloaded or
|
||||||
down for maintenance). Generally, this is a temporary state.
|
down for maintenance). Generally, this is a temporary state.
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Bad Request' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 503
|
status_code = 503
|
||||||
quiet = True
|
quiet = True
|
||||||
|
|
||||||
|
|
||||||
class URLBuildError(ServerError):
|
class URLBuildError(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 500 Internal Server Error
|
**Status**: 500 Internal Server Error
|
||||||
|
|
||||||
|
An exception used by Sanic internals when unable to build a URL.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 500
|
status_code = 500
|
||||||
|
@ -114,30 +304,77 @@ class URLBuildError(ServerError):
|
||||||
class FileNotFound(NotFound):
|
class FileNotFound(NotFound):
|
||||||
"""
|
"""
|
||||||
**Status**: 404 Not Found
|
**Status**: 404 Not Found
|
||||||
|
|
||||||
|
A specific form of :class:`.NotFound` that is specifically when looking
|
||||||
|
for a file on the file system at a known path.
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Not Found' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param path: The path, if any, to the file that could not
|
||||||
|
be found, defaults to None
|
||||||
|
:type path: Optional[PathLike], optional
|
||||||
|
:param relative_url: A relative URL of the file, defaults to None
|
||||||
|
:type relative_url: Optional[str], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, message, path, relative_url):
|
def __init__(
|
||||||
super().__init__(message)
|
self,
|
||||||
|
message: Optional[Union[str, bytes]] = None,
|
||||||
|
path: Optional[PathLike] = None,
|
||||||
|
relative_url: Optional[str] = None,
|
||||||
|
*,
|
||||||
|
quiet: Optional[bool] = None,
|
||||||
|
context: Optional[Dict[str, Any]] = None,
|
||||||
|
extra: Optional[Dict[str, Any]] = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
message,
|
||||||
|
quiet=quiet,
|
||||||
|
context=context,
|
||||||
|
extra=extra,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
self.path = path
|
self.path = path
|
||||||
self.relative_url = relative_url
|
self.relative_url = relative_url
|
||||||
|
|
||||||
|
|
||||||
class RequestTimeout(SanicException):
|
class RequestTimeout(HTTPException):
|
||||||
"""The Web server (running the Web site) thinks that there has been too
|
"""
|
||||||
|
The Web server (running the Web site) thinks that there has been too
|
||||||
long an interval of time between 1) the establishment of an IP
|
long an interval of time between 1) the establishment of an IP
|
||||||
connection (socket) between the client and the server and
|
connection (socket) between the client and the server and
|
||||||
2) the receipt of any data on that socket, so the server has dropped
|
2) the receipt of any data on that socket, so the server has dropped
|
||||||
the connection. The socket connection has actually been lost - the Web
|
the connection. The socket connection has actually been lost - the Web
|
||||||
server has 'timed out' on that particular socket connection.
|
server has 'timed out' on that particular socket connection.
|
||||||
|
|
||||||
|
This is an internal exception thrown by Sanic and should not be used
|
||||||
|
directly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 408
|
status_code = 408
|
||||||
quiet = True
|
quiet = True
|
||||||
|
|
||||||
|
|
||||||
class PayloadTooLarge(SanicException):
|
class PayloadTooLarge(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 413 Payload Too Large
|
**Status**: 413 Payload Too Large
|
||||||
|
|
||||||
|
This is an internal exception thrown by Sanic and should not be used
|
||||||
|
directly.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 413
|
status_code = 413
|
||||||
|
@ -147,34 +384,126 @@ class PayloadTooLarge(SanicException):
|
||||||
class HeaderNotFound(BadRequest):
|
class HeaderNotFound(BadRequest):
|
||||||
"""
|
"""
|
||||||
**Status**: 400 Bad Request
|
**Status**: 400 Bad Request
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Bad Request' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class InvalidHeader(BadRequest):
|
class InvalidHeader(BadRequest):
|
||||||
"""
|
"""
|
||||||
**Status**: 400 Bad Request
|
**Status**: 400 Bad Request
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Bad Request' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class RangeNotSatisfiable(SanicException):
|
class ContentRange(Protocol):
|
||||||
|
total: int
|
||||||
|
|
||||||
|
|
||||||
|
class RangeNotSatisfiable(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 416 Range Not Satisfiable
|
**Status**: 416 Range Not Satisfiable
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Range Not Satisfiable' will be sent,
|
||||||
|
defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param content_range: An object meeting the :class:`.ContentRange` protocol
|
||||||
|
that has a ``total`` property, defaults to None
|
||||||
|
:type content_range: Optional[ContentRange], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 416
|
status_code = 416
|
||||||
quiet = True
|
quiet = True
|
||||||
|
|
||||||
def __init__(self, message, content_range):
|
def __init__(
|
||||||
super().__init__(message)
|
self,
|
||||||
self.headers = {"Content-Range": f"bytes */{content_range.total}"}
|
message: Optional[Union[str, bytes]] = None,
|
||||||
|
content_range: Optional[ContentRange] = None,
|
||||||
|
*,
|
||||||
|
quiet: Optional[bool] = None,
|
||||||
|
context: Optional[Dict[str, Any]] = None,
|
||||||
|
extra: Optional[Dict[str, Any]] = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
message,
|
||||||
|
quiet=quiet,
|
||||||
|
context=context,
|
||||||
|
extra=extra,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
if content_range is not None:
|
||||||
|
self.headers = {
|
||||||
|
**self.headers,
|
||||||
|
"Content-Range": f"bytes */{content_range.total}",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ContentRangeError = RangeNotSatisfiable
|
ContentRangeError = RangeNotSatisfiable
|
||||||
|
|
||||||
|
|
||||||
class ExpectationFailed(SanicException):
|
class ExpectationFailed(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 417 Expectation Failed
|
**Status**: 417 Expectation Failed
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Expectation Failed' will be sent,
|
||||||
|
defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 417
|
status_code = 417
|
||||||
|
@ -184,9 +513,25 @@ class ExpectationFailed(SanicException):
|
||||||
HeaderExpectationFailed = ExpectationFailed
|
HeaderExpectationFailed = ExpectationFailed
|
||||||
|
|
||||||
|
|
||||||
class Forbidden(SanicException):
|
class Forbidden(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 403 Forbidden
|
**Status**: 403 Forbidden
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Forbidden' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 403
|
status_code = 403
|
||||||
|
@ -202,20 +547,33 @@ class InvalidRangeType(RangeNotSatisfiable):
|
||||||
quiet = True
|
quiet = True
|
||||||
|
|
||||||
|
|
||||||
class PyFileError(Exception):
|
class PyFileError(SanicException):
|
||||||
def __init__(self, file):
|
def __init__(
|
||||||
super().__init__("could not execute config file %s", file)
|
self,
|
||||||
|
file,
|
||||||
|
status_code: Optional[int] = None,
|
||||||
|
*,
|
||||||
|
quiet: Optional[bool] = None,
|
||||||
|
context: Optional[Dict[str, Any]] = None,
|
||||||
|
extra: Optional[Dict[str, Any]] = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
"could not execute config file %s" % file,
|
||||||
|
status_code=status_code,
|
||||||
|
quiet=quiet,
|
||||||
|
context=context,
|
||||||
|
extra=extra,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Unauthorized(SanicException):
|
class Unauthorized(HTTPException):
|
||||||
"""
|
"""
|
||||||
**Status**: 401 Unauthorized
|
**Status**: 401 Unauthorized
|
||||||
|
|
||||||
:param message: Message describing the exception.
|
When present, additional keyword arguments may be used to complete
|
||||||
:param status_code: HTTP Status code.
|
the WWW-Authentication header.
|
||||||
:param scheme: Name of the authentication scheme to be used.
|
|
||||||
|
|
||||||
When present, kwargs is used to complete the WWW-Authentication header.
|
|
||||||
|
|
||||||
Examples::
|
Examples::
|
||||||
|
|
||||||
|
@ -240,21 +598,58 @@ class Unauthorized(SanicException):
|
||||||
raise Unauthorized("Auth required.",
|
raise Unauthorized("Auth required.",
|
||||||
scheme="Bearer",
|
scheme="Bearer",
|
||||||
realm="Restricted Area")
|
realm="Restricted Area")
|
||||||
|
|
||||||
|
:param message: The message to be sent to the client. If ``None``
|
||||||
|
then the HTTP status 'Bad Request' will be sent, defaults to None
|
||||||
|
:type message: Optional[Union[str, bytes]], optional
|
||||||
|
:param scheme: Name of the authentication scheme to be used.
|
||||||
|
:type scheme: Optional[str], optional
|
||||||
|
:param quiet: When ``True``, the error traceback will be suppressed
|
||||||
|
from the logs, defaults to None
|
||||||
|
:type quiet: Optional[bool], optional
|
||||||
|
:param context: Additional mapping of key/value data that will be
|
||||||
|
sent to the client upon exception, defaults to None
|
||||||
|
:type context: Optional[Dict[str, Any]], optional
|
||||||
|
:param extra: Additional mapping of key/value data that will NOT be
|
||||||
|
sent to the client when in PRODUCTION mode, defaults to None
|
||||||
|
:type extra: Optional[Dict[str, Any]], optional
|
||||||
|
:param headers: Additional headers that should be sent with the HTTP
|
||||||
|
response, defaults to None
|
||||||
|
:type headers: Optional[Dict[str, Any]], optional
|
||||||
"""
|
"""
|
||||||
|
|
||||||
status_code = 401
|
status_code = 401
|
||||||
quiet = True
|
quiet = True
|
||||||
|
|
||||||
def __init__(self, message, status_code=None, scheme=None, **kwargs):
|
def __init__(
|
||||||
super().__init__(message, status_code)
|
self,
|
||||||
|
message: Optional[Union[str, bytes]] = None,
|
||||||
|
scheme: Optional[str] = None,
|
||||||
|
*,
|
||||||
|
quiet: Optional[bool] = None,
|
||||||
|
context: Optional[Dict[str, Any]] = None,
|
||||||
|
extra: Optional[Dict[str, Any]] = None,
|
||||||
|
headers: Optional[Dict[str, Any]] = None,
|
||||||
|
**challenges,
|
||||||
|
):
|
||||||
|
super().__init__(
|
||||||
|
message,
|
||||||
|
quiet=quiet,
|
||||||
|
context=context,
|
||||||
|
extra=extra,
|
||||||
|
headers=headers,
|
||||||
|
)
|
||||||
|
|
||||||
# if auth-scheme is specified, set "WWW-Authenticate" header
|
# if auth-scheme is specified, set "WWW-Authenticate" header
|
||||||
if scheme is not None:
|
if scheme is not None:
|
||||||
values = ['{!s}="{!s}"'.format(k, v) for k, v in kwargs.items()]
|
values = [
|
||||||
|
'{!s}="{!s}"'.format(k, v) for k, v in challenges.items()
|
||||||
|
]
|
||||||
challenge = ", ".join(values)
|
challenge = ", ".join(values)
|
||||||
|
|
||||||
self.headers = {
|
self.headers = {
|
||||||
"WWW-Authenticate": f"{scheme} {challenge}".rstrip()
|
**self.headers,
|
||||||
|
"WWW-Authenticate": f"{scheme} {challenge}".rstrip(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -75,4 +75,4 @@ class ContentRangeHandler:
|
||||||
}
|
}
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
return self.size > 0
|
return hasattr(self, "size") and self.size > 0
|
||||||
|
|
|
@ -10,7 +10,7 @@ except ImportError: # websockets >= 11.0
|
||||||
|
|
||||||
from websockets.typing import Subprotocol
|
from websockets.typing import Subprotocol
|
||||||
|
|
||||||
from sanic.exceptions import ServerError
|
from sanic.exceptions import SanicException
|
||||||
from sanic.log import logger
|
from sanic.log import logger
|
||||||
from sanic.server import HttpProtocol
|
from sanic.server import HttpProtocol
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ class WebSocketProtocol(HttpProtocol):
|
||||||
"Failed to open a WebSocket connection.\n"
|
"Failed to open a WebSocket connection.\n"
|
||||||
"See server log for more information.\n"
|
"See server log for more information.\n"
|
||||||
)
|
)
|
||||||
raise ServerError(msg, status_code=500)
|
raise SanicException(msg, status_code=500)
|
||||||
if 100 <= resp.status_code <= 299:
|
if 100 <= resp.status_code <= 299:
|
||||||
first_line = (
|
first_line = (
|
||||||
f"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\r\n"
|
f"HTTP/1.1 {resp.status_code} {resp.reason_phrase}\r\n"
|
||||||
|
@ -138,7 +138,7 @@ class WebSocketProtocol(HttpProtocol):
|
||||||
rbody += b"\r\n\r\n"
|
rbody += b"\r\n\r\n"
|
||||||
await super().send(rbody)
|
await super().send(rbody)
|
||||||
else:
|
else:
|
||||||
raise ServerError(resp.body, resp.status_code)
|
raise SanicException(resp.body, resp.status_code)
|
||||||
self.websocket = WebsocketImplProtocol(
|
self.websocket = WebsocketImplProtocol(
|
||||||
ws_proto,
|
ws_proto,
|
||||||
ping_interval=self.websocket_ping_interval,
|
ping_interval=self.websocket_ping_interval,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user