summaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/~ip/_vendor/cachecontrol/serialize.py
diff options
context:
space:
mode:
authorblackhao <13851610112@163.com>2025-08-22 02:51:50 -0500
committerblackhao <13851610112@163.com>2025-08-22 02:51:50 -0500
commit4aab4087dc97906d0b9890035401175cdaab32d4 (patch)
tree4e2e9d88a711ec5b1cfa02e8ac72a55183b99123 /.venv/lib/python3.12/site-packages/~ip/_vendor/cachecontrol/serialize.py
parentafa8f50d1d21c721dabcb31ad244610946ab65a3 (diff)
2.0
Diffstat (limited to '.venv/lib/python3.12/site-packages/~ip/_vendor/cachecontrol/serialize.py')
-rw-r--r--.venv/lib/python3.12/site-packages/~ip/_vendor/cachecontrol/serialize.py206
1 files changed, 206 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/~ip/_vendor/cachecontrol/serialize.py b/.venv/lib/python3.12/site-packages/~ip/_vendor/cachecontrol/serialize.py
new file mode 100644
index 0000000..f9e967c
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/~ip/_vendor/cachecontrol/serialize.py
@@ -0,0 +1,206 @@
+# SPDX-FileCopyrightText: 2015 Eric Larson
+#
+# SPDX-License-Identifier: Apache-2.0
+from __future__ import annotations
+
+import io
+from typing import IO, TYPE_CHECKING, Any, Mapping, cast
+
+from pip._vendor import msgpack
+from pip._vendor.requests.structures import CaseInsensitiveDict
+from pip._vendor.urllib3 import HTTPResponse
+
+if TYPE_CHECKING:
+ from pip._vendor.requests import PreparedRequest
+
+
+class Serializer:
+ serde_version = "4"
+
+ def dumps(
+ self,
+ request: PreparedRequest,
+ response: HTTPResponse,
+ body: bytes | None = None,
+ ) -> bytes:
+ response_headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(
+ response.headers
+ )
+
+ if body is None:
+ # When a body isn't passed in, we'll read the response. We
+ # also update the response with a new file handler to be
+ # sure it acts as though it was never read.
+ body = response.read(decode_content=False)
+ response._fp = io.BytesIO(body) # type: ignore[attr-defined]
+ response.length_remaining = len(body)
+
+ data = {
+ "response": {
+ "body": body, # Empty bytestring if body is stored separately
+ "headers": {str(k): str(v) for k, v in response.headers.items()}, # type: ignore[no-untyped-call]
+ "status": response.status,
+ "version": response.version,
+ "reason": str(response.reason),
+ "decode_content": response.decode_content,
+ }
+ }
+
+ # Construct our vary headers
+ data["vary"] = {}
+ if "vary" in response_headers:
+ varied_headers = response_headers["vary"].split(",")
+ for header in varied_headers:
+ header = str(header).strip()
+ header_value = request.headers.get(header, None)
+ if header_value is not None:
+ header_value = str(header_value)
+ data["vary"][header] = header_value
+
+ return b",".join([f"cc={self.serde_version}".encode(), self.serialize(data)])
+
+ def serialize(self, data: dict[str, Any]) -> bytes:
+ return cast(bytes, msgpack.dumps(data, use_bin_type=True))
+
+ def loads(
+ self,
+ request: PreparedRequest,
+ data: bytes,
+ body_file: IO[bytes] | None = None,
+ ) -> HTTPResponse | None:
+ # Short circuit if we've been given an empty set of data
+ if not data:
+ return None
+
+ # Determine what version of the serializer the data was serialized
+ # with
+ try:
+ ver, data = data.split(b",", 1)
+ except ValueError:
+ ver = b"cc=0"
+
+ # Make sure that our "ver" is actually a version and isn't a false
+ # positive from a , being in the data stream.
+ if ver[:3] != b"cc=":
+ data = ver + data
+ ver = b"cc=0"
+
+ # Get the version number out of the cc=N
+ verstr = ver.split(b"=", 1)[-1].decode("ascii")
+
+ # Dispatch to the actual load method for the given version
+ try:
+ return getattr(self, f"_loads_v{verstr}")(request, data, body_file) # type: ignore[no-any-return]
+
+ except AttributeError:
+ # This is a version we don't have a loads function for, so we'll
+ # just treat it as a miss and return None
+ return None
+
+ def prepare_response(
+ self,
+ request: PreparedRequest,
+ cached: Mapping[str, Any],
+ body_file: IO[bytes] | None = None,
+ ) -> HTTPResponse | None:
+ """Verify our vary headers match and construct a real urllib3
+ HTTPResponse object.
+ """
+ # Special case the '*' Vary value as it means we cannot actually
+ # determine if the cached response is suitable for this request.
+ # This case is also handled in the controller code when creating
+ # a cache entry, but is left here for backwards compatibility.
+ if "*" in cached.get("vary", {}):
+ return None
+
+ # Ensure that the Vary headers for the cached response match our
+ # request
+ for header, value in cached.get("vary", {}).items():
+ if request.headers.get(header, None) != value:
+ return None
+
+ body_raw = cached["response"].pop("body")
+
+ headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(
+ data=cached["response"]["headers"]
+ )
+ if headers.get("transfer-encoding", "") == "chunked":
+ headers.pop("transfer-encoding")
+
+ cached["response"]["headers"] = headers
+
+ try:
+ body: IO[bytes]
+ if body_file is None:
+ body = io.BytesIO(body_raw)
+ else:
+ body = body_file
+ except TypeError:
+ # This can happen if cachecontrol serialized to v1 format (pickle)
+ # using Python 2. A Python 2 str(byte string) will be unpickled as
+ # a Python 3 str (unicode string), which will cause the above to
+ # fail with:
+ #
+ # TypeError: 'str' does not support the buffer interface
+ body = io.BytesIO(body_raw.encode("utf8"))
+
+ # Discard any `strict` parameter serialized by older version of cachecontrol.
+ cached["response"].pop("strict", None)
+
+ return HTTPResponse(body=body, preload_content=False, **cached["response"])
+
+ def _loads_v0(
+ self,
+ request: PreparedRequest,
+ data: bytes,
+ body_file: IO[bytes] | None = None,
+ ) -> None:
+ # The original legacy cache data. This doesn't contain enough
+ # information to construct everything we need, so we'll treat this as
+ # a miss.
+ return None
+
+ def _loads_v1(
+ self,
+ request: PreparedRequest,
+ data: bytes,
+ body_file: IO[bytes] | None = None,
+ ) -> HTTPResponse | None:
+ # The "v1" pickled cache format. This is no longer supported
+ # for security reasons, so we treat it as a miss.
+ return None
+
+ def _loads_v2(
+ self,
+ request: PreparedRequest,
+ data: bytes,
+ body_file: IO[bytes] | None = None,
+ ) -> HTTPResponse | None:
+ # The "v2" compressed base64 cache format.
+ # This has been removed due to age and poor size/performance
+ # characteristics, so we treat it as a miss.
+ return None
+
+ def _loads_v3(
+ self,
+ request: PreparedRequest,
+ data: bytes,
+ body_file: IO[bytes] | None = None,
+ ) -> None:
+ # Due to Python 2 encoding issues, it's impossible to know for sure
+ # exactly how to load v3 entries, thus we'll treat these as a miss so
+ # that they get rewritten out as v4 entries.
+ return None
+
+ def _loads_v4(
+ self,
+ request: PreparedRequest,
+ data: bytes,
+ body_file: IO[bytes] | None = None,
+ ) -> HTTPResponse | None:
+ try:
+ cached = msgpack.loads(data, raw=False)
+ except ValueError:
+ return None
+
+ return self.prepare_response(request, cached, body_file)