1"""Low-level http related exceptions."""
2
3from textwrap import indent
4
5from .typedefs import _CIMultiDict
6
7__all__ = ("HttpProcessingError",)
8
9
10class HttpProcessingError(Exception):
11 """HTTP error.
12
13 Shortcut for raising HTTP errors with custom code, message and headers.
14
15 code: HTTP Error code.
16 message: (optional) Error message.
17 headers: (optional) Headers to be sent in response, a list of pairs
18 """
19
20 code = 0
21 message = ""
22 headers = None
23
24 def __init__(
25 self,
26 *,
27 code: int | None = None,
28 message: str = "",
29 headers: _CIMultiDict | None = None,
30 ) -> None:
31 if code is not None:
32 self.code = code
33 self.headers = headers
34 self.message = message
35
36 def __str__(self) -> str:
37 msg = indent(self.message, " ")
38 return f"{self.code}, message:\n{msg}"
39
40 def __repr__(self) -> str:
41 return f"<{self.__class__.__name__}: {self.code}, message={self.message!r}>"
42
43
44class BadHttpMessage(HttpProcessingError):
45
46 code = 400
47 message = "Bad Request"
48
49 def __init__(self, message: str, *, headers: _CIMultiDict | None = None) -> None:
50 super().__init__(message=message, headers=headers)
51 self.args = (message,)
52
53
54class HttpBadRequest(BadHttpMessage):
55
56 code = 400
57 message = "Bad Request"
58
59
60class PayloadEncodingError(BadHttpMessage):
61 """Base class for payload errors"""
62
63
64class ContentEncodingError(PayloadEncodingError):
65 """Content encoding error."""
66
67
68class TransferEncodingError(PayloadEncodingError):
69 """transfer encoding error."""
70
71
72class ContentLengthError(PayloadEncodingError):
73 """Not enough data to satisfy content length header."""
74
75
76class DecompressSizeError(PayloadEncodingError):
77 """Deprecated. Removed in v4."""
78
79
80class LineTooLong(BadHttpMessage):
81 def __init__(
82 self,
83 line: str | bytes,
84 limit: str | int = "Unknown",
85 actual_size: str = "Unknown",
86 ) -> None:
87 super().__init__(f"Got more than {limit} bytes when reading: {line!r}.")
88 self.args = (line, limit, actual_size)
89
90
91class InvalidHeader(BadHttpMessage):
92 def __init__(self, hdr: bytes | str) -> None:
93 hdr_s = hdr.decode(errors="backslashreplace") if isinstance(hdr, bytes) else hdr
94 super().__init__(f"Invalid HTTP header: {hdr!r}")
95 self.hdr = hdr_s
96 self.args = (hdr,)
97
98
99class BadStatusLine(BadHttpMessage):
100 def __init__(self, line: str = "", error: str | None = None) -> None:
101 if not isinstance(line, str):
102 line = repr(line)
103 super().__init__(error or f"Bad status line {line!r}")
104 self.args = (line,)
105 self.line = line
106
107
108class BadHttpMethod(BadStatusLine):
109 """Invalid HTTP method in status line."""
110
111 def __init__(self, line: str = "", error: str | None = None) -> None:
112 if error is None and line.startswith("\x16\x03"):
113 error = "Received HTTPS traffic on an HTTP port"
114 super().__init__(line, error or f"Bad HTTP method in status line {line!r}")
115
116
117class InvalidURLError(BadHttpMessage):
118 pass