diff options
Diffstat (limited to 'venv/lib/python3.11/site-packages/h11/_readers.py')
| -rw-r--r-- | venv/lib/python3.11/site-packages/h11/_readers.py | 247 | 
1 files changed, 0 insertions, 247 deletions
| diff --git a/venv/lib/python3.11/site-packages/h11/_readers.py b/venv/lib/python3.11/site-packages/h11/_readers.py deleted file mode 100644 index 08a9574..0000000 --- a/venv/lib/python3.11/site-packages/h11/_readers.py +++ /dev/null @@ -1,247 +0,0 @@ -# Code to read HTTP data -# -# Strategy: each reader is a callable which takes a ReceiveBuffer object, and -# either: -# 1) consumes some of it and returns an Event -# 2) raises a LocalProtocolError (for consistency -- e.g. we call validate() -#    and it might raise a LocalProtocolError, so simpler just to always use -#    this) -# 3) returns None, meaning "I need more data" -# -# If they have a .read_eof attribute, then this will be called if an EOF is -# received -- but this is optional. Either way, the actual ConnectionClosed -# event will be generated afterwards. -# -# READERS is a dict describing how to pick a reader. It maps states to either: -# - a reader -# - or, for body readers, a dict of per-framing reader factories - -import re -from typing import Any, Callable, Dict, Iterable, NoReturn, Optional, Tuple, Type, Union - -from ._abnf import chunk_header, header_field, request_line, status_line -from ._events import Data, EndOfMessage, InformationalResponse, Request, Response -from ._receivebuffer import ReceiveBuffer -from ._state import ( -    CLIENT, -    CLOSED, -    DONE, -    IDLE, -    MUST_CLOSE, -    SEND_BODY, -    SEND_RESPONSE, -    SERVER, -) -from ._util import LocalProtocolError, RemoteProtocolError, Sentinel, validate - -__all__ = ["READERS"] - -header_field_re = re.compile(header_field.encode("ascii")) -obs_fold_re = re.compile(rb"[ \t]+") - - -def _obsolete_line_fold(lines: Iterable[bytes]) -> Iterable[bytes]: -    it = iter(lines) -    last: Optional[bytes] = None -    for line in it: -        match = obs_fold_re.match(line) -        if match: -            if last is None: -                raise LocalProtocolError("continuation line at start of headers") -            if not isinstance(last, bytearray): -                # Cast to a mutable type, avoiding copy on append to ensure O(n) time -                last = bytearray(last) -            last += b" " -            last += line[match.end() :] -        else: -            if last is not None: -                yield last -            last = line -    if last is not None: -        yield last - - -def _decode_header_lines( -    lines: Iterable[bytes], -) -> Iterable[Tuple[bytes, bytes]]: -    for line in _obsolete_line_fold(lines): -        matches = validate(header_field_re, line, "illegal header line: {!r}", line) -        yield (matches["field_name"], matches["field_value"]) - - -request_line_re = re.compile(request_line.encode("ascii")) - - -def maybe_read_from_IDLE_client(buf: ReceiveBuffer) -> Optional[Request]: -    lines = buf.maybe_extract_lines() -    if lines is None: -        if buf.is_next_line_obviously_invalid_request_line(): -            raise LocalProtocolError("illegal request line") -        return None -    if not lines: -        raise LocalProtocolError("no request line received") -    matches = validate( -        request_line_re, lines[0], "illegal request line: {!r}", lines[0] -    ) -    return Request( -        headers=list(_decode_header_lines(lines[1:])), _parsed=True, **matches -    ) - - -status_line_re = re.compile(status_line.encode("ascii")) - - -def maybe_read_from_SEND_RESPONSE_server( -    buf: ReceiveBuffer, -) -> Union[InformationalResponse, Response, None]: -    lines = buf.maybe_extract_lines() -    if lines is None: -        if buf.is_next_line_obviously_invalid_request_line(): -            raise LocalProtocolError("illegal request line") -        return None -    if not lines: -        raise LocalProtocolError("no response line received") -    matches = validate(status_line_re, lines[0], "illegal status line: {!r}", lines[0]) -    http_version = ( -        b"1.1" if matches["http_version"] is None else matches["http_version"] -    ) -    reason = b"" if matches["reason"] is None else matches["reason"] -    status_code = int(matches["status_code"]) -    class_: Union[Type[InformationalResponse], Type[Response]] = ( -        InformationalResponse if status_code < 200 else Response -    ) -    return class_( -        headers=list(_decode_header_lines(lines[1:])), -        _parsed=True, -        status_code=status_code, -        reason=reason, -        http_version=http_version, -    ) - - -class ContentLengthReader: -    def __init__(self, length: int) -> None: -        self._length = length -        self._remaining = length - -    def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: -        if self._remaining == 0: -            return EndOfMessage() -        data = buf.maybe_extract_at_most(self._remaining) -        if data is None: -            return None -        self._remaining -= len(data) -        return Data(data=data) - -    def read_eof(self) -> NoReturn: -        raise RemoteProtocolError( -            "peer closed connection without sending complete message body " -            "(received {} bytes, expected {})".format( -                self._length - self._remaining, self._length -            ) -        ) - - -chunk_header_re = re.compile(chunk_header.encode("ascii")) - - -class ChunkedReader: -    def __init__(self) -> None: -        self._bytes_in_chunk = 0 -        # After reading a chunk, we have to throw away the trailing \r\n; if -        # this is >0 then we discard that many bytes before resuming regular -        # de-chunkification. -        self._bytes_to_discard = 0 -        self._reading_trailer = False - -    def __call__(self, buf: ReceiveBuffer) -> Union[Data, EndOfMessage, None]: -        if self._reading_trailer: -            lines = buf.maybe_extract_lines() -            if lines is None: -                return None -            return EndOfMessage(headers=list(_decode_header_lines(lines))) -        if self._bytes_to_discard > 0: -            data = buf.maybe_extract_at_most(self._bytes_to_discard) -            if data is None: -                return None -            self._bytes_to_discard -= len(data) -            if self._bytes_to_discard > 0: -                return None -            # else, fall through and read some more -        assert self._bytes_to_discard == 0 -        if self._bytes_in_chunk == 0: -            # We need to refill our chunk count -            chunk_header = buf.maybe_extract_next_line() -            if chunk_header is None: -                return None -            matches = validate( -                chunk_header_re, -                chunk_header, -                "illegal chunk header: {!r}", -                chunk_header, -            ) -            # XX FIXME: we discard chunk extensions. Does anyone care? -            self._bytes_in_chunk = int(matches["chunk_size"], base=16) -            if self._bytes_in_chunk == 0: -                self._reading_trailer = True -                return self(buf) -            chunk_start = True -        else: -            chunk_start = False -        assert self._bytes_in_chunk > 0 -        data = buf.maybe_extract_at_most(self._bytes_in_chunk) -        if data is None: -            return None -        self._bytes_in_chunk -= len(data) -        if self._bytes_in_chunk == 0: -            self._bytes_to_discard = 2 -            chunk_end = True -        else: -            chunk_end = False -        return Data(data=data, chunk_start=chunk_start, chunk_end=chunk_end) - -    def read_eof(self) -> NoReturn: -        raise RemoteProtocolError( -            "peer closed connection without sending complete message body " -            "(incomplete chunked read)" -        ) - - -class Http10Reader: -    def __call__(self, buf: ReceiveBuffer) -> Optional[Data]: -        data = buf.maybe_extract_at_most(999999999) -        if data is None: -            return None -        return Data(data=data) - -    def read_eof(self) -> EndOfMessage: -        return EndOfMessage() - - -def expect_nothing(buf: ReceiveBuffer) -> None: -    if buf: -        raise LocalProtocolError("Got data when expecting EOF") -    return None - - -ReadersType = Dict[ -    Union[Type[Sentinel], Tuple[Type[Sentinel], Type[Sentinel]]], -    Union[Callable[..., Any], Dict[str, Callable[..., Any]]], -] - -READERS: ReadersType = { -    (CLIENT, IDLE): maybe_read_from_IDLE_client, -    (SERVER, IDLE): maybe_read_from_SEND_RESPONSE_server, -    (SERVER, SEND_RESPONSE): maybe_read_from_SEND_RESPONSE_server, -    (CLIENT, DONE): expect_nothing, -    (CLIENT, MUST_CLOSE): expect_nothing, -    (CLIENT, CLOSED): expect_nothing, -    (SERVER, DONE): expect_nothing, -    (SERVER, MUST_CLOSE): expect_nothing, -    (SERVER, CLOSED): expect_nothing, -    SEND_BODY: { -        "chunked": ChunkedReader, -        "content-length": ContentLengthReader, -        "http/1.0": Http10Reader, -    }, -} | 
