about summary refs log tree commit diff
path: root/.venv/lib/python3.12/site-packages/h11/_writers.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/h11/_writers.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are here HEAD master
Diffstat (limited to '.venv/lib/python3.12/site-packages/h11/_writers.py')
-rw-r--r--.venv/lib/python3.12/site-packages/h11/_writers.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/h11/_writers.py b/.venv/lib/python3.12/site-packages/h11/_writers.py
new file mode 100644
index 00000000..939cdb91
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/h11/_writers.py
@@ -0,0 +1,145 @@
+# Code to read HTTP data
+#
+# Strategy: each writer takes an event + a write-some-bytes function, which is
+# calls.
+#
+# WRITERS is a dict describing how to pick a reader. It maps states to either:
+# - a writer
+# - or, for body writers, a dict of framin-dependent writer factories
+
+from typing import Any, Callable, Dict, List, Tuple, Type, Union
+
+from ._events import Data, EndOfMessage, Event, InformationalResponse, Request, Response
+from ._headers import Headers
+from ._state import CLIENT, IDLE, SEND_BODY, SEND_RESPONSE, SERVER
+from ._util import LocalProtocolError, Sentinel
+
+__all__ = ["WRITERS"]
+
+Writer = Callable[[bytes], Any]
+
+
+def write_headers(headers: Headers, write: Writer) -> None:
+    # "Since the Host field-value is critical information for handling a
+    # request, a user agent SHOULD generate Host as the first header field
+    # following the request-line." - RFC 7230
+    raw_items = headers._full_items
+    for raw_name, name, value in raw_items:
+        if name == b"host":
+            write(b"%s: %s\r\n" % (raw_name, value))
+    for raw_name, name, value in raw_items:
+        if name != b"host":
+            write(b"%s: %s\r\n" % (raw_name, value))
+    write(b"\r\n")
+
+
+def write_request(request: Request, write: Writer) -> None:
+    if request.http_version != b"1.1":
+        raise LocalProtocolError("I only send HTTP/1.1")
+    write(b"%s %s HTTP/1.1\r\n" % (request.method, request.target))
+    write_headers(request.headers, write)
+
+
+# Shared between InformationalResponse and Response
+def write_any_response(
+    response: Union[InformationalResponse, Response], write: Writer
+) -> None:
+    if response.http_version != b"1.1":
+        raise LocalProtocolError("I only send HTTP/1.1")
+    status_bytes = str(response.status_code).encode("ascii")
+    # We don't bother sending ascii status messages like "OK"; they're
+    # optional and ignored by the protocol. (But the space after the numeric
+    # status code is mandatory.)
+    #
+    # XX FIXME: could at least make an effort to pull out the status message
+    # from stdlib's http.HTTPStatus table. Or maybe just steal their enums
+    # (either by import or copy/paste). We already accept them as status codes
+    # since they're of type IntEnum < int.
+    write(b"HTTP/1.1 %s %s\r\n" % (status_bytes, response.reason))
+    write_headers(response.headers, write)
+
+
+class BodyWriter:
+    def __call__(self, event: Event, write: Writer) -> None:
+        if type(event) is Data:
+            self.send_data(event.data, write)
+        elif type(event) is EndOfMessage:
+            self.send_eom(event.headers, write)
+        else:  # pragma: no cover
+            assert False
+
+    def send_data(self, data: bytes, write: Writer) -> None:
+        pass
+
+    def send_eom(self, headers: Headers, write: Writer) -> None:
+        pass
+
+
+#
+# These are all careful not to do anything to 'data' except call len(data) and
+# write(data). This allows us to transparently pass-through funny objects,
+# like placeholder objects referring to files on disk that will be sent via
+# sendfile(2).
+#
+class ContentLengthWriter(BodyWriter):
+    def __init__(self, length: int) -> None:
+        self._length = length
+
+    def send_data(self, data: bytes, write: Writer) -> None:
+        self._length -= len(data)
+        if self._length < 0:
+            raise LocalProtocolError("Too much data for declared Content-Length")
+        write(data)
+
+    def send_eom(self, headers: Headers, write: Writer) -> None:
+        if self._length != 0:
+            raise LocalProtocolError("Too little data for declared Content-Length")
+        if headers:
+            raise LocalProtocolError("Content-Length and trailers don't mix")
+
+
+class ChunkedWriter(BodyWriter):
+    def send_data(self, data: bytes, write: Writer) -> None:
+        # if we encoded 0-length data in the naive way, it would look like an
+        # end-of-message.
+        if not data:
+            return
+        write(b"%x\r\n" % len(data))
+        write(data)
+        write(b"\r\n")
+
+    def send_eom(self, headers: Headers, write: Writer) -> None:
+        write(b"0\r\n")
+        write_headers(headers, write)
+
+
+class Http10Writer(BodyWriter):
+    def send_data(self, data: bytes, write: Writer) -> None:
+        write(data)
+
+    def send_eom(self, headers: Headers, write: Writer) -> None:
+        if headers:
+            raise LocalProtocolError("can't send trailers to HTTP/1.0 client")
+        # no need to close the socket ourselves, that will be taken care of by
+        # Connection: close machinery
+
+
+WritersType = Dict[
+    Union[Tuple[Type[Sentinel], Type[Sentinel]], Type[Sentinel]],
+    Union[
+        Dict[str, Type[BodyWriter]],
+        Callable[[Union[InformationalResponse, Response], Writer], None],
+        Callable[[Request, Writer], None],
+    ],
+]
+
+WRITERS: WritersType = {
+    (CLIENT, IDLE): write_request,
+    (SERVER, IDLE): write_any_response,
+    (SERVER, SEND_RESPONSE): write_any_response,
+    SEND_BODY: {
+        "chunked": ChunkedWriter,
+        "content-length": ContentLengthWriter,
+        "http/1.0": Http10Writer,
+    },
+}