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