| |
| |
| |
|
|
| import base64 |
| import io |
| import json |
| import zlib |
|
|
| from pip._vendor import msgpack |
| from pip._vendor.requests.structures import CaseInsensitiveDict |
|
|
| from .compat import HTTPResponse, pickle, text_type |
|
|
|
|
| def _b64_decode_bytes(b): |
| return base64.b64decode(b.encode("ascii")) |
|
|
|
|
| def _b64_decode_str(s): |
| return _b64_decode_bytes(s).decode("utf8") |
|
|
|
|
| _default_body_read = object() |
|
|
|
|
| class Serializer(object): |
| def dumps(self, request, response, body=None): |
| response_headers = CaseInsensitiveDict(response.headers) |
|
|
| if body is None: |
| |
| |
| |
| body = response.read(decode_content=False) |
| response._fp = io.BytesIO(body) |
|
|
| |
| |
| |
| |
| |
| |
| |
| data = { |
| u"response": { |
| u"body": body, |
| u"headers": dict( |
| (text_type(k), text_type(v)) for k, v in response.headers.items() |
| ), |
| u"status": response.status, |
| u"version": response.version, |
| u"reason": text_type(response.reason), |
| u"strict": response.strict, |
| u"decode_content": response.decode_content, |
| } |
| } |
|
|
| |
| data[u"vary"] = {} |
| if u"vary" in response_headers: |
| varied_headers = response_headers[u"vary"].split(",") |
| for header in varied_headers: |
| header = text_type(header).strip() |
| header_value = request.headers.get(header, None) |
| if header_value is not None: |
| header_value = text_type(header_value) |
| data[u"vary"][header] = header_value |
|
|
| return b",".join([b"cc=4", msgpack.dumps(data, use_bin_type=True)]) |
|
|
| def loads(self, request, data, body_file=None): |
| |
| if not data: |
| return |
|
|
| |
| |
| try: |
| ver, data = data.split(b",", 1) |
| except ValueError: |
| ver = b"cc=0" |
|
|
| |
| |
| if ver[:3] != b"cc=": |
| data = ver + data |
| ver = b"cc=0" |
|
|
| |
| ver = ver.split(b"=", 1)[-1].decode("ascii") |
|
|
| |
| try: |
| return getattr(self, "_loads_v{}".format(ver))(request, data, body_file) |
|
|
| except AttributeError: |
| |
| |
| return |
|
|
| def prepare_response(self, request, cached, body_file=None): |
| """Verify our vary headers match and construct a real urllib3 |
| HTTPResponse object. |
| """ |
| |
| |
| |
| |
| if "*" in cached.get("vary", {}): |
| return |
|
|
| |
| |
| for header, value in cached.get("vary", {}).items(): |
| if request.headers.get(header, None) != value: |
| return |
|
|
| body_raw = cached["response"].pop("body") |
|
|
| headers = CaseInsensitiveDict(data=cached["response"]["headers"]) |
| if headers.get("transfer-encoding", "") == "chunked": |
| headers.pop("transfer-encoding") |
|
|
| cached["response"]["headers"] = headers |
|
|
| try: |
| if body_file is None: |
| body = io.BytesIO(body_raw) |
| else: |
| body = body_file |
| except TypeError: |
| |
| |
| |
| |
| |
| |
| body = io.BytesIO(body_raw.encode("utf8")) |
|
|
| return HTTPResponse(body=body, preload_content=False, **cached["response"]) |
|
|
| def _loads_v0(self, request, data, body_file=None): |
| |
| |
| |
| return |
|
|
| def _loads_v1(self, request, data, body_file=None): |
| try: |
| cached = pickle.loads(data) |
| except ValueError: |
| return |
|
|
| return self.prepare_response(request, cached, body_file) |
|
|
| def _loads_v2(self, request, data, body_file=None): |
| assert body_file is None |
| try: |
| cached = json.loads(zlib.decompress(data).decode("utf8")) |
| except (ValueError, zlib.error): |
| return |
|
|
| |
| cached["response"]["body"] = _b64_decode_bytes(cached["response"]["body"]) |
| cached["response"]["headers"] = dict( |
| (_b64_decode_str(k), _b64_decode_str(v)) |
| for k, v in cached["response"]["headers"].items() |
| ) |
| cached["response"]["reason"] = _b64_decode_str(cached["response"]["reason"]) |
| cached["vary"] = dict( |
| (_b64_decode_str(k), _b64_decode_str(v) if v is not None else v) |
| for k, v in cached["vary"].items() |
| ) |
|
|
| return self.prepare_response(request, cached, body_file) |
|
|
| def _loads_v3(self, request, data, body_file): |
| |
| |
| |
| return |
|
|
| def _loads_v4(self, request, data, body_file=None): |
| try: |
| cached = msgpack.loads(data, raw=False) |
| except ValueError: |
| return |
|
|
| return self.prepare_response(request, cached, body_file) |
|
|