http_exceptions.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. """Low-level http related exceptions."""
  2. from textwrap import indent
  3. from typing import Optional, Union
  4. from .typedefs import _CIMultiDict
  5. __all__ = ("HttpProcessingError",)
  6. class HttpProcessingError(Exception):
  7. """HTTP error.
  8. Shortcut for raising HTTP errors with custom code, message and headers.
  9. code: HTTP Error code.
  10. message: (optional) Error message.
  11. headers: (optional) Headers to be sent in response, a list of pairs
  12. """
  13. code = 0
  14. message = ""
  15. headers = None
  16. def __init__(
  17. self,
  18. *,
  19. code: Optional[int] = None,
  20. message: str = "",
  21. headers: Optional[_CIMultiDict] = None,
  22. ) -> None:
  23. if code is not None:
  24. self.code = code
  25. self.headers = headers
  26. self.message = message
  27. def __str__(self) -> str:
  28. msg = indent(self.message, " ")
  29. return f"{self.code}, message:\n{msg}"
  30. def __repr__(self) -> str:
  31. return f"<{self.__class__.__name__}: {self.code}, message={self.message!r}>"
  32. class BadHttpMessage(HttpProcessingError):
  33. code = 400
  34. message = "Bad Request"
  35. def __init__(self, message: str, *, headers: Optional[_CIMultiDict] = None) -> None:
  36. super().__init__(message=message, headers=headers)
  37. self.args = (message,)
  38. class HttpBadRequest(BadHttpMessage):
  39. code = 400
  40. message = "Bad Request"
  41. class PayloadEncodingError(BadHttpMessage):
  42. """Base class for payload errors"""
  43. class ContentEncodingError(PayloadEncodingError):
  44. """Content encoding error."""
  45. class TransferEncodingError(PayloadEncodingError):
  46. """transfer encoding error."""
  47. class ContentLengthError(PayloadEncodingError):
  48. """Not enough data to satisfy content length header."""
  49. class DecompressSizeError(PayloadEncodingError):
  50. """Decompressed size exceeds the configured limit."""
  51. class LineTooLong(BadHttpMessage):
  52. def __init__(
  53. self,
  54. line: Union[str, bytes],
  55. limit: Union[str, int] = "Unknown",
  56. actual_size: str = "Unknown",
  57. ) -> None:
  58. super().__init__(f"Got more than {limit} bytes when reading: {line!r}.")
  59. self.args = (line, limit, actual_size)
  60. class InvalidHeader(BadHttpMessage):
  61. def __init__(self, hdr: Union[bytes, str]) -> None:
  62. hdr_s = hdr.decode(errors="backslashreplace") if isinstance(hdr, bytes) else hdr
  63. super().__init__(f"Invalid HTTP header: {hdr!r}")
  64. self.hdr = hdr_s
  65. self.args = (hdr,)
  66. class BadStatusLine(BadHttpMessage):
  67. def __init__(self, line: str = "", error: Optional[str] = None) -> None:
  68. if not isinstance(line, str):
  69. line = repr(line)
  70. super().__init__(error or f"Bad status line {line!r}")
  71. self.args = (line,)
  72. self.line = line
  73. class BadHttpMethod(BadStatusLine):
  74. """Invalid HTTP method in status line."""
  75. def __init__(self, line: str = "", error: Optional[str] = None) -> None:
  76. super().__init__(line, error or f"Bad HTTP method in status line {line!r}")
  77. class InvalidURLError(BadHttpMessage):
  78. pass