Add files using upload-large-folder tool
Browse files- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/__init__.py +3 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/__main__.py +12 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/cacert.pem +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/core.py +76 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/__init__.py +5 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/_base.py +40 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/py.py +67 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py +30 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py +54 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/sax.py +50 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/base.py +417 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/dom.py +239 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/tomli/__init__.py +6 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/tomli/_parser.py +703 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/tomli/_re.py +83 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/__init__.py +85 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/_collections.py +337 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/_version.py +2 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/connection.py +539 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/connectionpool.py +1067 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/__init__.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py +36 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py +0 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py +519 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py +396 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/appengine.py +314 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py +130 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py +511 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/securetransport.py +922 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/socks.py +216 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/exceptions.py +323 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/fields.py +274 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/filepost.py +98 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/__init__.py +5 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/six.py +1077 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/poolmanager.py +536 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/request.py +170 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/response.py +821 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/__init__.py +49 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/connection.py +150 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/proxy.py +56 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/queue.py +22 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/request.py +143 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/response.py +107 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/retry.py +602 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/ssl_.py +495 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/ssltransport.py +221 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/timeout.py +268 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/url.py +432 -0
- astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/wait.py +153 -0
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/__init__.py
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .core import contents, where
|
| 2 |
+
|
| 3 |
+
__version__ = "2021.05.30"
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/__main__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
|
| 3 |
+
from pip._vendor.certifi import contents, where
|
| 4 |
+
|
| 5 |
+
parser = argparse.ArgumentParser()
|
| 6 |
+
parser.add_argument("-c", "--contents", action="store_true")
|
| 7 |
+
args = parser.parse_args()
|
| 8 |
+
|
| 9 |
+
if args.contents:
|
| 10 |
+
print(contents())
|
| 11 |
+
else:
|
| 12 |
+
print(where())
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/cacert.pem
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/certifi/core.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
|
| 3 |
+
"""
|
| 4 |
+
certifi.py
|
| 5 |
+
~~~~~~~~~~
|
| 6 |
+
|
| 7 |
+
This module returns the installation location of cacert.pem or its contents.
|
| 8 |
+
"""
|
| 9 |
+
import os
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class _PipPatchedCertificate(Exception):
|
| 13 |
+
pass
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
try:
|
| 17 |
+
# Return a certificate file on disk for a standalone pip zipapp running in
|
| 18 |
+
# an isolated build environment to use. Passing --cert to the standalone
|
| 19 |
+
# pip does not work since requests calls where() unconditionally on import.
|
| 20 |
+
_PIP_STANDALONE_CERT = os.environ.get("_PIP_STANDALONE_CERT")
|
| 21 |
+
if _PIP_STANDALONE_CERT:
|
| 22 |
+
def where():
|
| 23 |
+
return _PIP_STANDALONE_CERT
|
| 24 |
+
raise _PipPatchedCertificate()
|
| 25 |
+
|
| 26 |
+
from importlib.resources import path as get_path, read_text
|
| 27 |
+
|
| 28 |
+
_CACERT_CTX = None
|
| 29 |
+
_CACERT_PATH = None
|
| 30 |
+
|
| 31 |
+
def where():
|
| 32 |
+
# This is slightly terrible, but we want to delay extracting the file
|
| 33 |
+
# in cases where we're inside of a zipimport situation until someone
|
| 34 |
+
# actually calls where(), but we don't want to re-extract the file
|
| 35 |
+
# on every call of where(), so we'll do it once then store it in a
|
| 36 |
+
# global variable.
|
| 37 |
+
global _CACERT_CTX
|
| 38 |
+
global _CACERT_PATH
|
| 39 |
+
if _CACERT_PATH is None:
|
| 40 |
+
# This is slightly janky, the importlib.resources API wants you to
|
| 41 |
+
# manage the cleanup of this file, so it doesn't actually return a
|
| 42 |
+
# path, it returns a context manager that will give you the path
|
| 43 |
+
# when you enter it and will do any cleanup when you leave it. In
|
| 44 |
+
# the common case of not needing a temporary file, it will just
|
| 45 |
+
# return the file system location and the __exit__() is a no-op.
|
| 46 |
+
#
|
| 47 |
+
# We also have to hold onto the actual context manager, because
|
| 48 |
+
# it will do the cleanup whenever it gets garbage collected, so
|
| 49 |
+
# we will also store that at the global level as well.
|
| 50 |
+
_CACERT_CTX = get_path("pip._vendor.certifi", "cacert.pem")
|
| 51 |
+
_CACERT_PATH = str(_CACERT_CTX.__enter__())
|
| 52 |
+
|
| 53 |
+
return _CACERT_PATH
|
| 54 |
+
|
| 55 |
+
except _PipPatchedCertificate:
|
| 56 |
+
pass
|
| 57 |
+
|
| 58 |
+
except ImportError:
|
| 59 |
+
# This fallback will work for Python versions prior to 3.7 that lack the
|
| 60 |
+
# importlib.resources module but relies on the existing `where` function
|
| 61 |
+
# so won't address issues with environments like PyOxidizer that don't set
|
| 62 |
+
# __file__ on modules.
|
| 63 |
+
def read_text(_module, _path, encoding="ascii"):
|
| 64 |
+
with open(where(), "r", encoding=encoding) as data:
|
| 65 |
+
return data.read()
|
| 66 |
+
|
| 67 |
+
# If we don't have importlib.resources, then we will just do the old logic
|
| 68 |
+
# of assuming we're on the filesystem and munge the path directly.
|
| 69 |
+
def where():
|
| 70 |
+
f = os.path.dirname(__file__)
|
| 71 |
+
|
| 72 |
+
return os.path.join(f, "cacert.pem")
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def contents():
|
| 76 |
+
return read_text("certifi", "cacert.pem", encoding="ascii")
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 2 |
+
|
| 3 |
+
from .py import Trie
|
| 4 |
+
|
| 5 |
+
__all__ = ["Trie"]
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/_base.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 2 |
+
|
| 3 |
+
try:
|
| 4 |
+
from collections.abc import Mapping
|
| 5 |
+
except ImportError: # Python 2.7
|
| 6 |
+
from collections import Mapping
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class Trie(Mapping):
|
| 10 |
+
"""Abstract base class for tries"""
|
| 11 |
+
|
| 12 |
+
def keys(self, prefix=None):
|
| 13 |
+
# pylint:disable=arguments-differ
|
| 14 |
+
keys = super(Trie, self).keys()
|
| 15 |
+
|
| 16 |
+
if prefix is None:
|
| 17 |
+
return set(keys)
|
| 18 |
+
|
| 19 |
+
return {x for x in keys if x.startswith(prefix)}
|
| 20 |
+
|
| 21 |
+
def has_keys_with_prefix(self, prefix):
|
| 22 |
+
for key in self.keys():
|
| 23 |
+
if key.startswith(prefix):
|
| 24 |
+
return True
|
| 25 |
+
|
| 26 |
+
return False
|
| 27 |
+
|
| 28 |
+
def longest_prefix(self, prefix):
|
| 29 |
+
if prefix in self:
|
| 30 |
+
return prefix
|
| 31 |
+
|
| 32 |
+
for i in range(1, len(prefix) + 1):
|
| 33 |
+
if prefix[:-i] in self:
|
| 34 |
+
return prefix[:-i]
|
| 35 |
+
|
| 36 |
+
raise KeyError(prefix)
|
| 37 |
+
|
| 38 |
+
def longest_prefix_item(self, prefix):
|
| 39 |
+
lprefix = self.longest_prefix(prefix)
|
| 40 |
+
return (lprefix, self[lprefix])
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/_trie/py.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 2 |
+
from pip._vendor.six import text_type
|
| 3 |
+
|
| 4 |
+
from bisect import bisect_left
|
| 5 |
+
|
| 6 |
+
from ._base import Trie as ABCTrie
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class Trie(ABCTrie):
|
| 10 |
+
def __init__(self, data):
|
| 11 |
+
if not all(isinstance(x, text_type) for x in data.keys()):
|
| 12 |
+
raise TypeError("All keys must be strings")
|
| 13 |
+
|
| 14 |
+
self._data = data
|
| 15 |
+
self._keys = sorted(data.keys())
|
| 16 |
+
self._cachestr = ""
|
| 17 |
+
self._cachepoints = (0, len(data))
|
| 18 |
+
|
| 19 |
+
def __contains__(self, key):
|
| 20 |
+
return key in self._data
|
| 21 |
+
|
| 22 |
+
def __len__(self):
|
| 23 |
+
return len(self._data)
|
| 24 |
+
|
| 25 |
+
def __iter__(self):
|
| 26 |
+
return iter(self._data)
|
| 27 |
+
|
| 28 |
+
def __getitem__(self, key):
|
| 29 |
+
return self._data[key]
|
| 30 |
+
|
| 31 |
+
def keys(self, prefix=None):
|
| 32 |
+
if prefix is None or prefix == "" or not self._keys:
|
| 33 |
+
return set(self._keys)
|
| 34 |
+
|
| 35 |
+
if prefix.startswith(self._cachestr):
|
| 36 |
+
lo, hi = self._cachepoints
|
| 37 |
+
start = i = bisect_left(self._keys, prefix, lo, hi)
|
| 38 |
+
else:
|
| 39 |
+
start = i = bisect_left(self._keys, prefix)
|
| 40 |
+
|
| 41 |
+
keys = set()
|
| 42 |
+
if start == len(self._keys):
|
| 43 |
+
return keys
|
| 44 |
+
|
| 45 |
+
while self._keys[i].startswith(prefix):
|
| 46 |
+
keys.add(self._keys[i])
|
| 47 |
+
i += 1
|
| 48 |
+
|
| 49 |
+
self._cachestr = prefix
|
| 50 |
+
self._cachepoints = (start, i)
|
| 51 |
+
|
| 52 |
+
return keys
|
| 53 |
+
|
| 54 |
+
def has_keys_with_prefix(self, prefix):
|
| 55 |
+
if prefix in self._data:
|
| 56 |
+
return True
|
| 57 |
+
|
| 58 |
+
if prefix.startswith(self._cachestr):
|
| 59 |
+
lo, hi = self._cachepoints
|
| 60 |
+
i = bisect_left(self._keys, prefix, lo, hi)
|
| 61 |
+
else:
|
| 62 |
+
i = bisect_left(self._keys, prefix)
|
| 63 |
+
|
| 64 |
+
if i == len(self._keys):
|
| 65 |
+
return False
|
| 66 |
+
|
| 67 |
+
return self._keys[i].startswith(prefix)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tree adapters let you convert from one tree structure to another
|
| 2 |
+
|
| 3 |
+
Example:
|
| 4 |
+
|
| 5 |
+
.. code-block:: python
|
| 6 |
+
|
| 7 |
+
from pip._vendor import html5lib
|
| 8 |
+
from pip._vendor.html5lib.treeadapters import genshi
|
| 9 |
+
|
| 10 |
+
doc = '<html><body>Hi!</body></html>'
|
| 11 |
+
treebuilder = html5lib.getTreeBuilder('etree')
|
| 12 |
+
parser = html5lib.HTMLParser(tree=treebuilder)
|
| 13 |
+
tree = parser.parse(doc)
|
| 14 |
+
TreeWalker = html5lib.getTreeWalker('etree')
|
| 15 |
+
|
| 16 |
+
genshi_tree = genshi.to_genshi(TreeWalker(tree))
|
| 17 |
+
|
| 18 |
+
"""
|
| 19 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 20 |
+
|
| 21 |
+
from . import sax
|
| 22 |
+
|
| 23 |
+
__all__ = ["sax"]
|
| 24 |
+
|
| 25 |
+
try:
|
| 26 |
+
from . import genshi # noqa
|
| 27 |
+
except ImportError:
|
| 28 |
+
pass
|
| 29 |
+
else:
|
| 30 |
+
__all__.append("genshi")
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 2 |
+
|
| 3 |
+
from genshi.core import QName, Attrs
|
| 4 |
+
from genshi.core import START, END, TEXT, COMMENT, DOCTYPE
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def to_genshi(walker):
|
| 8 |
+
"""Convert a tree to a genshi tree
|
| 9 |
+
|
| 10 |
+
:arg walker: the treewalker to use to walk the tree to convert it
|
| 11 |
+
|
| 12 |
+
:returns: generator of genshi nodes
|
| 13 |
+
|
| 14 |
+
"""
|
| 15 |
+
text = []
|
| 16 |
+
for token in walker:
|
| 17 |
+
type = token["type"]
|
| 18 |
+
if type in ("Characters", "SpaceCharacters"):
|
| 19 |
+
text.append(token["data"])
|
| 20 |
+
elif text:
|
| 21 |
+
yield TEXT, "".join(text), (None, -1, -1)
|
| 22 |
+
text = []
|
| 23 |
+
|
| 24 |
+
if type in ("StartTag", "EmptyTag"):
|
| 25 |
+
if token["namespace"]:
|
| 26 |
+
name = "{%s}%s" % (token["namespace"], token["name"])
|
| 27 |
+
else:
|
| 28 |
+
name = token["name"]
|
| 29 |
+
attrs = Attrs([(QName("{%s}%s" % attr if attr[0] is not None else attr[1]), value)
|
| 30 |
+
for attr, value in token["data"].items()])
|
| 31 |
+
yield (START, (QName(name), attrs), (None, -1, -1))
|
| 32 |
+
if type == "EmptyTag":
|
| 33 |
+
type = "EndTag"
|
| 34 |
+
|
| 35 |
+
if type == "EndTag":
|
| 36 |
+
if token["namespace"]:
|
| 37 |
+
name = "{%s}%s" % (token["namespace"], token["name"])
|
| 38 |
+
else:
|
| 39 |
+
name = token["name"]
|
| 40 |
+
|
| 41 |
+
yield END, QName(name), (None, -1, -1)
|
| 42 |
+
|
| 43 |
+
elif type == "Comment":
|
| 44 |
+
yield COMMENT, token["data"], (None, -1, -1)
|
| 45 |
+
|
| 46 |
+
elif type == "Doctype":
|
| 47 |
+
yield DOCTYPE, (token["name"], token["publicId"],
|
| 48 |
+
token["systemId"]), (None, -1, -1)
|
| 49 |
+
|
| 50 |
+
else:
|
| 51 |
+
pass # FIXME: What to do?
|
| 52 |
+
|
| 53 |
+
if text:
|
| 54 |
+
yield TEXT, "".join(text), (None, -1, -1)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treeadapters/sax.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 2 |
+
|
| 3 |
+
from xml.sax.xmlreader import AttributesNSImpl
|
| 4 |
+
|
| 5 |
+
from ..constants import adjustForeignAttributes, unadjustForeignAttributes
|
| 6 |
+
|
| 7 |
+
prefix_mapping = {}
|
| 8 |
+
for prefix, localName, namespace in adjustForeignAttributes.values():
|
| 9 |
+
if prefix is not None:
|
| 10 |
+
prefix_mapping[prefix] = namespace
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def to_sax(walker, handler):
|
| 14 |
+
"""Call SAX-like content handler based on treewalker walker
|
| 15 |
+
|
| 16 |
+
:arg walker: the treewalker to use to walk the tree to convert it
|
| 17 |
+
|
| 18 |
+
:arg handler: SAX handler to use
|
| 19 |
+
|
| 20 |
+
"""
|
| 21 |
+
handler.startDocument()
|
| 22 |
+
for prefix, namespace in prefix_mapping.items():
|
| 23 |
+
handler.startPrefixMapping(prefix, namespace)
|
| 24 |
+
|
| 25 |
+
for token in walker:
|
| 26 |
+
type = token["type"]
|
| 27 |
+
if type == "Doctype":
|
| 28 |
+
continue
|
| 29 |
+
elif type in ("StartTag", "EmptyTag"):
|
| 30 |
+
attrs = AttributesNSImpl(token["data"],
|
| 31 |
+
unadjustForeignAttributes)
|
| 32 |
+
handler.startElementNS((token["namespace"], token["name"]),
|
| 33 |
+
token["name"],
|
| 34 |
+
attrs)
|
| 35 |
+
if type == "EmptyTag":
|
| 36 |
+
handler.endElementNS((token["namespace"], token["name"]),
|
| 37 |
+
token["name"])
|
| 38 |
+
elif type == "EndTag":
|
| 39 |
+
handler.endElementNS((token["namespace"], token["name"]),
|
| 40 |
+
token["name"])
|
| 41 |
+
elif type in ("Characters", "SpaceCharacters"):
|
| 42 |
+
handler.characters(token["data"])
|
| 43 |
+
elif type == "Comment":
|
| 44 |
+
pass
|
| 45 |
+
else:
|
| 46 |
+
assert False, "Unknown token type"
|
| 47 |
+
|
| 48 |
+
for prefix, namespace in prefix_mapping.items():
|
| 49 |
+
handler.endPrefixMapping(prefix)
|
| 50 |
+
handler.endDocument()
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/base.py
ADDED
|
@@ -0,0 +1,417 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 2 |
+
from pip._vendor.six import text_type
|
| 3 |
+
|
| 4 |
+
from ..constants import scopingElements, tableInsertModeElements, namespaces
|
| 5 |
+
|
| 6 |
+
# The scope markers are inserted when entering object elements,
|
| 7 |
+
# marquees, table cells, and table captions, and are used to prevent formatting
|
| 8 |
+
# from "leaking" into tables, object elements, and marquees.
|
| 9 |
+
Marker = None
|
| 10 |
+
|
| 11 |
+
listElementsMap = {
|
| 12 |
+
None: (frozenset(scopingElements), False),
|
| 13 |
+
"button": (frozenset(scopingElements | {(namespaces["html"], "button")}), False),
|
| 14 |
+
"list": (frozenset(scopingElements | {(namespaces["html"], "ol"),
|
| 15 |
+
(namespaces["html"], "ul")}), False),
|
| 16 |
+
"table": (frozenset([(namespaces["html"], "html"),
|
| 17 |
+
(namespaces["html"], "table")]), False),
|
| 18 |
+
"select": (frozenset([(namespaces["html"], "optgroup"),
|
| 19 |
+
(namespaces["html"], "option")]), True)
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
|
| 23 |
+
class Node(object):
|
| 24 |
+
"""Represents an item in the tree"""
|
| 25 |
+
def __init__(self, name):
|
| 26 |
+
"""Creates a Node
|
| 27 |
+
|
| 28 |
+
:arg name: The tag name associated with the node
|
| 29 |
+
|
| 30 |
+
"""
|
| 31 |
+
# The tag name associated with the node
|
| 32 |
+
self.name = name
|
| 33 |
+
# The parent of the current node (or None for the document node)
|
| 34 |
+
self.parent = None
|
| 35 |
+
# The value of the current node (applies to text nodes and comments)
|
| 36 |
+
self.value = None
|
| 37 |
+
# A dict holding name -> value pairs for attributes of the node
|
| 38 |
+
self.attributes = {}
|
| 39 |
+
# A list of child nodes of the current node. This must include all
|
| 40 |
+
# elements but not necessarily other node types.
|
| 41 |
+
self.childNodes = []
|
| 42 |
+
# A list of miscellaneous flags that can be set on the node.
|
| 43 |
+
self._flags = []
|
| 44 |
+
|
| 45 |
+
def __str__(self):
|
| 46 |
+
attributesStr = " ".join(["%s=\"%s\"" % (name, value)
|
| 47 |
+
for name, value in
|
| 48 |
+
self.attributes.items()])
|
| 49 |
+
if attributesStr:
|
| 50 |
+
return "<%s %s>" % (self.name, attributesStr)
|
| 51 |
+
else:
|
| 52 |
+
return "<%s>" % (self.name)
|
| 53 |
+
|
| 54 |
+
def __repr__(self):
|
| 55 |
+
return "<%s>" % (self.name)
|
| 56 |
+
|
| 57 |
+
def appendChild(self, node):
|
| 58 |
+
"""Insert node as a child of the current node
|
| 59 |
+
|
| 60 |
+
:arg node: the node to insert
|
| 61 |
+
|
| 62 |
+
"""
|
| 63 |
+
raise NotImplementedError
|
| 64 |
+
|
| 65 |
+
def insertText(self, data, insertBefore=None):
|
| 66 |
+
"""Insert data as text in the current node, positioned before the
|
| 67 |
+
start of node insertBefore or to the end of the node's text.
|
| 68 |
+
|
| 69 |
+
:arg data: the data to insert
|
| 70 |
+
|
| 71 |
+
:arg insertBefore: True if you want to insert the text before the node
|
| 72 |
+
and False if you want to insert it after the node
|
| 73 |
+
|
| 74 |
+
"""
|
| 75 |
+
raise NotImplementedError
|
| 76 |
+
|
| 77 |
+
def insertBefore(self, node, refNode):
|
| 78 |
+
"""Insert node as a child of the current node, before refNode in the
|
| 79 |
+
list of child nodes. Raises ValueError if refNode is not a child of
|
| 80 |
+
the current node
|
| 81 |
+
|
| 82 |
+
:arg node: the node to insert
|
| 83 |
+
|
| 84 |
+
:arg refNode: the child node to insert the node before
|
| 85 |
+
|
| 86 |
+
"""
|
| 87 |
+
raise NotImplementedError
|
| 88 |
+
|
| 89 |
+
def removeChild(self, node):
|
| 90 |
+
"""Remove node from the children of the current node
|
| 91 |
+
|
| 92 |
+
:arg node: the child node to remove
|
| 93 |
+
|
| 94 |
+
"""
|
| 95 |
+
raise NotImplementedError
|
| 96 |
+
|
| 97 |
+
def reparentChildren(self, newParent):
|
| 98 |
+
"""Move all the children of the current node to newParent.
|
| 99 |
+
This is needed so that trees that don't store text as nodes move the
|
| 100 |
+
text in the correct way
|
| 101 |
+
|
| 102 |
+
:arg newParent: the node to move all this node's children to
|
| 103 |
+
|
| 104 |
+
"""
|
| 105 |
+
# XXX - should this method be made more general?
|
| 106 |
+
for child in self.childNodes:
|
| 107 |
+
newParent.appendChild(child)
|
| 108 |
+
self.childNodes = []
|
| 109 |
+
|
| 110 |
+
def cloneNode(self):
|
| 111 |
+
"""Return a shallow copy of the current node i.e. a node with the same
|
| 112 |
+
name and attributes but with no parent or child nodes
|
| 113 |
+
"""
|
| 114 |
+
raise NotImplementedError
|
| 115 |
+
|
| 116 |
+
def hasContent(self):
|
| 117 |
+
"""Return true if the node has children or text, false otherwise
|
| 118 |
+
"""
|
| 119 |
+
raise NotImplementedError
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
class ActiveFormattingElements(list):
|
| 123 |
+
def append(self, node):
|
| 124 |
+
equalCount = 0
|
| 125 |
+
if node != Marker:
|
| 126 |
+
for element in self[::-1]:
|
| 127 |
+
if element == Marker:
|
| 128 |
+
break
|
| 129 |
+
if self.nodesEqual(element, node):
|
| 130 |
+
equalCount += 1
|
| 131 |
+
if equalCount == 3:
|
| 132 |
+
self.remove(element)
|
| 133 |
+
break
|
| 134 |
+
list.append(self, node)
|
| 135 |
+
|
| 136 |
+
def nodesEqual(self, node1, node2):
|
| 137 |
+
if not node1.nameTuple == node2.nameTuple:
|
| 138 |
+
return False
|
| 139 |
+
|
| 140 |
+
if not node1.attributes == node2.attributes:
|
| 141 |
+
return False
|
| 142 |
+
|
| 143 |
+
return True
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
class TreeBuilder(object):
|
| 147 |
+
"""Base treebuilder implementation
|
| 148 |
+
|
| 149 |
+
* documentClass - the class to use for the bottommost node of a document
|
| 150 |
+
* elementClass - the class to use for HTML Elements
|
| 151 |
+
* commentClass - the class to use for comments
|
| 152 |
+
* doctypeClass - the class to use for doctypes
|
| 153 |
+
|
| 154 |
+
"""
|
| 155 |
+
# pylint:disable=not-callable
|
| 156 |
+
|
| 157 |
+
# Document class
|
| 158 |
+
documentClass = None
|
| 159 |
+
|
| 160 |
+
# The class to use for creating a node
|
| 161 |
+
elementClass = None
|
| 162 |
+
|
| 163 |
+
# The class to use for creating comments
|
| 164 |
+
commentClass = None
|
| 165 |
+
|
| 166 |
+
# The class to use for creating doctypes
|
| 167 |
+
doctypeClass = None
|
| 168 |
+
|
| 169 |
+
# Fragment class
|
| 170 |
+
fragmentClass = None
|
| 171 |
+
|
| 172 |
+
def __init__(self, namespaceHTMLElements):
|
| 173 |
+
"""Create a TreeBuilder
|
| 174 |
+
|
| 175 |
+
:arg namespaceHTMLElements: whether or not to namespace HTML elements
|
| 176 |
+
|
| 177 |
+
"""
|
| 178 |
+
if namespaceHTMLElements:
|
| 179 |
+
self.defaultNamespace = "http://www.w3.org/1999/xhtml"
|
| 180 |
+
else:
|
| 181 |
+
self.defaultNamespace = None
|
| 182 |
+
self.reset()
|
| 183 |
+
|
| 184 |
+
def reset(self):
|
| 185 |
+
self.openElements = []
|
| 186 |
+
self.activeFormattingElements = ActiveFormattingElements()
|
| 187 |
+
|
| 188 |
+
# XXX - rename these to headElement, formElement
|
| 189 |
+
self.headPointer = None
|
| 190 |
+
self.formPointer = None
|
| 191 |
+
|
| 192 |
+
self.insertFromTable = False
|
| 193 |
+
|
| 194 |
+
self.document = self.documentClass()
|
| 195 |
+
|
| 196 |
+
def elementInScope(self, target, variant=None):
|
| 197 |
+
|
| 198 |
+
# If we pass a node in we match that. if we pass a string
|
| 199 |
+
# match any node with that name
|
| 200 |
+
exactNode = hasattr(target, "nameTuple")
|
| 201 |
+
if not exactNode:
|
| 202 |
+
if isinstance(target, text_type):
|
| 203 |
+
target = (namespaces["html"], target)
|
| 204 |
+
assert isinstance(target, tuple)
|
| 205 |
+
|
| 206 |
+
listElements, invert = listElementsMap[variant]
|
| 207 |
+
|
| 208 |
+
for node in reversed(self.openElements):
|
| 209 |
+
if exactNode and node == target:
|
| 210 |
+
return True
|
| 211 |
+
elif not exactNode and node.nameTuple == target:
|
| 212 |
+
return True
|
| 213 |
+
elif (invert ^ (node.nameTuple in listElements)):
|
| 214 |
+
return False
|
| 215 |
+
|
| 216 |
+
assert False # We should never reach this point
|
| 217 |
+
|
| 218 |
+
def reconstructActiveFormattingElements(self):
|
| 219 |
+
# Within this algorithm the order of steps described in the
|
| 220 |
+
# specification is not quite the same as the order of steps in the
|
| 221 |
+
# code. It should still do the same though.
|
| 222 |
+
|
| 223 |
+
# Step 1: stop the algorithm when there's nothing to do.
|
| 224 |
+
if not self.activeFormattingElements:
|
| 225 |
+
return
|
| 226 |
+
|
| 227 |
+
# Step 2 and step 3: we start with the last element. So i is -1.
|
| 228 |
+
i = len(self.activeFormattingElements) - 1
|
| 229 |
+
entry = self.activeFormattingElements[i]
|
| 230 |
+
if entry == Marker or entry in self.openElements:
|
| 231 |
+
return
|
| 232 |
+
|
| 233 |
+
# Step 6
|
| 234 |
+
while entry != Marker and entry not in self.openElements:
|
| 235 |
+
if i == 0:
|
| 236 |
+
# This will be reset to 0 below
|
| 237 |
+
i = -1
|
| 238 |
+
break
|
| 239 |
+
i -= 1
|
| 240 |
+
# Step 5: let entry be one earlier in the list.
|
| 241 |
+
entry = self.activeFormattingElements[i]
|
| 242 |
+
|
| 243 |
+
while True:
|
| 244 |
+
# Step 7
|
| 245 |
+
i += 1
|
| 246 |
+
|
| 247 |
+
# Step 8
|
| 248 |
+
entry = self.activeFormattingElements[i]
|
| 249 |
+
clone = entry.cloneNode() # Mainly to get a new copy of the attributes
|
| 250 |
+
|
| 251 |
+
# Step 9
|
| 252 |
+
element = self.insertElement({"type": "StartTag",
|
| 253 |
+
"name": clone.name,
|
| 254 |
+
"namespace": clone.namespace,
|
| 255 |
+
"data": clone.attributes})
|
| 256 |
+
|
| 257 |
+
# Step 10
|
| 258 |
+
self.activeFormattingElements[i] = element
|
| 259 |
+
|
| 260 |
+
# Step 11
|
| 261 |
+
if element == self.activeFormattingElements[-1]:
|
| 262 |
+
break
|
| 263 |
+
|
| 264 |
+
def clearActiveFormattingElements(self):
|
| 265 |
+
entry = self.activeFormattingElements.pop()
|
| 266 |
+
while self.activeFormattingElements and entry != Marker:
|
| 267 |
+
entry = self.activeFormattingElements.pop()
|
| 268 |
+
|
| 269 |
+
def elementInActiveFormattingElements(self, name):
|
| 270 |
+
"""Check if an element exists between the end of the active
|
| 271 |
+
formatting elements and the last marker. If it does, return it, else
|
| 272 |
+
return false"""
|
| 273 |
+
|
| 274 |
+
for item in self.activeFormattingElements[::-1]:
|
| 275 |
+
# Check for Marker first because if it's a Marker it doesn't have a
|
| 276 |
+
# name attribute.
|
| 277 |
+
if item == Marker:
|
| 278 |
+
break
|
| 279 |
+
elif item.name == name:
|
| 280 |
+
return item
|
| 281 |
+
return False
|
| 282 |
+
|
| 283 |
+
def insertRoot(self, token):
|
| 284 |
+
element = self.createElement(token)
|
| 285 |
+
self.openElements.append(element)
|
| 286 |
+
self.document.appendChild(element)
|
| 287 |
+
|
| 288 |
+
def insertDoctype(self, token):
|
| 289 |
+
name = token["name"]
|
| 290 |
+
publicId = token["publicId"]
|
| 291 |
+
systemId = token["systemId"]
|
| 292 |
+
|
| 293 |
+
doctype = self.doctypeClass(name, publicId, systemId)
|
| 294 |
+
self.document.appendChild(doctype)
|
| 295 |
+
|
| 296 |
+
def insertComment(self, token, parent=None):
|
| 297 |
+
if parent is None:
|
| 298 |
+
parent = self.openElements[-1]
|
| 299 |
+
parent.appendChild(self.commentClass(token["data"]))
|
| 300 |
+
|
| 301 |
+
def createElement(self, token):
|
| 302 |
+
"""Create an element but don't insert it anywhere"""
|
| 303 |
+
name = token["name"]
|
| 304 |
+
namespace = token.get("namespace", self.defaultNamespace)
|
| 305 |
+
element = self.elementClass(name, namespace)
|
| 306 |
+
element.attributes = token["data"]
|
| 307 |
+
return element
|
| 308 |
+
|
| 309 |
+
def _getInsertFromTable(self):
|
| 310 |
+
return self._insertFromTable
|
| 311 |
+
|
| 312 |
+
def _setInsertFromTable(self, value):
|
| 313 |
+
"""Switch the function used to insert an element from the
|
| 314 |
+
normal one to the misnested table one and back again"""
|
| 315 |
+
self._insertFromTable = value
|
| 316 |
+
if value:
|
| 317 |
+
self.insertElement = self.insertElementTable
|
| 318 |
+
else:
|
| 319 |
+
self.insertElement = self.insertElementNormal
|
| 320 |
+
|
| 321 |
+
insertFromTable = property(_getInsertFromTable, _setInsertFromTable)
|
| 322 |
+
|
| 323 |
+
def insertElementNormal(self, token):
|
| 324 |
+
name = token["name"]
|
| 325 |
+
assert isinstance(name, text_type), "Element %s not unicode" % name
|
| 326 |
+
namespace = token.get("namespace", self.defaultNamespace)
|
| 327 |
+
element = self.elementClass(name, namespace)
|
| 328 |
+
element.attributes = token["data"]
|
| 329 |
+
self.openElements[-1].appendChild(element)
|
| 330 |
+
self.openElements.append(element)
|
| 331 |
+
return element
|
| 332 |
+
|
| 333 |
+
def insertElementTable(self, token):
|
| 334 |
+
"""Create an element and insert it into the tree"""
|
| 335 |
+
element = self.createElement(token)
|
| 336 |
+
if self.openElements[-1].name not in tableInsertModeElements:
|
| 337 |
+
return self.insertElementNormal(token)
|
| 338 |
+
else:
|
| 339 |
+
# We should be in the InTable mode. This means we want to do
|
| 340 |
+
# special magic element rearranging
|
| 341 |
+
parent, insertBefore = self.getTableMisnestedNodePosition()
|
| 342 |
+
if insertBefore is None:
|
| 343 |
+
parent.appendChild(element)
|
| 344 |
+
else:
|
| 345 |
+
parent.insertBefore(element, insertBefore)
|
| 346 |
+
self.openElements.append(element)
|
| 347 |
+
return element
|
| 348 |
+
|
| 349 |
+
def insertText(self, data, parent=None):
|
| 350 |
+
"""Insert text data."""
|
| 351 |
+
if parent is None:
|
| 352 |
+
parent = self.openElements[-1]
|
| 353 |
+
|
| 354 |
+
if (not self.insertFromTable or (self.insertFromTable and
|
| 355 |
+
self.openElements[-1].name
|
| 356 |
+
not in tableInsertModeElements)):
|
| 357 |
+
parent.insertText(data)
|
| 358 |
+
else:
|
| 359 |
+
# We should be in the InTable mode. This means we want to do
|
| 360 |
+
# special magic element rearranging
|
| 361 |
+
parent, insertBefore = self.getTableMisnestedNodePosition()
|
| 362 |
+
parent.insertText(data, insertBefore)
|
| 363 |
+
|
| 364 |
+
def getTableMisnestedNodePosition(self):
|
| 365 |
+
"""Get the foster parent element, and sibling to insert before
|
| 366 |
+
(or None) when inserting a misnested table node"""
|
| 367 |
+
# The foster parent element is the one which comes before the most
|
| 368 |
+
# recently opened table element
|
| 369 |
+
# XXX - this is really inelegant
|
| 370 |
+
lastTable = None
|
| 371 |
+
fosterParent = None
|
| 372 |
+
insertBefore = None
|
| 373 |
+
for elm in self.openElements[::-1]:
|
| 374 |
+
if elm.name == "table":
|
| 375 |
+
lastTable = elm
|
| 376 |
+
break
|
| 377 |
+
if lastTable:
|
| 378 |
+
# XXX - we should really check that this parent is actually a
|
| 379 |
+
# node here
|
| 380 |
+
if lastTable.parent:
|
| 381 |
+
fosterParent = lastTable.parent
|
| 382 |
+
insertBefore = lastTable
|
| 383 |
+
else:
|
| 384 |
+
fosterParent = self.openElements[
|
| 385 |
+
self.openElements.index(lastTable) - 1]
|
| 386 |
+
else:
|
| 387 |
+
fosterParent = self.openElements[0]
|
| 388 |
+
return fosterParent, insertBefore
|
| 389 |
+
|
| 390 |
+
def generateImpliedEndTags(self, exclude=None):
|
| 391 |
+
name = self.openElements[-1].name
|
| 392 |
+
# XXX td, th and tr are not actually needed
|
| 393 |
+
if (name in frozenset(("dd", "dt", "li", "option", "optgroup", "p", "rp", "rt")) and
|
| 394 |
+
name != exclude):
|
| 395 |
+
self.openElements.pop()
|
| 396 |
+
# XXX This is not entirely what the specification says. We should
|
| 397 |
+
# investigate it more closely.
|
| 398 |
+
self.generateImpliedEndTags(exclude)
|
| 399 |
+
|
| 400 |
+
def getDocument(self):
|
| 401 |
+
"""Return the final tree"""
|
| 402 |
+
return self.document
|
| 403 |
+
|
| 404 |
+
def getFragment(self):
|
| 405 |
+
"""Return the final fragment"""
|
| 406 |
+
# assert self.innerHTML
|
| 407 |
+
fragment = self.fragmentClass()
|
| 408 |
+
self.openElements[0].reparentChildren(fragment)
|
| 409 |
+
return fragment
|
| 410 |
+
|
| 411 |
+
def testSerializer(self, node):
|
| 412 |
+
"""Serialize the subtree of node in the format required by unit tests
|
| 413 |
+
|
| 414 |
+
:arg node: the node from which to start serializing
|
| 415 |
+
|
| 416 |
+
"""
|
| 417 |
+
raise NotImplementedError
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/html5lib/treebuilders/dom.py
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import, division, unicode_literals
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
try:
|
| 5 |
+
from collections.abc import MutableMapping
|
| 6 |
+
except ImportError: # Python 2.7
|
| 7 |
+
from collections import MutableMapping
|
| 8 |
+
from xml.dom import minidom, Node
|
| 9 |
+
import weakref
|
| 10 |
+
|
| 11 |
+
from . import base
|
| 12 |
+
from .. import constants
|
| 13 |
+
from ..constants import namespaces
|
| 14 |
+
from .._utils import moduleFactoryFactory
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def getDomBuilder(DomImplementation):
|
| 18 |
+
Dom = DomImplementation
|
| 19 |
+
|
| 20 |
+
class AttrList(MutableMapping):
|
| 21 |
+
def __init__(self, element):
|
| 22 |
+
self.element = element
|
| 23 |
+
|
| 24 |
+
def __iter__(self):
|
| 25 |
+
return iter(self.element.attributes.keys())
|
| 26 |
+
|
| 27 |
+
def __setitem__(self, name, value):
|
| 28 |
+
if isinstance(name, tuple):
|
| 29 |
+
raise NotImplementedError
|
| 30 |
+
else:
|
| 31 |
+
attr = self.element.ownerDocument.createAttribute(name)
|
| 32 |
+
attr.value = value
|
| 33 |
+
self.element.attributes[name] = attr
|
| 34 |
+
|
| 35 |
+
def __len__(self):
|
| 36 |
+
return len(self.element.attributes)
|
| 37 |
+
|
| 38 |
+
def items(self):
|
| 39 |
+
return list(self.element.attributes.items())
|
| 40 |
+
|
| 41 |
+
def values(self):
|
| 42 |
+
return list(self.element.attributes.values())
|
| 43 |
+
|
| 44 |
+
def __getitem__(self, name):
|
| 45 |
+
if isinstance(name, tuple):
|
| 46 |
+
raise NotImplementedError
|
| 47 |
+
else:
|
| 48 |
+
return self.element.attributes[name].value
|
| 49 |
+
|
| 50 |
+
def __delitem__(self, name):
|
| 51 |
+
if isinstance(name, tuple):
|
| 52 |
+
raise NotImplementedError
|
| 53 |
+
else:
|
| 54 |
+
del self.element.attributes[name]
|
| 55 |
+
|
| 56 |
+
class NodeBuilder(base.Node):
|
| 57 |
+
def __init__(self, element):
|
| 58 |
+
base.Node.__init__(self, element.nodeName)
|
| 59 |
+
self.element = element
|
| 60 |
+
|
| 61 |
+
namespace = property(lambda self: hasattr(self.element, "namespaceURI") and
|
| 62 |
+
self.element.namespaceURI or None)
|
| 63 |
+
|
| 64 |
+
def appendChild(self, node):
|
| 65 |
+
node.parent = self
|
| 66 |
+
self.element.appendChild(node.element)
|
| 67 |
+
|
| 68 |
+
def insertText(self, data, insertBefore=None):
|
| 69 |
+
text = self.element.ownerDocument.createTextNode(data)
|
| 70 |
+
if insertBefore:
|
| 71 |
+
self.element.insertBefore(text, insertBefore.element)
|
| 72 |
+
else:
|
| 73 |
+
self.element.appendChild(text)
|
| 74 |
+
|
| 75 |
+
def insertBefore(self, node, refNode):
|
| 76 |
+
self.element.insertBefore(node.element, refNode.element)
|
| 77 |
+
node.parent = self
|
| 78 |
+
|
| 79 |
+
def removeChild(self, node):
|
| 80 |
+
if node.element.parentNode == self.element:
|
| 81 |
+
self.element.removeChild(node.element)
|
| 82 |
+
node.parent = None
|
| 83 |
+
|
| 84 |
+
def reparentChildren(self, newParent):
|
| 85 |
+
while self.element.hasChildNodes():
|
| 86 |
+
child = self.element.firstChild
|
| 87 |
+
self.element.removeChild(child)
|
| 88 |
+
newParent.element.appendChild(child)
|
| 89 |
+
self.childNodes = []
|
| 90 |
+
|
| 91 |
+
def getAttributes(self):
|
| 92 |
+
return AttrList(self.element)
|
| 93 |
+
|
| 94 |
+
def setAttributes(self, attributes):
|
| 95 |
+
if attributes:
|
| 96 |
+
for name, value in list(attributes.items()):
|
| 97 |
+
if isinstance(name, tuple):
|
| 98 |
+
if name[0] is not None:
|
| 99 |
+
qualifiedName = (name[0] + ":" + name[1])
|
| 100 |
+
else:
|
| 101 |
+
qualifiedName = name[1]
|
| 102 |
+
self.element.setAttributeNS(name[2], qualifiedName,
|
| 103 |
+
value)
|
| 104 |
+
else:
|
| 105 |
+
self.element.setAttribute(
|
| 106 |
+
name, value)
|
| 107 |
+
attributes = property(getAttributes, setAttributes)
|
| 108 |
+
|
| 109 |
+
def cloneNode(self):
|
| 110 |
+
return NodeBuilder(self.element.cloneNode(False))
|
| 111 |
+
|
| 112 |
+
def hasContent(self):
|
| 113 |
+
return self.element.hasChildNodes()
|
| 114 |
+
|
| 115 |
+
def getNameTuple(self):
|
| 116 |
+
if self.namespace is None:
|
| 117 |
+
return namespaces["html"], self.name
|
| 118 |
+
else:
|
| 119 |
+
return self.namespace, self.name
|
| 120 |
+
|
| 121 |
+
nameTuple = property(getNameTuple)
|
| 122 |
+
|
| 123 |
+
class TreeBuilder(base.TreeBuilder): # pylint:disable=unused-variable
|
| 124 |
+
def documentClass(self):
|
| 125 |
+
self.dom = Dom.getDOMImplementation().createDocument(None, None, None)
|
| 126 |
+
return weakref.proxy(self)
|
| 127 |
+
|
| 128 |
+
def insertDoctype(self, token):
|
| 129 |
+
name = token["name"]
|
| 130 |
+
publicId = token["publicId"]
|
| 131 |
+
systemId = token["systemId"]
|
| 132 |
+
|
| 133 |
+
domimpl = Dom.getDOMImplementation()
|
| 134 |
+
doctype = domimpl.createDocumentType(name, publicId, systemId)
|
| 135 |
+
self.document.appendChild(NodeBuilder(doctype))
|
| 136 |
+
if Dom == minidom:
|
| 137 |
+
doctype.ownerDocument = self.dom
|
| 138 |
+
|
| 139 |
+
def elementClass(self, name, namespace=None):
|
| 140 |
+
if namespace is None and self.defaultNamespace is None:
|
| 141 |
+
node = self.dom.createElement(name)
|
| 142 |
+
else:
|
| 143 |
+
node = self.dom.createElementNS(namespace, name)
|
| 144 |
+
|
| 145 |
+
return NodeBuilder(node)
|
| 146 |
+
|
| 147 |
+
def commentClass(self, data):
|
| 148 |
+
return NodeBuilder(self.dom.createComment(data))
|
| 149 |
+
|
| 150 |
+
def fragmentClass(self):
|
| 151 |
+
return NodeBuilder(self.dom.createDocumentFragment())
|
| 152 |
+
|
| 153 |
+
def appendChild(self, node):
|
| 154 |
+
self.dom.appendChild(node.element)
|
| 155 |
+
|
| 156 |
+
def testSerializer(self, element):
|
| 157 |
+
return testSerializer(element)
|
| 158 |
+
|
| 159 |
+
def getDocument(self):
|
| 160 |
+
return self.dom
|
| 161 |
+
|
| 162 |
+
def getFragment(self):
|
| 163 |
+
return base.TreeBuilder.getFragment(self).element
|
| 164 |
+
|
| 165 |
+
def insertText(self, data, parent=None):
|
| 166 |
+
data = data
|
| 167 |
+
if parent != self:
|
| 168 |
+
base.TreeBuilder.insertText(self, data, parent)
|
| 169 |
+
else:
|
| 170 |
+
# HACK: allow text nodes as children of the document node
|
| 171 |
+
if hasattr(self.dom, '_child_node_types'):
|
| 172 |
+
# pylint:disable=protected-access
|
| 173 |
+
if Node.TEXT_NODE not in self.dom._child_node_types:
|
| 174 |
+
self.dom._child_node_types = list(self.dom._child_node_types)
|
| 175 |
+
self.dom._child_node_types.append(Node.TEXT_NODE)
|
| 176 |
+
self.dom.appendChild(self.dom.createTextNode(data))
|
| 177 |
+
|
| 178 |
+
implementation = DomImplementation
|
| 179 |
+
name = None
|
| 180 |
+
|
| 181 |
+
def testSerializer(element):
|
| 182 |
+
element.normalize()
|
| 183 |
+
rv = []
|
| 184 |
+
|
| 185 |
+
def serializeElement(element, indent=0):
|
| 186 |
+
if element.nodeType == Node.DOCUMENT_TYPE_NODE:
|
| 187 |
+
if element.name:
|
| 188 |
+
if element.publicId or element.systemId:
|
| 189 |
+
publicId = element.publicId or ""
|
| 190 |
+
systemId = element.systemId or ""
|
| 191 |
+
rv.append("""|%s<!DOCTYPE %s "%s" "%s">""" %
|
| 192 |
+
(' ' * indent, element.name, publicId, systemId))
|
| 193 |
+
else:
|
| 194 |
+
rv.append("|%s<!DOCTYPE %s>" % (' ' * indent, element.name))
|
| 195 |
+
else:
|
| 196 |
+
rv.append("|%s<!DOCTYPE >" % (' ' * indent,))
|
| 197 |
+
elif element.nodeType == Node.DOCUMENT_NODE:
|
| 198 |
+
rv.append("#document")
|
| 199 |
+
elif element.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
|
| 200 |
+
rv.append("#document-fragment")
|
| 201 |
+
elif element.nodeType == Node.COMMENT_NODE:
|
| 202 |
+
rv.append("|%s<!-- %s -->" % (' ' * indent, element.nodeValue))
|
| 203 |
+
elif element.nodeType == Node.TEXT_NODE:
|
| 204 |
+
rv.append("|%s\"%s\"" % (' ' * indent, element.nodeValue))
|
| 205 |
+
else:
|
| 206 |
+
if (hasattr(element, "namespaceURI") and
|
| 207 |
+
element.namespaceURI is not None):
|
| 208 |
+
name = "%s %s" % (constants.prefixes[element.namespaceURI],
|
| 209 |
+
element.nodeName)
|
| 210 |
+
else:
|
| 211 |
+
name = element.nodeName
|
| 212 |
+
rv.append("|%s<%s>" % (' ' * indent, name))
|
| 213 |
+
if element.hasAttributes():
|
| 214 |
+
attributes = []
|
| 215 |
+
for i in range(len(element.attributes)):
|
| 216 |
+
attr = element.attributes.item(i)
|
| 217 |
+
name = attr.nodeName
|
| 218 |
+
value = attr.value
|
| 219 |
+
ns = attr.namespaceURI
|
| 220 |
+
if ns:
|
| 221 |
+
name = "%s %s" % (constants.prefixes[ns], attr.localName)
|
| 222 |
+
else:
|
| 223 |
+
name = attr.nodeName
|
| 224 |
+
attributes.append((name, value))
|
| 225 |
+
|
| 226 |
+
for name, value in sorted(attributes):
|
| 227 |
+
rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value))
|
| 228 |
+
indent += 2
|
| 229 |
+
for child in element.childNodes:
|
| 230 |
+
serializeElement(child, indent)
|
| 231 |
+
serializeElement(element, 0)
|
| 232 |
+
|
| 233 |
+
return "\n".join(rv)
|
| 234 |
+
|
| 235 |
+
return locals()
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
# The actual means to get a module!
|
| 239 |
+
getDomModule = moduleFactoryFactory(getDomBuilder)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/tomli/__init__.py
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""A lil' TOML parser."""
|
| 2 |
+
|
| 3 |
+
__all__ = ("loads", "load", "TOMLDecodeError")
|
| 4 |
+
__version__ = "1.0.3" # DO NOT EDIT THIS LINE MANUALLY. LET bump2version UTILITY DO IT
|
| 5 |
+
|
| 6 |
+
from pip._vendor.tomli._parser import TOMLDecodeError, load, loads
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/tomli/_parser.py
ADDED
|
@@ -0,0 +1,703 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import string
|
| 2 |
+
from types import MappingProxyType
|
| 3 |
+
from typing import (
|
| 4 |
+
TYPE_CHECKING,
|
| 5 |
+
Any,
|
| 6 |
+
Callable,
|
| 7 |
+
Dict,
|
| 8 |
+
FrozenSet,
|
| 9 |
+
Iterable,
|
| 10 |
+
Optional,
|
| 11 |
+
TextIO,
|
| 12 |
+
Tuple,
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
from pip._vendor.tomli._re import (
|
| 16 |
+
RE_BIN,
|
| 17 |
+
RE_DATETIME,
|
| 18 |
+
RE_HEX,
|
| 19 |
+
RE_LOCALTIME,
|
| 20 |
+
RE_NUMBER,
|
| 21 |
+
RE_OCT,
|
| 22 |
+
match_to_datetime,
|
| 23 |
+
match_to_localtime,
|
| 24 |
+
match_to_number,
|
| 25 |
+
)
|
| 26 |
+
|
| 27 |
+
if TYPE_CHECKING:
|
| 28 |
+
from re import Pattern
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127))
|
| 32 |
+
|
| 33 |
+
# Neither of these sets include quotation mark or backslash. They are
|
| 34 |
+
# currently handled as separate cases in the parser functions.
|
| 35 |
+
ILLEGAL_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t")
|
| 36 |
+
ILLEGAL_MULTILINE_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t\n\r")
|
| 37 |
+
|
| 38 |
+
ILLEGAL_LITERAL_STR_CHARS = ILLEGAL_BASIC_STR_CHARS
|
| 39 |
+
ILLEGAL_MULTILINE_LITERAL_STR_CHARS = ASCII_CTRL - frozenset("\t\n")
|
| 40 |
+
|
| 41 |
+
ILLEGAL_COMMENT_CHARS = ILLEGAL_BASIC_STR_CHARS
|
| 42 |
+
|
| 43 |
+
TOML_WS = frozenset(" \t")
|
| 44 |
+
TOML_WS_AND_NEWLINE = TOML_WS | frozenset("\n")
|
| 45 |
+
BARE_KEY_CHARS = frozenset(string.ascii_letters + string.digits + "-_")
|
| 46 |
+
KEY_INITIAL_CHARS = BARE_KEY_CHARS | frozenset("\"'")
|
| 47 |
+
|
| 48 |
+
BASIC_STR_ESCAPE_REPLACEMENTS = MappingProxyType(
|
| 49 |
+
{
|
| 50 |
+
"\\b": "\u0008", # backspace
|
| 51 |
+
"\\t": "\u0009", # tab
|
| 52 |
+
"\\n": "\u000A", # linefeed
|
| 53 |
+
"\\f": "\u000C", # form feed
|
| 54 |
+
"\\r": "\u000D", # carriage return
|
| 55 |
+
'\\"': "\u0022", # quote
|
| 56 |
+
"\\\\": "\u005C", # backslash
|
| 57 |
+
}
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
# Type annotations
|
| 61 |
+
ParseFloat = Callable[[str], Any]
|
| 62 |
+
Key = Tuple[str, ...]
|
| 63 |
+
Pos = int
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
class TOMLDecodeError(ValueError):
|
| 67 |
+
"""An error raised if a document is not valid TOML."""
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
def load(fp: TextIO, *, parse_float: ParseFloat = float) -> Dict[str, Any]:
|
| 71 |
+
"""Parse TOML from a file object."""
|
| 72 |
+
s = fp.read()
|
| 73 |
+
return loads(s, parse_float=parse_float)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def loads(s: str, *, parse_float: ParseFloat = float) -> Dict[str, Any]: # noqa: C901
|
| 77 |
+
"""Parse TOML from a string."""
|
| 78 |
+
|
| 79 |
+
# The spec allows converting "\r\n" to "\n", even in string
|
| 80 |
+
# literals. Let's do so to simplify parsing.
|
| 81 |
+
src = s.replace("\r\n", "\n")
|
| 82 |
+
pos = 0
|
| 83 |
+
state = State()
|
| 84 |
+
|
| 85 |
+
# Parse one statement at a time
|
| 86 |
+
# (typically means one line in TOML source)
|
| 87 |
+
while True:
|
| 88 |
+
# 1. Skip line leading whitespace
|
| 89 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 90 |
+
|
| 91 |
+
# 2. Parse rules. Expect one of the following:
|
| 92 |
+
# - end of file
|
| 93 |
+
# - end of line
|
| 94 |
+
# - comment
|
| 95 |
+
# - key/value pair
|
| 96 |
+
# - append dict to list (and move to its namespace)
|
| 97 |
+
# - create dict (and move to its namespace)
|
| 98 |
+
# Skip trailing whitespace when applicable.
|
| 99 |
+
try:
|
| 100 |
+
char = src[pos]
|
| 101 |
+
except IndexError:
|
| 102 |
+
break
|
| 103 |
+
if char == "\n":
|
| 104 |
+
pos += 1
|
| 105 |
+
continue
|
| 106 |
+
if char in KEY_INITIAL_CHARS:
|
| 107 |
+
pos = key_value_rule(src, pos, state, parse_float)
|
| 108 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 109 |
+
elif char == "[":
|
| 110 |
+
try:
|
| 111 |
+
second_char: Optional[str] = src[pos + 1]
|
| 112 |
+
except IndexError:
|
| 113 |
+
second_char = None
|
| 114 |
+
if second_char == "[":
|
| 115 |
+
pos = create_list_rule(src, pos, state)
|
| 116 |
+
else:
|
| 117 |
+
pos = create_dict_rule(src, pos, state)
|
| 118 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 119 |
+
elif char != "#":
|
| 120 |
+
raise suffixed_err(src, pos, "Invalid statement")
|
| 121 |
+
|
| 122 |
+
# 3. Skip comment
|
| 123 |
+
pos = skip_comment(src, pos)
|
| 124 |
+
|
| 125 |
+
# 4. Expect end of line or end of file
|
| 126 |
+
try:
|
| 127 |
+
char = src[pos]
|
| 128 |
+
except IndexError:
|
| 129 |
+
break
|
| 130 |
+
if char != "\n":
|
| 131 |
+
raise suffixed_err(
|
| 132 |
+
src, pos, "Expected newline or end of document after a statement"
|
| 133 |
+
)
|
| 134 |
+
pos += 1
|
| 135 |
+
|
| 136 |
+
return state.out.dict
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class State:
|
| 140 |
+
def __init__(self) -> None:
|
| 141 |
+
# Mutable, read-only
|
| 142 |
+
self.out = NestedDict()
|
| 143 |
+
self.flags = Flags()
|
| 144 |
+
|
| 145 |
+
# Immutable, read and write
|
| 146 |
+
self.header_namespace: Key = ()
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
class Flags:
|
| 150 |
+
"""Flags that map to parsed keys/namespaces."""
|
| 151 |
+
|
| 152 |
+
# Marks an immutable namespace (inline array or inline table).
|
| 153 |
+
FROZEN = 0
|
| 154 |
+
# Marks a nest that has been explicitly created and can no longer
|
| 155 |
+
# be opened using the "[table]" syntax.
|
| 156 |
+
EXPLICIT_NEST = 1
|
| 157 |
+
|
| 158 |
+
def __init__(self) -> None:
|
| 159 |
+
self._flags: Dict[str, dict] = {}
|
| 160 |
+
|
| 161 |
+
def unset_all(self, key: Key) -> None:
|
| 162 |
+
cont = self._flags
|
| 163 |
+
for k in key[:-1]:
|
| 164 |
+
if k not in cont:
|
| 165 |
+
return
|
| 166 |
+
cont = cont[k]["nested"]
|
| 167 |
+
cont.pop(key[-1], None)
|
| 168 |
+
|
| 169 |
+
def set_for_relative_key(self, head_key: Key, rel_key: Key, flag: int) -> None:
|
| 170 |
+
cont = self._flags
|
| 171 |
+
for k in head_key:
|
| 172 |
+
if k not in cont:
|
| 173 |
+
cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}}
|
| 174 |
+
cont = cont[k]["nested"]
|
| 175 |
+
for k in rel_key:
|
| 176 |
+
if k in cont:
|
| 177 |
+
cont[k]["flags"].add(flag)
|
| 178 |
+
else:
|
| 179 |
+
cont[k] = {"flags": {flag}, "recursive_flags": set(), "nested": {}}
|
| 180 |
+
cont = cont[k]["nested"]
|
| 181 |
+
|
| 182 |
+
def set(self, key: Key, flag: int, *, recursive: bool) -> None: # noqa: A003
|
| 183 |
+
cont = self._flags
|
| 184 |
+
key_parent, key_stem = key[:-1], key[-1]
|
| 185 |
+
for k in key_parent:
|
| 186 |
+
if k not in cont:
|
| 187 |
+
cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}}
|
| 188 |
+
cont = cont[k]["nested"]
|
| 189 |
+
if key_stem not in cont:
|
| 190 |
+
cont[key_stem] = {"flags": set(), "recursive_flags": set(), "nested": {}}
|
| 191 |
+
cont[key_stem]["recursive_flags" if recursive else "flags"].add(flag)
|
| 192 |
+
|
| 193 |
+
def is_(self, key: Key, flag: int) -> bool:
|
| 194 |
+
if not key:
|
| 195 |
+
return False # document root has no flags
|
| 196 |
+
cont = self._flags
|
| 197 |
+
for k in key[:-1]:
|
| 198 |
+
if k not in cont:
|
| 199 |
+
return False
|
| 200 |
+
inner_cont = cont[k]
|
| 201 |
+
if flag in inner_cont["recursive_flags"]:
|
| 202 |
+
return True
|
| 203 |
+
cont = inner_cont["nested"]
|
| 204 |
+
key_stem = key[-1]
|
| 205 |
+
if key_stem in cont:
|
| 206 |
+
cont = cont[key_stem]
|
| 207 |
+
return flag in cont["flags"] or flag in cont["recursive_flags"]
|
| 208 |
+
return False
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
class NestedDict:
|
| 212 |
+
def __init__(self) -> None:
|
| 213 |
+
# The parsed content of the TOML document
|
| 214 |
+
self.dict: Dict[str, Any] = {}
|
| 215 |
+
|
| 216 |
+
def get_or_create_nest(
|
| 217 |
+
self,
|
| 218 |
+
key: Key,
|
| 219 |
+
*,
|
| 220 |
+
access_lists: bool = True,
|
| 221 |
+
) -> dict:
|
| 222 |
+
cont: Any = self.dict
|
| 223 |
+
for k in key:
|
| 224 |
+
if k not in cont:
|
| 225 |
+
cont[k] = {}
|
| 226 |
+
cont = cont[k]
|
| 227 |
+
if access_lists and isinstance(cont, list):
|
| 228 |
+
cont = cont[-1]
|
| 229 |
+
if not isinstance(cont, dict):
|
| 230 |
+
raise KeyError("There is no nest behind this key")
|
| 231 |
+
return cont
|
| 232 |
+
|
| 233 |
+
def append_nest_to_list(self, key: Key) -> None:
|
| 234 |
+
cont = self.get_or_create_nest(key[:-1])
|
| 235 |
+
last_key = key[-1]
|
| 236 |
+
if last_key in cont:
|
| 237 |
+
list_ = cont[last_key]
|
| 238 |
+
if not isinstance(list_, list):
|
| 239 |
+
raise KeyError("An object other than list found behind this key")
|
| 240 |
+
list_.append({})
|
| 241 |
+
else:
|
| 242 |
+
cont[last_key] = [{}]
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos:
|
| 246 |
+
try:
|
| 247 |
+
while src[pos] in chars:
|
| 248 |
+
pos += 1
|
| 249 |
+
except IndexError:
|
| 250 |
+
pass
|
| 251 |
+
return pos
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def skip_until(
|
| 255 |
+
src: str,
|
| 256 |
+
pos: Pos,
|
| 257 |
+
expect: str,
|
| 258 |
+
*,
|
| 259 |
+
error_on: FrozenSet[str],
|
| 260 |
+
error_on_eof: bool,
|
| 261 |
+
) -> Pos:
|
| 262 |
+
try:
|
| 263 |
+
new_pos = src.index(expect, pos)
|
| 264 |
+
except ValueError:
|
| 265 |
+
new_pos = len(src)
|
| 266 |
+
if error_on_eof:
|
| 267 |
+
raise suffixed_err(src, new_pos, f'Expected "{expect!r}"')
|
| 268 |
+
|
| 269 |
+
bad_chars = error_on.intersection(src[pos:new_pos])
|
| 270 |
+
if bad_chars:
|
| 271 |
+
bad_char = next(iter(bad_chars))
|
| 272 |
+
bad_pos = src.index(bad_char, pos)
|
| 273 |
+
raise suffixed_err(src, bad_pos, f'Found invalid character "{bad_char!r}"')
|
| 274 |
+
return new_pos
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
def skip_comment(src: str, pos: Pos) -> Pos:
|
| 278 |
+
try:
|
| 279 |
+
char: Optional[str] = src[pos]
|
| 280 |
+
except IndexError:
|
| 281 |
+
char = None
|
| 282 |
+
if char == "#":
|
| 283 |
+
return skip_until(
|
| 284 |
+
src, pos + 1, "\n", error_on=ILLEGAL_COMMENT_CHARS, error_on_eof=False
|
| 285 |
+
)
|
| 286 |
+
return pos
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos:
|
| 290 |
+
while True:
|
| 291 |
+
pos_before_skip = pos
|
| 292 |
+
pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE)
|
| 293 |
+
pos = skip_comment(src, pos)
|
| 294 |
+
if pos == pos_before_skip:
|
| 295 |
+
return pos
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
def create_dict_rule(src: str, pos: Pos, state: State) -> Pos:
|
| 299 |
+
pos += 1 # Skip "["
|
| 300 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 301 |
+
pos, key = parse_key(src, pos)
|
| 302 |
+
|
| 303 |
+
if state.flags.is_(key, Flags.EXPLICIT_NEST) or state.flags.is_(key, Flags.FROZEN):
|
| 304 |
+
raise suffixed_err(src, pos, f"Can not declare {key} twice")
|
| 305 |
+
state.flags.set(key, Flags.EXPLICIT_NEST, recursive=False)
|
| 306 |
+
try:
|
| 307 |
+
state.out.get_or_create_nest(key)
|
| 308 |
+
except KeyError:
|
| 309 |
+
raise suffixed_err(src, pos, "Can not overwrite a value")
|
| 310 |
+
state.header_namespace = key
|
| 311 |
+
|
| 312 |
+
if src[pos : pos + 1] != "]":
|
| 313 |
+
raise suffixed_err(src, pos, 'Expected "]" at the end of a table declaration')
|
| 314 |
+
return pos + 1
|
| 315 |
+
|
| 316 |
+
|
| 317 |
+
def create_list_rule(src: str, pos: Pos, state: State) -> Pos:
|
| 318 |
+
pos += 2 # Skip "[["
|
| 319 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 320 |
+
pos, key = parse_key(src, pos)
|
| 321 |
+
|
| 322 |
+
if state.flags.is_(key, Flags.FROZEN):
|
| 323 |
+
raise suffixed_err(src, pos, f"Can not mutate immutable namespace {key}")
|
| 324 |
+
# Free the namespace now that it points to another empty list item...
|
| 325 |
+
state.flags.unset_all(key)
|
| 326 |
+
# ...but this key precisely is still prohibited from table declaration
|
| 327 |
+
state.flags.set(key, Flags.EXPLICIT_NEST, recursive=False)
|
| 328 |
+
try:
|
| 329 |
+
state.out.append_nest_to_list(key)
|
| 330 |
+
except KeyError:
|
| 331 |
+
raise suffixed_err(src, pos, "Can not overwrite a value")
|
| 332 |
+
state.header_namespace = key
|
| 333 |
+
|
| 334 |
+
end_marker = src[pos : pos + 2]
|
| 335 |
+
if end_marker != "]]":
|
| 336 |
+
raise suffixed_err(
|
| 337 |
+
src,
|
| 338 |
+
pos,
|
| 339 |
+
f'Found "{end_marker!r}" at the end of an array declaration.'
|
| 340 |
+
' Expected "]]"',
|
| 341 |
+
)
|
| 342 |
+
return pos + 2
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
def key_value_rule(src: str, pos: Pos, state: State, parse_float: ParseFloat) -> Pos:
|
| 346 |
+
pos, key, value = parse_key_value_pair(src, pos, parse_float)
|
| 347 |
+
key_parent, key_stem = key[:-1], key[-1]
|
| 348 |
+
abs_key_parent = state.header_namespace + key_parent
|
| 349 |
+
|
| 350 |
+
if state.flags.is_(abs_key_parent, Flags.FROZEN):
|
| 351 |
+
raise suffixed_err(
|
| 352 |
+
src, pos, f"Can not mutate immutable namespace {abs_key_parent}"
|
| 353 |
+
)
|
| 354 |
+
# Containers in the relative path can't be opened with the table syntax after this
|
| 355 |
+
state.flags.set_for_relative_key(state.header_namespace, key, Flags.EXPLICIT_NEST)
|
| 356 |
+
try:
|
| 357 |
+
nest = state.out.get_or_create_nest(abs_key_parent)
|
| 358 |
+
except KeyError:
|
| 359 |
+
raise suffixed_err(src, pos, "Can not overwrite a value")
|
| 360 |
+
if key_stem in nest:
|
| 361 |
+
raise suffixed_err(src, pos, "Can not overwrite a value")
|
| 362 |
+
# Mark inline table and array namespaces recursively immutable
|
| 363 |
+
if isinstance(value, (dict, list)):
|
| 364 |
+
abs_key = state.header_namespace + key
|
| 365 |
+
state.flags.set(abs_key, Flags.FROZEN, recursive=True)
|
| 366 |
+
nest[key_stem] = value
|
| 367 |
+
return pos
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
def parse_key_value_pair(
|
| 371 |
+
src: str, pos: Pos, parse_float: ParseFloat
|
| 372 |
+
) -> Tuple[Pos, Key, Any]:
|
| 373 |
+
pos, key = parse_key(src, pos)
|
| 374 |
+
try:
|
| 375 |
+
char: Optional[str] = src[pos]
|
| 376 |
+
except IndexError:
|
| 377 |
+
char = None
|
| 378 |
+
if char != "=":
|
| 379 |
+
raise suffixed_err(src, pos, 'Expected "=" after a key in a key/value pair')
|
| 380 |
+
pos += 1
|
| 381 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 382 |
+
pos, value = parse_value(src, pos, parse_float)
|
| 383 |
+
return pos, key, value
|
| 384 |
+
|
| 385 |
+
|
| 386 |
+
def parse_key(src: str, pos: Pos) -> Tuple[Pos, Key]:
|
| 387 |
+
pos, key_part = parse_key_part(src, pos)
|
| 388 |
+
key = [key_part]
|
| 389 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 390 |
+
while True:
|
| 391 |
+
try:
|
| 392 |
+
char: Optional[str] = src[pos]
|
| 393 |
+
except IndexError:
|
| 394 |
+
char = None
|
| 395 |
+
if char != ".":
|
| 396 |
+
return pos, tuple(key)
|
| 397 |
+
pos += 1
|
| 398 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 399 |
+
pos, key_part = parse_key_part(src, pos)
|
| 400 |
+
key.append(key_part)
|
| 401 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
def parse_key_part(src: str, pos: Pos) -> Tuple[Pos, str]:
|
| 405 |
+
try:
|
| 406 |
+
char: Optional[str] = src[pos]
|
| 407 |
+
except IndexError:
|
| 408 |
+
char = None
|
| 409 |
+
if char in BARE_KEY_CHARS:
|
| 410 |
+
start_pos = pos
|
| 411 |
+
pos = skip_chars(src, pos, BARE_KEY_CHARS)
|
| 412 |
+
return pos, src[start_pos:pos]
|
| 413 |
+
if char == "'":
|
| 414 |
+
return parse_literal_str(src, pos)
|
| 415 |
+
if char == '"':
|
| 416 |
+
return parse_one_line_basic_str(src, pos)
|
| 417 |
+
raise suffixed_err(src, pos, "Invalid initial character for a key part")
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
def parse_one_line_basic_str(src: str, pos: Pos) -> Tuple[Pos, str]:
|
| 421 |
+
pos += 1
|
| 422 |
+
return parse_basic_str(src, pos, multiline=False)
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, list]:
|
| 426 |
+
pos += 1
|
| 427 |
+
array: list = []
|
| 428 |
+
|
| 429 |
+
pos = skip_comments_and_array_ws(src, pos)
|
| 430 |
+
if src[pos : pos + 1] == "]":
|
| 431 |
+
return pos + 1, array
|
| 432 |
+
while True:
|
| 433 |
+
pos, val = parse_value(src, pos, parse_float)
|
| 434 |
+
array.append(val)
|
| 435 |
+
pos = skip_comments_and_array_ws(src, pos)
|
| 436 |
+
|
| 437 |
+
c = src[pos : pos + 1]
|
| 438 |
+
if c == "]":
|
| 439 |
+
return pos + 1, array
|
| 440 |
+
if c != ",":
|
| 441 |
+
raise suffixed_err(src, pos, "Unclosed array")
|
| 442 |
+
pos += 1
|
| 443 |
+
|
| 444 |
+
pos = skip_comments_and_array_ws(src, pos)
|
| 445 |
+
if src[pos : pos + 1] == "]":
|
| 446 |
+
return pos + 1, array
|
| 447 |
+
|
| 448 |
+
|
| 449 |
+
def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> Tuple[Pos, dict]:
|
| 450 |
+
pos += 1
|
| 451 |
+
nested_dict = NestedDict()
|
| 452 |
+
flags = Flags()
|
| 453 |
+
|
| 454 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 455 |
+
if src[pos : pos + 1] == "}":
|
| 456 |
+
return pos + 1, nested_dict.dict
|
| 457 |
+
while True:
|
| 458 |
+
pos, key, value = parse_key_value_pair(src, pos, parse_float)
|
| 459 |
+
key_parent, key_stem = key[:-1], key[-1]
|
| 460 |
+
if flags.is_(key, Flags.FROZEN):
|
| 461 |
+
raise suffixed_err(src, pos, f"Can not mutate immutable namespace {key}")
|
| 462 |
+
try:
|
| 463 |
+
nest = nested_dict.get_or_create_nest(key_parent, access_lists=False)
|
| 464 |
+
except KeyError:
|
| 465 |
+
raise suffixed_err(src, pos, "Can not overwrite a value")
|
| 466 |
+
if key_stem in nest:
|
| 467 |
+
raise suffixed_err(src, pos, f'Duplicate inline table key "{key_stem}"')
|
| 468 |
+
nest[key_stem] = value
|
| 469 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 470 |
+
c = src[pos : pos + 1]
|
| 471 |
+
if c == "}":
|
| 472 |
+
return pos + 1, nested_dict.dict
|
| 473 |
+
if c != ",":
|
| 474 |
+
raise suffixed_err(src, pos, "Unclosed inline table")
|
| 475 |
+
if isinstance(value, (dict, list)):
|
| 476 |
+
flags.set(key, Flags.FROZEN, recursive=True)
|
| 477 |
+
pos += 1
|
| 478 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 479 |
+
|
| 480 |
+
|
| 481 |
+
def parse_basic_str_escape(
|
| 482 |
+
src: str, pos: Pos, *, multiline: bool = False
|
| 483 |
+
) -> Tuple[Pos, str]:
|
| 484 |
+
escape_id = src[pos : pos + 2]
|
| 485 |
+
pos += 2
|
| 486 |
+
if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}:
|
| 487 |
+
# Skip whitespace until next non-whitespace character or end of
|
| 488 |
+
# the doc. Error if non-whitespace is found before newline.
|
| 489 |
+
if escape_id != "\\\n":
|
| 490 |
+
pos = skip_chars(src, pos, TOML_WS)
|
| 491 |
+
char = src[pos : pos + 1]
|
| 492 |
+
if not char:
|
| 493 |
+
return pos, ""
|
| 494 |
+
if char != "\n":
|
| 495 |
+
raise suffixed_err(src, pos, 'Unescaped "\\" in a string')
|
| 496 |
+
pos += 1
|
| 497 |
+
pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE)
|
| 498 |
+
return pos, ""
|
| 499 |
+
if escape_id == "\\u":
|
| 500 |
+
return parse_hex_char(src, pos, 4)
|
| 501 |
+
if escape_id == "\\U":
|
| 502 |
+
return parse_hex_char(src, pos, 8)
|
| 503 |
+
try:
|
| 504 |
+
return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id]
|
| 505 |
+
except KeyError:
|
| 506 |
+
if len(escape_id) != 2:
|
| 507 |
+
raise suffixed_err(src, pos, "Unterminated string")
|
| 508 |
+
raise suffixed_err(src, pos, 'Unescaped "\\" in a string')
|
| 509 |
+
|
| 510 |
+
|
| 511 |
+
def parse_basic_str_escape_multiline(src: str, pos: Pos) -> Tuple[Pos, str]:
|
| 512 |
+
return parse_basic_str_escape(src, pos, multiline=True)
|
| 513 |
+
|
| 514 |
+
|
| 515 |
+
def parse_hex_char(src: str, pos: Pos, hex_len: int) -> Tuple[Pos, str]:
|
| 516 |
+
hex_str = src[pos : pos + hex_len]
|
| 517 |
+
if len(hex_str) != hex_len or any(c not in string.hexdigits for c in hex_str):
|
| 518 |
+
raise suffixed_err(src, pos, "Invalid hex value")
|
| 519 |
+
pos += hex_len
|
| 520 |
+
hex_int = int(hex_str, 16)
|
| 521 |
+
if not is_unicode_scalar_value(hex_int):
|
| 522 |
+
raise suffixed_err(src, pos, "Escaped character is not a Unicode scalar value")
|
| 523 |
+
return pos, chr(hex_int)
|
| 524 |
+
|
| 525 |
+
|
| 526 |
+
def parse_literal_str(src: str, pos: Pos) -> Tuple[Pos, str]:
|
| 527 |
+
pos += 1 # Skip starting apostrophe
|
| 528 |
+
start_pos = pos
|
| 529 |
+
pos = skip_until(
|
| 530 |
+
src, pos, "'", error_on=ILLEGAL_LITERAL_STR_CHARS, error_on_eof=True
|
| 531 |
+
)
|
| 532 |
+
return pos + 1, src[start_pos:pos] # Skip ending apostrophe
|
| 533 |
+
|
| 534 |
+
|
| 535 |
+
def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> Tuple[Pos, str]:
|
| 536 |
+
pos += 3
|
| 537 |
+
if src[pos : pos + 1] == "\n":
|
| 538 |
+
pos += 1
|
| 539 |
+
|
| 540 |
+
if literal:
|
| 541 |
+
delim = "'"
|
| 542 |
+
end_pos = skip_until(
|
| 543 |
+
src,
|
| 544 |
+
pos,
|
| 545 |
+
"'''",
|
| 546 |
+
error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS,
|
| 547 |
+
error_on_eof=True,
|
| 548 |
+
)
|
| 549 |
+
result = src[pos:end_pos]
|
| 550 |
+
pos = end_pos + 3
|
| 551 |
+
else:
|
| 552 |
+
delim = '"'
|
| 553 |
+
pos, result = parse_basic_str(src, pos, multiline=True)
|
| 554 |
+
|
| 555 |
+
# Add at maximum two extra apostrophes/quotes if the end sequence
|
| 556 |
+
# is 4 or 5 chars long instead of just 3.
|
| 557 |
+
if src[pos : pos + 1] != delim:
|
| 558 |
+
return pos, result
|
| 559 |
+
pos += 1
|
| 560 |
+
if src[pos : pos + 1] != delim:
|
| 561 |
+
return pos, result + delim
|
| 562 |
+
pos += 1
|
| 563 |
+
return pos, result + (delim * 2)
|
| 564 |
+
|
| 565 |
+
|
| 566 |
+
def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> Tuple[Pos, str]:
|
| 567 |
+
if multiline:
|
| 568 |
+
error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS
|
| 569 |
+
parse_escapes = parse_basic_str_escape_multiline
|
| 570 |
+
else:
|
| 571 |
+
error_on = ILLEGAL_BASIC_STR_CHARS
|
| 572 |
+
parse_escapes = parse_basic_str_escape
|
| 573 |
+
result = ""
|
| 574 |
+
start_pos = pos
|
| 575 |
+
while True:
|
| 576 |
+
try:
|
| 577 |
+
char = src[pos]
|
| 578 |
+
except IndexError:
|
| 579 |
+
raise suffixed_err(src, pos, "Unterminated string")
|
| 580 |
+
if char == '"':
|
| 581 |
+
if not multiline:
|
| 582 |
+
return pos + 1, result + src[start_pos:pos]
|
| 583 |
+
if src[pos + 1 : pos + 3] == '""':
|
| 584 |
+
return pos + 3, result + src[start_pos:pos]
|
| 585 |
+
pos += 1
|
| 586 |
+
continue
|
| 587 |
+
if char == "\\":
|
| 588 |
+
result += src[start_pos:pos]
|
| 589 |
+
pos, parsed_escape = parse_escapes(src, pos)
|
| 590 |
+
result += parsed_escape
|
| 591 |
+
start_pos = pos
|
| 592 |
+
continue
|
| 593 |
+
if char in error_on:
|
| 594 |
+
raise suffixed_err(src, pos, f'Illegal character "{char!r}"')
|
| 595 |
+
pos += 1
|
| 596 |
+
|
| 597 |
+
|
| 598 |
+
def parse_regex(src: str, pos: Pos, regex: "Pattern") -> Tuple[Pos, str]:
|
| 599 |
+
match = regex.match(src, pos)
|
| 600 |
+
if not match:
|
| 601 |
+
raise suffixed_err(src, pos, "Unexpected sequence")
|
| 602 |
+
return match.end(), match.group()
|
| 603 |
+
|
| 604 |
+
|
| 605 |
+
def parse_value( # noqa: C901
|
| 606 |
+
src: str, pos: Pos, parse_float: ParseFloat
|
| 607 |
+
) -> Tuple[Pos, Any]:
|
| 608 |
+
try:
|
| 609 |
+
char: Optional[str] = src[pos]
|
| 610 |
+
except IndexError:
|
| 611 |
+
char = None
|
| 612 |
+
|
| 613 |
+
# Basic strings
|
| 614 |
+
if char == '"':
|
| 615 |
+
if src[pos + 1 : pos + 3] == '""':
|
| 616 |
+
return parse_multiline_str(src, pos, literal=False)
|
| 617 |
+
return parse_one_line_basic_str(src, pos)
|
| 618 |
+
|
| 619 |
+
# Literal strings
|
| 620 |
+
if char == "'":
|
| 621 |
+
if src[pos + 1 : pos + 3] == "''":
|
| 622 |
+
return parse_multiline_str(src, pos, literal=True)
|
| 623 |
+
return parse_literal_str(src, pos)
|
| 624 |
+
|
| 625 |
+
# Booleans
|
| 626 |
+
if char == "t":
|
| 627 |
+
if src[pos + 1 : pos + 4] == "rue":
|
| 628 |
+
return pos + 4, True
|
| 629 |
+
if char == "f":
|
| 630 |
+
if src[pos + 1 : pos + 5] == "alse":
|
| 631 |
+
return pos + 5, False
|
| 632 |
+
|
| 633 |
+
# Dates and times
|
| 634 |
+
datetime_match = RE_DATETIME.match(src, pos)
|
| 635 |
+
if datetime_match:
|
| 636 |
+
try:
|
| 637 |
+
datetime_obj = match_to_datetime(datetime_match)
|
| 638 |
+
except ValueError:
|
| 639 |
+
raise suffixed_err(src, pos, "Invalid date or datetime")
|
| 640 |
+
return datetime_match.end(), datetime_obj
|
| 641 |
+
localtime_match = RE_LOCALTIME.match(src, pos)
|
| 642 |
+
if localtime_match:
|
| 643 |
+
return localtime_match.end(), match_to_localtime(localtime_match)
|
| 644 |
+
|
| 645 |
+
# Non-decimal integers
|
| 646 |
+
if char == "0":
|
| 647 |
+
second_char = src[pos + 1 : pos + 2]
|
| 648 |
+
if second_char == "x":
|
| 649 |
+
pos, hex_str = parse_regex(src, pos + 2, RE_HEX)
|
| 650 |
+
return pos, int(hex_str, 16)
|
| 651 |
+
if second_char == "o":
|
| 652 |
+
pos, oct_str = parse_regex(src, pos + 2, RE_OCT)
|
| 653 |
+
return pos, int(oct_str, 8)
|
| 654 |
+
if second_char == "b":
|
| 655 |
+
pos, bin_str = parse_regex(src, pos + 2, RE_BIN)
|
| 656 |
+
return pos, int(bin_str, 2)
|
| 657 |
+
|
| 658 |
+
# Decimal integers and "normal" floats.
|
| 659 |
+
# The regex will greedily match any type starting with a decimal
|
| 660 |
+
# char, so needs to be located after handling of non-decimal ints,
|
| 661 |
+
# and dates and times.
|
| 662 |
+
number_match = RE_NUMBER.match(src, pos)
|
| 663 |
+
if number_match:
|
| 664 |
+
return number_match.end(), match_to_number(number_match, parse_float)
|
| 665 |
+
|
| 666 |
+
# Arrays
|
| 667 |
+
if char == "[":
|
| 668 |
+
return parse_array(src, pos, parse_float)
|
| 669 |
+
|
| 670 |
+
# Inline tables
|
| 671 |
+
if char == "{":
|
| 672 |
+
return parse_inline_table(src, pos, parse_float)
|
| 673 |
+
|
| 674 |
+
# Special floats
|
| 675 |
+
first_three = src[pos : pos + 3]
|
| 676 |
+
if first_three in {"inf", "nan"}:
|
| 677 |
+
return pos + 3, parse_float(first_three)
|
| 678 |
+
first_four = src[pos : pos + 4]
|
| 679 |
+
if first_four in {"-inf", "+inf", "-nan", "+nan"}:
|
| 680 |
+
return pos + 4, parse_float(first_four)
|
| 681 |
+
|
| 682 |
+
raise suffixed_err(src, pos, "Invalid value")
|
| 683 |
+
|
| 684 |
+
|
| 685 |
+
def suffixed_err(src: str, pos: Pos, msg: str) -> TOMLDecodeError:
|
| 686 |
+
"""Return a `TOMLDecodeError` where error message is suffixed with
|
| 687 |
+
coordinates in source."""
|
| 688 |
+
|
| 689 |
+
def coord_repr(src: str, pos: Pos) -> str:
|
| 690 |
+
if pos >= len(src):
|
| 691 |
+
return "end of document"
|
| 692 |
+
line = src.count("\n", 0, pos) + 1
|
| 693 |
+
if line == 1:
|
| 694 |
+
column = pos + 1
|
| 695 |
+
else:
|
| 696 |
+
column = pos - src.rindex("\n", 0, pos)
|
| 697 |
+
return f"line {line}, column {column}"
|
| 698 |
+
|
| 699 |
+
return TOMLDecodeError(f"{msg} (at {coord_repr(src, pos)})")
|
| 700 |
+
|
| 701 |
+
|
| 702 |
+
def is_unicode_scalar_value(codepoint: int) -> bool:
|
| 703 |
+
return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/tomli/_re.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from datetime import date, datetime, time, timedelta, timezone, tzinfo
|
| 2 |
+
import re
|
| 3 |
+
from typing import TYPE_CHECKING, Any, Optional, Union
|
| 4 |
+
|
| 5 |
+
if TYPE_CHECKING:
|
| 6 |
+
from re import Match
|
| 7 |
+
|
| 8 |
+
from pip._vendor.tomli._parser import ParseFloat
|
| 9 |
+
|
| 10 |
+
# E.g.
|
| 11 |
+
# - 00:32:00.999999
|
| 12 |
+
# - 00:32:00
|
| 13 |
+
_TIME_RE_STR = r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?"
|
| 14 |
+
|
| 15 |
+
RE_HEX = re.compile(r"[0-9A-Fa-f](?:_?[0-9A-Fa-f])*")
|
| 16 |
+
RE_BIN = re.compile(r"[01](?:_?[01])*")
|
| 17 |
+
RE_OCT = re.compile(r"[0-7](?:_?[0-7])*")
|
| 18 |
+
RE_NUMBER = re.compile(
|
| 19 |
+
r"[+-]?(?:0|[1-9](?:_?[0-9])*)" # integer
|
| 20 |
+
+ r"(?:\.[0-9](?:_?[0-9])*)?" # optional fractional part
|
| 21 |
+
+ r"(?:[eE][+-]?[0-9](?:_?[0-9])*)?" # optional exponent part
|
| 22 |
+
)
|
| 23 |
+
RE_LOCALTIME = re.compile(_TIME_RE_STR)
|
| 24 |
+
RE_DATETIME = re.compile(
|
| 25 |
+
r"([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-9]|3[01])" # date, e.g. 1988-10-27
|
| 26 |
+
+ r"(?:"
|
| 27 |
+
+ r"[T ]"
|
| 28 |
+
+ _TIME_RE_STR
|
| 29 |
+
+ r"(?:(Z)|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))?" # time offset
|
| 30 |
+
+ r")?"
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def match_to_datetime(match: "Match") -> Union[datetime, date]:
|
| 35 |
+
"""Convert a `RE_DATETIME` match to `datetime.datetime` or `datetime.date`.
|
| 36 |
+
|
| 37 |
+
Raises ValueError if the match does not correspond to a valid date
|
| 38 |
+
or datetime.
|
| 39 |
+
"""
|
| 40 |
+
(
|
| 41 |
+
year_str,
|
| 42 |
+
month_str,
|
| 43 |
+
day_str,
|
| 44 |
+
hour_str,
|
| 45 |
+
minute_str,
|
| 46 |
+
sec_str,
|
| 47 |
+
micros_str,
|
| 48 |
+
zulu_time,
|
| 49 |
+
offset_dir_str,
|
| 50 |
+
offset_hour_str,
|
| 51 |
+
offset_minute_str,
|
| 52 |
+
) = match.groups()
|
| 53 |
+
year, month, day = int(year_str), int(month_str), int(day_str)
|
| 54 |
+
if hour_str is None:
|
| 55 |
+
return date(year, month, day)
|
| 56 |
+
hour, minute, sec = int(hour_str), int(minute_str), int(sec_str)
|
| 57 |
+
micros = int(micros_str[1:].ljust(6, "0")[:6]) if micros_str else 0
|
| 58 |
+
if offset_dir_str:
|
| 59 |
+
offset_dir = 1 if offset_dir_str == "+" else -1
|
| 60 |
+
tz: Optional[tzinfo] = timezone(
|
| 61 |
+
timedelta(
|
| 62 |
+
hours=offset_dir * int(offset_hour_str),
|
| 63 |
+
minutes=offset_dir * int(offset_minute_str),
|
| 64 |
+
)
|
| 65 |
+
)
|
| 66 |
+
elif zulu_time:
|
| 67 |
+
tz = timezone.utc
|
| 68 |
+
else: # local date-time
|
| 69 |
+
tz = None
|
| 70 |
+
return datetime(year, month, day, hour, minute, sec, micros, tzinfo=tz)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def match_to_localtime(match: "Match") -> time:
|
| 74 |
+
hour_str, minute_str, sec_str, micros_str = match.groups()
|
| 75 |
+
micros = int(micros_str[1:].ljust(6, "0")[:6]) if micros_str else 0
|
| 76 |
+
return time(int(hour_str), int(minute_str), int(sec_str), micros)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def match_to_number(match: "Match", parse_float: "ParseFloat") -> Any:
|
| 80 |
+
match_str = match.group()
|
| 81 |
+
if "." in match_str or "e" in match_str or "E" in match_str:
|
| 82 |
+
return parse_float(match_str)
|
| 83 |
+
return int(match_str)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/__init__.py
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more
|
| 3 |
+
"""
|
| 4 |
+
from __future__ import absolute_import
|
| 5 |
+
|
| 6 |
+
# Set default logging handler to avoid "No handler found" warnings.
|
| 7 |
+
import logging
|
| 8 |
+
import warnings
|
| 9 |
+
from logging import NullHandler
|
| 10 |
+
|
| 11 |
+
from . import exceptions
|
| 12 |
+
from ._version import __version__
|
| 13 |
+
from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url
|
| 14 |
+
from .filepost import encode_multipart_formdata
|
| 15 |
+
from .poolmanager import PoolManager, ProxyManager, proxy_from_url
|
| 16 |
+
from .response import HTTPResponse
|
| 17 |
+
from .util.request import make_headers
|
| 18 |
+
from .util.retry import Retry
|
| 19 |
+
from .util.timeout import Timeout
|
| 20 |
+
from .util.url import get_host
|
| 21 |
+
|
| 22 |
+
__author__ = "Andrey Petrov (andrey.petrov@shazow.net)"
|
| 23 |
+
__license__ = "MIT"
|
| 24 |
+
__version__ = __version__
|
| 25 |
+
|
| 26 |
+
__all__ = (
|
| 27 |
+
"HTTPConnectionPool",
|
| 28 |
+
"HTTPSConnectionPool",
|
| 29 |
+
"PoolManager",
|
| 30 |
+
"ProxyManager",
|
| 31 |
+
"HTTPResponse",
|
| 32 |
+
"Retry",
|
| 33 |
+
"Timeout",
|
| 34 |
+
"add_stderr_logger",
|
| 35 |
+
"connection_from_url",
|
| 36 |
+
"disable_warnings",
|
| 37 |
+
"encode_multipart_formdata",
|
| 38 |
+
"get_host",
|
| 39 |
+
"make_headers",
|
| 40 |
+
"proxy_from_url",
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
logging.getLogger(__name__).addHandler(NullHandler())
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def add_stderr_logger(level=logging.DEBUG):
|
| 47 |
+
"""
|
| 48 |
+
Helper for quickly adding a StreamHandler to the logger. Useful for
|
| 49 |
+
debugging.
|
| 50 |
+
|
| 51 |
+
Returns the handler after adding it.
|
| 52 |
+
"""
|
| 53 |
+
# This method needs to be in this __init__.py to get the __name__ correct
|
| 54 |
+
# even if urllib3 is vendored within another package.
|
| 55 |
+
logger = logging.getLogger(__name__)
|
| 56 |
+
handler = logging.StreamHandler()
|
| 57 |
+
handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
|
| 58 |
+
logger.addHandler(handler)
|
| 59 |
+
logger.setLevel(level)
|
| 60 |
+
logger.debug("Added a stderr logging handler to logger: %s", __name__)
|
| 61 |
+
return handler
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
# ... Clean up.
|
| 65 |
+
del NullHandler
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
# All warning filters *must* be appended unless you're really certain that they
|
| 69 |
+
# shouldn't be: otherwise, it's very hard for users to use most Python
|
| 70 |
+
# mechanisms to silence them.
|
| 71 |
+
# SecurityWarning's always go off by default.
|
| 72 |
+
warnings.simplefilter("always", exceptions.SecurityWarning, append=True)
|
| 73 |
+
# SubjectAltNameWarning's should go off once per host
|
| 74 |
+
warnings.simplefilter("default", exceptions.SubjectAltNameWarning, append=True)
|
| 75 |
+
# InsecurePlatformWarning's don't vary between requests, so we keep it default.
|
| 76 |
+
warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True)
|
| 77 |
+
# SNIMissingWarnings should go off only once.
|
| 78 |
+
warnings.simplefilter("default", exceptions.SNIMissingWarning, append=True)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def disable_warnings(category=exceptions.HTTPWarning):
|
| 82 |
+
"""
|
| 83 |
+
Helper for quickly disabling all urllib3 warnings.
|
| 84 |
+
"""
|
| 85 |
+
warnings.simplefilter("ignore", category)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/_collections.py
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
try:
|
| 4 |
+
from collections.abc import Mapping, MutableMapping
|
| 5 |
+
except ImportError:
|
| 6 |
+
from collections import Mapping, MutableMapping
|
| 7 |
+
try:
|
| 8 |
+
from threading import RLock
|
| 9 |
+
except ImportError: # Platform-specific: No threads available
|
| 10 |
+
|
| 11 |
+
class RLock:
|
| 12 |
+
def __enter__(self):
|
| 13 |
+
pass
|
| 14 |
+
|
| 15 |
+
def __exit__(self, exc_type, exc_value, traceback):
|
| 16 |
+
pass
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
from collections import OrderedDict
|
| 20 |
+
|
| 21 |
+
from .exceptions import InvalidHeader
|
| 22 |
+
from .packages import six
|
| 23 |
+
from .packages.six import iterkeys, itervalues
|
| 24 |
+
|
| 25 |
+
__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"]
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
_Null = object()
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class RecentlyUsedContainer(MutableMapping):
|
| 32 |
+
"""
|
| 33 |
+
Provides a thread-safe dict-like container which maintains up to
|
| 34 |
+
``maxsize`` keys while throwing away the least-recently-used keys beyond
|
| 35 |
+
``maxsize``.
|
| 36 |
+
|
| 37 |
+
:param maxsize:
|
| 38 |
+
Maximum number of recent elements to retain.
|
| 39 |
+
|
| 40 |
+
:param dispose_func:
|
| 41 |
+
Every time an item is evicted from the container,
|
| 42 |
+
``dispose_func(value)`` is called. Callback which will get called
|
| 43 |
+
"""
|
| 44 |
+
|
| 45 |
+
ContainerCls = OrderedDict
|
| 46 |
+
|
| 47 |
+
def __init__(self, maxsize=10, dispose_func=None):
|
| 48 |
+
self._maxsize = maxsize
|
| 49 |
+
self.dispose_func = dispose_func
|
| 50 |
+
|
| 51 |
+
self._container = self.ContainerCls()
|
| 52 |
+
self.lock = RLock()
|
| 53 |
+
|
| 54 |
+
def __getitem__(self, key):
|
| 55 |
+
# Re-insert the item, moving it to the end of the eviction line.
|
| 56 |
+
with self.lock:
|
| 57 |
+
item = self._container.pop(key)
|
| 58 |
+
self._container[key] = item
|
| 59 |
+
return item
|
| 60 |
+
|
| 61 |
+
def __setitem__(self, key, value):
|
| 62 |
+
evicted_value = _Null
|
| 63 |
+
with self.lock:
|
| 64 |
+
# Possibly evict the existing value of 'key'
|
| 65 |
+
evicted_value = self._container.get(key, _Null)
|
| 66 |
+
self._container[key] = value
|
| 67 |
+
|
| 68 |
+
# If we didn't evict an existing value, we might have to evict the
|
| 69 |
+
# least recently used item from the beginning of the container.
|
| 70 |
+
if len(self._container) > self._maxsize:
|
| 71 |
+
_key, evicted_value = self._container.popitem(last=False)
|
| 72 |
+
|
| 73 |
+
if self.dispose_func and evicted_value is not _Null:
|
| 74 |
+
self.dispose_func(evicted_value)
|
| 75 |
+
|
| 76 |
+
def __delitem__(self, key):
|
| 77 |
+
with self.lock:
|
| 78 |
+
value = self._container.pop(key)
|
| 79 |
+
|
| 80 |
+
if self.dispose_func:
|
| 81 |
+
self.dispose_func(value)
|
| 82 |
+
|
| 83 |
+
def __len__(self):
|
| 84 |
+
with self.lock:
|
| 85 |
+
return len(self._container)
|
| 86 |
+
|
| 87 |
+
def __iter__(self):
|
| 88 |
+
raise NotImplementedError(
|
| 89 |
+
"Iteration over this class is unlikely to be threadsafe."
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
def clear(self):
|
| 93 |
+
with self.lock:
|
| 94 |
+
# Copy pointers to all values, then wipe the mapping
|
| 95 |
+
values = list(itervalues(self._container))
|
| 96 |
+
self._container.clear()
|
| 97 |
+
|
| 98 |
+
if self.dispose_func:
|
| 99 |
+
for value in values:
|
| 100 |
+
self.dispose_func(value)
|
| 101 |
+
|
| 102 |
+
def keys(self):
|
| 103 |
+
with self.lock:
|
| 104 |
+
return list(iterkeys(self._container))
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
class HTTPHeaderDict(MutableMapping):
|
| 108 |
+
"""
|
| 109 |
+
:param headers:
|
| 110 |
+
An iterable of field-value pairs. Must not contain multiple field names
|
| 111 |
+
when compared case-insensitively.
|
| 112 |
+
|
| 113 |
+
:param kwargs:
|
| 114 |
+
Additional field-value pairs to pass in to ``dict.update``.
|
| 115 |
+
|
| 116 |
+
A ``dict`` like container for storing HTTP Headers.
|
| 117 |
+
|
| 118 |
+
Field names are stored and compared case-insensitively in compliance with
|
| 119 |
+
RFC 7230. Iteration provides the first case-sensitive key seen for each
|
| 120 |
+
case-insensitive pair.
|
| 121 |
+
|
| 122 |
+
Using ``__setitem__`` syntax overwrites fields that compare equal
|
| 123 |
+
case-insensitively in order to maintain ``dict``'s api. For fields that
|
| 124 |
+
compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add``
|
| 125 |
+
in a loop.
|
| 126 |
+
|
| 127 |
+
If multiple fields that are equal case-insensitively are passed to the
|
| 128 |
+
constructor or ``.update``, the behavior is undefined and some will be
|
| 129 |
+
lost.
|
| 130 |
+
|
| 131 |
+
>>> headers = HTTPHeaderDict()
|
| 132 |
+
>>> headers.add('Set-Cookie', 'foo=bar')
|
| 133 |
+
>>> headers.add('set-cookie', 'baz=quxx')
|
| 134 |
+
>>> headers['content-length'] = '7'
|
| 135 |
+
>>> headers['SET-cookie']
|
| 136 |
+
'foo=bar, baz=quxx'
|
| 137 |
+
>>> headers['Content-Length']
|
| 138 |
+
'7'
|
| 139 |
+
"""
|
| 140 |
+
|
| 141 |
+
def __init__(self, headers=None, **kwargs):
|
| 142 |
+
super(HTTPHeaderDict, self).__init__()
|
| 143 |
+
self._container = OrderedDict()
|
| 144 |
+
if headers is not None:
|
| 145 |
+
if isinstance(headers, HTTPHeaderDict):
|
| 146 |
+
self._copy_from(headers)
|
| 147 |
+
else:
|
| 148 |
+
self.extend(headers)
|
| 149 |
+
if kwargs:
|
| 150 |
+
self.extend(kwargs)
|
| 151 |
+
|
| 152 |
+
def __setitem__(self, key, val):
|
| 153 |
+
self._container[key.lower()] = [key, val]
|
| 154 |
+
return self._container[key.lower()]
|
| 155 |
+
|
| 156 |
+
def __getitem__(self, key):
|
| 157 |
+
val = self._container[key.lower()]
|
| 158 |
+
return ", ".join(val[1:])
|
| 159 |
+
|
| 160 |
+
def __delitem__(self, key):
|
| 161 |
+
del self._container[key.lower()]
|
| 162 |
+
|
| 163 |
+
def __contains__(self, key):
|
| 164 |
+
return key.lower() in self._container
|
| 165 |
+
|
| 166 |
+
def __eq__(self, other):
|
| 167 |
+
if not isinstance(other, Mapping) and not hasattr(other, "keys"):
|
| 168 |
+
return False
|
| 169 |
+
if not isinstance(other, type(self)):
|
| 170 |
+
other = type(self)(other)
|
| 171 |
+
return dict((k.lower(), v) for k, v in self.itermerged()) == dict(
|
| 172 |
+
(k.lower(), v) for k, v in other.itermerged()
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
def __ne__(self, other):
|
| 176 |
+
return not self.__eq__(other)
|
| 177 |
+
|
| 178 |
+
if six.PY2: # Python 2
|
| 179 |
+
iterkeys = MutableMapping.iterkeys
|
| 180 |
+
itervalues = MutableMapping.itervalues
|
| 181 |
+
|
| 182 |
+
__marker = object()
|
| 183 |
+
|
| 184 |
+
def __len__(self):
|
| 185 |
+
return len(self._container)
|
| 186 |
+
|
| 187 |
+
def __iter__(self):
|
| 188 |
+
# Only provide the originally cased names
|
| 189 |
+
for vals in self._container.values():
|
| 190 |
+
yield vals[0]
|
| 191 |
+
|
| 192 |
+
def pop(self, key, default=__marker):
|
| 193 |
+
"""D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
|
| 194 |
+
If key is not found, d is returned if given, otherwise KeyError is raised.
|
| 195 |
+
"""
|
| 196 |
+
# Using the MutableMapping function directly fails due to the private marker.
|
| 197 |
+
# Using ordinary dict.pop would expose the internal structures.
|
| 198 |
+
# So let's reinvent the wheel.
|
| 199 |
+
try:
|
| 200 |
+
value = self[key]
|
| 201 |
+
except KeyError:
|
| 202 |
+
if default is self.__marker:
|
| 203 |
+
raise
|
| 204 |
+
return default
|
| 205 |
+
else:
|
| 206 |
+
del self[key]
|
| 207 |
+
return value
|
| 208 |
+
|
| 209 |
+
def discard(self, key):
|
| 210 |
+
try:
|
| 211 |
+
del self[key]
|
| 212 |
+
except KeyError:
|
| 213 |
+
pass
|
| 214 |
+
|
| 215 |
+
def add(self, key, val):
|
| 216 |
+
"""Adds a (name, value) pair, doesn't overwrite the value if it already
|
| 217 |
+
exists.
|
| 218 |
+
|
| 219 |
+
>>> headers = HTTPHeaderDict(foo='bar')
|
| 220 |
+
>>> headers.add('Foo', 'baz')
|
| 221 |
+
>>> headers['foo']
|
| 222 |
+
'bar, baz'
|
| 223 |
+
"""
|
| 224 |
+
key_lower = key.lower()
|
| 225 |
+
new_vals = [key, val]
|
| 226 |
+
# Keep the common case aka no item present as fast as possible
|
| 227 |
+
vals = self._container.setdefault(key_lower, new_vals)
|
| 228 |
+
if new_vals is not vals:
|
| 229 |
+
vals.append(val)
|
| 230 |
+
|
| 231 |
+
def extend(self, *args, **kwargs):
|
| 232 |
+
"""Generic import function for any type of header-like object.
|
| 233 |
+
Adapted version of MutableMapping.update in order to insert items
|
| 234 |
+
with self.add instead of self.__setitem__
|
| 235 |
+
"""
|
| 236 |
+
if len(args) > 1:
|
| 237 |
+
raise TypeError(
|
| 238 |
+
"extend() takes at most 1 positional "
|
| 239 |
+
"arguments ({0} given)".format(len(args))
|
| 240 |
+
)
|
| 241 |
+
other = args[0] if len(args) >= 1 else ()
|
| 242 |
+
|
| 243 |
+
if isinstance(other, HTTPHeaderDict):
|
| 244 |
+
for key, val in other.iteritems():
|
| 245 |
+
self.add(key, val)
|
| 246 |
+
elif isinstance(other, Mapping):
|
| 247 |
+
for key in other:
|
| 248 |
+
self.add(key, other[key])
|
| 249 |
+
elif hasattr(other, "keys"):
|
| 250 |
+
for key in other.keys():
|
| 251 |
+
self.add(key, other[key])
|
| 252 |
+
else:
|
| 253 |
+
for key, value in other:
|
| 254 |
+
self.add(key, value)
|
| 255 |
+
|
| 256 |
+
for key, value in kwargs.items():
|
| 257 |
+
self.add(key, value)
|
| 258 |
+
|
| 259 |
+
def getlist(self, key, default=__marker):
|
| 260 |
+
"""Returns a list of all the values for the named field. Returns an
|
| 261 |
+
empty list if the key doesn't exist."""
|
| 262 |
+
try:
|
| 263 |
+
vals = self._container[key.lower()]
|
| 264 |
+
except KeyError:
|
| 265 |
+
if default is self.__marker:
|
| 266 |
+
return []
|
| 267 |
+
return default
|
| 268 |
+
else:
|
| 269 |
+
return vals[1:]
|
| 270 |
+
|
| 271 |
+
# Backwards compatibility for httplib
|
| 272 |
+
getheaders = getlist
|
| 273 |
+
getallmatchingheaders = getlist
|
| 274 |
+
iget = getlist
|
| 275 |
+
|
| 276 |
+
# Backwards compatibility for http.cookiejar
|
| 277 |
+
get_all = getlist
|
| 278 |
+
|
| 279 |
+
def __repr__(self):
|
| 280 |
+
return "%s(%s)" % (type(self).__name__, dict(self.itermerged()))
|
| 281 |
+
|
| 282 |
+
def _copy_from(self, other):
|
| 283 |
+
for key in other:
|
| 284 |
+
val = other.getlist(key)
|
| 285 |
+
if isinstance(val, list):
|
| 286 |
+
# Don't need to convert tuples
|
| 287 |
+
val = list(val)
|
| 288 |
+
self._container[key.lower()] = [key] + val
|
| 289 |
+
|
| 290 |
+
def copy(self):
|
| 291 |
+
clone = type(self)()
|
| 292 |
+
clone._copy_from(self)
|
| 293 |
+
return clone
|
| 294 |
+
|
| 295 |
+
def iteritems(self):
|
| 296 |
+
"""Iterate over all header lines, including duplicate ones."""
|
| 297 |
+
for key in self:
|
| 298 |
+
vals = self._container[key.lower()]
|
| 299 |
+
for val in vals[1:]:
|
| 300 |
+
yield vals[0], val
|
| 301 |
+
|
| 302 |
+
def itermerged(self):
|
| 303 |
+
"""Iterate over all headers, merging duplicate ones together."""
|
| 304 |
+
for key in self:
|
| 305 |
+
val = self._container[key.lower()]
|
| 306 |
+
yield val[0], ", ".join(val[1:])
|
| 307 |
+
|
| 308 |
+
def items(self):
|
| 309 |
+
return list(self.iteritems())
|
| 310 |
+
|
| 311 |
+
@classmethod
|
| 312 |
+
def from_httplib(cls, message): # Python 2
|
| 313 |
+
"""Read headers from a Python 2 httplib message object."""
|
| 314 |
+
# python2.7 does not expose a proper API for exporting multiheaders
|
| 315 |
+
# efficiently. This function re-reads raw lines from the message
|
| 316 |
+
# object and extracts the multiheaders properly.
|
| 317 |
+
obs_fold_continued_leaders = (" ", "\t")
|
| 318 |
+
headers = []
|
| 319 |
+
|
| 320 |
+
for line in message.headers:
|
| 321 |
+
if line.startswith(obs_fold_continued_leaders):
|
| 322 |
+
if not headers:
|
| 323 |
+
# We received a header line that starts with OWS as described
|
| 324 |
+
# in RFC-7230 S3.2.4. This indicates a multiline header, but
|
| 325 |
+
# there exists no previous header to which we can attach it.
|
| 326 |
+
raise InvalidHeader(
|
| 327 |
+
"Header continuation with no previous header: %s" % line
|
| 328 |
+
)
|
| 329 |
+
else:
|
| 330 |
+
key, value = headers[-1]
|
| 331 |
+
headers[-1] = (key, value + " " + line.strip())
|
| 332 |
+
continue
|
| 333 |
+
|
| 334 |
+
key, value = line.split(":", 1)
|
| 335 |
+
headers.append((key, value.strip()))
|
| 336 |
+
|
| 337 |
+
return cls(headers)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/_version.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file is protected via CODEOWNERS
|
| 2 |
+
__version__ = "1.26.6"
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/connection.py
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import datetime
|
| 4 |
+
import logging
|
| 5 |
+
import os
|
| 6 |
+
import re
|
| 7 |
+
import socket
|
| 8 |
+
import warnings
|
| 9 |
+
from socket import error as SocketError
|
| 10 |
+
from socket import timeout as SocketTimeout
|
| 11 |
+
|
| 12 |
+
from .packages import six
|
| 13 |
+
from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection
|
| 14 |
+
from .packages.six.moves.http_client import HTTPException # noqa: F401
|
| 15 |
+
from .util.proxy import create_proxy_ssl_context
|
| 16 |
+
|
| 17 |
+
try: # Compiled with SSL?
|
| 18 |
+
import ssl
|
| 19 |
+
|
| 20 |
+
BaseSSLError = ssl.SSLError
|
| 21 |
+
except (ImportError, AttributeError): # Platform-specific: No SSL.
|
| 22 |
+
ssl = None
|
| 23 |
+
|
| 24 |
+
class BaseSSLError(BaseException):
|
| 25 |
+
pass
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
try:
|
| 29 |
+
# Python 3: not a no-op, we're adding this to the namespace so it can be imported.
|
| 30 |
+
ConnectionError = ConnectionError
|
| 31 |
+
except NameError:
|
| 32 |
+
# Python 2
|
| 33 |
+
class ConnectionError(Exception):
|
| 34 |
+
pass
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
try: # Python 3:
|
| 38 |
+
# Not a no-op, we're adding this to the namespace so it can be imported.
|
| 39 |
+
BrokenPipeError = BrokenPipeError
|
| 40 |
+
except NameError: # Python 2:
|
| 41 |
+
|
| 42 |
+
class BrokenPipeError(Exception):
|
| 43 |
+
pass
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
from ._collections import HTTPHeaderDict # noqa (historical, removed in v2)
|
| 47 |
+
from ._version import __version__
|
| 48 |
+
from .exceptions import (
|
| 49 |
+
ConnectTimeoutError,
|
| 50 |
+
NewConnectionError,
|
| 51 |
+
SubjectAltNameWarning,
|
| 52 |
+
SystemTimeWarning,
|
| 53 |
+
)
|
| 54 |
+
from .packages.ssl_match_hostname import CertificateError, match_hostname
|
| 55 |
+
from .util import SKIP_HEADER, SKIPPABLE_HEADERS, connection
|
| 56 |
+
from .util.ssl_ import (
|
| 57 |
+
assert_fingerprint,
|
| 58 |
+
create_urllib3_context,
|
| 59 |
+
resolve_cert_reqs,
|
| 60 |
+
resolve_ssl_version,
|
| 61 |
+
ssl_wrap_socket,
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
log = logging.getLogger(__name__)
|
| 65 |
+
|
| 66 |
+
port_by_scheme = {"http": 80, "https": 443}
|
| 67 |
+
|
| 68 |
+
# When it comes time to update this value as a part of regular maintenance
|
| 69 |
+
# (ie test_recent_date is failing) update it to ~6 months before the current date.
|
| 70 |
+
RECENT_DATE = datetime.date(2020, 7, 1)
|
| 71 |
+
|
| 72 |
+
_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class HTTPConnection(_HTTPConnection, object):
|
| 76 |
+
"""
|
| 77 |
+
Based on :class:`http.client.HTTPConnection` but provides an extra constructor
|
| 78 |
+
backwards-compatibility layer between older and newer Pythons.
|
| 79 |
+
|
| 80 |
+
Additional keyword parameters are used to configure attributes of the connection.
|
| 81 |
+
Accepted parameters include:
|
| 82 |
+
|
| 83 |
+
- ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool`
|
| 84 |
+
- ``source_address``: Set the source address for the current connection.
|
| 85 |
+
- ``socket_options``: Set specific options on the underlying socket. If not specified, then
|
| 86 |
+
defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling
|
| 87 |
+
Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy.
|
| 88 |
+
|
| 89 |
+
For example, if you wish to enable TCP Keep Alive in addition to the defaults,
|
| 90 |
+
you might pass:
|
| 91 |
+
|
| 92 |
+
.. code-block:: python
|
| 93 |
+
|
| 94 |
+
HTTPConnection.default_socket_options + [
|
| 95 |
+
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
|
| 96 |
+
]
|
| 97 |
+
|
| 98 |
+
Or you may want to disable the defaults by passing an empty list (e.g., ``[]``).
|
| 99 |
+
"""
|
| 100 |
+
|
| 101 |
+
default_port = port_by_scheme["http"]
|
| 102 |
+
|
| 103 |
+
#: Disable Nagle's algorithm by default.
|
| 104 |
+
#: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]``
|
| 105 |
+
default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]
|
| 106 |
+
|
| 107 |
+
#: Whether this connection verifies the host's certificate.
|
| 108 |
+
is_verified = False
|
| 109 |
+
|
| 110 |
+
def __init__(self, *args, **kw):
|
| 111 |
+
if not six.PY2:
|
| 112 |
+
kw.pop("strict", None)
|
| 113 |
+
|
| 114 |
+
# Pre-set source_address.
|
| 115 |
+
self.source_address = kw.get("source_address")
|
| 116 |
+
|
| 117 |
+
#: The socket options provided by the user. If no options are
|
| 118 |
+
#: provided, we use the default options.
|
| 119 |
+
self.socket_options = kw.pop("socket_options", self.default_socket_options)
|
| 120 |
+
|
| 121 |
+
# Proxy options provided by the user.
|
| 122 |
+
self.proxy = kw.pop("proxy", None)
|
| 123 |
+
self.proxy_config = kw.pop("proxy_config", None)
|
| 124 |
+
|
| 125 |
+
_HTTPConnection.__init__(self, *args, **kw)
|
| 126 |
+
|
| 127 |
+
@property
|
| 128 |
+
def host(self):
|
| 129 |
+
"""
|
| 130 |
+
Getter method to remove any trailing dots that indicate the hostname is an FQDN.
|
| 131 |
+
|
| 132 |
+
In general, SSL certificates don't include the trailing dot indicating a
|
| 133 |
+
fully-qualified domain name, and thus, they don't validate properly when
|
| 134 |
+
checked against a domain name that includes the dot. In addition, some
|
| 135 |
+
servers may not expect to receive the trailing dot when provided.
|
| 136 |
+
|
| 137 |
+
However, the hostname with trailing dot is critical to DNS resolution; doing a
|
| 138 |
+
lookup with the trailing dot will properly only resolve the appropriate FQDN,
|
| 139 |
+
whereas a lookup without a trailing dot will search the system's search domain
|
| 140 |
+
list. Thus, it's important to keep the original host around for use only in
|
| 141 |
+
those cases where it's appropriate (i.e., when doing DNS lookup to establish the
|
| 142 |
+
actual TCP connection across which we're going to send HTTP requests).
|
| 143 |
+
"""
|
| 144 |
+
return self._dns_host.rstrip(".")
|
| 145 |
+
|
| 146 |
+
@host.setter
|
| 147 |
+
def host(self, value):
|
| 148 |
+
"""
|
| 149 |
+
Setter for the `host` property.
|
| 150 |
+
|
| 151 |
+
We assume that only urllib3 uses the _dns_host attribute; httplib itself
|
| 152 |
+
only uses `host`, and it seems reasonable that other libraries follow suit.
|
| 153 |
+
"""
|
| 154 |
+
self._dns_host = value
|
| 155 |
+
|
| 156 |
+
def _new_conn(self):
|
| 157 |
+
"""Establish a socket connection and set nodelay settings on it.
|
| 158 |
+
|
| 159 |
+
:return: New socket connection.
|
| 160 |
+
"""
|
| 161 |
+
extra_kw = {}
|
| 162 |
+
if self.source_address:
|
| 163 |
+
extra_kw["source_address"] = self.source_address
|
| 164 |
+
|
| 165 |
+
if self.socket_options:
|
| 166 |
+
extra_kw["socket_options"] = self.socket_options
|
| 167 |
+
|
| 168 |
+
try:
|
| 169 |
+
conn = connection.create_connection(
|
| 170 |
+
(self._dns_host, self.port), self.timeout, **extra_kw
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
except SocketTimeout:
|
| 174 |
+
raise ConnectTimeoutError(
|
| 175 |
+
self,
|
| 176 |
+
"Connection to %s timed out. (connect timeout=%s)"
|
| 177 |
+
% (self.host, self.timeout),
|
| 178 |
+
)
|
| 179 |
+
|
| 180 |
+
except SocketError as e:
|
| 181 |
+
raise NewConnectionError(
|
| 182 |
+
self, "Failed to establish a new connection: %s" % e
|
| 183 |
+
)
|
| 184 |
+
|
| 185 |
+
return conn
|
| 186 |
+
|
| 187 |
+
def _is_using_tunnel(self):
|
| 188 |
+
# Google App Engine's httplib does not define _tunnel_host
|
| 189 |
+
return getattr(self, "_tunnel_host", None)
|
| 190 |
+
|
| 191 |
+
def _prepare_conn(self, conn):
|
| 192 |
+
self.sock = conn
|
| 193 |
+
if self._is_using_tunnel():
|
| 194 |
+
# TODO: Fix tunnel so it doesn't depend on self.sock state.
|
| 195 |
+
self._tunnel()
|
| 196 |
+
# Mark this connection as not reusable
|
| 197 |
+
self.auto_open = 0
|
| 198 |
+
|
| 199 |
+
def connect(self):
|
| 200 |
+
conn = self._new_conn()
|
| 201 |
+
self._prepare_conn(conn)
|
| 202 |
+
|
| 203 |
+
def putrequest(self, method, url, *args, **kwargs):
|
| 204 |
+
""" """
|
| 205 |
+
# Empty docstring because the indentation of CPython's implementation
|
| 206 |
+
# is broken but we don't want this method in our documentation.
|
| 207 |
+
match = _CONTAINS_CONTROL_CHAR_RE.search(method)
|
| 208 |
+
if match:
|
| 209 |
+
raise ValueError(
|
| 210 |
+
"Method cannot contain non-token characters %r (found at least %r)"
|
| 211 |
+
% (method, match.group())
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
+
return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)
|
| 215 |
+
|
| 216 |
+
def putheader(self, header, *values):
|
| 217 |
+
""" """
|
| 218 |
+
if not any(isinstance(v, str) and v == SKIP_HEADER for v in values):
|
| 219 |
+
_HTTPConnection.putheader(self, header, *values)
|
| 220 |
+
elif six.ensure_str(header.lower()) not in SKIPPABLE_HEADERS:
|
| 221 |
+
raise ValueError(
|
| 222 |
+
"urllib3.util.SKIP_HEADER only supports '%s'"
|
| 223 |
+
% ("', '".join(map(str.title, sorted(SKIPPABLE_HEADERS))),)
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
def request(self, method, url, body=None, headers=None):
|
| 227 |
+
if headers is None:
|
| 228 |
+
headers = {}
|
| 229 |
+
else:
|
| 230 |
+
# Avoid modifying the headers passed into .request()
|
| 231 |
+
headers = headers.copy()
|
| 232 |
+
if "user-agent" not in (six.ensure_str(k.lower()) for k in headers):
|
| 233 |
+
headers["User-Agent"] = _get_default_user_agent()
|
| 234 |
+
super(HTTPConnection, self).request(method, url, body=body, headers=headers)
|
| 235 |
+
|
| 236 |
+
def request_chunked(self, method, url, body=None, headers=None):
|
| 237 |
+
"""
|
| 238 |
+
Alternative to the common request method, which sends the
|
| 239 |
+
body with chunked encoding and not as one block
|
| 240 |
+
"""
|
| 241 |
+
headers = headers or {}
|
| 242 |
+
header_keys = set([six.ensure_str(k.lower()) for k in headers])
|
| 243 |
+
skip_accept_encoding = "accept-encoding" in header_keys
|
| 244 |
+
skip_host = "host" in header_keys
|
| 245 |
+
self.putrequest(
|
| 246 |
+
method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host
|
| 247 |
+
)
|
| 248 |
+
if "user-agent" not in header_keys:
|
| 249 |
+
self.putheader("User-Agent", _get_default_user_agent())
|
| 250 |
+
for header, value in headers.items():
|
| 251 |
+
self.putheader(header, value)
|
| 252 |
+
if "transfer-encoding" not in header_keys:
|
| 253 |
+
self.putheader("Transfer-Encoding", "chunked")
|
| 254 |
+
self.endheaders()
|
| 255 |
+
|
| 256 |
+
if body is not None:
|
| 257 |
+
stringish_types = six.string_types + (bytes,)
|
| 258 |
+
if isinstance(body, stringish_types):
|
| 259 |
+
body = (body,)
|
| 260 |
+
for chunk in body:
|
| 261 |
+
if not chunk:
|
| 262 |
+
continue
|
| 263 |
+
if not isinstance(chunk, bytes):
|
| 264 |
+
chunk = chunk.encode("utf8")
|
| 265 |
+
len_str = hex(len(chunk))[2:]
|
| 266 |
+
to_send = bytearray(len_str.encode())
|
| 267 |
+
to_send += b"\r\n"
|
| 268 |
+
to_send += chunk
|
| 269 |
+
to_send += b"\r\n"
|
| 270 |
+
self.send(to_send)
|
| 271 |
+
|
| 272 |
+
# After the if clause, to always have a closed body
|
| 273 |
+
self.send(b"0\r\n\r\n")
|
| 274 |
+
|
| 275 |
+
|
| 276 |
+
class HTTPSConnection(HTTPConnection):
|
| 277 |
+
"""
|
| 278 |
+
Many of the parameters to this constructor are passed to the underlying SSL
|
| 279 |
+
socket by means of :py:func:`urllib3.util.ssl_wrap_socket`.
|
| 280 |
+
"""
|
| 281 |
+
|
| 282 |
+
default_port = port_by_scheme["https"]
|
| 283 |
+
|
| 284 |
+
cert_reqs = None
|
| 285 |
+
ca_certs = None
|
| 286 |
+
ca_cert_dir = None
|
| 287 |
+
ca_cert_data = None
|
| 288 |
+
ssl_version = None
|
| 289 |
+
assert_fingerprint = None
|
| 290 |
+
tls_in_tls_required = False
|
| 291 |
+
|
| 292 |
+
def __init__(
|
| 293 |
+
self,
|
| 294 |
+
host,
|
| 295 |
+
port=None,
|
| 296 |
+
key_file=None,
|
| 297 |
+
cert_file=None,
|
| 298 |
+
key_password=None,
|
| 299 |
+
strict=None,
|
| 300 |
+
timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
|
| 301 |
+
ssl_context=None,
|
| 302 |
+
server_hostname=None,
|
| 303 |
+
**kw
|
| 304 |
+
):
|
| 305 |
+
|
| 306 |
+
HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw)
|
| 307 |
+
|
| 308 |
+
self.key_file = key_file
|
| 309 |
+
self.cert_file = cert_file
|
| 310 |
+
self.key_password = key_password
|
| 311 |
+
self.ssl_context = ssl_context
|
| 312 |
+
self.server_hostname = server_hostname
|
| 313 |
+
|
| 314 |
+
# Required property for Google AppEngine 1.9.0 which otherwise causes
|
| 315 |
+
# HTTPS requests to go out as HTTP. (See Issue #356)
|
| 316 |
+
self._protocol = "https"
|
| 317 |
+
|
| 318 |
+
def set_cert(
|
| 319 |
+
self,
|
| 320 |
+
key_file=None,
|
| 321 |
+
cert_file=None,
|
| 322 |
+
cert_reqs=None,
|
| 323 |
+
key_password=None,
|
| 324 |
+
ca_certs=None,
|
| 325 |
+
assert_hostname=None,
|
| 326 |
+
assert_fingerprint=None,
|
| 327 |
+
ca_cert_dir=None,
|
| 328 |
+
ca_cert_data=None,
|
| 329 |
+
):
|
| 330 |
+
"""
|
| 331 |
+
This method should only be called once, before the connection is used.
|
| 332 |
+
"""
|
| 333 |
+
# If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also
|
| 334 |
+
# have an SSLContext object in which case we'll use its verify_mode.
|
| 335 |
+
if cert_reqs is None:
|
| 336 |
+
if self.ssl_context is not None:
|
| 337 |
+
cert_reqs = self.ssl_context.verify_mode
|
| 338 |
+
else:
|
| 339 |
+
cert_reqs = resolve_cert_reqs(None)
|
| 340 |
+
|
| 341 |
+
self.key_file = key_file
|
| 342 |
+
self.cert_file = cert_file
|
| 343 |
+
self.cert_reqs = cert_reqs
|
| 344 |
+
self.key_password = key_password
|
| 345 |
+
self.assert_hostname = assert_hostname
|
| 346 |
+
self.assert_fingerprint = assert_fingerprint
|
| 347 |
+
self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
|
| 348 |
+
self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
|
| 349 |
+
self.ca_cert_data = ca_cert_data
|
| 350 |
+
|
| 351 |
+
def connect(self):
|
| 352 |
+
# Add certificate verification
|
| 353 |
+
conn = self._new_conn()
|
| 354 |
+
hostname = self.host
|
| 355 |
+
tls_in_tls = False
|
| 356 |
+
|
| 357 |
+
if self._is_using_tunnel():
|
| 358 |
+
if self.tls_in_tls_required:
|
| 359 |
+
conn = self._connect_tls_proxy(hostname, conn)
|
| 360 |
+
tls_in_tls = True
|
| 361 |
+
|
| 362 |
+
self.sock = conn
|
| 363 |
+
|
| 364 |
+
# Calls self._set_hostport(), so self.host is
|
| 365 |
+
# self._tunnel_host below.
|
| 366 |
+
self._tunnel()
|
| 367 |
+
# Mark this connection as not reusable
|
| 368 |
+
self.auto_open = 0
|
| 369 |
+
|
| 370 |
+
# Override the host with the one we're requesting data from.
|
| 371 |
+
hostname = self._tunnel_host
|
| 372 |
+
|
| 373 |
+
server_hostname = hostname
|
| 374 |
+
if self.server_hostname is not None:
|
| 375 |
+
server_hostname = self.server_hostname
|
| 376 |
+
|
| 377 |
+
is_time_off = datetime.date.today() < RECENT_DATE
|
| 378 |
+
if is_time_off:
|
| 379 |
+
warnings.warn(
|
| 380 |
+
(
|
| 381 |
+
"System time is way off (before {0}). This will probably "
|
| 382 |
+
"lead to SSL verification errors"
|
| 383 |
+
).format(RECENT_DATE),
|
| 384 |
+
SystemTimeWarning,
|
| 385 |
+
)
|
| 386 |
+
|
| 387 |
+
# Wrap socket using verification with the root certs in
|
| 388 |
+
# trusted_root_certs
|
| 389 |
+
default_ssl_context = False
|
| 390 |
+
if self.ssl_context is None:
|
| 391 |
+
default_ssl_context = True
|
| 392 |
+
self.ssl_context = create_urllib3_context(
|
| 393 |
+
ssl_version=resolve_ssl_version(self.ssl_version),
|
| 394 |
+
cert_reqs=resolve_cert_reqs(self.cert_reqs),
|
| 395 |
+
)
|
| 396 |
+
|
| 397 |
+
context = self.ssl_context
|
| 398 |
+
context.verify_mode = resolve_cert_reqs(self.cert_reqs)
|
| 399 |
+
|
| 400 |
+
# Try to load OS default certs if none are given.
|
| 401 |
+
# Works well on Windows (requires Python3.4+)
|
| 402 |
+
if (
|
| 403 |
+
not self.ca_certs
|
| 404 |
+
and not self.ca_cert_dir
|
| 405 |
+
and not self.ca_cert_data
|
| 406 |
+
and default_ssl_context
|
| 407 |
+
and hasattr(context, "load_default_certs")
|
| 408 |
+
):
|
| 409 |
+
context.load_default_certs()
|
| 410 |
+
|
| 411 |
+
self.sock = ssl_wrap_socket(
|
| 412 |
+
sock=conn,
|
| 413 |
+
keyfile=self.key_file,
|
| 414 |
+
certfile=self.cert_file,
|
| 415 |
+
key_password=self.key_password,
|
| 416 |
+
ca_certs=self.ca_certs,
|
| 417 |
+
ca_cert_dir=self.ca_cert_dir,
|
| 418 |
+
ca_cert_data=self.ca_cert_data,
|
| 419 |
+
server_hostname=server_hostname,
|
| 420 |
+
ssl_context=context,
|
| 421 |
+
tls_in_tls=tls_in_tls,
|
| 422 |
+
)
|
| 423 |
+
|
| 424 |
+
# If we're using all defaults and the connection
|
| 425 |
+
# is TLSv1 or TLSv1.1 we throw a DeprecationWarning
|
| 426 |
+
# for the host.
|
| 427 |
+
if (
|
| 428 |
+
default_ssl_context
|
| 429 |
+
and self.ssl_version is None
|
| 430 |
+
and hasattr(self.sock, "version")
|
| 431 |
+
and self.sock.version() in {"TLSv1", "TLSv1.1"}
|
| 432 |
+
):
|
| 433 |
+
warnings.warn(
|
| 434 |
+
"Negotiating TLSv1/TLSv1.1 by default is deprecated "
|
| 435 |
+
"and will be disabled in urllib3 v2.0.0. Connecting to "
|
| 436 |
+
"'%s' with '%s' can be enabled by explicitly opting-in "
|
| 437 |
+
"with 'ssl_version'" % (self.host, self.sock.version()),
|
| 438 |
+
DeprecationWarning,
|
| 439 |
+
)
|
| 440 |
+
|
| 441 |
+
if self.assert_fingerprint:
|
| 442 |
+
assert_fingerprint(
|
| 443 |
+
self.sock.getpeercert(binary_form=True), self.assert_fingerprint
|
| 444 |
+
)
|
| 445 |
+
elif (
|
| 446 |
+
context.verify_mode != ssl.CERT_NONE
|
| 447 |
+
and not getattr(context, "check_hostname", False)
|
| 448 |
+
and self.assert_hostname is not False
|
| 449 |
+
):
|
| 450 |
+
# While urllib3 attempts to always turn off hostname matching from
|
| 451 |
+
# the TLS library, this cannot always be done. So we check whether
|
| 452 |
+
# the TLS Library still thinks it's matching hostnames.
|
| 453 |
+
cert = self.sock.getpeercert()
|
| 454 |
+
if not cert.get("subjectAltName", ()):
|
| 455 |
+
warnings.warn(
|
| 456 |
+
(
|
| 457 |
+
"Certificate for {0} has no `subjectAltName`, falling back to check for a "
|
| 458 |
+
"`commonName` for now. This feature is being removed by major browsers and "
|
| 459 |
+
"deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 "
|
| 460 |
+
"for details.)".format(hostname)
|
| 461 |
+
),
|
| 462 |
+
SubjectAltNameWarning,
|
| 463 |
+
)
|
| 464 |
+
_match_hostname(cert, self.assert_hostname or server_hostname)
|
| 465 |
+
|
| 466 |
+
self.is_verified = (
|
| 467 |
+
context.verify_mode == ssl.CERT_REQUIRED
|
| 468 |
+
or self.assert_fingerprint is not None
|
| 469 |
+
)
|
| 470 |
+
|
| 471 |
+
def _connect_tls_proxy(self, hostname, conn):
|
| 472 |
+
"""
|
| 473 |
+
Establish a TLS connection to the proxy using the provided SSL context.
|
| 474 |
+
"""
|
| 475 |
+
proxy_config = self.proxy_config
|
| 476 |
+
ssl_context = proxy_config.ssl_context
|
| 477 |
+
if ssl_context:
|
| 478 |
+
# If the user provided a proxy context, we assume CA and client
|
| 479 |
+
# certificates have already been set
|
| 480 |
+
return ssl_wrap_socket(
|
| 481 |
+
sock=conn,
|
| 482 |
+
server_hostname=hostname,
|
| 483 |
+
ssl_context=ssl_context,
|
| 484 |
+
)
|
| 485 |
+
|
| 486 |
+
ssl_context = create_proxy_ssl_context(
|
| 487 |
+
self.ssl_version,
|
| 488 |
+
self.cert_reqs,
|
| 489 |
+
self.ca_certs,
|
| 490 |
+
self.ca_cert_dir,
|
| 491 |
+
self.ca_cert_data,
|
| 492 |
+
)
|
| 493 |
+
# By default urllib3's SSLContext disables `check_hostname` and uses
|
| 494 |
+
# a custom check. For proxies we're good with relying on the default
|
| 495 |
+
# verification.
|
| 496 |
+
ssl_context.check_hostname = True
|
| 497 |
+
|
| 498 |
+
# If no cert was provided, use only the default options for server
|
| 499 |
+
# certificate validation
|
| 500 |
+
return ssl_wrap_socket(
|
| 501 |
+
sock=conn,
|
| 502 |
+
ca_certs=self.ca_certs,
|
| 503 |
+
ca_cert_dir=self.ca_cert_dir,
|
| 504 |
+
ca_cert_data=self.ca_cert_data,
|
| 505 |
+
server_hostname=hostname,
|
| 506 |
+
ssl_context=ssl_context,
|
| 507 |
+
)
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
def _match_hostname(cert, asserted_hostname):
|
| 511 |
+
try:
|
| 512 |
+
match_hostname(cert, asserted_hostname)
|
| 513 |
+
except CertificateError as e:
|
| 514 |
+
log.warning(
|
| 515 |
+
"Certificate did not match expected hostname: %s. Certificate: %s",
|
| 516 |
+
asserted_hostname,
|
| 517 |
+
cert,
|
| 518 |
+
)
|
| 519 |
+
# Add cert to exception and reraise so client code can inspect
|
| 520 |
+
# the cert when catching the exception, if they want to
|
| 521 |
+
e._peer_cert = cert
|
| 522 |
+
raise
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
def _get_default_user_agent():
|
| 526 |
+
return "python-urllib3/%s" % __version__
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
class DummyConnection(object):
|
| 530 |
+
"""Used to detect a failed ConnectionCls import."""
|
| 531 |
+
|
| 532 |
+
pass
|
| 533 |
+
|
| 534 |
+
|
| 535 |
+
if not ssl:
|
| 536 |
+
HTTPSConnection = DummyConnection # noqa: F811
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
VerifiedHTTPSConnection = HTTPSConnection
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/connectionpool.py
ADDED
|
@@ -0,0 +1,1067 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import errno
|
| 4 |
+
import logging
|
| 5 |
+
import socket
|
| 6 |
+
import sys
|
| 7 |
+
import warnings
|
| 8 |
+
from socket import error as SocketError
|
| 9 |
+
from socket import timeout as SocketTimeout
|
| 10 |
+
|
| 11 |
+
from .connection import (
|
| 12 |
+
BaseSSLError,
|
| 13 |
+
BrokenPipeError,
|
| 14 |
+
DummyConnection,
|
| 15 |
+
HTTPConnection,
|
| 16 |
+
HTTPException,
|
| 17 |
+
HTTPSConnection,
|
| 18 |
+
VerifiedHTTPSConnection,
|
| 19 |
+
port_by_scheme,
|
| 20 |
+
)
|
| 21 |
+
from .exceptions import (
|
| 22 |
+
ClosedPoolError,
|
| 23 |
+
EmptyPoolError,
|
| 24 |
+
HeaderParsingError,
|
| 25 |
+
HostChangedError,
|
| 26 |
+
InsecureRequestWarning,
|
| 27 |
+
LocationValueError,
|
| 28 |
+
MaxRetryError,
|
| 29 |
+
NewConnectionError,
|
| 30 |
+
ProtocolError,
|
| 31 |
+
ProxyError,
|
| 32 |
+
ReadTimeoutError,
|
| 33 |
+
SSLError,
|
| 34 |
+
TimeoutError,
|
| 35 |
+
)
|
| 36 |
+
from .packages import six
|
| 37 |
+
from .packages.six.moves import queue
|
| 38 |
+
from .packages.ssl_match_hostname import CertificateError
|
| 39 |
+
from .request import RequestMethods
|
| 40 |
+
from .response import HTTPResponse
|
| 41 |
+
from .util.connection import is_connection_dropped
|
| 42 |
+
from .util.proxy import connection_requires_http_tunnel
|
| 43 |
+
from .util.queue import LifoQueue
|
| 44 |
+
from .util.request import set_file_position
|
| 45 |
+
from .util.response import assert_header_parsing
|
| 46 |
+
from .util.retry import Retry
|
| 47 |
+
from .util.timeout import Timeout
|
| 48 |
+
from .util.url import Url, _encode_target
|
| 49 |
+
from .util.url import _normalize_host as normalize_host
|
| 50 |
+
from .util.url import get_host, parse_url
|
| 51 |
+
|
| 52 |
+
xrange = six.moves.xrange
|
| 53 |
+
|
| 54 |
+
log = logging.getLogger(__name__)
|
| 55 |
+
|
| 56 |
+
_Default = object()
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
# Pool objects
|
| 60 |
+
class ConnectionPool(object):
|
| 61 |
+
"""
|
| 62 |
+
Base class for all connection pools, such as
|
| 63 |
+
:class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
|
| 64 |
+
|
| 65 |
+
.. note::
|
| 66 |
+
ConnectionPool.urlopen() does not normalize or percent-encode target URIs
|
| 67 |
+
which is useful if your target server doesn't support percent-encoded
|
| 68 |
+
target URIs.
|
| 69 |
+
"""
|
| 70 |
+
|
| 71 |
+
scheme = None
|
| 72 |
+
QueueCls = LifoQueue
|
| 73 |
+
|
| 74 |
+
def __init__(self, host, port=None):
|
| 75 |
+
if not host:
|
| 76 |
+
raise LocationValueError("No host specified.")
|
| 77 |
+
|
| 78 |
+
self.host = _normalize_host(host, scheme=self.scheme)
|
| 79 |
+
self._proxy_host = host.lower()
|
| 80 |
+
self.port = port
|
| 81 |
+
|
| 82 |
+
def __str__(self):
|
| 83 |
+
return "%s(host=%r, port=%r)" % (type(self).__name__, self.host, self.port)
|
| 84 |
+
|
| 85 |
+
def __enter__(self):
|
| 86 |
+
return self
|
| 87 |
+
|
| 88 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
| 89 |
+
self.close()
|
| 90 |
+
# Return False to re-raise any potential exceptions
|
| 91 |
+
return False
|
| 92 |
+
|
| 93 |
+
def close(self):
|
| 94 |
+
"""
|
| 95 |
+
Close all pooled connections and disable the pool.
|
| 96 |
+
"""
|
| 97 |
+
pass
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252
|
| 101 |
+
_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK}
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class HTTPConnectionPool(ConnectionPool, RequestMethods):
|
| 105 |
+
"""
|
| 106 |
+
Thread-safe connection pool for one host.
|
| 107 |
+
|
| 108 |
+
:param host:
|
| 109 |
+
Host used for this HTTP Connection (e.g. "localhost"), passed into
|
| 110 |
+
:class:`http.client.HTTPConnection`.
|
| 111 |
+
|
| 112 |
+
:param port:
|
| 113 |
+
Port used for this HTTP Connection (None is equivalent to 80), passed
|
| 114 |
+
into :class:`http.client.HTTPConnection`.
|
| 115 |
+
|
| 116 |
+
:param strict:
|
| 117 |
+
Causes BadStatusLine to be raised if the status line can't be parsed
|
| 118 |
+
as a valid HTTP/1.0 or 1.1 status line, passed into
|
| 119 |
+
:class:`http.client.HTTPConnection`.
|
| 120 |
+
|
| 121 |
+
.. note::
|
| 122 |
+
Only works in Python 2. This parameter is ignored in Python 3.
|
| 123 |
+
|
| 124 |
+
:param timeout:
|
| 125 |
+
Socket timeout in seconds for each individual connection. This can
|
| 126 |
+
be a float or integer, which sets the timeout for the HTTP request,
|
| 127 |
+
or an instance of :class:`urllib3.util.Timeout` which gives you more
|
| 128 |
+
fine-grained control over request timeouts. After the constructor has
|
| 129 |
+
been parsed, this is always a `urllib3.util.Timeout` object.
|
| 130 |
+
|
| 131 |
+
:param maxsize:
|
| 132 |
+
Number of connections to save that can be reused. More than 1 is useful
|
| 133 |
+
in multithreaded situations. If ``block`` is set to False, more
|
| 134 |
+
connections will be created but they will not be saved once they've
|
| 135 |
+
been used.
|
| 136 |
+
|
| 137 |
+
:param block:
|
| 138 |
+
If set to True, no more than ``maxsize`` connections will be used at
|
| 139 |
+
a time. When no free connections are available, the call will block
|
| 140 |
+
until a connection has been released. This is a useful side effect for
|
| 141 |
+
particular multithreaded situations where one does not want to use more
|
| 142 |
+
than maxsize connections per host to prevent flooding.
|
| 143 |
+
|
| 144 |
+
:param headers:
|
| 145 |
+
Headers to include with all requests, unless other headers are given
|
| 146 |
+
explicitly.
|
| 147 |
+
|
| 148 |
+
:param retries:
|
| 149 |
+
Retry configuration to use by default with requests in this pool.
|
| 150 |
+
|
| 151 |
+
:param _proxy:
|
| 152 |
+
Parsed proxy URL, should not be used directly, instead, see
|
| 153 |
+
:class:`urllib3.ProxyManager`
|
| 154 |
+
|
| 155 |
+
:param _proxy_headers:
|
| 156 |
+
A dictionary with proxy headers, should not be used directly,
|
| 157 |
+
instead, see :class:`urllib3.ProxyManager`
|
| 158 |
+
|
| 159 |
+
:param \\**conn_kw:
|
| 160 |
+
Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`,
|
| 161 |
+
:class:`urllib3.connection.HTTPSConnection` instances.
|
| 162 |
+
"""
|
| 163 |
+
|
| 164 |
+
scheme = "http"
|
| 165 |
+
ConnectionCls = HTTPConnection
|
| 166 |
+
ResponseCls = HTTPResponse
|
| 167 |
+
|
| 168 |
+
def __init__(
|
| 169 |
+
self,
|
| 170 |
+
host,
|
| 171 |
+
port=None,
|
| 172 |
+
strict=False,
|
| 173 |
+
timeout=Timeout.DEFAULT_TIMEOUT,
|
| 174 |
+
maxsize=1,
|
| 175 |
+
block=False,
|
| 176 |
+
headers=None,
|
| 177 |
+
retries=None,
|
| 178 |
+
_proxy=None,
|
| 179 |
+
_proxy_headers=None,
|
| 180 |
+
_proxy_config=None,
|
| 181 |
+
**conn_kw
|
| 182 |
+
):
|
| 183 |
+
ConnectionPool.__init__(self, host, port)
|
| 184 |
+
RequestMethods.__init__(self, headers)
|
| 185 |
+
|
| 186 |
+
self.strict = strict
|
| 187 |
+
|
| 188 |
+
if not isinstance(timeout, Timeout):
|
| 189 |
+
timeout = Timeout.from_float(timeout)
|
| 190 |
+
|
| 191 |
+
if retries is None:
|
| 192 |
+
retries = Retry.DEFAULT
|
| 193 |
+
|
| 194 |
+
self.timeout = timeout
|
| 195 |
+
self.retries = retries
|
| 196 |
+
|
| 197 |
+
self.pool = self.QueueCls(maxsize)
|
| 198 |
+
self.block = block
|
| 199 |
+
|
| 200 |
+
self.proxy = _proxy
|
| 201 |
+
self.proxy_headers = _proxy_headers or {}
|
| 202 |
+
self.proxy_config = _proxy_config
|
| 203 |
+
|
| 204 |
+
# Fill the queue up so that doing get() on it will block properly
|
| 205 |
+
for _ in xrange(maxsize):
|
| 206 |
+
self.pool.put(None)
|
| 207 |
+
|
| 208 |
+
# These are mostly for testing and debugging purposes.
|
| 209 |
+
self.num_connections = 0
|
| 210 |
+
self.num_requests = 0
|
| 211 |
+
self.conn_kw = conn_kw
|
| 212 |
+
|
| 213 |
+
if self.proxy:
|
| 214 |
+
# Enable Nagle's algorithm for proxies, to avoid packet fragmentation.
|
| 215 |
+
# We cannot know if the user has added default socket options, so we cannot replace the
|
| 216 |
+
# list.
|
| 217 |
+
self.conn_kw.setdefault("socket_options", [])
|
| 218 |
+
|
| 219 |
+
self.conn_kw["proxy"] = self.proxy
|
| 220 |
+
self.conn_kw["proxy_config"] = self.proxy_config
|
| 221 |
+
|
| 222 |
+
def _new_conn(self):
|
| 223 |
+
"""
|
| 224 |
+
Return a fresh :class:`HTTPConnection`.
|
| 225 |
+
"""
|
| 226 |
+
self.num_connections += 1
|
| 227 |
+
log.debug(
|
| 228 |
+
"Starting new HTTP connection (%d): %s:%s",
|
| 229 |
+
self.num_connections,
|
| 230 |
+
self.host,
|
| 231 |
+
self.port or "80",
|
| 232 |
+
)
|
| 233 |
+
|
| 234 |
+
conn = self.ConnectionCls(
|
| 235 |
+
host=self.host,
|
| 236 |
+
port=self.port,
|
| 237 |
+
timeout=self.timeout.connect_timeout,
|
| 238 |
+
strict=self.strict,
|
| 239 |
+
**self.conn_kw
|
| 240 |
+
)
|
| 241 |
+
return conn
|
| 242 |
+
|
| 243 |
+
def _get_conn(self, timeout=None):
|
| 244 |
+
"""
|
| 245 |
+
Get a connection. Will return a pooled connection if one is available.
|
| 246 |
+
|
| 247 |
+
If no connections are available and :prop:`.block` is ``False``, then a
|
| 248 |
+
fresh connection is returned.
|
| 249 |
+
|
| 250 |
+
:param timeout:
|
| 251 |
+
Seconds to wait before giving up and raising
|
| 252 |
+
:class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and
|
| 253 |
+
:prop:`.block` is ``True``.
|
| 254 |
+
"""
|
| 255 |
+
conn = None
|
| 256 |
+
try:
|
| 257 |
+
conn = self.pool.get(block=self.block, timeout=timeout)
|
| 258 |
+
|
| 259 |
+
except AttributeError: # self.pool is None
|
| 260 |
+
raise ClosedPoolError(self, "Pool is closed.")
|
| 261 |
+
|
| 262 |
+
except queue.Empty:
|
| 263 |
+
if self.block:
|
| 264 |
+
raise EmptyPoolError(
|
| 265 |
+
self,
|
| 266 |
+
"Pool reached maximum size and no more connections are allowed.",
|
| 267 |
+
)
|
| 268 |
+
pass # Oh well, we'll create a new connection then
|
| 269 |
+
|
| 270 |
+
# If this is a persistent connection, check if it got disconnected
|
| 271 |
+
if conn and is_connection_dropped(conn):
|
| 272 |
+
log.debug("Resetting dropped connection: %s", self.host)
|
| 273 |
+
conn.close()
|
| 274 |
+
if getattr(conn, "auto_open", 1) == 0:
|
| 275 |
+
# This is a proxied connection that has been mutated by
|
| 276 |
+
# http.client._tunnel() and cannot be reused (since it would
|
| 277 |
+
# attempt to bypass the proxy)
|
| 278 |
+
conn = None
|
| 279 |
+
|
| 280 |
+
return conn or self._new_conn()
|
| 281 |
+
|
| 282 |
+
def _put_conn(self, conn):
|
| 283 |
+
"""
|
| 284 |
+
Put a connection back into the pool.
|
| 285 |
+
|
| 286 |
+
:param conn:
|
| 287 |
+
Connection object for the current host and port as returned by
|
| 288 |
+
:meth:`._new_conn` or :meth:`._get_conn`.
|
| 289 |
+
|
| 290 |
+
If the pool is already full, the connection is closed and discarded
|
| 291 |
+
because we exceeded maxsize. If connections are discarded frequently,
|
| 292 |
+
then maxsize should be increased.
|
| 293 |
+
|
| 294 |
+
If the pool is closed, then the connection will be closed and discarded.
|
| 295 |
+
"""
|
| 296 |
+
try:
|
| 297 |
+
self.pool.put(conn, block=False)
|
| 298 |
+
return # Everything is dandy, done.
|
| 299 |
+
except AttributeError:
|
| 300 |
+
# self.pool is None.
|
| 301 |
+
pass
|
| 302 |
+
except queue.Full:
|
| 303 |
+
# This should never happen if self.block == True
|
| 304 |
+
log.warning("Connection pool is full, discarding connection: %s", self.host)
|
| 305 |
+
|
| 306 |
+
# Connection never got put back into the pool, close it.
|
| 307 |
+
if conn:
|
| 308 |
+
conn.close()
|
| 309 |
+
|
| 310 |
+
def _validate_conn(self, conn):
|
| 311 |
+
"""
|
| 312 |
+
Called right before a request is made, after the socket is created.
|
| 313 |
+
"""
|
| 314 |
+
pass
|
| 315 |
+
|
| 316 |
+
def _prepare_proxy(self, conn):
|
| 317 |
+
# Nothing to do for HTTP connections.
|
| 318 |
+
pass
|
| 319 |
+
|
| 320 |
+
def _get_timeout(self, timeout):
|
| 321 |
+
"""Helper that always returns a :class:`urllib3.util.Timeout`"""
|
| 322 |
+
if timeout is _Default:
|
| 323 |
+
return self.timeout.clone()
|
| 324 |
+
|
| 325 |
+
if isinstance(timeout, Timeout):
|
| 326 |
+
return timeout.clone()
|
| 327 |
+
else:
|
| 328 |
+
# User passed us an int/float. This is for backwards compatibility,
|
| 329 |
+
# can be removed later
|
| 330 |
+
return Timeout.from_float(timeout)
|
| 331 |
+
|
| 332 |
+
def _raise_timeout(self, err, url, timeout_value):
|
| 333 |
+
"""Is the error actually a timeout? Will raise a ReadTimeout or pass"""
|
| 334 |
+
|
| 335 |
+
if isinstance(err, SocketTimeout):
|
| 336 |
+
raise ReadTimeoutError(
|
| 337 |
+
self, url, "Read timed out. (read timeout=%s)" % timeout_value
|
| 338 |
+
)
|
| 339 |
+
|
| 340 |
+
# See the above comment about EAGAIN in Python 3. In Python 2 we have
|
| 341 |
+
# to specifically catch it and throw the timeout error
|
| 342 |
+
if hasattr(err, "errno") and err.errno in _blocking_errnos:
|
| 343 |
+
raise ReadTimeoutError(
|
| 344 |
+
self, url, "Read timed out. (read timeout=%s)" % timeout_value
|
| 345 |
+
)
|
| 346 |
+
|
| 347 |
+
# Catch possible read timeouts thrown as SSL errors. If not the
|
| 348 |
+
# case, rethrow the original. We need to do this because of:
|
| 349 |
+
# http://bugs.python.org/issue10272
|
| 350 |
+
if "timed out" in str(err) or "did not complete (read)" in str(
|
| 351 |
+
err
|
| 352 |
+
): # Python < 2.7.4
|
| 353 |
+
raise ReadTimeoutError(
|
| 354 |
+
self, url, "Read timed out. (read timeout=%s)" % timeout_value
|
| 355 |
+
)
|
| 356 |
+
|
| 357 |
+
def _make_request(
|
| 358 |
+
self, conn, method, url, timeout=_Default, chunked=False, **httplib_request_kw
|
| 359 |
+
):
|
| 360 |
+
"""
|
| 361 |
+
Perform a request on a given urllib connection object taken from our
|
| 362 |
+
pool.
|
| 363 |
+
|
| 364 |
+
:param conn:
|
| 365 |
+
a connection from one of our connection pools
|
| 366 |
+
|
| 367 |
+
:param timeout:
|
| 368 |
+
Socket timeout in seconds for the request. This can be a
|
| 369 |
+
float or integer, which will set the same timeout value for
|
| 370 |
+
the socket connect and the socket read, or an instance of
|
| 371 |
+
:class:`urllib3.util.Timeout`, which gives you more fine-grained
|
| 372 |
+
control over your timeouts.
|
| 373 |
+
"""
|
| 374 |
+
self.num_requests += 1
|
| 375 |
+
|
| 376 |
+
timeout_obj = self._get_timeout(timeout)
|
| 377 |
+
timeout_obj.start_connect()
|
| 378 |
+
conn.timeout = timeout_obj.connect_timeout
|
| 379 |
+
|
| 380 |
+
# Trigger any extra validation we need to do.
|
| 381 |
+
try:
|
| 382 |
+
self._validate_conn(conn)
|
| 383 |
+
except (SocketTimeout, BaseSSLError) as e:
|
| 384 |
+
# Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout.
|
| 385 |
+
self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)
|
| 386 |
+
raise
|
| 387 |
+
|
| 388 |
+
# conn.request() calls http.client.*.request, not the method in
|
| 389 |
+
# urllib3.request. It also calls makefile (recv) on the socket.
|
| 390 |
+
try:
|
| 391 |
+
if chunked:
|
| 392 |
+
conn.request_chunked(method, url, **httplib_request_kw)
|
| 393 |
+
else:
|
| 394 |
+
conn.request(method, url, **httplib_request_kw)
|
| 395 |
+
|
| 396 |
+
# We are swallowing BrokenPipeError (errno.EPIPE) since the server is
|
| 397 |
+
# legitimately able to close the connection after sending a valid response.
|
| 398 |
+
# With this behaviour, the received response is still readable.
|
| 399 |
+
except BrokenPipeError:
|
| 400 |
+
# Python 3
|
| 401 |
+
pass
|
| 402 |
+
except IOError as e:
|
| 403 |
+
# Python 2 and macOS/Linux
|
| 404 |
+
# EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE is needed on macOS
|
| 405 |
+
# https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
|
| 406 |
+
if e.errno not in {
|
| 407 |
+
errno.EPIPE,
|
| 408 |
+
errno.ESHUTDOWN,
|
| 409 |
+
errno.EPROTOTYPE,
|
| 410 |
+
}:
|
| 411 |
+
raise
|
| 412 |
+
|
| 413 |
+
# Reset the timeout for the recv() on the socket
|
| 414 |
+
read_timeout = timeout_obj.read_timeout
|
| 415 |
+
|
| 416 |
+
# App Engine doesn't have a sock attr
|
| 417 |
+
if getattr(conn, "sock", None):
|
| 418 |
+
# In Python 3 socket.py will catch EAGAIN and return None when you
|
| 419 |
+
# try and read into the file pointer created by http.client, which
|
| 420 |
+
# instead raises a BadStatusLine exception. Instead of catching
|
| 421 |
+
# the exception and assuming all BadStatusLine exceptions are read
|
| 422 |
+
# timeouts, check for a zero timeout before making the request.
|
| 423 |
+
if read_timeout == 0:
|
| 424 |
+
raise ReadTimeoutError(
|
| 425 |
+
self, url, "Read timed out. (read timeout=%s)" % read_timeout
|
| 426 |
+
)
|
| 427 |
+
if read_timeout is Timeout.DEFAULT_TIMEOUT:
|
| 428 |
+
conn.sock.settimeout(socket.getdefaulttimeout())
|
| 429 |
+
else: # None or a value
|
| 430 |
+
conn.sock.settimeout(read_timeout)
|
| 431 |
+
|
| 432 |
+
# Receive the response from the server
|
| 433 |
+
try:
|
| 434 |
+
try:
|
| 435 |
+
# Python 2.7, use buffering of HTTP responses
|
| 436 |
+
httplib_response = conn.getresponse(buffering=True)
|
| 437 |
+
except TypeError:
|
| 438 |
+
# Python 3
|
| 439 |
+
try:
|
| 440 |
+
httplib_response = conn.getresponse()
|
| 441 |
+
except BaseException as e:
|
| 442 |
+
# Remove the TypeError from the exception chain in
|
| 443 |
+
# Python 3 (including for exceptions like SystemExit).
|
| 444 |
+
# Otherwise it looks like a bug in the code.
|
| 445 |
+
six.raise_from(e, None)
|
| 446 |
+
except (SocketTimeout, BaseSSLError, SocketError) as e:
|
| 447 |
+
self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
|
| 448 |
+
raise
|
| 449 |
+
|
| 450 |
+
# AppEngine doesn't have a version attr.
|
| 451 |
+
http_version = getattr(conn, "_http_vsn_str", "HTTP/?")
|
| 452 |
+
log.debug(
|
| 453 |
+
'%s://%s:%s "%s %s %s" %s %s',
|
| 454 |
+
self.scheme,
|
| 455 |
+
self.host,
|
| 456 |
+
self.port,
|
| 457 |
+
method,
|
| 458 |
+
url,
|
| 459 |
+
http_version,
|
| 460 |
+
httplib_response.status,
|
| 461 |
+
httplib_response.length,
|
| 462 |
+
)
|
| 463 |
+
|
| 464 |
+
try:
|
| 465 |
+
assert_header_parsing(httplib_response.msg)
|
| 466 |
+
except (HeaderParsingError, TypeError) as hpe: # Platform-specific: Python 3
|
| 467 |
+
log.warning(
|
| 468 |
+
"Failed to parse headers (url=%s): %s",
|
| 469 |
+
self._absolute_url(url),
|
| 470 |
+
hpe,
|
| 471 |
+
exc_info=True,
|
| 472 |
+
)
|
| 473 |
+
|
| 474 |
+
return httplib_response
|
| 475 |
+
|
| 476 |
+
def _absolute_url(self, path):
|
| 477 |
+
return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url
|
| 478 |
+
|
| 479 |
+
def close(self):
|
| 480 |
+
"""
|
| 481 |
+
Close all pooled connections and disable the pool.
|
| 482 |
+
"""
|
| 483 |
+
if self.pool is None:
|
| 484 |
+
return
|
| 485 |
+
# Disable access to the pool
|
| 486 |
+
old_pool, self.pool = self.pool, None
|
| 487 |
+
|
| 488 |
+
try:
|
| 489 |
+
while True:
|
| 490 |
+
conn = old_pool.get(block=False)
|
| 491 |
+
if conn:
|
| 492 |
+
conn.close()
|
| 493 |
+
|
| 494 |
+
except queue.Empty:
|
| 495 |
+
pass # Done.
|
| 496 |
+
|
| 497 |
+
def is_same_host(self, url):
|
| 498 |
+
"""
|
| 499 |
+
Check if the given ``url`` is a member of the same host as this
|
| 500 |
+
connection pool.
|
| 501 |
+
"""
|
| 502 |
+
if url.startswith("/"):
|
| 503 |
+
return True
|
| 504 |
+
|
| 505 |
+
# TODO: Add optional support for socket.gethostbyname checking.
|
| 506 |
+
scheme, host, port = get_host(url)
|
| 507 |
+
if host is not None:
|
| 508 |
+
host = _normalize_host(host, scheme=scheme)
|
| 509 |
+
|
| 510 |
+
# Use explicit default port for comparison when none is given
|
| 511 |
+
if self.port and not port:
|
| 512 |
+
port = port_by_scheme.get(scheme)
|
| 513 |
+
elif not self.port and port == port_by_scheme.get(scheme):
|
| 514 |
+
port = None
|
| 515 |
+
|
| 516 |
+
return (scheme, host, port) == (self.scheme, self.host, self.port)
|
| 517 |
+
|
| 518 |
+
def urlopen(
|
| 519 |
+
self,
|
| 520 |
+
method,
|
| 521 |
+
url,
|
| 522 |
+
body=None,
|
| 523 |
+
headers=None,
|
| 524 |
+
retries=None,
|
| 525 |
+
redirect=True,
|
| 526 |
+
assert_same_host=True,
|
| 527 |
+
timeout=_Default,
|
| 528 |
+
pool_timeout=None,
|
| 529 |
+
release_conn=None,
|
| 530 |
+
chunked=False,
|
| 531 |
+
body_pos=None,
|
| 532 |
+
**response_kw
|
| 533 |
+
):
|
| 534 |
+
"""
|
| 535 |
+
Get a connection from the pool and perform an HTTP request. This is the
|
| 536 |
+
lowest level call for making a request, so you'll need to specify all
|
| 537 |
+
the raw details.
|
| 538 |
+
|
| 539 |
+
.. note::
|
| 540 |
+
|
| 541 |
+
More commonly, it's appropriate to use a convenience method provided
|
| 542 |
+
by :class:`.RequestMethods`, such as :meth:`request`.
|
| 543 |
+
|
| 544 |
+
.. note::
|
| 545 |
+
|
| 546 |
+
`release_conn` will only behave as expected if
|
| 547 |
+
`preload_content=False` because we want to make
|
| 548 |
+
`preload_content=False` the default behaviour someday soon without
|
| 549 |
+
breaking backwards compatibility.
|
| 550 |
+
|
| 551 |
+
:param method:
|
| 552 |
+
HTTP request method (such as GET, POST, PUT, etc.)
|
| 553 |
+
|
| 554 |
+
:param url:
|
| 555 |
+
The URL to perform the request on.
|
| 556 |
+
|
| 557 |
+
:param body:
|
| 558 |
+
Data to send in the request body, either :class:`str`, :class:`bytes`,
|
| 559 |
+
an iterable of :class:`str`/:class:`bytes`, or a file-like object.
|
| 560 |
+
|
| 561 |
+
:param headers:
|
| 562 |
+
Dictionary of custom headers to send, such as User-Agent,
|
| 563 |
+
If-None-Match, etc. If None, pool headers are used. If provided,
|
| 564 |
+
these headers completely replace any pool-specific headers.
|
| 565 |
+
|
| 566 |
+
:param retries:
|
| 567 |
+
Configure the number of retries to allow before raising a
|
| 568 |
+
:class:`~urllib3.exceptions.MaxRetryError` exception.
|
| 569 |
+
|
| 570 |
+
Pass ``None`` to retry until you receive a response. Pass a
|
| 571 |
+
:class:`~urllib3.util.retry.Retry` object for fine-grained control
|
| 572 |
+
over different types of retries.
|
| 573 |
+
Pass an integer number to retry connection errors that many times,
|
| 574 |
+
but no other types of errors. Pass zero to never retry.
|
| 575 |
+
|
| 576 |
+
If ``False``, then retries are disabled and any exception is raised
|
| 577 |
+
immediately. Also, instead of raising a MaxRetryError on redirects,
|
| 578 |
+
the redirect response will be returned.
|
| 579 |
+
|
| 580 |
+
:type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
|
| 581 |
+
|
| 582 |
+
:param redirect:
|
| 583 |
+
If True, automatically handle redirects (status codes 301, 302,
|
| 584 |
+
303, 307, 308). Each redirect counts as a retry. Disabling retries
|
| 585 |
+
will disable redirect, too.
|
| 586 |
+
|
| 587 |
+
:param assert_same_host:
|
| 588 |
+
If ``True``, will make sure that the host of the pool requests is
|
| 589 |
+
consistent else will raise HostChangedError. When ``False``, you can
|
| 590 |
+
use the pool on an HTTP proxy and request foreign hosts.
|
| 591 |
+
|
| 592 |
+
:param timeout:
|
| 593 |
+
If specified, overrides the default timeout for this one
|
| 594 |
+
request. It may be a float (in seconds) or an instance of
|
| 595 |
+
:class:`urllib3.util.Timeout`.
|
| 596 |
+
|
| 597 |
+
:param pool_timeout:
|
| 598 |
+
If set and the pool is set to block=True, then this method will
|
| 599 |
+
block for ``pool_timeout`` seconds and raise EmptyPoolError if no
|
| 600 |
+
connection is available within the time period.
|
| 601 |
+
|
| 602 |
+
:param release_conn:
|
| 603 |
+
If False, then the urlopen call will not release the connection
|
| 604 |
+
back into the pool once a response is received (but will release if
|
| 605 |
+
you read the entire contents of the response such as when
|
| 606 |
+
`preload_content=True`). This is useful if you're not preloading
|
| 607 |
+
the response's content immediately. You will need to call
|
| 608 |
+
``r.release_conn()`` on the response ``r`` to return the connection
|
| 609 |
+
back into the pool. If None, it takes the value of
|
| 610 |
+
``response_kw.get('preload_content', True)``.
|
| 611 |
+
|
| 612 |
+
:param chunked:
|
| 613 |
+
If True, urllib3 will send the body using chunked transfer
|
| 614 |
+
encoding. Otherwise, urllib3 will send the body using the standard
|
| 615 |
+
content-length form. Defaults to False.
|
| 616 |
+
|
| 617 |
+
:param int body_pos:
|
| 618 |
+
Position to seek to in file-like body in the event of a retry or
|
| 619 |
+
redirect. Typically this won't need to be set because urllib3 will
|
| 620 |
+
auto-populate the value when needed.
|
| 621 |
+
|
| 622 |
+
:param \\**response_kw:
|
| 623 |
+
Additional parameters are passed to
|
| 624 |
+
:meth:`urllib3.response.HTTPResponse.from_httplib`
|
| 625 |
+
"""
|
| 626 |
+
|
| 627 |
+
parsed_url = parse_url(url)
|
| 628 |
+
destination_scheme = parsed_url.scheme
|
| 629 |
+
|
| 630 |
+
if headers is None:
|
| 631 |
+
headers = self.headers
|
| 632 |
+
|
| 633 |
+
if not isinstance(retries, Retry):
|
| 634 |
+
retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
|
| 635 |
+
|
| 636 |
+
if release_conn is None:
|
| 637 |
+
release_conn = response_kw.get("preload_content", True)
|
| 638 |
+
|
| 639 |
+
# Check host
|
| 640 |
+
if assert_same_host and not self.is_same_host(url):
|
| 641 |
+
raise HostChangedError(self, url, retries)
|
| 642 |
+
|
| 643 |
+
# Ensure that the URL we're connecting to is properly encoded
|
| 644 |
+
if url.startswith("/"):
|
| 645 |
+
url = six.ensure_str(_encode_target(url))
|
| 646 |
+
else:
|
| 647 |
+
url = six.ensure_str(parsed_url.url)
|
| 648 |
+
|
| 649 |
+
conn = None
|
| 650 |
+
|
| 651 |
+
# Track whether `conn` needs to be released before
|
| 652 |
+
# returning/raising/recursing. Update this variable if necessary, and
|
| 653 |
+
# leave `release_conn` constant throughout the function. That way, if
|
| 654 |
+
# the function recurses, the original value of `release_conn` will be
|
| 655 |
+
# passed down into the recursive call, and its value will be respected.
|
| 656 |
+
#
|
| 657 |
+
# See issue #651 [1] for details.
|
| 658 |
+
#
|
| 659 |
+
# [1] <https://github.com/urllib3/urllib3/issues/651>
|
| 660 |
+
release_this_conn = release_conn
|
| 661 |
+
|
| 662 |
+
http_tunnel_required = connection_requires_http_tunnel(
|
| 663 |
+
self.proxy, self.proxy_config, destination_scheme
|
| 664 |
+
)
|
| 665 |
+
|
| 666 |
+
# Merge the proxy headers. Only done when not using HTTP CONNECT. We
|
| 667 |
+
# have to copy the headers dict so we can safely change it without those
|
| 668 |
+
# changes being reflected in anyone else's copy.
|
| 669 |
+
if not http_tunnel_required:
|
| 670 |
+
headers = headers.copy()
|
| 671 |
+
headers.update(self.proxy_headers)
|
| 672 |
+
|
| 673 |
+
# Must keep the exception bound to a separate variable or else Python 3
|
| 674 |
+
# complains about UnboundLocalError.
|
| 675 |
+
err = None
|
| 676 |
+
|
| 677 |
+
# Keep track of whether we cleanly exited the except block. This
|
| 678 |
+
# ensures we do proper cleanup in finally.
|
| 679 |
+
clean_exit = False
|
| 680 |
+
|
| 681 |
+
# Rewind body position, if needed. Record current position
|
| 682 |
+
# for future rewinds in the event of a redirect/retry.
|
| 683 |
+
body_pos = set_file_position(body, body_pos)
|
| 684 |
+
|
| 685 |
+
try:
|
| 686 |
+
# Request a connection from the queue.
|
| 687 |
+
timeout_obj = self._get_timeout(timeout)
|
| 688 |
+
conn = self._get_conn(timeout=pool_timeout)
|
| 689 |
+
|
| 690 |
+
conn.timeout = timeout_obj.connect_timeout
|
| 691 |
+
|
| 692 |
+
is_new_proxy_conn = self.proxy is not None and not getattr(
|
| 693 |
+
conn, "sock", None
|
| 694 |
+
)
|
| 695 |
+
if is_new_proxy_conn and http_tunnel_required:
|
| 696 |
+
self._prepare_proxy(conn)
|
| 697 |
+
|
| 698 |
+
# Make the request on the httplib connection object.
|
| 699 |
+
httplib_response = self._make_request(
|
| 700 |
+
conn,
|
| 701 |
+
method,
|
| 702 |
+
url,
|
| 703 |
+
timeout=timeout_obj,
|
| 704 |
+
body=body,
|
| 705 |
+
headers=headers,
|
| 706 |
+
chunked=chunked,
|
| 707 |
+
)
|
| 708 |
+
|
| 709 |
+
# If we're going to release the connection in ``finally:``, then
|
| 710 |
+
# the response doesn't need to know about the connection. Otherwise
|
| 711 |
+
# it will also try to release it and we'll have a double-release
|
| 712 |
+
# mess.
|
| 713 |
+
response_conn = conn if not release_conn else None
|
| 714 |
+
|
| 715 |
+
# Pass method to Response for length checking
|
| 716 |
+
response_kw["request_method"] = method
|
| 717 |
+
|
| 718 |
+
# Import httplib's response into our own wrapper object
|
| 719 |
+
response = self.ResponseCls.from_httplib(
|
| 720 |
+
httplib_response,
|
| 721 |
+
pool=self,
|
| 722 |
+
connection=response_conn,
|
| 723 |
+
retries=retries,
|
| 724 |
+
**response_kw
|
| 725 |
+
)
|
| 726 |
+
|
| 727 |
+
# Everything went great!
|
| 728 |
+
clean_exit = True
|
| 729 |
+
|
| 730 |
+
except EmptyPoolError:
|
| 731 |
+
# Didn't get a connection from the pool, no need to clean up
|
| 732 |
+
clean_exit = True
|
| 733 |
+
release_this_conn = False
|
| 734 |
+
raise
|
| 735 |
+
|
| 736 |
+
except (
|
| 737 |
+
TimeoutError,
|
| 738 |
+
HTTPException,
|
| 739 |
+
SocketError,
|
| 740 |
+
ProtocolError,
|
| 741 |
+
BaseSSLError,
|
| 742 |
+
SSLError,
|
| 743 |
+
CertificateError,
|
| 744 |
+
) as e:
|
| 745 |
+
# Discard the connection for these exceptions. It will be
|
| 746 |
+
# replaced during the next _get_conn() call.
|
| 747 |
+
clean_exit = False
|
| 748 |
+
if isinstance(e, (BaseSSLError, CertificateError)):
|
| 749 |
+
e = SSLError(e)
|
| 750 |
+
elif isinstance(e, (SocketError, NewConnectionError)) and self.proxy:
|
| 751 |
+
e = ProxyError("Cannot connect to proxy.", e)
|
| 752 |
+
elif isinstance(e, (SocketError, HTTPException)):
|
| 753 |
+
e = ProtocolError("Connection aborted.", e)
|
| 754 |
+
|
| 755 |
+
retries = retries.increment(
|
| 756 |
+
method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
|
| 757 |
+
)
|
| 758 |
+
retries.sleep()
|
| 759 |
+
|
| 760 |
+
# Keep track of the error for the retry warning.
|
| 761 |
+
err = e
|
| 762 |
+
|
| 763 |
+
finally:
|
| 764 |
+
if not clean_exit:
|
| 765 |
+
# We hit some kind of exception, handled or otherwise. We need
|
| 766 |
+
# to throw the connection away unless explicitly told not to.
|
| 767 |
+
# Close the connection, set the variable to None, and make sure
|
| 768 |
+
# we put the None back in the pool to avoid leaking it.
|
| 769 |
+
conn = conn and conn.close()
|
| 770 |
+
release_this_conn = True
|
| 771 |
+
|
| 772 |
+
if release_this_conn:
|
| 773 |
+
# Put the connection back to be reused. If the connection is
|
| 774 |
+
# expired then it will be None, which will get replaced with a
|
| 775 |
+
# fresh connection during _get_conn.
|
| 776 |
+
self._put_conn(conn)
|
| 777 |
+
|
| 778 |
+
if not conn:
|
| 779 |
+
# Try again
|
| 780 |
+
log.warning(
|
| 781 |
+
"Retrying (%r) after connection broken by '%r': %s", retries, err, url
|
| 782 |
+
)
|
| 783 |
+
return self.urlopen(
|
| 784 |
+
method,
|
| 785 |
+
url,
|
| 786 |
+
body,
|
| 787 |
+
headers,
|
| 788 |
+
retries,
|
| 789 |
+
redirect,
|
| 790 |
+
assert_same_host,
|
| 791 |
+
timeout=timeout,
|
| 792 |
+
pool_timeout=pool_timeout,
|
| 793 |
+
release_conn=release_conn,
|
| 794 |
+
chunked=chunked,
|
| 795 |
+
body_pos=body_pos,
|
| 796 |
+
**response_kw
|
| 797 |
+
)
|
| 798 |
+
|
| 799 |
+
# Handle redirect?
|
| 800 |
+
redirect_location = redirect and response.get_redirect_location()
|
| 801 |
+
if redirect_location:
|
| 802 |
+
if response.status == 303:
|
| 803 |
+
method = "GET"
|
| 804 |
+
|
| 805 |
+
try:
|
| 806 |
+
retries = retries.increment(method, url, response=response, _pool=self)
|
| 807 |
+
except MaxRetryError:
|
| 808 |
+
if retries.raise_on_redirect:
|
| 809 |
+
response.drain_conn()
|
| 810 |
+
raise
|
| 811 |
+
return response
|
| 812 |
+
|
| 813 |
+
response.drain_conn()
|
| 814 |
+
retries.sleep_for_retry(response)
|
| 815 |
+
log.debug("Redirecting %s -> %s", url, redirect_location)
|
| 816 |
+
return self.urlopen(
|
| 817 |
+
method,
|
| 818 |
+
redirect_location,
|
| 819 |
+
body,
|
| 820 |
+
headers,
|
| 821 |
+
retries=retries,
|
| 822 |
+
redirect=redirect,
|
| 823 |
+
assert_same_host=assert_same_host,
|
| 824 |
+
timeout=timeout,
|
| 825 |
+
pool_timeout=pool_timeout,
|
| 826 |
+
release_conn=release_conn,
|
| 827 |
+
chunked=chunked,
|
| 828 |
+
body_pos=body_pos,
|
| 829 |
+
**response_kw
|
| 830 |
+
)
|
| 831 |
+
|
| 832 |
+
# Check if we should retry the HTTP response.
|
| 833 |
+
has_retry_after = bool(response.getheader("Retry-After"))
|
| 834 |
+
if retries.is_retry(method, response.status, has_retry_after):
|
| 835 |
+
try:
|
| 836 |
+
retries = retries.increment(method, url, response=response, _pool=self)
|
| 837 |
+
except MaxRetryError:
|
| 838 |
+
if retries.raise_on_status:
|
| 839 |
+
response.drain_conn()
|
| 840 |
+
raise
|
| 841 |
+
return response
|
| 842 |
+
|
| 843 |
+
response.drain_conn()
|
| 844 |
+
retries.sleep(response)
|
| 845 |
+
log.debug("Retry: %s", url)
|
| 846 |
+
return self.urlopen(
|
| 847 |
+
method,
|
| 848 |
+
url,
|
| 849 |
+
body,
|
| 850 |
+
headers,
|
| 851 |
+
retries=retries,
|
| 852 |
+
redirect=redirect,
|
| 853 |
+
assert_same_host=assert_same_host,
|
| 854 |
+
timeout=timeout,
|
| 855 |
+
pool_timeout=pool_timeout,
|
| 856 |
+
release_conn=release_conn,
|
| 857 |
+
chunked=chunked,
|
| 858 |
+
body_pos=body_pos,
|
| 859 |
+
**response_kw
|
| 860 |
+
)
|
| 861 |
+
|
| 862 |
+
return response
|
| 863 |
+
|
| 864 |
+
|
| 865 |
+
class HTTPSConnectionPool(HTTPConnectionPool):
|
| 866 |
+
"""
|
| 867 |
+
Same as :class:`.HTTPConnectionPool`, but HTTPS.
|
| 868 |
+
|
| 869 |
+
:class:`.HTTPSConnection` uses one of ``assert_fingerprint``,
|
| 870 |
+
``assert_hostname`` and ``host`` in this order to verify connections.
|
| 871 |
+
If ``assert_hostname`` is False, no verification is done.
|
| 872 |
+
|
| 873 |
+
The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``,
|
| 874 |
+
``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl`
|
| 875 |
+
is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade
|
| 876 |
+
the connection socket into an SSL socket.
|
| 877 |
+
"""
|
| 878 |
+
|
| 879 |
+
scheme = "https"
|
| 880 |
+
ConnectionCls = HTTPSConnection
|
| 881 |
+
|
| 882 |
+
def __init__(
|
| 883 |
+
self,
|
| 884 |
+
host,
|
| 885 |
+
port=None,
|
| 886 |
+
strict=False,
|
| 887 |
+
timeout=Timeout.DEFAULT_TIMEOUT,
|
| 888 |
+
maxsize=1,
|
| 889 |
+
block=False,
|
| 890 |
+
headers=None,
|
| 891 |
+
retries=None,
|
| 892 |
+
_proxy=None,
|
| 893 |
+
_proxy_headers=None,
|
| 894 |
+
key_file=None,
|
| 895 |
+
cert_file=None,
|
| 896 |
+
cert_reqs=None,
|
| 897 |
+
key_password=None,
|
| 898 |
+
ca_certs=None,
|
| 899 |
+
ssl_version=None,
|
| 900 |
+
assert_hostname=None,
|
| 901 |
+
assert_fingerprint=None,
|
| 902 |
+
ca_cert_dir=None,
|
| 903 |
+
**conn_kw
|
| 904 |
+
):
|
| 905 |
+
|
| 906 |
+
HTTPConnectionPool.__init__(
|
| 907 |
+
self,
|
| 908 |
+
host,
|
| 909 |
+
port,
|
| 910 |
+
strict,
|
| 911 |
+
timeout,
|
| 912 |
+
maxsize,
|
| 913 |
+
block,
|
| 914 |
+
headers,
|
| 915 |
+
retries,
|
| 916 |
+
_proxy,
|
| 917 |
+
_proxy_headers,
|
| 918 |
+
**conn_kw
|
| 919 |
+
)
|
| 920 |
+
|
| 921 |
+
self.key_file = key_file
|
| 922 |
+
self.cert_file = cert_file
|
| 923 |
+
self.cert_reqs = cert_reqs
|
| 924 |
+
self.key_password = key_password
|
| 925 |
+
self.ca_certs = ca_certs
|
| 926 |
+
self.ca_cert_dir = ca_cert_dir
|
| 927 |
+
self.ssl_version = ssl_version
|
| 928 |
+
self.assert_hostname = assert_hostname
|
| 929 |
+
self.assert_fingerprint = assert_fingerprint
|
| 930 |
+
|
| 931 |
+
def _prepare_conn(self, conn):
|
| 932 |
+
"""
|
| 933 |
+
Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket`
|
| 934 |
+
and establish the tunnel if proxy is used.
|
| 935 |
+
"""
|
| 936 |
+
|
| 937 |
+
if isinstance(conn, VerifiedHTTPSConnection):
|
| 938 |
+
conn.set_cert(
|
| 939 |
+
key_file=self.key_file,
|
| 940 |
+
key_password=self.key_password,
|
| 941 |
+
cert_file=self.cert_file,
|
| 942 |
+
cert_reqs=self.cert_reqs,
|
| 943 |
+
ca_certs=self.ca_certs,
|
| 944 |
+
ca_cert_dir=self.ca_cert_dir,
|
| 945 |
+
assert_hostname=self.assert_hostname,
|
| 946 |
+
assert_fingerprint=self.assert_fingerprint,
|
| 947 |
+
)
|
| 948 |
+
conn.ssl_version = self.ssl_version
|
| 949 |
+
return conn
|
| 950 |
+
|
| 951 |
+
def _prepare_proxy(self, conn):
|
| 952 |
+
"""
|
| 953 |
+
Establishes a tunnel connection through HTTP CONNECT.
|
| 954 |
+
|
| 955 |
+
Tunnel connection is established early because otherwise httplib would
|
| 956 |
+
improperly set Host: header to proxy's IP:port.
|
| 957 |
+
"""
|
| 958 |
+
|
| 959 |
+
conn.set_tunnel(self._proxy_host, self.port, self.proxy_headers)
|
| 960 |
+
|
| 961 |
+
if self.proxy.scheme == "https":
|
| 962 |
+
conn.tls_in_tls_required = True
|
| 963 |
+
|
| 964 |
+
conn.connect()
|
| 965 |
+
|
| 966 |
+
def _new_conn(self):
|
| 967 |
+
"""
|
| 968 |
+
Return a fresh :class:`http.client.HTTPSConnection`.
|
| 969 |
+
"""
|
| 970 |
+
self.num_connections += 1
|
| 971 |
+
log.debug(
|
| 972 |
+
"Starting new HTTPS connection (%d): %s:%s",
|
| 973 |
+
self.num_connections,
|
| 974 |
+
self.host,
|
| 975 |
+
self.port or "443",
|
| 976 |
+
)
|
| 977 |
+
|
| 978 |
+
if not self.ConnectionCls or self.ConnectionCls is DummyConnection:
|
| 979 |
+
raise SSLError(
|
| 980 |
+
"Can't connect to HTTPS URL because the SSL module is not available."
|
| 981 |
+
)
|
| 982 |
+
|
| 983 |
+
actual_host = self.host
|
| 984 |
+
actual_port = self.port
|
| 985 |
+
if self.proxy is not None:
|
| 986 |
+
actual_host = self.proxy.host
|
| 987 |
+
actual_port = self.proxy.port
|
| 988 |
+
|
| 989 |
+
conn = self.ConnectionCls(
|
| 990 |
+
host=actual_host,
|
| 991 |
+
port=actual_port,
|
| 992 |
+
timeout=self.timeout.connect_timeout,
|
| 993 |
+
strict=self.strict,
|
| 994 |
+
cert_file=self.cert_file,
|
| 995 |
+
key_file=self.key_file,
|
| 996 |
+
key_password=self.key_password,
|
| 997 |
+
**self.conn_kw
|
| 998 |
+
)
|
| 999 |
+
|
| 1000 |
+
return self._prepare_conn(conn)
|
| 1001 |
+
|
| 1002 |
+
def _validate_conn(self, conn):
|
| 1003 |
+
"""
|
| 1004 |
+
Called right before a request is made, after the socket is created.
|
| 1005 |
+
"""
|
| 1006 |
+
super(HTTPSConnectionPool, self)._validate_conn(conn)
|
| 1007 |
+
|
| 1008 |
+
# Force connect early to allow us to validate the connection.
|
| 1009 |
+
if not getattr(conn, "sock", None): # AppEngine might not have `.sock`
|
| 1010 |
+
conn.connect()
|
| 1011 |
+
|
| 1012 |
+
if not conn.is_verified:
|
| 1013 |
+
warnings.warn(
|
| 1014 |
+
(
|
| 1015 |
+
"Unverified HTTPS request is being made to host '%s'. "
|
| 1016 |
+
"Adding certificate verification is strongly advised. See: "
|
| 1017 |
+
"https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html"
|
| 1018 |
+
"#ssl-warnings" % conn.host
|
| 1019 |
+
),
|
| 1020 |
+
InsecureRequestWarning,
|
| 1021 |
+
)
|
| 1022 |
+
|
| 1023 |
+
|
| 1024 |
+
def connection_from_url(url, **kw):
|
| 1025 |
+
"""
|
| 1026 |
+
Given a url, return an :class:`.ConnectionPool` instance of its host.
|
| 1027 |
+
|
| 1028 |
+
This is a shortcut for not having to parse out the scheme, host, and port
|
| 1029 |
+
of the url before creating an :class:`.ConnectionPool` instance.
|
| 1030 |
+
|
| 1031 |
+
:param url:
|
| 1032 |
+
Absolute URL string that must include the scheme. Port is optional.
|
| 1033 |
+
|
| 1034 |
+
:param \\**kw:
|
| 1035 |
+
Passes additional parameters to the constructor of the appropriate
|
| 1036 |
+
:class:`.ConnectionPool`. Useful for specifying things like
|
| 1037 |
+
timeout, maxsize, headers, etc.
|
| 1038 |
+
|
| 1039 |
+
Example::
|
| 1040 |
+
|
| 1041 |
+
>>> conn = connection_from_url('http://google.com/')
|
| 1042 |
+
>>> r = conn.request('GET', '/')
|
| 1043 |
+
"""
|
| 1044 |
+
scheme, host, port = get_host(url)
|
| 1045 |
+
port = port or port_by_scheme.get(scheme, 80)
|
| 1046 |
+
if scheme == "https":
|
| 1047 |
+
return HTTPSConnectionPool(host, port=port, **kw)
|
| 1048 |
+
else:
|
| 1049 |
+
return HTTPConnectionPool(host, port=port, **kw)
|
| 1050 |
+
|
| 1051 |
+
|
| 1052 |
+
def _normalize_host(host, scheme):
|
| 1053 |
+
"""
|
| 1054 |
+
Normalize hosts for comparisons and use with sockets.
|
| 1055 |
+
"""
|
| 1056 |
+
|
| 1057 |
+
host = normalize_host(host, scheme)
|
| 1058 |
+
|
| 1059 |
+
# httplib doesn't like it when we include brackets in IPv6 addresses
|
| 1060 |
+
# Specifically, if we include brackets but also pass the port then
|
| 1061 |
+
# httplib crazily doubles up the square brackets on the Host header.
|
| 1062 |
+
# Instead, we need to make sure we never pass ``None`` as the port.
|
| 1063 |
+
# However, for backward compatibility reasons we can't actually
|
| 1064 |
+
# *assert* that. See http://bugs.python.org/issue28539
|
| 1065 |
+
if host.startswith("[") and host.endswith("]"):
|
| 1066 |
+
host = host[1:-1]
|
| 1067 |
+
return host
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/__init__.py
ADDED
|
File without changes
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module provides means to detect the App Engine environment.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def is_appengine():
|
| 9 |
+
return is_local_appengine() or is_prod_appengine()
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def is_appengine_sandbox():
|
| 13 |
+
"""Reports if the app is running in the first generation sandbox.
|
| 14 |
+
|
| 15 |
+
The second generation runtimes are technically still in a sandbox, but it
|
| 16 |
+
is much less restrictive, so generally you shouldn't need to check for it.
|
| 17 |
+
see https://cloud.google.com/appengine/docs/standard/runtimes
|
| 18 |
+
"""
|
| 19 |
+
return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27"
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def is_local_appengine():
|
| 23 |
+
return "APPENGINE_RUNTIME" in os.environ and os.environ.get(
|
| 24 |
+
"SERVER_SOFTWARE", ""
|
| 25 |
+
).startswith("Development/")
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def is_prod_appengine():
|
| 29 |
+
return "APPENGINE_RUNTIME" in os.environ and os.environ.get(
|
| 30 |
+
"SERVER_SOFTWARE", ""
|
| 31 |
+
).startswith("Google App Engine/")
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def is_prod_appengine_mvms():
|
| 35 |
+
"""Deprecated."""
|
| 36 |
+
return False
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py
ADDED
|
File without changes
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py
ADDED
|
@@ -0,0 +1,519 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module uses ctypes to bind a whole bunch of functions and constants from
|
| 3 |
+
SecureTransport. The goal here is to provide the low-level API to
|
| 4 |
+
SecureTransport. These are essentially the C-level functions and constants, and
|
| 5 |
+
they're pretty gross to work with.
|
| 6 |
+
|
| 7 |
+
This code is a bastardised version of the code found in Will Bond's oscrypto
|
| 8 |
+
library. An enormous debt is owed to him for blazing this trail for us. For
|
| 9 |
+
that reason, this code should be considered to be covered both by urllib3's
|
| 10 |
+
license and by oscrypto's:
|
| 11 |
+
|
| 12 |
+
Copyright (c) 2015-2016 Will Bond <will@wbond.net>
|
| 13 |
+
|
| 14 |
+
Permission is hereby granted, free of charge, to any person obtaining a
|
| 15 |
+
copy of this software and associated documentation files (the "Software"),
|
| 16 |
+
to deal in the Software without restriction, including without limitation
|
| 17 |
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
| 18 |
+
and/or sell copies of the Software, and to permit persons to whom the
|
| 19 |
+
Software is furnished to do so, subject to the following conditions:
|
| 20 |
+
|
| 21 |
+
The above copyright notice and this permission notice shall be included in
|
| 22 |
+
all copies or substantial portions of the Software.
|
| 23 |
+
|
| 24 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 25 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 26 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 27 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 28 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 29 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
| 30 |
+
DEALINGS IN THE SOFTWARE.
|
| 31 |
+
"""
|
| 32 |
+
from __future__ import absolute_import
|
| 33 |
+
|
| 34 |
+
import platform
|
| 35 |
+
from ctypes import (
|
| 36 |
+
CDLL,
|
| 37 |
+
CFUNCTYPE,
|
| 38 |
+
POINTER,
|
| 39 |
+
c_bool,
|
| 40 |
+
c_byte,
|
| 41 |
+
c_char_p,
|
| 42 |
+
c_int32,
|
| 43 |
+
c_long,
|
| 44 |
+
c_size_t,
|
| 45 |
+
c_uint32,
|
| 46 |
+
c_ulong,
|
| 47 |
+
c_void_p,
|
| 48 |
+
)
|
| 49 |
+
from ctypes.util import find_library
|
| 50 |
+
|
| 51 |
+
from pip._vendor.urllib3.packages.six import raise_from
|
| 52 |
+
|
| 53 |
+
if platform.system() != "Darwin":
|
| 54 |
+
raise ImportError("Only macOS is supported")
|
| 55 |
+
|
| 56 |
+
version = platform.mac_ver()[0]
|
| 57 |
+
version_info = tuple(map(int, version.split(".")))
|
| 58 |
+
if version_info < (10, 8):
|
| 59 |
+
raise OSError(
|
| 60 |
+
"Only OS X 10.8 and newer are supported, not %s.%s"
|
| 61 |
+
% (version_info[0], version_info[1])
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def load_cdll(name, macos10_16_path):
|
| 66 |
+
"""Loads a CDLL by name, falling back to known path on 10.16+"""
|
| 67 |
+
try:
|
| 68 |
+
# Big Sur is technically 11 but we use 10.16 due to the Big Sur
|
| 69 |
+
# beta being labeled as 10.16.
|
| 70 |
+
if version_info >= (10, 16):
|
| 71 |
+
path = macos10_16_path
|
| 72 |
+
else:
|
| 73 |
+
path = find_library(name)
|
| 74 |
+
if not path:
|
| 75 |
+
raise OSError # Caught and reraised as 'ImportError'
|
| 76 |
+
return CDLL(path, use_errno=True)
|
| 77 |
+
except OSError:
|
| 78 |
+
raise_from(ImportError("The library %s failed to load" % name), None)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
Security = load_cdll(
|
| 82 |
+
"Security", "/System/Library/Frameworks/Security.framework/Security"
|
| 83 |
+
)
|
| 84 |
+
CoreFoundation = load_cdll(
|
| 85 |
+
"CoreFoundation",
|
| 86 |
+
"/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation",
|
| 87 |
+
)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
Boolean = c_bool
|
| 91 |
+
CFIndex = c_long
|
| 92 |
+
CFStringEncoding = c_uint32
|
| 93 |
+
CFData = c_void_p
|
| 94 |
+
CFString = c_void_p
|
| 95 |
+
CFArray = c_void_p
|
| 96 |
+
CFMutableArray = c_void_p
|
| 97 |
+
CFDictionary = c_void_p
|
| 98 |
+
CFError = c_void_p
|
| 99 |
+
CFType = c_void_p
|
| 100 |
+
CFTypeID = c_ulong
|
| 101 |
+
|
| 102 |
+
CFTypeRef = POINTER(CFType)
|
| 103 |
+
CFAllocatorRef = c_void_p
|
| 104 |
+
|
| 105 |
+
OSStatus = c_int32
|
| 106 |
+
|
| 107 |
+
CFDataRef = POINTER(CFData)
|
| 108 |
+
CFStringRef = POINTER(CFString)
|
| 109 |
+
CFArrayRef = POINTER(CFArray)
|
| 110 |
+
CFMutableArrayRef = POINTER(CFMutableArray)
|
| 111 |
+
CFDictionaryRef = POINTER(CFDictionary)
|
| 112 |
+
CFArrayCallBacks = c_void_p
|
| 113 |
+
CFDictionaryKeyCallBacks = c_void_p
|
| 114 |
+
CFDictionaryValueCallBacks = c_void_p
|
| 115 |
+
|
| 116 |
+
SecCertificateRef = POINTER(c_void_p)
|
| 117 |
+
SecExternalFormat = c_uint32
|
| 118 |
+
SecExternalItemType = c_uint32
|
| 119 |
+
SecIdentityRef = POINTER(c_void_p)
|
| 120 |
+
SecItemImportExportFlags = c_uint32
|
| 121 |
+
SecItemImportExportKeyParameters = c_void_p
|
| 122 |
+
SecKeychainRef = POINTER(c_void_p)
|
| 123 |
+
SSLProtocol = c_uint32
|
| 124 |
+
SSLCipherSuite = c_uint32
|
| 125 |
+
SSLContextRef = POINTER(c_void_p)
|
| 126 |
+
SecTrustRef = POINTER(c_void_p)
|
| 127 |
+
SSLConnectionRef = c_uint32
|
| 128 |
+
SecTrustResultType = c_uint32
|
| 129 |
+
SecTrustOptionFlags = c_uint32
|
| 130 |
+
SSLProtocolSide = c_uint32
|
| 131 |
+
SSLConnectionType = c_uint32
|
| 132 |
+
SSLSessionOption = c_uint32
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
try:
|
| 136 |
+
Security.SecItemImport.argtypes = [
|
| 137 |
+
CFDataRef,
|
| 138 |
+
CFStringRef,
|
| 139 |
+
POINTER(SecExternalFormat),
|
| 140 |
+
POINTER(SecExternalItemType),
|
| 141 |
+
SecItemImportExportFlags,
|
| 142 |
+
POINTER(SecItemImportExportKeyParameters),
|
| 143 |
+
SecKeychainRef,
|
| 144 |
+
POINTER(CFArrayRef),
|
| 145 |
+
]
|
| 146 |
+
Security.SecItemImport.restype = OSStatus
|
| 147 |
+
|
| 148 |
+
Security.SecCertificateGetTypeID.argtypes = []
|
| 149 |
+
Security.SecCertificateGetTypeID.restype = CFTypeID
|
| 150 |
+
|
| 151 |
+
Security.SecIdentityGetTypeID.argtypes = []
|
| 152 |
+
Security.SecIdentityGetTypeID.restype = CFTypeID
|
| 153 |
+
|
| 154 |
+
Security.SecKeyGetTypeID.argtypes = []
|
| 155 |
+
Security.SecKeyGetTypeID.restype = CFTypeID
|
| 156 |
+
|
| 157 |
+
Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef]
|
| 158 |
+
Security.SecCertificateCreateWithData.restype = SecCertificateRef
|
| 159 |
+
|
| 160 |
+
Security.SecCertificateCopyData.argtypes = [SecCertificateRef]
|
| 161 |
+
Security.SecCertificateCopyData.restype = CFDataRef
|
| 162 |
+
|
| 163 |
+
Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p]
|
| 164 |
+
Security.SecCopyErrorMessageString.restype = CFStringRef
|
| 165 |
+
|
| 166 |
+
Security.SecIdentityCreateWithCertificate.argtypes = [
|
| 167 |
+
CFTypeRef,
|
| 168 |
+
SecCertificateRef,
|
| 169 |
+
POINTER(SecIdentityRef),
|
| 170 |
+
]
|
| 171 |
+
Security.SecIdentityCreateWithCertificate.restype = OSStatus
|
| 172 |
+
|
| 173 |
+
Security.SecKeychainCreate.argtypes = [
|
| 174 |
+
c_char_p,
|
| 175 |
+
c_uint32,
|
| 176 |
+
c_void_p,
|
| 177 |
+
Boolean,
|
| 178 |
+
c_void_p,
|
| 179 |
+
POINTER(SecKeychainRef),
|
| 180 |
+
]
|
| 181 |
+
Security.SecKeychainCreate.restype = OSStatus
|
| 182 |
+
|
| 183 |
+
Security.SecKeychainDelete.argtypes = [SecKeychainRef]
|
| 184 |
+
Security.SecKeychainDelete.restype = OSStatus
|
| 185 |
+
|
| 186 |
+
Security.SecPKCS12Import.argtypes = [
|
| 187 |
+
CFDataRef,
|
| 188 |
+
CFDictionaryRef,
|
| 189 |
+
POINTER(CFArrayRef),
|
| 190 |
+
]
|
| 191 |
+
Security.SecPKCS12Import.restype = OSStatus
|
| 192 |
+
|
| 193 |
+
SSLReadFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, c_void_p, POINTER(c_size_t))
|
| 194 |
+
SSLWriteFunc = CFUNCTYPE(
|
| 195 |
+
OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t)
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
Security.SSLSetIOFuncs.argtypes = [SSLContextRef, SSLReadFunc, SSLWriteFunc]
|
| 199 |
+
Security.SSLSetIOFuncs.restype = OSStatus
|
| 200 |
+
|
| 201 |
+
Security.SSLSetPeerID.argtypes = [SSLContextRef, c_char_p, c_size_t]
|
| 202 |
+
Security.SSLSetPeerID.restype = OSStatus
|
| 203 |
+
|
| 204 |
+
Security.SSLSetCertificate.argtypes = [SSLContextRef, CFArrayRef]
|
| 205 |
+
Security.SSLSetCertificate.restype = OSStatus
|
| 206 |
+
|
| 207 |
+
Security.SSLSetCertificateAuthorities.argtypes = [SSLContextRef, CFTypeRef, Boolean]
|
| 208 |
+
Security.SSLSetCertificateAuthorities.restype = OSStatus
|
| 209 |
+
|
| 210 |
+
Security.SSLSetConnection.argtypes = [SSLContextRef, SSLConnectionRef]
|
| 211 |
+
Security.SSLSetConnection.restype = OSStatus
|
| 212 |
+
|
| 213 |
+
Security.SSLSetPeerDomainName.argtypes = [SSLContextRef, c_char_p, c_size_t]
|
| 214 |
+
Security.SSLSetPeerDomainName.restype = OSStatus
|
| 215 |
+
|
| 216 |
+
Security.SSLHandshake.argtypes = [SSLContextRef]
|
| 217 |
+
Security.SSLHandshake.restype = OSStatus
|
| 218 |
+
|
| 219 |
+
Security.SSLRead.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)]
|
| 220 |
+
Security.SSLRead.restype = OSStatus
|
| 221 |
+
|
| 222 |
+
Security.SSLWrite.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)]
|
| 223 |
+
Security.SSLWrite.restype = OSStatus
|
| 224 |
+
|
| 225 |
+
Security.SSLClose.argtypes = [SSLContextRef]
|
| 226 |
+
Security.SSLClose.restype = OSStatus
|
| 227 |
+
|
| 228 |
+
Security.SSLGetNumberSupportedCiphers.argtypes = [SSLContextRef, POINTER(c_size_t)]
|
| 229 |
+
Security.SSLGetNumberSupportedCiphers.restype = OSStatus
|
| 230 |
+
|
| 231 |
+
Security.SSLGetSupportedCiphers.argtypes = [
|
| 232 |
+
SSLContextRef,
|
| 233 |
+
POINTER(SSLCipherSuite),
|
| 234 |
+
POINTER(c_size_t),
|
| 235 |
+
]
|
| 236 |
+
Security.SSLGetSupportedCiphers.restype = OSStatus
|
| 237 |
+
|
| 238 |
+
Security.SSLSetEnabledCiphers.argtypes = [
|
| 239 |
+
SSLContextRef,
|
| 240 |
+
POINTER(SSLCipherSuite),
|
| 241 |
+
c_size_t,
|
| 242 |
+
]
|
| 243 |
+
Security.SSLSetEnabledCiphers.restype = OSStatus
|
| 244 |
+
|
| 245 |
+
Security.SSLGetNumberEnabledCiphers.argtype = [SSLContextRef, POINTER(c_size_t)]
|
| 246 |
+
Security.SSLGetNumberEnabledCiphers.restype = OSStatus
|
| 247 |
+
|
| 248 |
+
Security.SSLGetEnabledCiphers.argtypes = [
|
| 249 |
+
SSLContextRef,
|
| 250 |
+
POINTER(SSLCipherSuite),
|
| 251 |
+
POINTER(c_size_t),
|
| 252 |
+
]
|
| 253 |
+
Security.SSLGetEnabledCiphers.restype = OSStatus
|
| 254 |
+
|
| 255 |
+
Security.SSLGetNegotiatedCipher.argtypes = [SSLContextRef, POINTER(SSLCipherSuite)]
|
| 256 |
+
Security.SSLGetNegotiatedCipher.restype = OSStatus
|
| 257 |
+
|
| 258 |
+
Security.SSLGetNegotiatedProtocolVersion.argtypes = [
|
| 259 |
+
SSLContextRef,
|
| 260 |
+
POINTER(SSLProtocol),
|
| 261 |
+
]
|
| 262 |
+
Security.SSLGetNegotiatedProtocolVersion.restype = OSStatus
|
| 263 |
+
|
| 264 |
+
Security.SSLCopyPeerTrust.argtypes = [SSLContextRef, POINTER(SecTrustRef)]
|
| 265 |
+
Security.SSLCopyPeerTrust.restype = OSStatus
|
| 266 |
+
|
| 267 |
+
Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef]
|
| 268 |
+
Security.SecTrustSetAnchorCertificates.restype = OSStatus
|
| 269 |
+
|
| 270 |
+
Security.SecTrustSetAnchorCertificatesOnly.argstypes = [SecTrustRef, Boolean]
|
| 271 |
+
Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus
|
| 272 |
+
|
| 273 |
+
Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)]
|
| 274 |
+
Security.SecTrustEvaluate.restype = OSStatus
|
| 275 |
+
|
| 276 |
+
Security.SecTrustGetCertificateCount.argtypes = [SecTrustRef]
|
| 277 |
+
Security.SecTrustGetCertificateCount.restype = CFIndex
|
| 278 |
+
|
| 279 |
+
Security.SecTrustGetCertificateAtIndex.argtypes = [SecTrustRef, CFIndex]
|
| 280 |
+
Security.SecTrustGetCertificateAtIndex.restype = SecCertificateRef
|
| 281 |
+
|
| 282 |
+
Security.SSLCreateContext.argtypes = [
|
| 283 |
+
CFAllocatorRef,
|
| 284 |
+
SSLProtocolSide,
|
| 285 |
+
SSLConnectionType,
|
| 286 |
+
]
|
| 287 |
+
Security.SSLCreateContext.restype = SSLContextRef
|
| 288 |
+
|
| 289 |
+
Security.SSLSetSessionOption.argtypes = [SSLContextRef, SSLSessionOption, Boolean]
|
| 290 |
+
Security.SSLSetSessionOption.restype = OSStatus
|
| 291 |
+
|
| 292 |
+
Security.SSLSetProtocolVersionMin.argtypes = [SSLContextRef, SSLProtocol]
|
| 293 |
+
Security.SSLSetProtocolVersionMin.restype = OSStatus
|
| 294 |
+
|
| 295 |
+
Security.SSLSetProtocolVersionMax.argtypes = [SSLContextRef, SSLProtocol]
|
| 296 |
+
Security.SSLSetProtocolVersionMax.restype = OSStatus
|
| 297 |
+
|
| 298 |
+
try:
|
| 299 |
+
Security.SSLSetALPNProtocols.argtypes = [SSLContextRef, CFArrayRef]
|
| 300 |
+
Security.SSLSetALPNProtocols.restype = OSStatus
|
| 301 |
+
except AttributeError:
|
| 302 |
+
# Supported only in 10.12+
|
| 303 |
+
pass
|
| 304 |
+
|
| 305 |
+
Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p]
|
| 306 |
+
Security.SecCopyErrorMessageString.restype = CFStringRef
|
| 307 |
+
|
| 308 |
+
Security.SSLReadFunc = SSLReadFunc
|
| 309 |
+
Security.SSLWriteFunc = SSLWriteFunc
|
| 310 |
+
Security.SSLContextRef = SSLContextRef
|
| 311 |
+
Security.SSLProtocol = SSLProtocol
|
| 312 |
+
Security.SSLCipherSuite = SSLCipherSuite
|
| 313 |
+
Security.SecIdentityRef = SecIdentityRef
|
| 314 |
+
Security.SecKeychainRef = SecKeychainRef
|
| 315 |
+
Security.SecTrustRef = SecTrustRef
|
| 316 |
+
Security.SecTrustResultType = SecTrustResultType
|
| 317 |
+
Security.SecExternalFormat = SecExternalFormat
|
| 318 |
+
Security.OSStatus = OSStatus
|
| 319 |
+
|
| 320 |
+
Security.kSecImportExportPassphrase = CFStringRef.in_dll(
|
| 321 |
+
Security, "kSecImportExportPassphrase"
|
| 322 |
+
)
|
| 323 |
+
Security.kSecImportItemIdentity = CFStringRef.in_dll(
|
| 324 |
+
Security, "kSecImportItemIdentity"
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
# CoreFoundation time!
|
| 328 |
+
CoreFoundation.CFRetain.argtypes = [CFTypeRef]
|
| 329 |
+
CoreFoundation.CFRetain.restype = CFTypeRef
|
| 330 |
+
|
| 331 |
+
CoreFoundation.CFRelease.argtypes = [CFTypeRef]
|
| 332 |
+
CoreFoundation.CFRelease.restype = None
|
| 333 |
+
|
| 334 |
+
CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef]
|
| 335 |
+
CoreFoundation.CFGetTypeID.restype = CFTypeID
|
| 336 |
+
|
| 337 |
+
CoreFoundation.CFStringCreateWithCString.argtypes = [
|
| 338 |
+
CFAllocatorRef,
|
| 339 |
+
c_char_p,
|
| 340 |
+
CFStringEncoding,
|
| 341 |
+
]
|
| 342 |
+
CoreFoundation.CFStringCreateWithCString.restype = CFStringRef
|
| 343 |
+
|
| 344 |
+
CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding]
|
| 345 |
+
CoreFoundation.CFStringGetCStringPtr.restype = c_char_p
|
| 346 |
+
|
| 347 |
+
CoreFoundation.CFStringGetCString.argtypes = [
|
| 348 |
+
CFStringRef,
|
| 349 |
+
c_char_p,
|
| 350 |
+
CFIndex,
|
| 351 |
+
CFStringEncoding,
|
| 352 |
+
]
|
| 353 |
+
CoreFoundation.CFStringGetCString.restype = c_bool
|
| 354 |
+
|
| 355 |
+
CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex]
|
| 356 |
+
CoreFoundation.CFDataCreate.restype = CFDataRef
|
| 357 |
+
|
| 358 |
+
CoreFoundation.CFDataGetLength.argtypes = [CFDataRef]
|
| 359 |
+
CoreFoundation.CFDataGetLength.restype = CFIndex
|
| 360 |
+
|
| 361 |
+
CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef]
|
| 362 |
+
CoreFoundation.CFDataGetBytePtr.restype = c_void_p
|
| 363 |
+
|
| 364 |
+
CoreFoundation.CFDictionaryCreate.argtypes = [
|
| 365 |
+
CFAllocatorRef,
|
| 366 |
+
POINTER(CFTypeRef),
|
| 367 |
+
POINTER(CFTypeRef),
|
| 368 |
+
CFIndex,
|
| 369 |
+
CFDictionaryKeyCallBacks,
|
| 370 |
+
CFDictionaryValueCallBacks,
|
| 371 |
+
]
|
| 372 |
+
CoreFoundation.CFDictionaryCreate.restype = CFDictionaryRef
|
| 373 |
+
|
| 374 |
+
CoreFoundation.CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef]
|
| 375 |
+
CoreFoundation.CFDictionaryGetValue.restype = CFTypeRef
|
| 376 |
+
|
| 377 |
+
CoreFoundation.CFArrayCreate.argtypes = [
|
| 378 |
+
CFAllocatorRef,
|
| 379 |
+
POINTER(CFTypeRef),
|
| 380 |
+
CFIndex,
|
| 381 |
+
CFArrayCallBacks,
|
| 382 |
+
]
|
| 383 |
+
CoreFoundation.CFArrayCreate.restype = CFArrayRef
|
| 384 |
+
|
| 385 |
+
CoreFoundation.CFArrayCreateMutable.argtypes = [
|
| 386 |
+
CFAllocatorRef,
|
| 387 |
+
CFIndex,
|
| 388 |
+
CFArrayCallBacks,
|
| 389 |
+
]
|
| 390 |
+
CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef
|
| 391 |
+
|
| 392 |
+
CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p]
|
| 393 |
+
CoreFoundation.CFArrayAppendValue.restype = None
|
| 394 |
+
|
| 395 |
+
CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef]
|
| 396 |
+
CoreFoundation.CFArrayGetCount.restype = CFIndex
|
| 397 |
+
|
| 398 |
+
CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex]
|
| 399 |
+
CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p
|
| 400 |
+
|
| 401 |
+
CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll(
|
| 402 |
+
CoreFoundation, "kCFAllocatorDefault"
|
| 403 |
+
)
|
| 404 |
+
CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll(
|
| 405 |
+
CoreFoundation, "kCFTypeArrayCallBacks"
|
| 406 |
+
)
|
| 407 |
+
CoreFoundation.kCFTypeDictionaryKeyCallBacks = c_void_p.in_dll(
|
| 408 |
+
CoreFoundation, "kCFTypeDictionaryKeyCallBacks"
|
| 409 |
+
)
|
| 410 |
+
CoreFoundation.kCFTypeDictionaryValueCallBacks = c_void_p.in_dll(
|
| 411 |
+
CoreFoundation, "kCFTypeDictionaryValueCallBacks"
|
| 412 |
+
)
|
| 413 |
+
|
| 414 |
+
CoreFoundation.CFTypeRef = CFTypeRef
|
| 415 |
+
CoreFoundation.CFArrayRef = CFArrayRef
|
| 416 |
+
CoreFoundation.CFStringRef = CFStringRef
|
| 417 |
+
CoreFoundation.CFDictionaryRef = CFDictionaryRef
|
| 418 |
+
|
| 419 |
+
except (AttributeError):
|
| 420 |
+
raise ImportError("Error initializing ctypes")
|
| 421 |
+
|
| 422 |
+
|
| 423 |
+
class CFConst(object):
|
| 424 |
+
"""
|
| 425 |
+
A class object that acts as essentially a namespace for CoreFoundation
|
| 426 |
+
constants.
|
| 427 |
+
"""
|
| 428 |
+
|
| 429 |
+
kCFStringEncodingUTF8 = CFStringEncoding(0x08000100)
|
| 430 |
+
|
| 431 |
+
|
| 432 |
+
class SecurityConst(object):
|
| 433 |
+
"""
|
| 434 |
+
A class object that acts as essentially a namespace for Security constants.
|
| 435 |
+
"""
|
| 436 |
+
|
| 437 |
+
kSSLSessionOptionBreakOnServerAuth = 0
|
| 438 |
+
|
| 439 |
+
kSSLProtocol2 = 1
|
| 440 |
+
kSSLProtocol3 = 2
|
| 441 |
+
kTLSProtocol1 = 4
|
| 442 |
+
kTLSProtocol11 = 7
|
| 443 |
+
kTLSProtocol12 = 8
|
| 444 |
+
# SecureTransport does not support TLS 1.3 even if there's a constant for it
|
| 445 |
+
kTLSProtocol13 = 10
|
| 446 |
+
kTLSProtocolMaxSupported = 999
|
| 447 |
+
|
| 448 |
+
kSSLClientSide = 1
|
| 449 |
+
kSSLStreamType = 0
|
| 450 |
+
|
| 451 |
+
kSecFormatPEMSequence = 10
|
| 452 |
+
|
| 453 |
+
kSecTrustResultInvalid = 0
|
| 454 |
+
kSecTrustResultProceed = 1
|
| 455 |
+
# This gap is present on purpose: this was kSecTrustResultConfirm, which
|
| 456 |
+
# is deprecated.
|
| 457 |
+
kSecTrustResultDeny = 3
|
| 458 |
+
kSecTrustResultUnspecified = 4
|
| 459 |
+
kSecTrustResultRecoverableTrustFailure = 5
|
| 460 |
+
kSecTrustResultFatalTrustFailure = 6
|
| 461 |
+
kSecTrustResultOtherError = 7
|
| 462 |
+
|
| 463 |
+
errSSLProtocol = -9800
|
| 464 |
+
errSSLWouldBlock = -9803
|
| 465 |
+
errSSLClosedGraceful = -9805
|
| 466 |
+
errSSLClosedNoNotify = -9816
|
| 467 |
+
errSSLClosedAbort = -9806
|
| 468 |
+
|
| 469 |
+
errSSLXCertChainInvalid = -9807
|
| 470 |
+
errSSLCrypto = -9809
|
| 471 |
+
errSSLInternal = -9810
|
| 472 |
+
errSSLCertExpired = -9814
|
| 473 |
+
errSSLCertNotYetValid = -9815
|
| 474 |
+
errSSLUnknownRootCert = -9812
|
| 475 |
+
errSSLNoRootCert = -9813
|
| 476 |
+
errSSLHostNameMismatch = -9843
|
| 477 |
+
errSSLPeerHandshakeFail = -9824
|
| 478 |
+
errSSLPeerUserCancelled = -9839
|
| 479 |
+
errSSLWeakPeerEphemeralDHKey = -9850
|
| 480 |
+
errSSLServerAuthCompleted = -9841
|
| 481 |
+
errSSLRecordOverflow = -9847
|
| 482 |
+
|
| 483 |
+
errSecVerifyFailed = -67808
|
| 484 |
+
errSecNoTrustSettings = -25263
|
| 485 |
+
errSecItemNotFound = -25300
|
| 486 |
+
errSecInvalidTrustSettings = -25262
|
| 487 |
+
|
| 488 |
+
# Cipher suites. We only pick the ones our default cipher string allows.
|
| 489 |
+
# Source: https://developer.apple.com/documentation/security/1550981-ssl_cipher_suite_values
|
| 490 |
+
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C
|
| 491 |
+
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030
|
| 492 |
+
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B
|
| 493 |
+
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F
|
| 494 |
+
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9
|
| 495 |
+
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8
|
| 496 |
+
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F
|
| 497 |
+
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E
|
| 498 |
+
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024
|
| 499 |
+
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028
|
| 500 |
+
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A
|
| 501 |
+
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014
|
| 502 |
+
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B
|
| 503 |
+
TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039
|
| 504 |
+
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023
|
| 505 |
+
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027
|
| 506 |
+
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009
|
| 507 |
+
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013
|
| 508 |
+
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067
|
| 509 |
+
TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033
|
| 510 |
+
TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D
|
| 511 |
+
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C
|
| 512 |
+
TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D
|
| 513 |
+
TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C
|
| 514 |
+
TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035
|
| 515 |
+
TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F
|
| 516 |
+
TLS_AES_128_GCM_SHA256 = 0x1301
|
| 517 |
+
TLS_AES_256_GCM_SHA384 = 0x1302
|
| 518 |
+
TLS_AES_128_CCM_8_SHA256 = 0x1305
|
| 519 |
+
TLS_AES_128_CCM_SHA256 = 0x1304
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Low-level helpers for the SecureTransport bindings.
|
| 3 |
+
|
| 4 |
+
These are Python functions that are not directly related to the high-level APIs
|
| 5 |
+
but are necessary to get them to work. They include a whole bunch of low-level
|
| 6 |
+
CoreFoundation messing about and memory management. The concerns in this module
|
| 7 |
+
are almost entirely about trying to avoid memory leaks and providing
|
| 8 |
+
appropriate and useful assistance to the higher-level code.
|
| 9 |
+
"""
|
| 10 |
+
import base64
|
| 11 |
+
import ctypes
|
| 12 |
+
import itertools
|
| 13 |
+
import os
|
| 14 |
+
import re
|
| 15 |
+
import ssl
|
| 16 |
+
import struct
|
| 17 |
+
import tempfile
|
| 18 |
+
|
| 19 |
+
from .bindings import CFConst, CoreFoundation, Security
|
| 20 |
+
|
| 21 |
+
# This regular expression is used to grab PEM data out of a PEM bundle.
|
| 22 |
+
_PEM_CERTS_RE = re.compile(
|
| 23 |
+
b"-----BEGIN CERTIFICATE-----\n(.*?)\n-----END CERTIFICATE-----", re.DOTALL
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _cf_data_from_bytes(bytestring):
|
| 28 |
+
"""
|
| 29 |
+
Given a bytestring, create a CFData object from it. This CFData object must
|
| 30 |
+
be CFReleased by the caller.
|
| 31 |
+
"""
|
| 32 |
+
return CoreFoundation.CFDataCreate(
|
| 33 |
+
CoreFoundation.kCFAllocatorDefault, bytestring, len(bytestring)
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def _cf_dictionary_from_tuples(tuples):
|
| 38 |
+
"""
|
| 39 |
+
Given a list of Python tuples, create an associated CFDictionary.
|
| 40 |
+
"""
|
| 41 |
+
dictionary_size = len(tuples)
|
| 42 |
+
|
| 43 |
+
# We need to get the dictionary keys and values out in the same order.
|
| 44 |
+
keys = (t[0] for t in tuples)
|
| 45 |
+
values = (t[1] for t in tuples)
|
| 46 |
+
cf_keys = (CoreFoundation.CFTypeRef * dictionary_size)(*keys)
|
| 47 |
+
cf_values = (CoreFoundation.CFTypeRef * dictionary_size)(*values)
|
| 48 |
+
|
| 49 |
+
return CoreFoundation.CFDictionaryCreate(
|
| 50 |
+
CoreFoundation.kCFAllocatorDefault,
|
| 51 |
+
cf_keys,
|
| 52 |
+
cf_values,
|
| 53 |
+
dictionary_size,
|
| 54 |
+
CoreFoundation.kCFTypeDictionaryKeyCallBacks,
|
| 55 |
+
CoreFoundation.kCFTypeDictionaryValueCallBacks,
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def _cfstr(py_bstr):
|
| 60 |
+
"""
|
| 61 |
+
Given a Python binary data, create a CFString.
|
| 62 |
+
The string must be CFReleased by the caller.
|
| 63 |
+
"""
|
| 64 |
+
c_str = ctypes.c_char_p(py_bstr)
|
| 65 |
+
cf_str = CoreFoundation.CFStringCreateWithCString(
|
| 66 |
+
CoreFoundation.kCFAllocatorDefault,
|
| 67 |
+
c_str,
|
| 68 |
+
CFConst.kCFStringEncodingUTF8,
|
| 69 |
+
)
|
| 70 |
+
return cf_str
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def _create_cfstring_array(lst):
|
| 74 |
+
"""
|
| 75 |
+
Given a list of Python binary data, create an associated CFMutableArray.
|
| 76 |
+
The array must be CFReleased by the caller.
|
| 77 |
+
|
| 78 |
+
Raises an ssl.SSLError on failure.
|
| 79 |
+
"""
|
| 80 |
+
cf_arr = None
|
| 81 |
+
try:
|
| 82 |
+
cf_arr = CoreFoundation.CFArrayCreateMutable(
|
| 83 |
+
CoreFoundation.kCFAllocatorDefault,
|
| 84 |
+
0,
|
| 85 |
+
ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
|
| 86 |
+
)
|
| 87 |
+
if not cf_arr:
|
| 88 |
+
raise MemoryError("Unable to allocate memory!")
|
| 89 |
+
for item in lst:
|
| 90 |
+
cf_str = _cfstr(item)
|
| 91 |
+
if not cf_str:
|
| 92 |
+
raise MemoryError("Unable to allocate memory!")
|
| 93 |
+
try:
|
| 94 |
+
CoreFoundation.CFArrayAppendValue(cf_arr, cf_str)
|
| 95 |
+
finally:
|
| 96 |
+
CoreFoundation.CFRelease(cf_str)
|
| 97 |
+
except BaseException as e:
|
| 98 |
+
if cf_arr:
|
| 99 |
+
CoreFoundation.CFRelease(cf_arr)
|
| 100 |
+
raise ssl.SSLError("Unable to allocate array: %s" % (e,))
|
| 101 |
+
return cf_arr
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
def _cf_string_to_unicode(value):
|
| 105 |
+
"""
|
| 106 |
+
Creates a Unicode string from a CFString object. Used entirely for error
|
| 107 |
+
reporting.
|
| 108 |
+
|
| 109 |
+
Yes, it annoys me quite a lot that this function is this complex.
|
| 110 |
+
"""
|
| 111 |
+
value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p))
|
| 112 |
+
|
| 113 |
+
string = CoreFoundation.CFStringGetCStringPtr(
|
| 114 |
+
value_as_void_p, CFConst.kCFStringEncodingUTF8
|
| 115 |
+
)
|
| 116 |
+
if string is None:
|
| 117 |
+
buffer = ctypes.create_string_buffer(1024)
|
| 118 |
+
result = CoreFoundation.CFStringGetCString(
|
| 119 |
+
value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8
|
| 120 |
+
)
|
| 121 |
+
if not result:
|
| 122 |
+
raise OSError("Error copying C string from CFStringRef")
|
| 123 |
+
string = buffer.value
|
| 124 |
+
if string is not None:
|
| 125 |
+
string = string.decode("utf-8")
|
| 126 |
+
return string
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
def _assert_no_error(error, exception_class=None):
|
| 130 |
+
"""
|
| 131 |
+
Checks the return code and throws an exception if there is an error to
|
| 132 |
+
report
|
| 133 |
+
"""
|
| 134 |
+
if error == 0:
|
| 135 |
+
return
|
| 136 |
+
|
| 137 |
+
cf_error_string = Security.SecCopyErrorMessageString(error, None)
|
| 138 |
+
output = _cf_string_to_unicode(cf_error_string)
|
| 139 |
+
CoreFoundation.CFRelease(cf_error_string)
|
| 140 |
+
|
| 141 |
+
if output is None or output == u"":
|
| 142 |
+
output = u"OSStatus %s" % error
|
| 143 |
+
|
| 144 |
+
if exception_class is None:
|
| 145 |
+
exception_class = ssl.SSLError
|
| 146 |
+
|
| 147 |
+
raise exception_class(output)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def _cert_array_from_pem(pem_bundle):
|
| 151 |
+
"""
|
| 152 |
+
Given a bundle of certs in PEM format, turns them into a CFArray of certs
|
| 153 |
+
that can be used to validate a cert chain.
|
| 154 |
+
"""
|
| 155 |
+
# Normalize the PEM bundle's line endings.
|
| 156 |
+
pem_bundle = pem_bundle.replace(b"\r\n", b"\n")
|
| 157 |
+
|
| 158 |
+
der_certs = [
|
| 159 |
+
base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle)
|
| 160 |
+
]
|
| 161 |
+
if not der_certs:
|
| 162 |
+
raise ssl.SSLError("No root certificates specified")
|
| 163 |
+
|
| 164 |
+
cert_array = CoreFoundation.CFArrayCreateMutable(
|
| 165 |
+
CoreFoundation.kCFAllocatorDefault,
|
| 166 |
+
0,
|
| 167 |
+
ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
|
| 168 |
+
)
|
| 169 |
+
if not cert_array:
|
| 170 |
+
raise ssl.SSLError("Unable to allocate memory!")
|
| 171 |
+
|
| 172 |
+
try:
|
| 173 |
+
for der_bytes in der_certs:
|
| 174 |
+
certdata = _cf_data_from_bytes(der_bytes)
|
| 175 |
+
if not certdata:
|
| 176 |
+
raise ssl.SSLError("Unable to allocate memory!")
|
| 177 |
+
cert = Security.SecCertificateCreateWithData(
|
| 178 |
+
CoreFoundation.kCFAllocatorDefault, certdata
|
| 179 |
+
)
|
| 180 |
+
CoreFoundation.CFRelease(certdata)
|
| 181 |
+
if not cert:
|
| 182 |
+
raise ssl.SSLError("Unable to build cert object!")
|
| 183 |
+
|
| 184 |
+
CoreFoundation.CFArrayAppendValue(cert_array, cert)
|
| 185 |
+
CoreFoundation.CFRelease(cert)
|
| 186 |
+
except Exception:
|
| 187 |
+
# We need to free the array before the exception bubbles further.
|
| 188 |
+
# We only want to do that if an error occurs: otherwise, the caller
|
| 189 |
+
# should free.
|
| 190 |
+
CoreFoundation.CFRelease(cert_array)
|
| 191 |
+
|
| 192 |
+
return cert_array
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
def _is_cert(item):
|
| 196 |
+
"""
|
| 197 |
+
Returns True if a given CFTypeRef is a certificate.
|
| 198 |
+
"""
|
| 199 |
+
expected = Security.SecCertificateGetTypeID()
|
| 200 |
+
return CoreFoundation.CFGetTypeID(item) == expected
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
def _is_identity(item):
|
| 204 |
+
"""
|
| 205 |
+
Returns True if a given CFTypeRef is an identity.
|
| 206 |
+
"""
|
| 207 |
+
expected = Security.SecIdentityGetTypeID()
|
| 208 |
+
return CoreFoundation.CFGetTypeID(item) == expected
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def _temporary_keychain():
|
| 212 |
+
"""
|
| 213 |
+
This function creates a temporary Mac keychain that we can use to work with
|
| 214 |
+
credentials. This keychain uses a one-time password and a temporary file to
|
| 215 |
+
store the data. We expect to have one keychain per socket. The returned
|
| 216 |
+
SecKeychainRef must be freed by the caller, including calling
|
| 217 |
+
SecKeychainDelete.
|
| 218 |
+
|
| 219 |
+
Returns a tuple of the SecKeychainRef and the path to the temporary
|
| 220 |
+
directory that contains it.
|
| 221 |
+
"""
|
| 222 |
+
# Unfortunately, SecKeychainCreate requires a path to a keychain. This
|
| 223 |
+
# means we cannot use mkstemp to use a generic temporary file. Instead,
|
| 224 |
+
# we're going to create a temporary directory and a filename to use there.
|
| 225 |
+
# This filename will be 8 random bytes expanded into base64. We also need
|
| 226 |
+
# some random bytes to password-protect the keychain we're creating, so we
|
| 227 |
+
# ask for 40 random bytes.
|
| 228 |
+
random_bytes = os.urandom(40)
|
| 229 |
+
filename = base64.b16encode(random_bytes[:8]).decode("utf-8")
|
| 230 |
+
password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8
|
| 231 |
+
tempdirectory = tempfile.mkdtemp()
|
| 232 |
+
|
| 233 |
+
keychain_path = os.path.join(tempdirectory, filename).encode("utf-8")
|
| 234 |
+
|
| 235 |
+
# We now want to create the keychain itself.
|
| 236 |
+
keychain = Security.SecKeychainRef()
|
| 237 |
+
status = Security.SecKeychainCreate(
|
| 238 |
+
keychain_path, len(password), password, False, None, ctypes.byref(keychain)
|
| 239 |
+
)
|
| 240 |
+
_assert_no_error(status)
|
| 241 |
+
|
| 242 |
+
# Having created the keychain, we want to pass it off to the caller.
|
| 243 |
+
return keychain, tempdirectory
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
def _load_items_from_file(keychain, path):
|
| 247 |
+
"""
|
| 248 |
+
Given a single file, loads all the trust objects from it into arrays and
|
| 249 |
+
the keychain.
|
| 250 |
+
Returns a tuple of lists: the first list is a list of identities, the
|
| 251 |
+
second a list of certs.
|
| 252 |
+
"""
|
| 253 |
+
certificates = []
|
| 254 |
+
identities = []
|
| 255 |
+
result_array = None
|
| 256 |
+
|
| 257 |
+
with open(path, "rb") as f:
|
| 258 |
+
raw_filedata = f.read()
|
| 259 |
+
|
| 260 |
+
try:
|
| 261 |
+
filedata = CoreFoundation.CFDataCreate(
|
| 262 |
+
CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata)
|
| 263 |
+
)
|
| 264 |
+
result_array = CoreFoundation.CFArrayRef()
|
| 265 |
+
result = Security.SecItemImport(
|
| 266 |
+
filedata, # cert data
|
| 267 |
+
None, # Filename, leaving it out for now
|
| 268 |
+
None, # What the type of the file is, we don't care
|
| 269 |
+
None, # what's in the file, we don't care
|
| 270 |
+
0, # import flags
|
| 271 |
+
None, # key params, can include passphrase in the future
|
| 272 |
+
keychain, # The keychain to insert into
|
| 273 |
+
ctypes.byref(result_array), # Results
|
| 274 |
+
)
|
| 275 |
+
_assert_no_error(result)
|
| 276 |
+
|
| 277 |
+
# A CFArray is not very useful to us as an intermediary
|
| 278 |
+
# representation, so we are going to extract the objects we want
|
| 279 |
+
# and then free the array. We don't need to keep hold of keys: the
|
| 280 |
+
# keychain already has them!
|
| 281 |
+
result_count = CoreFoundation.CFArrayGetCount(result_array)
|
| 282 |
+
for index in range(result_count):
|
| 283 |
+
item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index)
|
| 284 |
+
item = ctypes.cast(item, CoreFoundation.CFTypeRef)
|
| 285 |
+
|
| 286 |
+
if _is_cert(item):
|
| 287 |
+
CoreFoundation.CFRetain(item)
|
| 288 |
+
certificates.append(item)
|
| 289 |
+
elif _is_identity(item):
|
| 290 |
+
CoreFoundation.CFRetain(item)
|
| 291 |
+
identities.append(item)
|
| 292 |
+
finally:
|
| 293 |
+
if result_array:
|
| 294 |
+
CoreFoundation.CFRelease(result_array)
|
| 295 |
+
|
| 296 |
+
CoreFoundation.CFRelease(filedata)
|
| 297 |
+
|
| 298 |
+
return (identities, certificates)
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
def _load_client_cert_chain(keychain, *paths):
|
| 302 |
+
"""
|
| 303 |
+
Load certificates and maybe keys from a number of files. Has the end goal
|
| 304 |
+
of returning a CFArray containing one SecIdentityRef, and then zero or more
|
| 305 |
+
SecCertificateRef objects, suitable for use as a client certificate trust
|
| 306 |
+
chain.
|
| 307 |
+
"""
|
| 308 |
+
# Ok, the strategy.
|
| 309 |
+
#
|
| 310 |
+
# This relies on knowing that macOS will not give you a SecIdentityRef
|
| 311 |
+
# unless you have imported a key into a keychain. This is a somewhat
|
| 312 |
+
# artificial limitation of macOS (for example, it doesn't necessarily
|
| 313 |
+
# affect iOS), but there is nothing inside Security.framework that lets you
|
| 314 |
+
# get a SecIdentityRef without having a key in a keychain.
|
| 315 |
+
#
|
| 316 |
+
# So the policy here is we take all the files and iterate them in order.
|
| 317 |
+
# Each one will use SecItemImport to have one or more objects loaded from
|
| 318 |
+
# it. We will also point at a keychain that macOS can use to work with the
|
| 319 |
+
# private key.
|
| 320 |
+
#
|
| 321 |
+
# Once we have all the objects, we'll check what we actually have. If we
|
| 322 |
+
# already have a SecIdentityRef in hand, fab: we'll use that. Otherwise,
|
| 323 |
+
# we'll take the first certificate (which we assume to be our leaf) and
|
| 324 |
+
# ask the keychain to give us a SecIdentityRef with that cert's associated
|
| 325 |
+
# key.
|
| 326 |
+
#
|
| 327 |
+
# We'll then return a CFArray containing the trust chain: one
|
| 328 |
+
# SecIdentityRef and then zero-or-more SecCertificateRef objects. The
|
| 329 |
+
# responsibility for freeing this CFArray will be with the caller. This
|
| 330 |
+
# CFArray must remain alive for the entire connection, so in practice it
|
| 331 |
+
# will be stored with a single SSLSocket, along with the reference to the
|
| 332 |
+
# keychain.
|
| 333 |
+
certificates = []
|
| 334 |
+
identities = []
|
| 335 |
+
|
| 336 |
+
# Filter out bad paths.
|
| 337 |
+
paths = (path for path in paths if path)
|
| 338 |
+
|
| 339 |
+
try:
|
| 340 |
+
for file_path in paths:
|
| 341 |
+
new_identities, new_certs = _load_items_from_file(keychain, file_path)
|
| 342 |
+
identities.extend(new_identities)
|
| 343 |
+
certificates.extend(new_certs)
|
| 344 |
+
|
| 345 |
+
# Ok, we have everything. The question is: do we have an identity? If
|
| 346 |
+
# not, we want to grab one from the first cert we have.
|
| 347 |
+
if not identities:
|
| 348 |
+
new_identity = Security.SecIdentityRef()
|
| 349 |
+
status = Security.SecIdentityCreateWithCertificate(
|
| 350 |
+
keychain, certificates[0], ctypes.byref(new_identity)
|
| 351 |
+
)
|
| 352 |
+
_assert_no_error(status)
|
| 353 |
+
identities.append(new_identity)
|
| 354 |
+
|
| 355 |
+
# We now want to release the original certificate, as we no longer
|
| 356 |
+
# need it.
|
| 357 |
+
CoreFoundation.CFRelease(certificates.pop(0))
|
| 358 |
+
|
| 359 |
+
# We now need to build a new CFArray that holds the trust chain.
|
| 360 |
+
trust_chain = CoreFoundation.CFArrayCreateMutable(
|
| 361 |
+
CoreFoundation.kCFAllocatorDefault,
|
| 362 |
+
0,
|
| 363 |
+
ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
|
| 364 |
+
)
|
| 365 |
+
for item in itertools.chain(identities, certificates):
|
| 366 |
+
# ArrayAppendValue does a CFRetain on the item. That's fine,
|
| 367 |
+
# because the finally block will release our other refs to them.
|
| 368 |
+
CoreFoundation.CFArrayAppendValue(trust_chain, item)
|
| 369 |
+
|
| 370 |
+
return trust_chain
|
| 371 |
+
finally:
|
| 372 |
+
for obj in itertools.chain(identities, certificates):
|
| 373 |
+
CoreFoundation.CFRelease(obj)
|
| 374 |
+
|
| 375 |
+
|
| 376 |
+
TLS_PROTOCOL_VERSIONS = {
|
| 377 |
+
"SSLv2": (0, 2),
|
| 378 |
+
"SSLv3": (3, 0),
|
| 379 |
+
"TLSv1": (3, 1),
|
| 380 |
+
"TLSv1.1": (3, 2),
|
| 381 |
+
"TLSv1.2": (3, 3),
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
|
| 385 |
+
def _build_tls_unknown_ca_alert(version):
|
| 386 |
+
"""
|
| 387 |
+
Builds a TLS alert record for an unknown CA.
|
| 388 |
+
"""
|
| 389 |
+
ver_maj, ver_min = TLS_PROTOCOL_VERSIONS[version]
|
| 390 |
+
severity_fatal = 0x02
|
| 391 |
+
description_unknown_ca = 0x30
|
| 392 |
+
msg = struct.pack(">BB", severity_fatal, description_unknown_ca)
|
| 393 |
+
msg_len = len(msg)
|
| 394 |
+
record_type_alert = 0x15
|
| 395 |
+
record = struct.pack(">BBBH", record_type_alert, ver_maj, ver_min, msg_len) + msg
|
| 396 |
+
return record
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/appengine.py
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module provides a pool manager that uses Google App Engine's
|
| 3 |
+
`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_.
|
| 4 |
+
|
| 5 |
+
Example usage::
|
| 6 |
+
|
| 7 |
+
from pip._vendor.urllib3 import PoolManager
|
| 8 |
+
from pip._vendor.urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox
|
| 9 |
+
|
| 10 |
+
if is_appengine_sandbox():
|
| 11 |
+
# AppEngineManager uses AppEngine's URLFetch API behind the scenes
|
| 12 |
+
http = AppEngineManager()
|
| 13 |
+
else:
|
| 14 |
+
# PoolManager uses a socket-level API behind the scenes
|
| 15 |
+
http = PoolManager()
|
| 16 |
+
|
| 17 |
+
r = http.request('GET', 'https://google.com/')
|
| 18 |
+
|
| 19 |
+
There are `limitations <https://cloud.google.com/appengine/docs/python/\
|
| 20 |
+
urlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be
|
| 21 |
+
the best choice for your application. There are three options for using
|
| 22 |
+
urllib3 on Google App Engine:
|
| 23 |
+
|
| 24 |
+
1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is
|
| 25 |
+
cost-effective in many circumstances as long as your usage is within the
|
| 26 |
+
limitations.
|
| 27 |
+
2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets.
|
| 28 |
+
Sockets also have `limitations and restrictions
|
| 29 |
+
<https://cloud.google.com/appengine/docs/python/sockets/\
|
| 30 |
+
#limitations-and-restrictions>`_ and have a lower free quota than URLFetch.
|
| 31 |
+
To use sockets, be sure to specify the following in your ``app.yaml``::
|
| 32 |
+
|
| 33 |
+
env_variables:
|
| 34 |
+
GAE_USE_SOCKETS_HTTPLIB : 'true'
|
| 35 |
+
|
| 36 |
+
3. If you are using `App Engine Flexible
|
| 37 |
+
<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard
|
| 38 |
+
:class:`PoolManager` without any configuration or special environment variables.
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
from __future__ import absolute_import
|
| 42 |
+
|
| 43 |
+
import io
|
| 44 |
+
import logging
|
| 45 |
+
import warnings
|
| 46 |
+
|
| 47 |
+
from ..exceptions import (
|
| 48 |
+
HTTPError,
|
| 49 |
+
HTTPWarning,
|
| 50 |
+
MaxRetryError,
|
| 51 |
+
ProtocolError,
|
| 52 |
+
SSLError,
|
| 53 |
+
TimeoutError,
|
| 54 |
+
)
|
| 55 |
+
from ..packages.six.moves.urllib.parse import urljoin
|
| 56 |
+
from ..request import RequestMethods
|
| 57 |
+
from ..response import HTTPResponse
|
| 58 |
+
from ..util.retry import Retry
|
| 59 |
+
from ..util.timeout import Timeout
|
| 60 |
+
from . import _appengine_environ
|
| 61 |
+
|
| 62 |
+
try:
|
| 63 |
+
from google.appengine.api import urlfetch
|
| 64 |
+
except ImportError:
|
| 65 |
+
urlfetch = None
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
log = logging.getLogger(__name__)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class AppEnginePlatformWarning(HTTPWarning):
|
| 72 |
+
pass
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class AppEnginePlatformError(HTTPError):
|
| 76 |
+
pass
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
class AppEngineManager(RequestMethods):
|
| 80 |
+
"""
|
| 81 |
+
Connection manager for Google App Engine sandbox applications.
|
| 82 |
+
|
| 83 |
+
This manager uses the URLFetch service directly instead of using the
|
| 84 |
+
emulated httplib, and is subject to URLFetch limitations as described in
|
| 85 |
+
the App Engine documentation `here
|
| 86 |
+
<https://cloud.google.com/appengine/docs/python/urlfetch>`_.
|
| 87 |
+
|
| 88 |
+
Notably it will raise an :class:`AppEnginePlatformError` if:
|
| 89 |
+
* URLFetch is not available.
|
| 90 |
+
* If you attempt to use this on App Engine Flexible, as full socket
|
| 91 |
+
support is available.
|
| 92 |
+
* If a request size is more than 10 megabytes.
|
| 93 |
+
* If a response size is more than 32 megabytes.
|
| 94 |
+
* If you use an unsupported request method such as OPTIONS.
|
| 95 |
+
|
| 96 |
+
Beyond those cases, it will raise normal urllib3 errors.
|
| 97 |
+
"""
|
| 98 |
+
|
| 99 |
+
def __init__(
|
| 100 |
+
self,
|
| 101 |
+
headers=None,
|
| 102 |
+
retries=None,
|
| 103 |
+
validate_certificate=True,
|
| 104 |
+
urlfetch_retries=True,
|
| 105 |
+
):
|
| 106 |
+
if not urlfetch:
|
| 107 |
+
raise AppEnginePlatformError(
|
| 108 |
+
"URLFetch is not available in this environment."
|
| 109 |
+
)
|
| 110 |
+
|
| 111 |
+
warnings.warn(
|
| 112 |
+
"urllib3 is using URLFetch on Google App Engine sandbox instead "
|
| 113 |
+
"of sockets. To use sockets directly instead of URLFetch see "
|
| 114 |
+
"https://urllib3.readthedocs.io/en/1.26.x/reference/urllib3.contrib.html.",
|
| 115 |
+
AppEnginePlatformWarning,
|
| 116 |
+
)
|
| 117 |
+
|
| 118 |
+
RequestMethods.__init__(self, headers)
|
| 119 |
+
self.validate_certificate = validate_certificate
|
| 120 |
+
self.urlfetch_retries = urlfetch_retries
|
| 121 |
+
|
| 122 |
+
self.retries = retries or Retry.DEFAULT
|
| 123 |
+
|
| 124 |
+
def __enter__(self):
|
| 125 |
+
return self
|
| 126 |
+
|
| 127 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
| 128 |
+
# Return False to re-raise any potential exceptions
|
| 129 |
+
return False
|
| 130 |
+
|
| 131 |
+
def urlopen(
|
| 132 |
+
self,
|
| 133 |
+
method,
|
| 134 |
+
url,
|
| 135 |
+
body=None,
|
| 136 |
+
headers=None,
|
| 137 |
+
retries=None,
|
| 138 |
+
redirect=True,
|
| 139 |
+
timeout=Timeout.DEFAULT_TIMEOUT,
|
| 140 |
+
**response_kw
|
| 141 |
+
):
|
| 142 |
+
|
| 143 |
+
retries = self._get_retries(retries, redirect)
|
| 144 |
+
|
| 145 |
+
try:
|
| 146 |
+
follow_redirects = redirect and retries.redirect != 0 and retries.total
|
| 147 |
+
response = urlfetch.fetch(
|
| 148 |
+
url,
|
| 149 |
+
payload=body,
|
| 150 |
+
method=method,
|
| 151 |
+
headers=headers or {},
|
| 152 |
+
allow_truncated=False,
|
| 153 |
+
follow_redirects=self.urlfetch_retries and follow_redirects,
|
| 154 |
+
deadline=self._get_absolute_timeout(timeout),
|
| 155 |
+
validate_certificate=self.validate_certificate,
|
| 156 |
+
)
|
| 157 |
+
except urlfetch.DeadlineExceededError as e:
|
| 158 |
+
raise TimeoutError(self, e)
|
| 159 |
+
|
| 160 |
+
except urlfetch.InvalidURLError as e:
|
| 161 |
+
if "too large" in str(e):
|
| 162 |
+
raise AppEnginePlatformError(
|
| 163 |
+
"URLFetch request too large, URLFetch only "
|
| 164 |
+
"supports requests up to 10mb in size.",
|
| 165 |
+
e,
|
| 166 |
+
)
|
| 167 |
+
raise ProtocolError(e)
|
| 168 |
+
|
| 169 |
+
except urlfetch.DownloadError as e:
|
| 170 |
+
if "Too many redirects" in str(e):
|
| 171 |
+
raise MaxRetryError(self, url, reason=e)
|
| 172 |
+
raise ProtocolError(e)
|
| 173 |
+
|
| 174 |
+
except urlfetch.ResponseTooLargeError as e:
|
| 175 |
+
raise AppEnginePlatformError(
|
| 176 |
+
"URLFetch response too large, URLFetch only supports"
|
| 177 |
+
"responses up to 32mb in size.",
|
| 178 |
+
e,
|
| 179 |
+
)
|
| 180 |
+
|
| 181 |
+
except urlfetch.SSLCertificateError as e:
|
| 182 |
+
raise SSLError(e)
|
| 183 |
+
|
| 184 |
+
except urlfetch.InvalidMethodError as e:
|
| 185 |
+
raise AppEnginePlatformError(
|
| 186 |
+
"URLFetch does not support method: %s" % method, e
|
| 187 |
+
)
|
| 188 |
+
|
| 189 |
+
http_response = self._urlfetch_response_to_http_response(
|
| 190 |
+
response, retries=retries, **response_kw
|
| 191 |
+
)
|
| 192 |
+
|
| 193 |
+
# Handle redirect?
|
| 194 |
+
redirect_location = redirect and http_response.get_redirect_location()
|
| 195 |
+
if redirect_location:
|
| 196 |
+
# Check for redirect response
|
| 197 |
+
if self.urlfetch_retries and retries.raise_on_redirect:
|
| 198 |
+
raise MaxRetryError(self, url, "too many redirects")
|
| 199 |
+
else:
|
| 200 |
+
if http_response.status == 303:
|
| 201 |
+
method = "GET"
|
| 202 |
+
|
| 203 |
+
try:
|
| 204 |
+
retries = retries.increment(
|
| 205 |
+
method, url, response=http_response, _pool=self
|
| 206 |
+
)
|
| 207 |
+
except MaxRetryError:
|
| 208 |
+
if retries.raise_on_redirect:
|
| 209 |
+
raise MaxRetryError(self, url, "too many redirects")
|
| 210 |
+
return http_response
|
| 211 |
+
|
| 212 |
+
retries.sleep_for_retry(http_response)
|
| 213 |
+
log.debug("Redirecting %s -> %s", url, redirect_location)
|
| 214 |
+
redirect_url = urljoin(url, redirect_location)
|
| 215 |
+
return self.urlopen(
|
| 216 |
+
method,
|
| 217 |
+
redirect_url,
|
| 218 |
+
body,
|
| 219 |
+
headers,
|
| 220 |
+
retries=retries,
|
| 221 |
+
redirect=redirect,
|
| 222 |
+
timeout=timeout,
|
| 223 |
+
**response_kw
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
# Check if we should retry the HTTP response.
|
| 227 |
+
has_retry_after = bool(http_response.getheader("Retry-After"))
|
| 228 |
+
if retries.is_retry(method, http_response.status, has_retry_after):
|
| 229 |
+
retries = retries.increment(method, url, response=http_response, _pool=self)
|
| 230 |
+
log.debug("Retry: %s", url)
|
| 231 |
+
retries.sleep(http_response)
|
| 232 |
+
return self.urlopen(
|
| 233 |
+
method,
|
| 234 |
+
url,
|
| 235 |
+
body=body,
|
| 236 |
+
headers=headers,
|
| 237 |
+
retries=retries,
|
| 238 |
+
redirect=redirect,
|
| 239 |
+
timeout=timeout,
|
| 240 |
+
**response_kw
|
| 241 |
+
)
|
| 242 |
+
|
| 243 |
+
return http_response
|
| 244 |
+
|
| 245 |
+
def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw):
|
| 246 |
+
|
| 247 |
+
if is_prod_appengine():
|
| 248 |
+
# Production GAE handles deflate encoding automatically, but does
|
| 249 |
+
# not remove the encoding header.
|
| 250 |
+
content_encoding = urlfetch_resp.headers.get("content-encoding")
|
| 251 |
+
|
| 252 |
+
if content_encoding == "deflate":
|
| 253 |
+
del urlfetch_resp.headers["content-encoding"]
|
| 254 |
+
|
| 255 |
+
transfer_encoding = urlfetch_resp.headers.get("transfer-encoding")
|
| 256 |
+
# We have a full response's content,
|
| 257 |
+
# so let's make sure we don't report ourselves as chunked data.
|
| 258 |
+
if transfer_encoding == "chunked":
|
| 259 |
+
encodings = transfer_encoding.split(",")
|
| 260 |
+
encodings.remove("chunked")
|
| 261 |
+
urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings)
|
| 262 |
+
|
| 263 |
+
original_response = HTTPResponse(
|
| 264 |
+
# In order for decoding to work, we must present the content as
|
| 265 |
+
# a file-like object.
|
| 266 |
+
body=io.BytesIO(urlfetch_resp.content),
|
| 267 |
+
msg=urlfetch_resp.header_msg,
|
| 268 |
+
headers=urlfetch_resp.headers,
|
| 269 |
+
status=urlfetch_resp.status_code,
|
| 270 |
+
**response_kw
|
| 271 |
+
)
|
| 272 |
+
|
| 273 |
+
return HTTPResponse(
|
| 274 |
+
body=io.BytesIO(urlfetch_resp.content),
|
| 275 |
+
headers=urlfetch_resp.headers,
|
| 276 |
+
status=urlfetch_resp.status_code,
|
| 277 |
+
original_response=original_response,
|
| 278 |
+
**response_kw
|
| 279 |
+
)
|
| 280 |
+
|
| 281 |
+
def _get_absolute_timeout(self, timeout):
|
| 282 |
+
if timeout is Timeout.DEFAULT_TIMEOUT:
|
| 283 |
+
return None # Defer to URLFetch's default.
|
| 284 |
+
if isinstance(timeout, Timeout):
|
| 285 |
+
if timeout._read is not None or timeout._connect is not None:
|
| 286 |
+
warnings.warn(
|
| 287 |
+
"URLFetch does not support granular timeout settings, "
|
| 288 |
+
"reverting to total or default URLFetch timeout.",
|
| 289 |
+
AppEnginePlatformWarning,
|
| 290 |
+
)
|
| 291 |
+
return timeout.total
|
| 292 |
+
return timeout
|
| 293 |
+
|
| 294 |
+
def _get_retries(self, retries, redirect):
|
| 295 |
+
if not isinstance(retries, Retry):
|
| 296 |
+
retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
|
| 297 |
+
|
| 298 |
+
if retries.connect or retries.read or retries.redirect:
|
| 299 |
+
warnings.warn(
|
| 300 |
+
"URLFetch only supports total retries and does not "
|
| 301 |
+
"recognize connect, read, or redirect retry parameters.",
|
| 302 |
+
AppEnginePlatformWarning,
|
| 303 |
+
)
|
| 304 |
+
|
| 305 |
+
return retries
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
# Alias methods from _appengine_environ to maintain public API interface.
|
| 309 |
+
|
| 310 |
+
is_appengine = _appengine_environ.is_appengine
|
| 311 |
+
is_appengine_sandbox = _appengine_environ.is_appengine_sandbox
|
| 312 |
+
is_local_appengine = _appengine_environ.is_local_appengine
|
| 313 |
+
is_prod_appengine = _appengine_environ.is_prod_appengine
|
| 314 |
+
is_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
NTLM authenticating pool, contributed by erikcederstran
|
| 3 |
+
|
| 4 |
+
Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10
|
| 5 |
+
"""
|
| 6 |
+
from __future__ import absolute_import
|
| 7 |
+
|
| 8 |
+
import warnings
|
| 9 |
+
from logging import getLogger
|
| 10 |
+
|
| 11 |
+
from ntlm import ntlm
|
| 12 |
+
|
| 13 |
+
from .. import HTTPSConnectionPool
|
| 14 |
+
from ..packages.six.moves.http_client import HTTPSConnection
|
| 15 |
+
|
| 16 |
+
warnings.warn(
|
| 17 |
+
"The 'urllib3.contrib.ntlmpool' module is deprecated and will be removed "
|
| 18 |
+
"in urllib3 v2.0 release, urllib3 is not able to support it properly due "
|
| 19 |
+
"to reasons listed in issue: https://github.com/urllib3/urllib3/issues/2282. "
|
| 20 |
+
"If you are a user of this module please comment in the mentioned issue.",
|
| 21 |
+
DeprecationWarning,
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
log = getLogger(__name__)
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class NTLMConnectionPool(HTTPSConnectionPool):
|
| 28 |
+
"""
|
| 29 |
+
Implements an NTLM authentication version of an urllib3 connection pool
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
scheme = "https"
|
| 33 |
+
|
| 34 |
+
def __init__(self, user, pw, authurl, *args, **kwargs):
|
| 35 |
+
"""
|
| 36 |
+
authurl is a random URL on the server that is protected by NTLM.
|
| 37 |
+
user is the Windows user, probably in the DOMAIN\\username format.
|
| 38 |
+
pw is the password for the user.
|
| 39 |
+
"""
|
| 40 |
+
super(NTLMConnectionPool, self).__init__(*args, **kwargs)
|
| 41 |
+
self.authurl = authurl
|
| 42 |
+
self.rawuser = user
|
| 43 |
+
user_parts = user.split("\\", 1)
|
| 44 |
+
self.domain = user_parts[0].upper()
|
| 45 |
+
self.user = user_parts[1]
|
| 46 |
+
self.pw = pw
|
| 47 |
+
|
| 48 |
+
def _new_conn(self):
|
| 49 |
+
# Performs the NTLM handshake that secures the connection. The socket
|
| 50 |
+
# must be kept open while requests are performed.
|
| 51 |
+
self.num_connections += 1
|
| 52 |
+
log.debug(
|
| 53 |
+
"Starting NTLM HTTPS connection no. %d: https://%s%s",
|
| 54 |
+
self.num_connections,
|
| 55 |
+
self.host,
|
| 56 |
+
self.authurl,
|
| 57 |
+
)
|
| 58 |
+
|
| 59 |
+
headers = {"Connection": "Keep-Alive"}
|
| 60 |
+
req_header = "Authorization"
|
| 61 |
+
resp_header = "www-authenticate"
|
| 62 |
+
|
| 63 |
+
conn = HTTPSConnection(host=self.host, port=self.port)
|
| 64 |
+
|
| 65 |
+
# Send negotiation message
|
| 66 |
+
headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE(
|
| 67 |
+
self.rawuser
|
| 68 |
+
)
|
| 69 |
+
log.debug("Request headers: %s", headers)
|
| 70 |
+
conn.request("GET", self.authurl, None, headers)
|
| 71 |
+
res = conn.getresponse()
|
| 72 |
+
reshdr = dict(res.getheaders())
|
| 73 |
+
log.debug("Response status: %s %s", res.status, res.reason)
|
| 74 |
+
log.debug("Response headers: %s", reshdr)
|
| 75 |
+
log.debug("Response data: %s [...]", res.read(100))
|
| 76 |
+
|
| 77 |
+
# Remove the reference to the socket, so that it can not be closed by
|
| 78 |
+
# the response object (we want to keep the socket open)
|
| 79 |
+
res.fp = None
|
| 80 |
+
|
| 81 |
+
# Server should respond with a challenge message
|
| 82 |
+
auth_header_values = reshdr[resp_header].split(", ")
|
| 83 |
+
auth_header_value = None
|
| 84 |
+
for s in auth_header_values:
|
| 85 |
+
if s[:5] == "NTLM ":
|
| 86 |
+
auth_header_value = s[5:]
|
| 87 |
+
if auth_header_value is None:
|
| 88 |
+
raise Exception(
|
| 89 |
+
"Unexpected %s response header: %s" % (resp_header, reshdr[resp_header])
|
| 90 |
+
)
|
| 91 |
+
|
| 92 |
+
# Send authentication message
|
| 93 |
+
ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(
|
| 94 |
+
auth_header_value
|
| 95 |
+
)
|
| 96 |
+
auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(
|
| 97 |
+
ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags
|
| 98 |
+
)
|
| 99 |
+
headers[req_header] = "NTLM %s" % auth_msg
|
| 100 |
+
log.debug("Request headers: %s", headers)
|
| 101 |
+
conn.request("GET", self.authurl, None, headers)
|
| 102 |
+
res = conn.getresponse()
|
| 103 |
+
log.debug("Response status: %s %s", res.status, res.reason)
|
| 104 |
+
log.debug("Response headers: %s", dict(res.getheaders()))
|
| 105 |
+
log.debug("Response data: %s [...]", res.read()[:100])
|
| 106 |
+
if res.status != 200:
|
| 107 |
+
if res.status == 401:
|
| 108 |
+
raise Exception("Server rejected request: wrong username or password")
|
| 109 |
+
raise Exception("Wrong server response: %s %s" % (res.status, res.reason))
|
| 110 |
+
|
| 111 |
+
res.fp = None
|
| 112 |
+
log.debug("Connection established")
|
| 113 |
+
return conn
|
| 114 |
+
|
| 115 |
+
def urlopen(
|
| 116 |
+
self,
|
| 117 |
+
method,
|
| 118 |
+
url,
|
| 119 |
+
body=None,
|
| 120 |
+
headers=None,
|
| 121 |
+
retries=3,
|
| 122 |
+
redirect=True,
|
| 123 |
+
assert_same_host=True,
|
| 124 |
+
):
|
| 125 |
+
if headers is None:
|
| 126 |
+
headers = {}
|
| 127 |
+
headers["Connection"] = "Keep-Alive"
|
| 128 |
+
return super(NTLMConnectionPool, self).urlopen(
|
| 129 |
+
method, url, body, headers, retries, redirect, assert_same_host
|
| 130 |
+
)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
TLS with SNI_-support for Python 2. Follow these instructions if you would
|
| 3 |
+
like to verify TLS certificates in Python 2. Note, the default libraries do
|
| 4 |
+
*not* do certificate checking; you need to do additional work to validate
|
| 5 |
+
certificates yourself.
|
| 6 |
+
|
| 7 |
+
This needs the following packages installed:
|
| 8 |
+
|
| 9 |
+
* `pyOpenSSL`_ (tested with 16.0.0)
|
| 10 |
+
* `cryptography`_ (minimum 1.3.4, from pyopenssl)
|
| 11 |
+
* `idna`_ (minimum 2.0, from cryptography)
|
| 12 |
+
|
| 13 |
+
However, pyopenssl depends on cryptography, which depends on idna, so while we
|
| 14 |
+
use all three directly here we end up having relatively few packages required.
|
| 15 |
+
|
| 16 |
+
You can install them with the following command:
|
| 17 |
+
|
| 18 |
+
.. code-block:: bash
|
| 19 |
+
|
| 20 |
+
$ python -m pip install pyopenssl cryptography idna
|
| 21 |
+
|
| 22 |
+
To activate certificate checking, call
|
| 23 |
+
:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code
|
| 24 |
+
before you begin making HTTP requests. This can be done in a ``sitecustomize``
|
| 25 |
+
module, or at any other time before your application begins using ``urllib3``,
|
| 26 |
+
like this:
|
| 27 |
+
|
| 28 |
+
.. code-block:: python
|
| 29 |
+
|
| 30 |
+
try:
|
| 31 |
+
import urllib3.contrib.pyopenssl
|
| 32 |
+
urllib3.contrib.pyopenssl.inject_into_urllib3()
|
| 33 |
+
except ImportError:
|
| 34 |
+
pass
|
| 35 |
+
|
| 36 |
+
Now you can use :mod:`urllib3` as you normally would, and it will support SNI
|
| 37 |
+
when the required modules are installed.
|
| 38 |
+
|
| 39 |
+
Activating this module also has the positive side effect of disabling SSL/TLS
|
| 40 |
+
compression in Python 2 (see `CRIME attack`_).
|
| 41 |
+
|
| 42 |
+
.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication
|
| 43 |
+
.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit)
|
| 44 |
+
.. _pyopenssl: https://www.pyopenssl.org
|
| 45 |
+
.. _cryptography: https://cryptography.io
|
| 46 |
+
.. _idna: https://github.com/kjd/idna
|
| 47 |
+
"""
|
| 48 |
+
from __future__ import absolute_import
|
| 49 |
+
|
| 50 |
+
import OpenSSL.SSL
|
| 51 |
+
from cryptography import x509
|
| 52 |
+
from cryptography.hazmat.backends.openssl import backend as openssl_backend
|
| 53 |
+
from cryptography.hazmat.backends.openssl.x509 import _Certificate
|
| 54 |
+
|
| 55 |
+
try:
|
| 56 |
+
from cryptography.x509 import UnsupportedExtension
|
| 57 |
+
except ImportError:
|
| 58 |
+
# UnsupportedExtension is gone in cryptography >= 2.1.0
|
| 59 |
+
class UnsupportedExtension(Exception):
|
| 60 |
+
pass
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
from io import BytesIO
|
| 64 |
+
from socket import error as SocketError
|
| 65 |
+
from socket import timeout
|
| 66 |
+
|
| 67 |
+
try: # Platform-specific: Python 2
|
| 68 |
+
from socket import _fileobject
|
| 69 |
+
except ImportError: # Platform-specific: Python 3
|
| 70 |
+
_fileobject = None
|
| 71 |
+
from ..packages.backports.makefile import backport_makefile
|
| 72 |
+
|
| 73 |
+
import logging
|
| 74 |
+
import ssl
|
| 75 |
+
import sys
|
| 76 |
+
|
| 77 |
+
from .. import util
|
| 78 |
+
from ..packages import six
|
| 79 |
+
from ..util.ssl_ import PROTOCOL_TLS_CLIENT
|
| 80 |
+
|
| 81 |
+
__all__ = ["inject_into_urllib3", "extract_from_urllib3"]
|
| 82 |
+
|
| 83 |
+
# SNI always works.
|
| 84 |
+
HAS_SNI = True
|
| 85 |
+
|
| 86 |
+
# Map from urllib3 to PyOpenSSL compatible parameter-values.
|
| 87 |
+
_openssl_versions = {
|
| 88 |
+
util.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD,
|
| 89 |
+
PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD,
|
| 90 |
+
ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
if hasattr(ssl, "PROTOCOL_SSLv3") and hasattr(OpenSSL.SSL, "SSLv3_METHOD"):
|
| 94 |
+
_openssl_versions[ssl.PROTOCOL_SSLv3] = OpenSSL.SSL.SSLv3_METHOD
|
| 95 |
+
|
| 96 |
+
if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"):
|
| 97 |
+
_openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD
|
| 98 |
+
|
| 99 |
+
if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"):
|
| 100 |
+
_openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
_stdlib_to_openssl_verify = {
|
| 104 |
+
ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,
|
| 105 |
+
ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,
|
| 106 |
+
ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER
|
| 107 |
+
+ OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
|
| 108 |
+
}
|
| 109 |
+
_openssl_to_stdlib_verify = dict((v, k) for k, v in _stdlib_to_openssl_verify.items())
|
| 110 |
+
|
| 111 |
+
# OpenSSL will only write 16K at a time
|
| 112 |
+
SSL_WRITE_BLOCKSIZE = 16384
|
| 113 |
+
|
| 114 |
+
orig_util_HAS_SNI = util.HAS_SNI
|
| 115 |
+
orig_util_SSLContext = util.ssl_.SSLContext
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
log = logging.getLogger(__name__)
|
| 119 |
+
|
| 120 |
+
|
| 121 |
+
def inject_into_urllib3():
|
| 122 |
+
"Monkey-patch urllib3 with PyOpenSSL-backed SSL-support."
|
| 123 |
+
|
| 124 |
+
_validate_dependencies_met()
|
| 125 |
+
|
| 126 |
+
util.SSLContext = PyOpenSSLContext
|
| 127 |
+
util.ssl_.SSLContext = PyOpenSSLContext
|
| 128 |
+
util.HAS_SNI = HAS_SNI
|
| 129 |
+
util.ssl_.HAS_SNI = HAS_SNI
|
| 130 |
+
util.IS_PYOPENSSL = True
|
| 131 |
+
util.ssl_.IS_PYOPENSSL = True
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def extract_from_urllib3():
|
| 135 |
+
"Undo monkey-patching by :func:`inject_into_urllib3`."
|
| 136 |
+
|
| 137 |
+
util.SSLContext = orig_util_SSLContext
|
| 138 |
+
util.ssl_.SSLContext = orig_util_SSLContext
|
| 139 |
+
util.HAS_SNI = orig_util_HAS_SNI
|
| 140 |
+
util.ssl_.HAS_SNI = orig_util_HAS_SNI
|
| 141 |
+
util.IS_PYOPENSSL = False
|
| 142 |
+
util.ssl_.IS_PYOPENSSL = False
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
def _validate_dependencies_met():
|
| 146 |
+
"""
|
| 147 |
+
Verifies that PyOpenSSL's package-level dependencies have been met.
|
| 148 |
+
Throws `ImportError` if they are not met.
|
| 149 |
+
"""
|
| 150 |
+
# Method added in `cryptography==1.1`; not available in older versions
|
| 151 |
+
from cryptography.x509.extensions import Extensions
|
| 152 |
+
|
| 153 |
+
if getattr(Extensions, "get_extension_for_class", None) is None:
|
| 154 |
+
raise ImportError(
|
| 155 |
+
"'cryptography' module missing required functionality. "
|
| 156 |
+
"Try upgrading to v1.3.4 or newer."
|
| 157 |
+
)
|
| 158 |
+
|
| 159 |
+
# pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509
|
| 160 |
+
# attribute is only present on those versions.
|
| 161 |
+
from OpenSSL.crypto import X509
|
| 162 |
+
|
| 163 |
+
x509 = X509()
|
| 164 |
+
if getattr(x509, "_x509", None) is None:
|
| 165 |
+
raise ImportError(
|
| 166 |
+
"'pyOpenSSL' module missing required functionality. "
|
| 167 |
+
"Try upgrading to v0.14 or newer."
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
def _dnsname_to_stdlib(name):
|
| 172 |
+
"""
|
| 173 |
+
Converts a dNSName SubjectAlternativeName field to the form used by the
|
| 174 |
+
standard library on the given Python version.
|
| 175 |
+
|
| 176 |
+
Cryptography produces a dNSName as a unicode string that was idna-decoded
|
| 177 |
+
from ASCII bytes. We need to idna-encode that string to get it back, and
|
| 178 |
+
then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib
|
| 179 |
+
uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8).
|
| 180 |
+
|
| 181 |
+
If the name cannot be idna-encoded then we return None signalling that
|
| 182 |
+
the name given should be skipped.
|
| 183 |
+
"""
|
| 184 |
+
|
| 185 |
+
def idna_encode(name):
|
| 186 |
+
"""
|
| 187 |
+
Borrowed wholesale from the Python Cryptography Project. It turns out
|
| 188 |
+
that we can't just safely call `idna.encode`: it can explode for
|
| 189 |
+
wildcard names. This avoids that problem.
|
| 190 |
+
"""
|
| 191 |
+
from pip._vendor import idna
|
| 192 |
+
|
| 193 |
+
try:
|
| 194 |
+
for prefix in [u"*.", u"."]:
|
| 195 |
+
if name.startswith(prefix):
|
| 196 |
+
name = name[len(prefix) :]
|
| 197 |
+
return prefix.encode("ascii") + idna.encode(name)
|
| 198 |
+
return idna.encode(name)
|
| 199 |
+
except idna.core.IDNAError:
|
| 200 |
+
return None
|
| 201 |
+
|
| 202 |
+
# Don't send IPv6 addresses through the IDNA encoder.
|
| 203 |
+
if ":" in name:
|
| 204 |
+
return name
|
| 205 |
+
|
| 206 |
+
name = idna_encode(name)
|
| 207 |
+
if name is None:
|
| 208 |
+
return None
|
| 209 |
+
elif sys.version_info >= (3, 0):
|
| 210 |
+
name = name.decode("utf-8")
|
| 211 |
+
return name
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def get_subj_alt_name(peer_cert):
|
| 215 |
+
"""
|
| 216 |
+
Given an PyOpenSSL certificate, provides all the subject alternative names.
|
| 217 |
+
"""
|
| 218 |
+
# Pass the cert to cryptography, which has much better APIs for this.
|
| 219 |
+
if hasattr(peer_cert, "to_cryptography"):
|
| 220 |
+
cert = peer_cert.to_cryptography()
|
| 221 |
+
else:
|
| 222 |
+
# This is technically using private APIs, but should work across all
|
| 223 |
+
# relevant versions before PyOpenSSL got a proper API for this.
|
| 224 |
+
cert = _Certificate(openssl_backend, peer_cert._x509)
|
| 225 |
+
|
| 226 |
+
# We want to find the SAN extension. Ask Cryptography to locate it (it's
|
| 227 |
+
# faster than looping in Python)
|
| 228 |
+
try:
|
| 229 |
+
ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value
|
| 230 |
+
except x509.ExtensionNotFound:
|
| 231 |
+
# No such extension, return the empty list.
|
| 232 |
+
return []
|
| 233 |
+
except (
|
| 234 |
+
x509.DuplicateExtension,
|
| 235 |
+
UnsupportedExtension,
|
| 236 |
+
x509.UnsupportedGeneralNameType,
|
| 237 |
+
UnicodeError,
|
| 238 |
+
) as e:
|
| 239 |
+
# A problem has been found with the quality of the certificate. Assume
|
| 240 |
+
# no SAN field is present.
|
| 241 |
+
log.warning(
|
| 242 |
+
"A problem was encountered with the certificate that prevented "
|
| 243 |
+
"urllib3 from finding the SubjectAlternativeName field. This can "
|
| 244 |
+
"affect certificate validation. The error was %s",
|
| 245 |
+
e,
|
| 246 |
+
)
|
| 247 |
+
return []
|
| 248 |
+
|
| 249 |
+
# We want to return dNSName and iPAddress fields. We need to cast the IPs
|
| 250 |
+
# back to strings because the match_hostname function wants them as
|
| 251 |
+
# strings.
|
| 252 |
+
# Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8
|
| 253 |
+
# decoded. This is pretty frustrating, but that's what the standard library
|
| 254 |
+
# does with certificates, and so we need to attempt to do the same.
|
| 255 |
+
# We also want to skip over names which cannot be idna encoded.
|
| 256 |
+
names = [
|
| 257 |
+
("DNS", name)
|
| 258 |
+
for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName))
|
| 259 |
+
if name is not None
|
| 260 |
+
]
|
| 261 |
+
names.extend(
|
| 262 |
+
("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress)
|
| 263 |
+
)
|
| 264 |
+
|
| 265 |
+
return names
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
class WrappedSocket(object):
|
| 269 |
+
"""API-compatibility wrapper for Python OpenSSL's Connection-class.
|
| 270 |
+
|
| 271 |
+
Note: _makefile_refs, _drop() and _reuse() are needed for the garbage
|
| 272 |
+
collector of pypy.
|
| 273 |
+
"""
|
| 274 |
+
|
| 275 |
+
def __init__(self, connection, socket, suppress_ragged_eofs=True):
|
| 276 |
+
self.connection = connection
|
| 277 |
+
self.socket = socket
|
| 278 |
+
self.suppress_ragged_eofs = suppress_ragged_eofs
|
| 279 |
+
self._makefile_refs = 0
|
| 280 |
+
self._closed = False
|
| 281 |
+
|
| 282 |
+
def fileno(self):
|
| 283 |
+
return self.socket.fileno()
|
| 284 |
+
|
| 285 |
+
# Copy-pasted from Python 3.5 source code
|
| 286 |
+
def _decref_socketios(self):
|
| 287 |
+
if self._makefile_refs > 0:
|
| 288 |
+
self._makefile_refs -= 1
|
| 289 |
+
if self._closed:
|
| 290 |
+
self.close()
|
| 291 |
+
|
| 292 |
+
def recv(self, *args, **kwargs):
|
| 293 |
+
try:
|
| 294 |
+
data = self.connection.recv(*args, **kwargs)
|
| 295 |
+
except OpenSSL.SSL.SysCallError as e:
|
| 296 |
+
if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
|
| 297 |
+
return b""
|
| 298 |
+
else:
|
| 299 |
+
raise SocketError(str(e))
|
| 300 |
+
except OpenSSL.SSL.ZeroReturnError:
|
| 301 |
+
if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
|
| 302 |
+
return b""
|
| 303 |
+
else:
|
| 304 |
+
raise
|
| 305 |
+
except OpenSSL.SSL.WantReadError:
|
| 306 |
+
if not util.wait_for_read(self.socket, self.socket.gettimeout()):
|
| 307 |
+
raise timeout("The read operation timed out")
|
| 308 |
+
else:
|
| 309 |
+
return self.recv(*args, **kwargs)
|
| 310 |
+
|
| 311 |
+
# TLS 1.3 post-handshake authentication
|
| 312 |
+
except OpenSSL.SSL.Error as e:
|
| 313 |
+
raise ssl.SSLError("read error: %r" % e)
|
| 314 |
+
else:
|
| 315 |
+
return data
|
| 316 |
+
|
| 317 |
+
def recv_into(self, *args, **kwargs):
|
| 318 |
+
try:
|
| 319 |
+
return self.connection.recv_into(*args, **kwargs)
|
| 320 |
+
except OpenSSL.SSL.SysCallError as e:
|
| 321 |
+
if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
|
| 322 |
+
return 0
|
| 323 |
+
else:
|
| 324 |
+
raise SocketError(str(e))
|
| 325 |
+
except OpenSSL.SSL.ZeroReturnError:
|
| 326 |
+
if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
|
| 327 |
+
return 0
|
| 328 |
+
else:
|
| 329 |
+
raise
|
| 330 |
+
except OpenSSL.SSL.WantReadError:
|
| 331 |
+
if not util.wait_for_read(self.socket, self.socket.gettimeout()):
|
| 332 |
+
raise timeout("The read operation timed out")
|
| 333 |
+
else:
|
| 334 |
+
return self.recv_into(*args, **kwargs)
|
| 335 |
+
|
| 336 |
+
# TLS 1.3 post-handshake authentication
|
| 337 |
+
except OpenSSL.SSL.Error as e:
|
| 338 |
+
raise ssl.SSLError("read error: %r" % e)
|
| 339 |
+
|
| 340 |
+
def settimeout(self, timeout):
|
| 341 |
+
return self.socket.settimeout(timeout)
|
| 342 |
+
|
| 343 |
+
def _send_until_done(self, data):
|
| 344 |
+
while True:
|
| 345 |
+
try:
|
| 346 |
+
return self.connection.send(data)
|
| 347 |
+
except OpenSSL.SSL.WantWriteError:
|
| 348 |
+
if not util.wait_for_write(self.socket, self.socket.gettimeout()):
|
| 349 |
+
raise timeout()
|
| 350 |
+
continue
|
| 351 |
+
except OpenSSL.SSL.SysCallError as e:
|
| 352 |
+
raise SocketError(str(e))
|
| 353 |
+
|
| 354 |
+
def sendall(self, data):
|
| 355 |
+
total_sent = 0
|
| 356 |
+
while total_sent < len(data):
|
| 357 |
+
sent = self._send_until_done(
|
| 358 |
+
data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]
|
| 359 |
+
)
|
| 360 |
+
total_sent += sent
|
| 361 |
+
|
| 362 |
+
def shutdown(self):
|
| 363 |
+
# FIXME rethrow compatible exceptions should we ever use this
|
| 364 |
+
self.connection.shutdown()
|
| 365 |
+
|
| 366 |
+
def close(self):
|
| 367 |
+
if self._makefile_refs < 1:
|
| 368 |
+
try:
|
| 369 |
+
self._closed = True
|
| 370 |
+
return self.connection.close()
|
| 371 |
+
except OpenSSL.SSL.Error:
|
| 372 |
+
return
|
| 373 |
+
else:
|
| 374 |
+
self._makefile_refs -= 1
|
| 375 |
+
|
| 376 |
+
def getpeercert(self, binary_form=False):
|
| 377 |
+
x509 = self.connection.get_peer_certificate()
|
| 378 |
+
|
| 379 |
+
if not x509:
|
| 380 |
+
return x509
|
| 381 |
+
|
| 382 |
+
if binary_form:
|
| 383 |
+
return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509)
|
| 384 |
+
|
| 385 |
+
return {
|
| 386 |
+
"subject": ((("commonName", x509.get_subject().CN),),),
|
| 387 |
+
"subjectAltName": get_subj_alt_name(x509),
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
def version(self):
|
| 391 |
+
return self.connection.get_protocol_version_name()
|
| 392 |
+
|
| 393 |
+
def _reuse(self):
|
| 394 |
+
self._makefile_refs += 1
|
| 395 |
+
|
| 396 |
+
def _drop(self):
|
| 397 |
+
if self._makefile_refs < 1:
|
| 398 |
+
self.close()
|
| 399 |
+
else:
|
| 400 |
+
self._makefile_refs -= 1
|
| 401 |
+
|
| 402 |
+
|
| 403 |
+
if _fileobject: # Platform-specific: Python 2
|
| 404 |
+
|
| 405 |
+
def makefile(self, mode, bufsize=-1):
|
| 406 |
+
self._makefile_refs += 1
|
| 407 |
+
return _fileobject(self, mode, bufsize, close=True)
|
| 408 |
+
|
| 409 |
+
|
| 410 |
+
else: # Platform-specific: Python 3
|
| 411 |
+
makefile = backport_makefile
|
| 412 |
+
|
| 413 |
+
WrappedSocket.makefile = makefile
|
| 414 |
+
|
| 415 |
+
|
| 416 |
+
class PyOpenSSLContext(object):
|
| 417 |
+
"""
|
| 418 |
+
I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible
|
| 419 |
+
for translating the interface of the standard library ``SSLContext`` object
|
| 420 |
+
to calls into PyOpenSSL.
|
| 421 |
+
"""
|
| 422 |
+
|
| 423 |
+
def __init__(self, protocol):
|
| 424 |
+
self.protocol = _openssl_versions[protocol]
|
| 425 |
+
self._ctx = OpenSSL.SSL.Context(self.protocol)
|
| 426 |
+
self._options = 0
|
| 427 |
+
self.check_hostname = False
|
| 428 |
+
|
| 429 |
+
@property
|
| 430 |
+
def options(self):
|
| 431 |
+
return self._options
|
| 432 |
+
|
| 433 |
+
@options.setter
|
| 434 |
+
def options(self, value):
|
| 435 |
+
self._options = value
|
| 436 |
+
self._ctx.set_options(value)
|
| 437 |
+
|
| 438 |
+
@property
|
| 439 |
+
def verify_mode(self):
|
| 440 |
+
return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()]
|
| 441 |
+
|
| 442 |
+
@verify_mode.setter
|
| 443 |
+
def verify_mode(self, value):
|
| 444 |
+
self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback)
|
| 445 |
+
|
| 446 |
+
def set_default_verify_paths(self):
|
| 447 |
+
self._ctx.set_default_verify_paths()
|
| 448 |
+
|
| 449 |
+
def set_ciphers(self, ciphers):
|
| 450 |
+
if isinstance(ciphers, six.text_type):
|
| 451 |
+
ciphers = ciphers.encode("utf-8")
|
| 452 |
+
self._ctx.set_cipher_list(ciphers)
|
| 453 |
+
|
| 454 |
+
def load_verify_locations(self, cafile=None, capath=None, cadata=None):
|
| 455 |
+
if cafile is not None:
|
| 456 |
+
cafile = cafile.encode("utf-8")
|
| 457 |
+
if capath is not None:
|
| 458 |
+
capath = capath.encode("utf-8")
|
| 459 |
+
try:
|
| 460 |
+
self._ctx.load_verify_locations(cafile, capath)
|
| 461 |
+
if cadata is not None:
|
| 462 |
+
self._ctx.load_verify_locations(BytesIO(cadata))
|
| 463 |
+
except OpenSSL.SSL.Error as e:
|
| 464 |
+
raise ssl.SSLError("unable to load trusted certificates: %r" % e)
|
| 465 |
+
|
| 466 |
+
def load_cert_chain(self, certfile, keyfile=None, password=None):
|
| 467 |
+
self._ctx.use_certificate_chain_file(certfile)
|
| 468 |
+
if password is not None:
|
| 469 |
+
if not isinstance(password, six.binary_type):
|
| 470 |
+
password = password.encode("utf-8")
|
| 471 |
+
self._ctx.set_passwd_cb(lambda *_: password)
|
| 472 |
+
self._ctx.use_privatekey_file(keyfile or certfile)
|
| 473 |
+
|
| 474 |
+
def set_alpn_protocols(self, protocols):
|
| 475 |
+
protocols = [six.ensure_binary(p) for p in protocols]
|
| 476 |
+
return self._ctx.set_alpn_protos(protocols)
|
| 477 |
+
|
| 478 |
+
def wrap_socket(
|
| 479 |
+
self,
|
| 480 |
+
sock,
|
| 481 |
+
server_side=False,
|
| 482 |
+
do_handshake_on_connect=True,
|
| 483 |
+
suppress_ragged_eofs=True,
|
| 484 |
+
server_hostname=None,
|
| 485 |
+
):
|
| 486 |
+
cnx = OpenSSL.SSL.Connection(self._ctx, sock)
|
| 487 |
+
|
| 488 |
+
if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3
|
| 489 |
+
server_hostname = server_hostname.encode("utf-8")
|
| 490 |
+
|
| 491 |
+
if server_hostname is not None:
|
| 492 |
+
cnx.set_tlsext_host_name(server_hostname)
|
| 493 |
+
|
| 494 |
+
cnx.set_connect_state()
|
| 495 |
+
|
| 496 |
+
while True:
|
| 497 |
+
try:
|
| 498 |
+
cnx.do_handshake()
|
| 499 |
+
except OpenSSL.SSL.WantReadError:
|
| 500 |
+
if not util.wait_for_read(sock, sock.gettimeout()):
|
| 501 |
+
raise timeout("select timed out")
|
| 502 |
+
continue
|
| 503 |
+
except OpenSSL.SSL.Error as e:
|
| 504 |
+
raise ssl.SSLError("bad handshake: %r" % e)
|
| 505 |
+
break
|
| 506 |
+
|
| 507 |
+
return WrappedSocket(cnx, sock)
|
| 508 |
+
|
| 509 |
+
|
| 510 |
+
def _verify_callback(cnx, x509, err_no, err_depth, return_code):
|
| 511 |
+
return err_no == 0
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/securetransport.py
ADDED
|
@@ -0,0 +1,922 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
SecureTranport support for urllib3 via ctypes.
|
| 3 |
+
|
| 4 |
+
This makes platform-native TLS available to urllib3 users on macOS without the
|
| 5 |
+
use of a compiler. This is an important feature because the Python Package
|
| 6 |
+
Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL
|
| 7 |
+
that ships with macOS is not capable of doing TLSv1.2. The only way to resolve
|
| 8 |
+
this is to give macOS users an alternative solution to the problem, and that
|
| 9 |
+
solution is to use SecureTransport.
|
| 10 |
+
|
| 11 |
+
We use ctypes here because this solution must not require a compiler. That's
|
| 12 |
+
because pip is not allowed to require a compiler either.
|
| 13 |
+
|
| 14 |
+
This is not intended to be a seriously long-term solution to this problem.
|
| 15 |
+
The hope is that PEP 543 will eventually solve this issue for us, at which
|
| 16 |
+
point we can retire this contrib module. But in the short term, we need to
|
| 17 |
+
solve the impending tire fire that is Python on Mac without this kind of
|
| 18 |
+
contrib module. So...here we are.
|
| 19 |
+
|
| 20 |
+
To use this module, simply import and inject it::
|
| 21 |
+
|
| 22 |
+
import urllib3.contrib.securetransport
|
| 23 |
+
urllib3.contrib.securetransport.inject_into_urllib3()
|
| 24 |
+
|
| 25 |
+
Happy TLSing!
|
| 26 |
+
|
| 27 |
+
This code is a bastardised version of the code found in Will Bond's oscrypto
|
| 28 |
+
library. An enormous debt is owed to him for blazing this trail for us. For
|
| 29 |
+
that reason, this code should be considered to be covered both by urllib3's
|
| 30 |
+
license and by oscrypto's:
|
| 31 |
+
|
| 32 |
+
.. code-block::
|
| 33 |
+
|
| 34 |
+
Copyright (c) 2015-2016 Will Bond <will@wbond.net>
|
| 35 |
+
|
| 36 |
+
Permission is hereby granted, free of charge, to any person obtaining a
|
| 37 |
+
copy of this software and associated documentation files (the "Software"),
|
| 38 |
+
to deal in the Software without restriction, including without limitation
|
| 39 |
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
| 40 |
+
and/or sell copies of the Software, and to permit persons to whom the
|
| 41 |
+
Software is furnished to do so, subject to the following conditions:
|
| 42 |
+
|
| 43 |
+
The above copyright notice and this permission notice shall be included in
|
| 44 |
+
all copies or substantial portions of the Software.
|
| 45 |
+
|
| 46 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 47 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 48 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 49 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 50 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
| 51 |
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
| 52 |
+
DEALINGS IN THE SOFTWARE.
|
| 53 |
+
"""
|
| 54 |
+
from __future__ import absolute_import
|
| 55 |
+
|
| 56 |
+
import contextlib
|
| 57 |
+
import ctypes
|
| 58 |
+
import errno
|
| 59 |
+
import os.path
|
| 60 |
+
import shutil
|
| 61 |
+
import socket
|
| 62 |
+
import ssl
|
| 63 |
+
import struct
|
| 64 |
+
import threading
|
| 65 |
+
import weakref
|
| 66 |
+
|
| 67 |
+
from pip._vendor import six
|
| 68 |
+
|
| 69 |
+
from .. import util
|
| 70 |
+
from ..util.ssl_ import PROTOCOL_TLS_CLIENT
|
| 71 |
+
from ._securetransport.bindings import CoreFoundation, Security, SecurityConst
|
| 72 |
+
from ._securetransport.low_level import (
|
| 73 |
+
_assert_no_error,
|
| 74 |
+
_build_tls_unknown_ca_alert,
|
| 75 |
+
_cert_array_from_pem,
|
| 76 |
+
_create_cfstring_array,
|
| 77 |
+
_load_client_cert_chain,
|
| 78 |
+
_temporary_keychain,
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
try: # Platform-specific: Python 2
|
| 82 |
+
from socket import _fileobject
|
| 83 |
+
except ImportError: # Platform-specific: Python 3
|
| 84 |
+
_fileobject = None
|
| 85 |
+
from ..packages.backports.makefile import backport_makefile
|
| 86 |
+
|
| 87 |
+
__all__ = ["inject_into_urllib3", "extract_from_urllib3"]
|
| 88 |
+
|
| 89 |
+
# SNI always works
|
| 90 |
+
HAS_SNI = True
|
| 91 |
+
|
| 92 |
+
orig_util_HAS_SNI = util.HAS_SNI
|
| 93 |
+
orig_util_SSLContext = util.ssl_.SSLContext
|
| 94 |
+
|
| 95 |
+
# This dictionary is used by the read callback to obtain a handle to the
|
| 96 |
+
# calling wrapped socket. This is a pretty silly approach, but for now it'll
|
| 97 |
+
# do. I feel like I should be able to smuggle a handle to the wrapped socket
|
| 98 |
+
# directly in the SSLConnectionRef, but for now this approach will work I
|
| 99 |
+
# guess.
|
| 100 |
+
#
|
| 101 |
+
# We need to lock around this structure for inserts, but we don't do it for
|
| 102 |
+
# reads/writes in the callbacks. The reasoning here goes as follows:
|
| 103 |
+
#
|
| 104 |
+
# 1. It is not possible to call into the callbacks before the dictionary is
|
| 105 |
+
# populated, so once in the callback the id must be in the dictionary.
|
| 106 |
+
# 2. The callbacks don't mutate the dictionary, they only read from it, and
|
| 107 |
+
# so cannot conflict with any of the insertions.
|
| 108 |
+
#
|
| 109 |
+
# This is good: if we had to lock in the callbacks we'd drastically slow down
|
| 110 |
+
# the performance of this code.
|
| 111 |
+
_connection_refs = weakref.WeakValueDictionary()
|
| 112 |
+
_connection_ref_lock = threading.Lock()
|
| 113 |
+
|
| 114 |
+
# Limit writes to 16kB. This is OpenSSL's limit, but we'll cargo-cult it over
|
| 115 |
+
# for no better reason than we need *a* limit, and this one is right there.
|
| 116 |
+
SSL_WRITE_BLOCKSIZE = 16384
|
| 117 |
+
|
| 118 |
+
# This is our equivalent of util.ssl_.DEFAULT_CIPHERS, but expanded out to
|
| 119 |
+
# individual cipher suites. We need to do this because this is how
|
| 120 |
+
# SecureTransport wants them.
|
| 121 |
+
CIPHER_SUITES = [
|
| 122 |
+
SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
|
| 123 |
+
SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
|
| 124 |
+
SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
| 125 |
+
SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
|
| 126 |
+
SecurityConst.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
|
| 127 |
+
SecurityConst.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
|
| 128 |
+
SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
|
| 129 |
+
SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
|
| 130 |
+
SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
|
| 131 |
+
SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
| 132 |
+
SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
|
| 133 |
+
SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
| 134 |
+
SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
|
| 135 |
+
SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
| 136 |
+
SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
|
| 137 |
+
SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
| 138 |
+
SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
|
| 139 |
+
SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
|
| 140 |
+
SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
|
| 141 |
+
SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
|
| 142 |
+
SecurityConst.TLS_AES_256_GCM_SHA384,
|
| 143 |
+
SecurityConst.TLS_AES_128_GCM_SHA256,
|
| 144 |
+
SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
| 145 |
+
SecurityConst.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
| 146 |
+
SecurityConst.TLS_AES_128_CCM_8_SHA256,
|
| 147 |
+
SecurityConst.TLS_AES_128_CCM_SHA256,
|
| 148 |
+
SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA256,
|
| 149 |
+
SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA256,
|
| 150 |
+
SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA,
|
| 151 |
+
SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA,
|
| 152 |
+
]
|
| 153 |
+
|
| 154 |
+
# Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of
|
| 155 |
+
# TLSv1 and a high of TLSv1.2. For everything else, we pin to that version.
|
| 156 |
+
# TLSv1 to 1.2 are supported on macOS 10.8+
|
| 157 |
+
_protocol_to_min_max = {
|
| 158 |
+
util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12),
|
| 159 |
+
PROTOCOL_TLS_CLIENT: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12),
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
if hasattr(ssl, "PROTOCOL_SSLv2"):
|
| 163 |
+
_protocol_to_min_max[ssl.PROTOCOL_SSLv2] = (
|
| 164 |
+
SecurityConst.kSSLProtocol2,
|
| 165 |
+
SecurityConst.kSSLProtocol2,
|
| 166 |
+
)
|
| 167 |
+
if hasattr(ssl, "PROTOCOL_SSLv3"):
|
| 168 |
+
_protocol_to_min_max[ssl.PROTOCOL_SSLv3] = (
|
| 169 |
+
SecurityConst.kSSLProtocol3,
|
| 170 |
+
SecurityConst.kSSLProtocol3,
|
| 171 |
+
)
|
| 172 |
+
if hasattr(ssl, "PROTOCOL_TLSv1"):
|
| 173 |
+
_protocol_to_min_max[ssl.PROTOCOL_TLSv1] = (
|
| 174 |
+
SecurityConst.kTLSProtocol1,
|
| 175 |
+
SecurityConst.kTLSProtocol1,
|
| 176 |
+
)
|
| 177 |
+
if hasattr(ssl, "PROTOCOL_TLSv1_1"):
|
| 178 |
+
_protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = (
|
| 179 |
+
SecurityConst.kTLSProtocol11,
|
| 180 |
+
SecurityConst.kTLSProtocol11,
|
| 181 |
+
)
|
| 182 |
+
if hasattr(ssl, "PROTOCOL_TLSv1_2"):
|
| 183 |
+
_protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = (
|
| 184 |
+
SecurityConst.kTLSProtocol12,
|
| 185 |
+
SecurityConst.kTLSProtocol12,
|
| 186 |
+
)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def inject_into_urllib3():
|
| 190 |
+
"""
|
| 191 |
+
Monkey-patch urllib3 with SecureTransport-backed SSL-support.
|
| 192 |
+
"""
|
| 193 |
+
util.SSLContext = SecureTransportContext
|
| 194 |
+
util.ssl_.SSLContext = SecureTransportContext
|
| 195 |
+
util.HAS_SNI = HAS_SNI
|
| 196 |
+
util.ssl_.HAS_SNI = HAS_SNI
|
| 197 |
+
util.IS_SECURETRANSPORT = True
|
| 198 |
+
util.ssl_.IS_SECURETRANSPORT = True
|
| 199 |
+
|
| 200 |
+
|
| 201 |
+
def extract_from_urllib3():
|
| 202 |
+
"""
|
| 203 |
+
Undo monkey-patching by :func:`inject_into_urllib3`.
|
| 204 |
+
"""
|
| 205 |
+
util.SSLContext = orig_util_SSLContext
|
| 206 |
+
util.ssl_.SSLContext = orig_util_SSLContext
|
| 207 |
+
util.HAS_SNI = orig_util_HAS_SNI
|
| 208 |
+
util.ssl_.HAS_SNI = orig_util_HAS_SNI
|
| 209 |
+
util.IS_SECURETRANSPORT = False
|
| 210 |
+
util.ssl_.IS_SECURETRANSPORT = False
|
| 211 |
+
|
| 212 |
+
|
| 213 |
+
def _read_callback(connection_id, data_buffer, data_length_pointer):
|
| 214 |
+
"""
|
| 215 |
+
SecureTransport read callback. This is called by ST to request that data
|
| 216 |
+
be returned from the socket.
|
| 217 |
+
"""
|
| 218 |
+
wrapped_socket = None
|
| 219 |
+
try:
|
| 220 |
+
wrapped_socket = _connection_refs.get(connection_id)
|
| 221 |
+
if wrapped_socket is None:
|
| 222 |
+
return SecurityConst.errSSLInternal
|
| 223 |
+
base_socket = wrapped_socket.socket
|
| 224 |
+
|
| 225 |
+
requested_length = data_length_pointer[0]
|
| 226 |
+
|
| 227 |
+
timeout = wrapped_socket.gettimeout()
|
| 228 |
+
error = None
|
| 229 |
+
read_count = 0
|
| 230 |
+
|
| 231 |
+
try:
|
| 232 |
+
while read_count < requested_length:
|
| 233 |
+
if timeout is None or timeout >= 0:
|
| 234 |
+
if not util.wait_for_read(base_socket, timeout):
|
| 235 |
+
raise socket.error(errno.EAGAIN, "timed out")
|
| 236 |
+
|
| 237 |
+
remaining = requested_length - read_count
|
| 238 |
+
buffer = (ctypes.c_char * remaining).from_address(
|
| 239 |
+
data_buffer + read_count
|
| 240 |
+
)
|
| 241 |
+
chunk_size = base_socket.recv_into(buffer, remaining)
|
| 242 |
+
read_count += chunk_size
|
| 243 |
+
if not chunk_size:
|
| 244 |
+
if not read_count:
|
| 245 |
+
return SecurityConst.errSSLClosedGraceful
|
| 246 |
+
break
|
| 247 |
+
except (socket.error) as e:
|
| 248 |
+
error = e.errno
|
| 249 |
+
|
| 250 |
+
if error is not None and error != errno.EAGAIN:
|
| 251 |
+
data_length_pointer[0] = read_count
|
| 252 |
+
if error == errno.ECONNRESET or error == errno.EPIPE:
|
| 253 |
+
return SecurityConst.errSSLClosedAbort
|
| 254 |
+
raise
|
| 255 |
+
|
| 256 |
+
data_length_pointer[0] = read_count
|
| 257 |
+
|
| 258 |
+
if read_count != requested_length:
|
| 259 |
+
return SecurityConst.errSSLWouldBlock
|
| 260 |
+
|
| 261 |
+
return 0
|
| 262 |
+
except Exception as e:
|
| 263 |
+
if wrapped_socket is not None:
|
| 264 |
+
wrapped_socket._exception = e
|
| 265 |
+
return SecurityConst.errSSLInternal
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
def _write_callback(connection_id, data_buffer, data_length_pointer):
|
| 269 |
+
"""
|
| 270 |
+
SecureTransport write callback. This is called by ST to request that data
|
| 271 |
+
actually be sent on the network.
|
| 272 |
+
"""
|
| 273 |
+
wrapped_socket = None
|
| 274 |
+
try:
|
| 275 |
+
wrapped_socket = _connection_refs.get(connection_id)
|
| 276 |
+
if wrapped_socket is None:
|
| 277 |
+
return SecurityConst.errSSLInternal
|
| 278 |
+
base_socket = wrapped_socket.socket
|
| 279 |
+
|
| 280 |
+
bytes_to_write = data_length_pointer[0]
|
| 281 |
+
data = ctypes.string_at(data_buffer, bytes_to_write)
|
| 282 |
+
|
| 283 |
+
timeout = wrapped_socket.gettimeout()
|
| 284 |
+
error = None
|
| 285 |
+
sent = 0
|
| 286 |
+
|
| 287 |
+
try:
|
| 288 |
+
while sent < bytes_to_write:
|
| 289 |
+
if timeout is None or timeout >= 0:
|
| 290 |
+
if not util.wait_for_write(base_socket, timeout):
|
| 291 |
+
raise socket.error(errno.EAGAIN, "timed out")
|
| 292 |
+
chunk_sent = base_socket.send(data)
|
| 293 |
+
sent += chunk_sent
|
| 294 |
+
|
| 295 |
+
# This has some needless copying here, but I'm not sure there's
|
| 296 |
+
# much value in optimising this data path.
|
| 297 |
+
data = data[chunk_sent:]
|
| 298 |
+
except (socket.error) as e:
|
| 299 |
+
error = e.errno
|
| 300 |
+
|
| 301 |
+
if error is not None and error != errno.EAGAIN:
|
| 302 |
+
data_length_pointer[0] = sent
|
| 303 |
+
if error == errno.ECONNRESET or error == errno.EPIPE:
|
| 304 |
+
return SecurityConst.errSSLClosedAbort
|
| 305 |
+
raise
|
| 306 |
+
|
| 307 |
+
data_length_pointer[0] = sent
|
| 308 |
+
|
| 309 |
+
if sent != bytes_to_write:
|
| 310 |
+
return SecurityConst.errSSLWouldBlock
|
| 311 |
+
|
| 312 |
+
return 0
|
| 313 |
+
except Exception as e:
|
| 314 |
+
if wrapped_socket is not None:
|
| 315 |
+
wrapped_socket._exception = e
|
| 316 |
+
return SecurityConst.errSSLInternal
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
# We need to keep these two objects references alive: if they get GC'd while
|
| 320 |
+
# in use then SecureTransport could attempt to call a function that is in freed
|
| 321 |
+
# memory. That would be...uh...bad. Yeah, that's the word. Bad.
|
| 322 |
+
_read_callback_pointer = Security.SSLReadFunc(_read_callback)
|
| 323 |
+
_write_callback_pointer = Security.SSLWriteFunc(_write_callback)
|
| 324 |
+
|
| 325 |
+
|
| 326 |
+
class WrappedSocket(object):
|
| 327 |
+
"""
|
| 328 |
+
API-compatibility wrapper for Python's OpenSSL wrapped socket object.
|
| 329 |
+
|
| 330 |
+
Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage
|
| 331 |
+
collector of PyPy.
|
| 332 |
+
"""
|
| 333 |
+
|
| 334 |
+
def __init__(self, socket):
|
| 335 |
+
self.socket = socket
|
| 336 |
+
self.context = None
|
| 337 |
+
self._makefile_refs = 0
|
| 338 |
+
self._closed = False
|
| 339 |
+
self._exception = None
|
| 340 |
+
self._keychain = None
|
| 341 |
+
self._keychain_dir = None
|
| 342 |
+
self._client_cert_chain = None
|
| 343 |
+
|
| 344 |
+
# We save off the previously-configured timeout and then set it to
|
| 345 |
+
# zero. This is done because we use select and friends to handle the
|
| 346 |
+
# timeouts, but if we leave the timeout set on the lower socket then
|
| 347 |
+
# Python will "kindly" call select on that socket again for us. Avoid
|
| 348 |
+
# that by forcing the timeout to zero.
|
| 349 |
+
self._timeout = self.socket.gettimeout()
|
| 350 |
+
self.socket.settimeout(0)
|
| 351 |
+
|
| 352 |
+
@contextlib.contextmanager
|
| 353 |
+
def _raise_on_error(self):
|
| 354 |
+
"""
|
| 355 |
+
A context manager that can be used to wrap calls that do I/O from
|
| 356 |
+
SecureTransport. If any of the I/O callbacks hit an exception, this
|
| 357 |
+
context manager will correctly propagate the exception after the fact.
|
| 358 |
+
This avoids silently swallowing those exceptions.
|
| 359 |
+
|
| 360 |
+
It also correctly forces the socket closed.
|
| 361 |
+
"""
|
| 362 |
+
self._exception = None
|
| 363 |
+
|
| 364 |
+
# We explicitly don't catch around this yield because in the unlikely
|
| 365 |
+
# event that an exception was hit in the block we don't want to swallow
|
| 366 |
+
# it.
|
| 367 |
+
yield
|
| 368 |
+
if self._exception is not None:
|
| 369 |
+
exception, self._exception = self._exception, None
|
| 370 |
+
self.close()
|
| 371 |
+
raise exception
|
| 372 |
+
|
| 373 |
+
def _set_ciphers(self):
|
| 374 |
+
"""
|
| 375 |
+
Sets up the allowed ciphers. By default this matches the set in
|
| 376 |
+
util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done
|
| 377 |
+
custom and doesn't allow changing at this time, mostly because parsing
|
| 378 |
+
OpenSSL cipher strings is going to be a freaking nightmare.
|
| 379 |
+
"""
|
| 380 |
+
ciphers = (Security.SSLCipherSuite * len(CIPHER_SUITES))(*CIPHER_SUITES)
|
| 381 |
+
result = Security.SSLSetEnabledCiphers(
|
| 382 |
+
self.context, ciphers, len(CIPHER_SUITES)
|
| 383 |
+
)
|
| 384 |
+
_assert_no_error(result)
|
| 385 |
+
|
| 386 |
+
def _set_alpn_protocols(self, protocols):
|
| 387 |
+
"""
|
| 388 |
+
Sets up the ALPN protocols on the context.
|
| 389 |
+
"""
|
| 390 |
+
if not protocols:
|
| 391 |
+
return
|
| 392 |
+
protocols_arr = _create_cfstring_array(protocols)
|
| 393 |
+
try:
|
| 394 |
+
result = Security.SSLSetALPNProtocols(self.context, protocols_arr)
|
| 395 |
+
_assert_no_error(result)
|
| 396 |
+
finally:
|
| 397 |
+
CoreFoundation.CFRelease(protocols_arr)
|
| 398 |
+
|
| 399 |
+
def _custom_validate(self, verify, trust_bundle):
|
| 400 |
+
"""
|
| 401 |
+
Called when we have set custom validation. We do this in two cases:
|
| 402 |
+
first, when cert validation is entirely disabled; and second, when
|
| 403 |
+
using a custom trust DB.
|
| 404 |
+
Raises an SSLError if the connection is not trusted.
|
| 405 |
+
"""
|
| 406 |
+
# If we disabled cert validation, just say: cool.
|
| 407 |
+
if not verify:
|
| 408 |
+
return
|
| 409 |
+
|
| 410 |
+
successes = (
|
| 411 |
+
SecurityConst.kSecTrustResultUnspecified,
|
| 412 |
+
SecurityConst.kSecTrustResultProceed,
|
| 413 |
+
)
|
| 414 |
+
try:
|
| 415 |
+
trust_result = self._evaluate_trust(trust_bundle)
|
| 416 |
+
if trust_result in successes:
|
| 417 |
+
return
|
| 418 |
+
reason = "error code: %d" % (trust_result,)
|
| 419 |
+
except Exception as e:
|
| 420 |
+
# Do not trust on error
|
| 421 |
+
reason = "exception: %r" % (e,)
|
| 422 |
+
|
| 423 |
+
# SecureTransport does not send an alert nor shuts down the connection.
|
| 424 |
+
rec = _build_tls_unknown_ca_alert(self.version())
|
| 425 |
+
self.socket.sendall(rec)
|
| 426 |
+
# close the connection immediately
|
| 427 |
+
# l_onoff = 1, activate linger
|
| 428 |
+
# l_linger = 0, linger for 0 seoncds
|
| 429 |
+
opts = struct.pack("ii", 1, 0)
|
| 430 |
+
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, opts)
|
| 431 |
+
self.close()
|
| 432 |
+
raise ssl.SSLError("certificate verify failed, %s" % reason)
|
| 433 |
+
|
| 434 |
+
def _evaluate_trust(self, trust_bundle):
|
| 435 |
+
# We want data in memory, so load it up.
|
| 436 |
+
if os.path.isfile(trust_bundle):
|
| 437 |
+
with open(trust_bundle, "rb") as f:
|
| 438 |
+
trust_bundle = f.read()
|
| 439 |
+
|
| 440 |
+
cert_array = None
|
| 441 |
+
trust = Security.SecTrustRef()
|
| 442 |
+
|
| 443 |
+
try:
|
| 444 |
+
# Get a CFArray that contains the certs we want.
|
| 445 |
+
cert_array = _cert_array_from_pem(trust_bundle)
|
| 446 |
+
|
| 447 |
+
# Ok, now the hard part. We want to get the SecTrustRef that ST has
|
| 448 |
+
# created for this connection, shove our CAs into it, tell ST to
|
| 449 |
+
# ignore everything else it knows, and then ask if it can build a
|
| 450 |
+
# chain. This is a buuuunch of code.
|
| 451 |
+
result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust))
|
| 452 |
+
_assert_no_error(result)
|
| 453 |
+
if not trust:
|
| 454 |
+
raise ssl.SSLError("Failed to copy trust reference")
|
| 455 |
+
|
| 456 |
+
result = Security.SecTrustSetAnchorCertificates(trust, cert_array)
|
| 457 |
+
_assert_no_error(result)
|
| 458 |
+
|
| 459 |
+
result = Security.SecTrustSetAnchorCertificatesOnly(trust, True)
|
| 460 |
+
_assert_no_error(result)
|
| 461 |
+
|
| 462 |
+
trust_result = Security.SecTrustResultType()
|
| 463 |
+
result = Security.SecTrustEvaluate(trust, ctypes.byref(trust_result))
|
| 464 |
+
_assert_no_error(result)
|
| 465 |
+
finally:
|
| 466 |
+
if trust:
|
| 467 |
+
CoreFoundation.CFRelease(trust)
|
| 468 |
+
|
| 469 |
+
if cert_array is not None:
|
| 470 |
+
CoreFoundation.CFRelease(cert_array)
|
| 471 |
+
|
| 472 |
+
return trust_result.value
|
| 473 |
+
|
| 474 |
+
def handshake(
|
| 475 |
+
self,
|
| 476 |
+
server_hostname,
|
| 477 |
+
verify,
|
| 478 |
+
trust_bundle,
|
| 479 |
+
min_version,
|
| 480 |
+
max_version,
|
| 481 |
+
client_cert,
|
| 482 |
+
client_key,
|
| 483 |
+
client_key_passphrase,
|
| 484 |
+
alpn_protocols,
|
| 485 |
+
):
|
| 486 |
+
"""
|
| 487 |
+
Actually performs the TLS handshake. This is run automatically by
|
| 488 |
+
wrapped socket, and shouldn't be needed in user code.
|
| 489 |
+
"""
|
| 490 |
+
# First, we do the initial bits of connection setup. We need to create
|
| 491 |
+
# a context, set its I/O funcs, and set the connection reference.
|
| 492 |
+
self.context = Security.SSLCreateContext(
|
| 493 |
+
None, SecurityConst.kSSLClientSide, SecurityConst.kSSLStreamType
|
| 494 |
+
)
|
| 495 |
+
result = Security.SSLSetIOFuncs(
|
| 496 |
+
self.context, _read_callback_pointer, _write_callback_pointer
|
| 497 |
+
)
|
| 498 |
+
_assert_no_error(result)
|
| 499 |
+
|
| 500 |
+
# Here we need to compute the handle to use. We do this by taking the
|
| 501 |
+
# id of self modulo 2**31 - 1. If this is already in the dictionary, we
|
| 502 |
+
# just keep incrementing by one until we find a free space.
|
| 503 |
+
with _connection_ref_lock:
|
| 504 |
+
handle = id(self) % 2147483647
|
| 505 |
+
while handle in _connection_refs:
|
| 506 |
+
handle = (handle + 1) % 2147483647
|
| 507 |
+
_connection_refs[handle] = self
|
| 508 |
+
|
| 509 |
+
result = Security.SSLSetConnection(self.context, handle)
|
| 510 |
+
_assert_no_error(result)
|
| 511 |
+
|
| 512 |
+
# If we have a server hostname, we should set that too.
|
| 513 |
+
if server_hostname:
|
| 514 |
+
if not isinstance(server_hostname, bytes):
|
| 515 |
+
server_hostname = server_hostname.encode("utf-8")
|
| 516 |
+
|
| 517 |
+
result = Security.SSLSetPeerDomainName(
|
| 518 |
+
self.context, server_hostname, len(server_hostname)
|
| 519 |
+
)
|
| 520 |
+
_assert_no_error(result)
|
| 521 |
+
|
| 522 |
+
# Setup the ciphers.
|
| 523 |
+
self._set_ciphers()
|
| 524 |
+
|
| 525 |
+
# Setup the ALPN protocols.
|
| 526 |
+
self._set_alpn_protocols(alpn_protocols)
|
| 527 |
+
|
| 528 |
+
# Set the minimum and maximum TLS versions.
|
| 529 |
+
result = Security.SSLSetProtocolVersionMin(self.context, min_version)
|
| 530 |
+
_assert_no_error(result)
|
| 531 |
+
|
| 532 |
+
result = Security.SSLSetProtocolVersionMax(self.context, max_version)
|
| 533 |
+
_assert_no_error(result)
|
| 534 |
+
|
| 535 |
+
# If there's a trust DB, we need to use it. We do that by telling
|
| 536 |
+
# SecureTransport to break on server auth. We also do that if we don't
|
| 537 |
+
# want to validate the certs at all: we just won't actually do any
|
| 538 |
+
# authing in that case.
|
| 539 |
+
if not verify or trust_bundle is not None:
|
| 540 |
+
result = Security.SSLSetSessionOption(
|
| 541 |
+
self.context, SecurityConst.kSSLSessionOptionBreakOnServerAuth, True
|
| 542 |
+
)
|
| 543 |
+
_assert_no_error(result)
|
| 544 |
+
|
| 545 |
+
# If there's a client cert, we need to use it.
|
| 546 |
+
if client_cert:
|
| 547 |
+
self._keychain, self._keychain_dir = _temporary_keychain()
|
| 548 |
+
self._client_cert_chain = _load_client_cert_chain(
|
| 549 |
+
self._keychain, client_cert, client_key
|
| 550 |
+
)
|
| 551 |
+
result = Security.SSLSetCertificate(self.context, self._client_cert_chain)
|
| 552 |
+
_assert_no_error(result)
|
| 553 |
+
|
| 554 |
+
while True:
|
| 555 |
+
with self._raise_on_error():
|
| 556 |
+
result = Security.SSLHandshake(self.context)
|
| 557 |
+
|
| 558 |
+
if result == SecurityConst.errSSLWouldBlock:
|
| 559 |
+
raise socket.timeout("handshake timed out")
|
| 560 |
+
elif result == SecurityConst.errSSLServerAuthCompleted:
|
| 561 |
+
self._custom_validate(verify, trust_bundle)
|
| 562 |
+
continue
|
| 563 |
+
else:
|
| 564 |
+
_assert_no_error(result)
|
| 565 |
+
break
|
| 566 |
+
|
| 567 |
+
def fileno(self):
|
| 568 |
+
return self.socket.fileno()
|
| 569 |
+
|
| 570 |
+
# Copy-pasted from Python 3.5 source code
|
| 571 |
+
def _decref_socketios(self):
|
| 572 |
+
if self._makefile_refs > 0:
|
| 573 |
+
self._makefile_refs -= 1
|
| 574 |
+
if self._closed:
|
| 575 |
+
self.close()
|
| 576 |
+
|
| 577 |
+
def recv(self, bufsiz):
|
| 578 |
+
buffer = ctypes.create_string_buffer(bufsiz)
|
| 579 |
+
bytes_read = self.recv_into(buffer, bufsiz)
|
| 580 |
+
data = buffer[:bytes_read]
|
| 581 |
+
return data
|
| 582 |
+
|
| 583 |
+
def recv_into(self, buffer, nbytes=None):
|
| 584 |
+
# Read short on EOF.
|
| 585 |
+
if self._closed:
|
| 586 |
+
return 0
|
| 587 |
+
|
| 588 |
+
if nbytes is None:
|
| 589 |
+
nbytes = len(buffer)
|
| 590 |
+
|
| 591 |
+
buffer = (ctypes.c_char * nbytes).from_buffer(buffer)
|
| 592 |
+
processed_bytes = ctypes.c_size_t(0)
|
| 593 |
+
|
| 594 |
+
with self._raise_on_error():
|
| 595 |
+
result = Security.SSLRead(
|
| 596 |
+
self.context, buffer, nbytes, ctypes.byref(processed_bytes)
|
| 597 |
+
)
|
| 598 |
+
|
| 599 |
+
# There are some result codes that we want to treat as "not always
|
| 600 |
+
# errors". Specifically, those are errSSLWouldBlock,
|
| 601 |
+
# errSSLClosedGraceful, and errSSLClosedNoNotify.
|
| 602 |
+
if result == SecurityConst.errSSLWouldBlock:
|
| 603 |
+
# If we didn't process any bytes, then this was just a time out.
|
| 604 |
+
# However, we can get errSSLWouldBlock in situations when we *did*
|
| 605 |
+
# read some data, and in those cases we should just read "short"
|
| 606 |
+
# and return.
|
| 607 |
+
if processed_bytes.value == 0:
|
| 608 |
+
# Timed out, no data read.
|
| 609 |
+
raise socket.timeout("recv timed out")
|
| 610 |
+
elif result in (
|
| 611 |
+
SecurityConst.errSSLClosedGraceful,
|
| 612 |
+
SecurityConst.errSSLClosedNoNotify,
|
| 613 |
+
):
|
| 614 |
+
# The remote peer has closed this connection. We should do so as
|
| 615 |
+
# well. Note that we don't actually return here because in
|
| 616 |
+
# principle this could actually be fired along with return data.
|
| 617 |
+
# It's unlikely though.
|
| 618 |
+
self.close()
|
| 619 |
+
else:
|
| 620 |
+
_assert_no_error(result)
|
| 621 |
+
|
| 622 |
+
# Ok, we read and probably succeeded. We should return whatever data
|
| 623 |
+
# was actually read.
|
| 624 |
+
return processed_bytes.value
|
| 625 |
+
|
| 626 |
+
def settimeout(self, timeout):
|
| 627 |
+
self._timeout = timeout
|
| 628 |
+
|
| 629 |
+
def gettimeout(self):
|
| 630 |
+
return self._timeout
|
| 631 |
+
|
| 632 |
+
def send(self, data):
|
| 633 |
+
processed_bytes = ctypes.c_size_t(0)
|
| 634 |
+
|
| 635 |
+
with self._raise_on_error():
|
| 636 |
+
result = Security.SSLWrite(
|
| 637 |
+
self.context, data, len(data), ctypes.byref(processed_bytes)
|
| 638 |
+
)
|
| 639 |
+
|
| 640 |
+
if result == SecurityConst.errSSLWouldBlock and processed_bytes.value == 0:
|
| 641 |
+
# Timed out
|
| 642 |
+
raise socket.timeout("send timed out")
|
| 643 |
+
else:
|
| 644 |
+
_assert_no_error(result)
|
| 645 |
+
|
| 646 |
+
# We sent, and probably succeeded. Tell them how much we sent.
|
| 647 |
+
return processed_bytes.value
|
| 648 |
+
|
| 649 |
+
def sendall(self, data):
|
| 650 |
+
total_sent = 0
|
| 651 |
+
while total_sent < len(data):
|
| 652 |
+
sent = self.send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE])
|
| 653 |
+
total_sent += sent
|
| 654 |
+
|
| 655 |
+
def shutdown(self):
|
| 656 |
+
with self._raise_on_error():
|
| 657 |
+
Security.SSLClose(self.context)
|
| 658 |
+
|
| 659 |
+
def close(self):
|
| 660 |
+
# TODO: should I do clean shutdown here? Do I have to?
|
| 661 |
+
if self._makefile_refs < 1:
|
| 662 |
+
self._closed = True
|
| 663 |
+
if self.context:
|
| 664 |
+
CoreFoundation.CFRelease(self.context)
|
| 665 |
+
self.context = None
|
| 666 |
+
if self._client_cert_chain:
|
| 667 |
+
CoreFoundation.CFRelease(self._client_cert_chain)
|
| 668 |
+
self._client_cert_chain = None
|
| 669 |
+
if self._keychain:
|
| 670 |
+
Security.SecKeychainDelete(self._keychain)
|
| 671 |
+
CoreFoundation.CFRelease(self._keychain)
|
| 672 |
+
shutil.rmtree(self._keychain_dir)
|
| 673 |
+
self._keychain = self._keychain_dir = None
|
| 674 |
+
return self.socket.close()
|
| 675 |
+
else:
|
| 676 |
+
self._makefile_refs -= 1
|
| 677 |
+
|
| 678 |
+
def getpeercert(self, binary_form=False):
|
| 679 |
+
# Urgh, annoying.
|
| 680 |
+
#
|
| 681 |
+
# Here's how we do this:
|
| 682 |
+
#
|
| 683 |
+
# 1. Call SSLCopyPeerTrust to get hold of the trust object for this
|
| 684 |
+
# connection.
|
| 685 |
+
# 2. Call SecTrustGetCertificateAtIndex for index 0 to get the leaf.
|
| 686 |
+
# 3. To get the CN, call SecCertificateCopyCommonName and process that
|
| 687 |
+
# string so that it's of the appropriate type.
|
| 688 |
+
# 4. To get the SAN, we need to do something a bit more complex:
|
| 689 |
+
# a. Call SecCertificateCopyValues to get the data, requesting
|
| 690 |
+
# kSecOIDSubjectAltName.
|
| 691 |
+
# b. Mess about with this dictionary to try to get the SANs out.
|
| 692 |
+
#
|
| 693 |
+
# This is gross. Really gross. It's going to be a few hundred LoC extra
|
| 694 |
+
# just to repeat something that SecureTransport can *already do*. So my
|
| 695 |
+
# operating assumption at this time is that what we want to do is
|
| 696 |
+
# instead to just flag to urllib3 that it shouldn't do its own hostname
|
| 697 |
+
# validation when using SecureTransport.
|
| 698 |
+
if not binary_form:
|
| 699 |
+
raise ValueError("SecureTransport only supports dumping binary certs")
|
| 700 |
+
trust = Security.SecTrustRef()
|
| 701 |
+
certdata = None
|
| 702 |
+
der_bytes = None
|
| 703 |
+
|
| 704 |
+
try:
|
| 705 |
+
# Grab the trust store.
|
| 706 |
+
result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust))
|
| 707 |
+
_assert_no_error(result)
|
| 708 |
+
if not trust:
|
| 709 |
+
# Probably we haven't done the handshake yet. No biggie.
|
| 710 |
+
return None
|
| 711 |
+
|
| 712 |
+
cert_count = Security.SecTrustGetCertificateCount(trust)
|
| 713 |
+
if not cert_count:
|
| 714 |
+
# Also a case that might happen if we haven't handshaked.
|
| 715 |
+
# Handshook? Handshaken?
|
| 716 |
+
return None
|
| 717 |
+
|
| 718 |
+
leaf = Security.SecTrustGetCertificateAtIndex(trust, 0)
|
| 719 |
+
assert leaf
|
| 720 |
+
|
| 721 |
+
# Ok, now we want the DER bytes.
|
| 722 |
+
certdata = Security.SecCertificateCopyData(leaf)
|
| 723 |
+
assert certdata
|
| 724 |
+
|
| 725 |
+
data_length = CoreFoundation.CFDataGetLength(certdata)
|
| 726 |
+
data_buffer = CoreFoundation.CFDataGetBytePtr(certdata)
|
| 727 |
+
der_bytes = ctypes.string_at(data_buffer, data_length)
|
| 728 |
+
finally:
|
| 729 |
+
if certdata:
|
| 730 |
+
CoreFoundation.CFRelease(certdata)
|
| 731 |
+
if trust:
|
| 732 |
+
CoreFoundation.CFRelease(trust)
|
| 733 |
+
|
| 734 |
+
return der_bytes
|
| 735 |
+
|
| 736 |
+
def version(self):
|
| 737 |
+
protocol = Security.SSLProtocol()
|
| 738 |
+
result = Security.SSLGetNegotiatedProtocolVersion(
|
| 739 |
+
self.context, ctypes.byref(protocol)
|
| 740 |
+
)
|
| 741 |
+
_assert_no_error(result)
|
| 742 |
+
if protocol.value == SecurityConst.kTLSProtocol13:
|
| 743 |
+
raise ssl.SSLError("SecureTransport does not support TLS 1.3")
|
| 744 |
+
elif protocol.value == SecurityConst.kTLSProtocol12:
|
| 745 |
+
return "TLSv1.2"
|
| 746 |
+
elif protocol.value == SecurityConst.kTLSProtocol11:
|
| 747 |
+
return "TLSv1.1"
|
| 748 |
+
elif protocol.value == SecurityConst.kTLSProtocol1:
|
| 749 |
+
return "TLSv1"
|
| 750 |
+
elif protocol.value == SecurityConst.kSSLProtocol3:
|
| 751 |
+
return "SSLv3"
|
| 752 |
+
elif protocol.value == SecurityConst.kSSLProtocol2:
|
| 753 |
+
return "SSLv2"
|
| 754 |
+
else:
|
| 755 |
+
raise ssl.SSLError("Unknown TLS version: %r" % protocol)
|
| 756 |
+
|
| 757 |
+
def _reuse(self):
|
| 758 |
+
self._makefile_refs += 1
|
| 759 |
+
|
| 760 |
+
def _drop(self):
|
| 761 |
+
if self._makefile_refs < 1:
|
| 762 |
+
self.close()
|
| 763 |
+
else:
|
| 764 |
+
self._makefile_refs -= 1
|
| 765 |
+
|
| 766 |
+
|
| 767 |
+
if _fileobject: # Platform-specific: Python 2
|
| 768 |
+
|
| 769 |
+
def makefile(self, mode, bufsize=-1):
|
| 770 |
+
self._makefile_refs += 1
|
| 771 |
+
return _fileobject(self, mode, bufsize, close=True)
|
| 772 |
+
|
| 773 |
+
|
| 774 |
+
else: # Platform-specific: Python 3
|
| 775 |
+
|
| 776 |
+
def makefile(self, mode="r", buffering=None, *args, **kwargs):
|
| 777 |
+
# We disable buffering with SecureTransport because it conflicts with
|
| 778 |
+
# the buffering that ST does internally (see issue #1153 for more).
|
| 779 |
+
buffering = 0
|
| 780 |
+
return backport_makefile(self, mode, buffering, *args, **kwargs)
|
| 781 |
+
|
| 782 |
+
|
| 783 |
+
WrappedSocket.makefile = makefile
|
| 784 |
+
|
| 785 |
+
|
| 786 |
+
class SecureTransportContext(object):
|
| 787 |
+
"""
|
| 788 |
+
I am a wrapper class for the SecureTransport library, to translate the
|
| 789 |
+
interface of the standard library ``SSLContext`` object to calls into
|
| 790 |
+
SecureTransport.
|
| 791 |
+
"""
|
| 792 |
+
|
| 793 |
+
def __init__(self, protocol):
|
| 794 |
+
self._min_version, self._max_version = _protocol_to_min_max[protocol]
|
| 795 |
+
self._options = 0
|
| 796 |
+
self._verify = False
|
| 797 |
+
self._trust_bundle = None
|
| 798 |
+
self._client_cert = None
|
| 799 |
+
self._client_key = None
|
| 800 |
+
self._client_key_passphrase = None
|
| 801 |
+
self._alpn_protocols = None
|
| 802 |
+
|
| 803 |
+
@property
|
| 804 |
+
def check_hostname(self):
|
| 805 |
+
"""
|
| 806 |
+
SecureTransport cannot have its hostname checking disabled. For more,
|
| 807 |
+
see the comment on getpeercert() in this file.
|
| 808 |
+
"""
|
| 809 |
+
return True
|
| 810 |
+
|
| 811 |
+
@check_hostname.setter
|
| 812 |
+
def check_hostname(self, value):
|
| 813 |
+
"""
|
| 814 |
+
SecureTransport cannot have its hostname checking disabled. For more,
|
| 815 |
+
see the comment on getpeercert() in this file.
|
| 816 |
+
"""
|
| 817 |
+
pass
|
| 818 |
+
|
| 819 |
+
@property
|
| 820 |
+
def options(self):
|
| 821 |
+
# TODO: Well, crap.
|
| 822 |
+
#
|
| 823 |
+
# So this is the bit of the code that is the most likely to cause us
|
| 824 |
+
# trouble. Essentially we need to enumerate all of the SSL options that
|
| 825 |
+
# users might want to use and try to see if we can sensibly translate
|
| 826 |
+
# them, or whether we should just ignore them.
|
| 827 |
+
return self._options
|
| 828 |
+
|
| 829 |
+
@options.setter
|
| 830 |
+
def options(self, value):
|
| 831 |
+
# TODO: Update in line with above.
|
| 832 |
+
self._options = value
|
| 833 |
+
|
| 834 |
+
@property
|
| 835 |
+
def verify_mode(self):
|
| 836 |
+
return ssl.CERT_REQUIRED if self._verify else ssl.CERT_NONE
|
| 837 |
+
|
| 838 |
+
@verify_mode.setter
|
| 839 |
+
def verify_mode(self, value):
|
| 840 |
+
self._verify = True if value == ssl.CERT_REQUIRED else False
|
| 841 |
+
|
| 842 |
+
def set_default_verify_paths(self):
|
| 843 |
+
# So, this has to do something a bit weird. Specifically, what it does
|
| 844 |
+
# is nothing.
|
| 845 |
+
#
|
| 846 |
+
# This means that, if we had previously had load_verify_locations
|
| 847 |
+
# called, this does not undo that. We need to do that because it turns
|
| 848 |
+
# out that the rest of the urllib3 code will attempt to load the
|
| 849 |
+
# default verify paths if it hasn't been told about any paths, even if
|
| 850 |
+
# the context itself was sometime earlier. We resolve that by just
|
| 851 |
+
# ignoring it.
|
| 852 |
+
pass
|
| 853 |
+
|
| 854 |
+
def load_default_certs(self):
|
| 855 |
+
return self.set_default_verify_paths()
|
| 856 |
+
|
| 857 |
+
def set_ciphers(self, ciphers):
|
| 858 |
+
# For now, we just require the default cipher string.
|
| 859 |
+
if ciphers != util.ssl_.DEFAULT_CIPHERS:
|
| 860 |
+
raise ValueError("SecureTransport doesn't support custom cipher strings")
|
| 861 |
+
|
| 862 |
+
def load_verify_locations(self, cafile=None, capath=None, cadata=None):
|
| 863 |
+
# OK, we only really support cadata and cafile.
|
| 864 |
+
if capath is not None:
|
| 865 |
+
raise ValueError("SecureTransport does not support cert directories")
|
| 866 |
+
|
| 867 |
+
# Raise if cafile does not exist.
|
| 868 |
+
if cafile is not None:
|
| 869 |
+
with open(cafile):
|
| 870 |
+
pass
|
| 871 |
+
|
| 872 |
+
self._trust_bundle = cafile or cadata
|
| 873 |
+
|
| 874 |
+
def load_cert_chain(self, certfile, keyfile=None, password=None):
|
| 875 |
+
self._client_cert = certfile
|
| 876 |
+
self._client_key = keyfile
|
| 877 |
+
self._client_cert_passphrase = password
|
| 878 |
+
|
| 879 |
+
def set_alpn_protocols(self, protocols):
|
| 880 |
+
"""
|
| 881 |
+
Sets the ALPN protocols that will later be set on the context.
|
| 882 |
+
|
| 883 |
+
Raises a NotImplementedError if ALPN is not supported.
|
| 884 |
+
"""
|
| 885 |
+
if not hasattr(Security, "SSLSetALPNProtocols"):
|
| 886 |
+
raise NotImplementedError(
|
| 887 |
+
"SecureTransport supports ALPN only in macOS 10.12+"
|
| 888 |
+
)
|
| 889 |
+
self._alpn_protocols = [six.ensure_binary(p) for p in protocols]
|
| 890 |
+
|
| 891 |
+
def wrap_socket(
|
| 892 |
+
self,
|
| 893 |
+
sock,
|
| 894 |
+
server_side=False,
|
| 895 |
+
do_handshake_on_connect=True,
|
| 896 |
+
suppress_ragged_eofs=True,
|
| 897 |
+
server_hostname=None,
|
| 898 |
+
):
|
| 899 |
+
# So, what do we do here? Firstly, we assert some properties. This is a
|
| 900 |
+
# stripped down shim, so there is some functionality we don't support.
|
| 901 |
+
# See PEP 543 for the real deal.
|
| 902 |
+
assert not server_side
|
| 903 |
+
assert do_handshake_on_connect
|
| 904 |
+
assert suppress_ragged_eofs
|
| 905 |
+
|
| 906 |
+
# Ok, we're good to go. Now we want to create the wrapped socket object
|
| 907 |
+
# and store it in the appropriate place.
|
| 908 |
+
wrapped_socket = WrappedSocket(sock)
|
| 909 |
+
|
| 910 |
+
# Now we can handshake
|
| 911 |
+
wrapped_socket.handshake(
|
| 912 |
+
server_hostname,
|
| 913 |
+
self._verify,
|
| 914 |
+
self._trust_bundle,
|
| 915 |
+
self._min_version,
|
| 916 |
+
self._max_version,
|
| 917 |
+
self._client_cert,
|
| 918 |
+
self._client_key,
|
| 919 |
+
self._client_key_passphrase,
|
| 920 |
+
self._alpn_protocols,
|
| 921 |
+
)
|
| 922 |
+
return wrapped_socket
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/contrib/socks.py
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# -*- coding: utf-8 -*-
|
| 2 |
+
"""
|
| 3 |
+
This module contains provisional support for SOCKS proxies from within
|
| 4 |
+
urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and
|
| 5 |
+
SOCKS5. To enable its functionality, either install PySocks or install this
|
| 6 |
+
module with the ``socks`` extra.
|
| 7 |
+
|
| 8 |
+
The SOCKS implementation supports the full range of urllib3 features. It also
|
| 9 |
+
supports the following SOCKS features:
|
| 10 |
+
|
| 11 |
+
- SOCKS4A (``proxy_url='socks4a://...``)
|
| 12 |
+
- SOCKS4 (``proxy_url='socks4://...``)
|
| 13 |
+
- SOCKS5 with remote DNS (``proxy_url='socks5h://...``)
|
| 14 |
+
- SOCKS5 with local DNS (``proxy_url='socks5://...``)
|
| 15 |
+
- Usernames and passwords for the SOCKS proxy
|
| 16 |
+
|
| 17 |
+
.. note::
|
| 18 |
+
It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in
|
| 19 |
+
your ``proxy_url`` to ensure that DNS resolution is done from the remote
|
| 20 |
+
server instead of client-side when connecting to a domain name.
|
| 21 |
+
|
| 22 |
+
SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5
|
| 23 |
+
supports IPv4, IPv6, and domain names.
|
| 24 |
+
|
| 25 |
+
When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url``
|
| 26 |
+
will be sent as the ``userid`` section of the SOCKS request:
|
| 27 |
+
|
| 28 |
+
.. code-block:: python
|
| 29 |
+
|
| 30 |
+
proxy_url="socks4a://<userid>@proxy-host"
|
| 31 |
+
|
| 32 |
+
When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion
|
| 33 |
+
of the ``proxy_url`` will be sent as the username/password to authenticate
|
| 34 |
+
with the proxy:
|
| 35 |
+
|
| 36 |
+
.. code-block:: python
|
| 37 |
+
|
| 38 |
+
proxy_url="socks5h://<username>:<password>@proxy-host"
|
| 39 |
+
|
| 40 |
+
"""
|
| 41 |
+
from __future__ import absolute_import
|
| 42 |
+
|
| 43 |
+
try:
|
| 44 |
+
import socks
|
| 45 |
+
except ImportError:
|
| 46 |
+
import warnings
|
| 47 |
+
|
| 48 |
+
from ..exceptions import DependencyWarning
|
| 49 |
+
|
| 50 |
+
warnings.warn(
|
| 51 |
+
(
|
| 52 |
+
"SOCKS support in urllib3 requires the installation of optional "
|
| 53 |
+
"dependencies: specifically, PySocks. For more information, see "
|
| 54 |
+
"https://urllib3.readthedocs.io/en/1.26.x/contrib.html#socks-proxies"
|
| 55 |
+
),
|
| 56 |
+
DependencyWarning,
|
| 57 |
+
)
|
| 58 |
+
raise
|
| 59 |
+
|
| 60 |
+
from socket import error as SocketError
|
| 61 |
+
from socket import timeout as SocketTimeout
|
| 62 |
+
|
| 63 |
+
from ..connection import HTTPConnection, HTTPSConnection
|
| 64 |
+
from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool
|
| 65 |
+
from ..exceptions import ConnectTimeoutError, NewConnectionError
|
| 66 |
+
from ..poolmanager import PoolManager
|
| 67 |
+
from ..util.url import parse_url
|
| 68 |
+
|
| 69 |
+
try:
|
| 70 |
+
import ssl
|
| 71 |
+
except ImportError:
|
| 72 |
+
ssl = None
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class SOCKSConnection(HTTPConnection):
|
| 76 |
+
"""
|
| 77 |
+
A plain-text HTTP connection that connects via a SOCKS proxy.
|
| 78 |
+
"""
|
| 79 |
+
|
| 80 |
+
def __init__(self, *args, **kwargs):
|
| 81 |
+
self._socks_options = kwargs.pop("_socks_options")
|
| 82 |
+
super(SOCKSConnection, self).__init__(*args, **kwargs)
|
| 83 |
+
|
| 84 |
+
def _new_conn(self):
|
| 85 |
+
"""
|
| 86 |
+
Establish a new connection via the SOCKS proxy.
|
| 87 |
+
"""
|
| 88 |
+
extra_kw = {}
|
| 89 |
+
if self.source_address:
|
| 90 |
+
extra_kw["source_address"] = self.source_address
|
| 91 |
+
|
| 92 |
+
if self.socket_options:
|
| 93 |
+
extra_kw["socket_options"] = self.socket_options
|
| 94 |
+
|
| 95 |
+
try:
|
| 96 |
+
conn = socks.create_connection(
|
| 97 |
+
(self.host, self.port),
|
| 98 |
+
proxy_type=self._socks_options["socks_version"],
|
| 99 |
+
proxy_addr=self._socks_options["proxy_host"],
|
| 100 |
+
proxy_port=self._socks_options["proxy_port"],
|
| 101 |
+
proxy_username=self._socks_options["username"],
|
| 102 |
+
proxy_password=self._socks_options["password"],
|
| 103 |
+
proxy_rdns=self._socks_options["rdns"],
|
| 104 |
+
timeout=self.timeout,
|
| 105 |
+
**extra_kw
|
| 106 |
+
)
|
| 107 |
+
|
| 108 |
+
except SocketTimeout:
|
| 109 |
+
raise ConnectTimeoutError(
|
| 110 |
+
self,
|
| 111 |
+
"Connection to %s timed out. (connect timeout=%s)"
|
| 112 |
+
% (self.host, self.timeout),
|
| 113 |
+
)
|
| 114 |
+
|
| 115 |
+
except socks.ProxyError as e:
|
| 116 |
+
# This is fragile as hell, but it seems to be the only way to raise
|
| 117 |
+
# useful errors here.
|
| 118 |
+
if e.socket_err:
|
| 119 |
+
error = e.socket_err
|
| 120 |
+
if isinstance(error, SocketTimeout):
|
| 121 |
+
raise ConnectTimeoutError(
|
| 122 |
+
self,
|
| 123 |
+
"Connection to %s timed out. (connect timeout=%s)"
|
| 124 |
+
% (self.host, self.timeout),
|
| 125 |
+
)
|
| 126 |
+
else:
|
| 127 |
+
raise NewConnectionError(
|
| 128 |
+
self, "Failed to establish a new connection: %s" % error
|
| 129 |
+
)
|
| 130 |
+
else:
|
| 131 |
+
raise NewConnectionError(
|
| 132 |
+
self, "Failed to establish a new connection: %s" % e
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
except SocketError as e: # Defensive: PySocks should catch all these.
|
| 136 |
+
raise NewConnectionError(
|
| 137 |
+
self, "Failed to establish a new connection: %s" % e
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
return conn
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
# We don't need to duplicate the Verified/Unverified distinction from
|
| 144 |
+
# urllib3/connection.py here because the HTTPSConnection will already have been
|
| 145 |
+
# correctly set to either the Verified or Unverified form by that module. This
|
| 146 |
+
# means the SOCKSHTTPSConnection will automatically be the correct type.
|
| 147 |
+
class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection):
|
| 148 |
+
pass
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
class SOCKSHTTPConnectionPool(HTTPConnectionPool):
|
| 152 |
+
ConnectionCls = SOCKSConnection
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
class SOCKSHTTPSConnectionPool(HTTPSConnectionPool):
|
| 156 |
+
ConnectionCls = SOCKSHTTPSConnection
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
class SOCKSProxyManager(PoolManager):
|
| 160 |
+
"""
|
| 161 |
+
A version of the urllib3 ProxyManager that routes connections via the
|
| 162 |
+
defined SOCKS proxy.
|
| 163 |
+
"""
|
| 164 |
+
|
| 165 |
+
pool_classes_by_scheme = {
|
| 166 |
+
"http": SOCKSHTTPConnectionPool,
|
| 167 |
+
"https": SOCKSHTTPSConnectionPool,
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
def __init__(
|
| 171 |
+
self,
|
| 172 |
+
proxy_url,
|
| 173 |
+
username=None,
|
| 174 |
+
password=None,
|
| 175 |
+
num_pools=10,
|
| 176 |
+
headers=None,
|
| 177 |
+
**connection_pool_kw
|
| 178 |
+
):
|
| 179 |
+
parsed = parse_url(proxy_url)
|
| 180 |
+
|
| 181 |
+
if username is None and password is None and parsed.auth is not None:
|
| 182 |
+
split = parsed.auth.split(":")
|
| 183 |
+
if len(split) == 2:
|
| 184 |
+
username, password = split
|
| 185 |
+
if parsed.scheme == "socks5":
|
| 186 |
+
socks_version = socks.PROXY_TYPE_SOCKS5
|
| 187 |
+
rdns = False
|
| 188 |
+
elif parsed.scheme == "socks5h":
|
| 189 |
+
socks_version = socks.PROXY_TYPE_SOCKS5
|
| 190 |
+
rdns = True
|
| 191 |
+
elif parsed.scheme == "socks4":
|
| 192 |
+
socks_version = socks.PROXY_TYPE_SOCKS4
|
| 193 |
+
rdns = False
|
| 194 |
+
elif parsed.scheme == "socks4a":
|
| 195 |
+
socks_version = socks.PROXY_TYPE_SOCKS4
|
| 196 |
+
rdns = True
|
| 197 |
+
else:
|
| 198 |
+
raise ValueError("Unable to determine SOCKS version from %s" % proxy_url)
|
| 199 |
+
|
| 200 |
+
self.proxy_url = proxy_url
|
| 201 |
+
|
| 202 |
+
socks_options = {
|
| 203 |
+
"socks_version": socks_version,
|
| 204 |
+
"proxy_host": parsed.host,
|
| 205 |
+
"proxy_port": parsed.port,
|
| 206 |
+
"username": username,
|
| 207 |
+
"password": password,
|
| 208 |
+
"rdns": rdns,
|
| 209 |
+
}
|
| 210 |
+
connection_pool_kw["_socks_options"] = socks_options
|
| 211 |
+
|
| 212 |
+
super(SOCKSProxyManager, self).__init__(
|
| 213 |
+
num_pools, headers, **connection_pool_kw
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/exceptions.py
ADDED
|
@@ -0,0 +1,323 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead
|
| 4 |
+
|
| 5 |
+
# Base Exceptions
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class HTTPError(Exception):
|
| 9 |
+
"""Base exception used by this module."""
|
| 10 |
+
|
| 11 |
+
pass
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class HTTPWarning(Warning):
|
| 15 |
+
"""Base warning used by this module."""
|
| 16 |
+
|
| 17 |
+
pass
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class PoolError(HTTPError):
|
| 21 |
+
"""Base exception for errors caused within a pool."""
|
| 22 |
+
|
| 23 |
+
def __init__(self, pool, message):
|
| 24 |
+
self.pool = pool
|
| 25 |
+
HTTPError.__init__(self, "%s: %s" % (pool, message))
|
| 26 |
+
|
| 27 |
+
def __reduce__(self):
|
| 28 |
+
# For pickling purposes.
|
| 29 |
+
return self.__class__, (None, None)
|
| 30 |
+
|
| 31 |
+
|
| 32 |
+
class RequestError(PoolError):
|
| 33 |
+
"""Base exception for PoolErrors that have associated URLs."""
|
| 34 |
+
|
| 35 |
+
def __init__(self, pool, url, message):
|
| 36 |
+
self.url = url
|
| 37 |
+
PoolError.__init__(self, pool, message)
|
| 38 |
+
|
| 39 |
+
def __reduce__(self):
|
| 40 |
+
# For pickling purposes.
|
| 41 |
+
return self.__class__, (None, self.url, None)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class SSLError(HTTPError):
|
| 45 |
+
"""Raised when SSL certificate fails in an HTTPS connection."""
|
| 46 |
+
|
| 47 |
+
pass
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
class ProxyError(HTTPError):
|
| 51 |
+
"""Raised when the connection to a proxy fails."""
|
| 52 |
+
|
| 53 |
+
def __init__(self, message, error, *args):
|
| 54 |
+
super(ProxyError, self).__init__(message, error, *args)
|
| 55 |
+
self.original_error = error
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
class DecodeError(HTTPError):
|
| 59 |
+
"""Raised when automatic decoding based on Content-Type fails."""
|
| 60 |
+
|
| 61 |
+
pass
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
class ProtocolError(HTTPError):
|
| 65 |
+
"""Raised when something unexpected happens mid-request/response."""
|
| 66 |
+
|
| 67 |
+
pass
|
| 68 |
+
|
| 69 |
+
|
| 70 |
+
#: Renamed to ProtocolError but aliased for backwards compatibility.
|
| 71 |
+
ConnectionError = ProtocolError
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
# Leaf Exceptions
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
class MaxRetryError(RequestError):
|
| 78 |
+
"""Raised when the maximum number of retries is exceeded.
|
| 79 |
+
|
| 80 |
+
:param pool: The connection pool
|
| 81 |
+
:type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool`
|
| 82 |
+
:param string url: The requested Url
|
| 83 |
+
:param exceptions.Exception reason: The underlying error
|
| 84 |
+
|
| 85 |
+
"""
|
| 86 |
+
|
| 87 |
+
def __init__(self, pool, url, reason=None):
|
| 88 |
+
self.reason = reason
|
| 89 |
+
|
| 90 |
+
message = "Max retries exceeded with url: %s (Caused by %r)" % (url, reason)
|
| 91 |
+
|
| 92 |
+
RequestError.__init__(self, pool, url, message)
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
class HostChangedError(RequestError):
|
| 96 |
+
"""Raised when an existing pool gets a request for a foreign host."""
|
| 97 |
+
|
| 98 |
+
def __init__(self, pool, url, retries=3):
|
| 99 |
+
message = "Tried to open a foreign host with url: %s" % url
|
| 100 |
+
RequestError.__init__(self, pool, url, message)
|
| 101 |
+
self.retries = retries
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class TimeoutStateError(HTTPError):
|
| 105 |
+
"""Raised when passing an invalid state to a timeout"""
|
| 106 |
+
|
| 107 |
+
pass
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
class TimeoutError(HTTPError):
|
| 111 |
+
"""Raised when a socket timeout error occurs.
|
| 112 |
+
|
| 113 |
+
Catching this error will catch both :exc:`ReadTimeoutErrors
|
| 114 |
+
<ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`.
|
| 115 |
+
"""
|
| 116 |
+
|
| 117 |
+
pass
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
class ReadTimeoutError(TimeoutError, RequestError):
|
| 121 |
+
"""Raised when a socket timeout occurs while receiving data from a server"""
|
| 122 |
+
|
| 123 |
+
pass
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
# This timeout error does not have a URL attached and needs to inherit from the
|
| 127 |
+
# base HTTPError
|
| 128 |
+
class ConnectTimeoutError(TimeoutError):
|
| 129 |
+
"""Raised when a socket timeout occurs while connecting to a server"""
|
| 130 |
+
|
| 131 |
+
pass
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
class NewConnectionError(ConnectTimeoutError, PoolError):
|
| 135 |
+
"""Raised when we fail to establish a new connection. Usually ECONNREFUSED."""
|
| 136 |
+
|
| 137 |
+
pass
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
class EmptyPoolError(PoolError):
|
| 141 |
+
"""Raised when a pool runs out of connections and no more are allowed."""
|
| 142 |
+
|
| 143 |
+
pass
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
class ClosedPoolError(PoolError):
|
| 147 |
+
"""Raised when a request enters a pool after the pool has been closed."""
|
| 148 |
+
|
| 149 |
+
pass
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
class LocationValueError(ValueError, HTTPError):
|
| 153 |
+
"""Raised when there is something wrong with a given URL input."""
|
| 154 |
+
|
| 155 |
+
pass
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class LocationParseError(LocationValueError):
|
| 159 |
+
"""Raised when get_host or similar fails to parse the URL input."""
|
| 160 |
+
|
| 161 |
+
def __init__(self, location):
|
| 162 |
+
message = "Failed to parse: %s" % location
|
| 163 |
+
HTTPError.__init__(self, message)
|
| 164 |
+
|
| 165 |
+
self.location = location
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
class URLSchemeUnknown(LocationValueError):
|
| 169 |
+
"""Raised when a URL input has an unsupported scheme."""
|
| 170 |
+
|
| 171 |
+
def __init__(self, scheme):
|
| 172 |
+
message = "Not supported URL scheme %s" % scheme
|
| 173 |
+
super(URLSchemeUnknown, self).__init__(message)
|
| 174 |
+
|
| 175 |
+
self.scheme = scheme
|
| 176 |
+
|
| 177 |
+
|
| 178 |
+
class ResponseError(HTTPError):
|
| 179 |
+
"""Used as a container for an error reason supplied in a MaxRetryError."""
|
| 180 |
+
|
| 181 |
+
GENERIC_ERROR = "too many error responses"
|
| 182 |
+
SPECIFIC_ERROR = "too many {status_code} error responses"
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
class SecurityWarning(HTTPWarning):
|
| 186 |
+
"""Warned when performing security reducing actions"""
|
| 187 |
+
|
| 188 |
+
pass
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
class SubjectAltNameWarning(SecurityWarning):
|
| 192 |
+
"""Warned when connecting to a host with a certificate missing a SAN."""
|
| 193 |
+
|
| 194 |
+
pass
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
class InsecureRequestWarning(SecurityWarning):
|
| 198 |
+
"""Warned when making an unverified HTTPS request."""
|
| 199 |
+
|
| 200 |
+
pass
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
class SystemTimeWarning(SecurityWarning):
|
| 204 |
+
"""Warned when system time is suspected to be wrong"""
|
| 205 |
+
|
| 206 |
+
pass
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
class InsecurePlatformWarning(SecurityWarning):
|
| 210 |
+
"""Warned when certain TLS/SSL configuration is not available on a platform."""
|
| 211 |
+
|
| 212 |
+
pass
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
class SNIMissingWarning(HTTPWarning):
|
| 216 |
+
"""Warned when making a HTTPS request without SNI available."""
|
| 217 |
+
|
| 218 |
+
pass
|
| 219 |
+
|
| 220 |
+
|
| 221 |
+
class DependencyWarning(HTTPWarning):
|
| 222 |
+
"""
|
| 223 |
+
Warned when an attempt is made to import a module with missing optional
|
| 224 |
+
dependencies.
|
| 225 |
+
"""
|
| 226 |
+
|
| 227 |
+
pass
|
| 228 |
+
|
| 229 |
+
|
| 230 |
+
class ResponseNotChunked(ProtocolError, ValueError):
|
| 231 |
+
"""Response needs to be chunked in order to read it as chunks."""
|
| 232 |
+
|
| 233 |
+
pass
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
class BodyNotHttplibCompatible(HTTPError):
|
| 237 |
+
"""
|
| 238 |
+
Body should be :class:`http.client.HTTPResponse` like
|
| 239 |
+
(have an fp attribute which returns raw chunks) for read_chunked().
|
| 240 |
+
"""
|
| 241 |
+
|
| 242 |
+
pass
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
class IncompleteRead(HTTPError, httplib_IncompleteRead):
|
| 246 |
+
"""
|
| 247 |
+
Response length doesn't match expected Content-Length
|
| 248 |
+
|
| 249 |
+
Subclass of :class:`http.client.IncompleteRead` to allow int value
|
| 250 |
+
for ``partial`` to avoid creating large objects on streamed reads.
|
| 251 |
+
"""
|
| 252 |
+
|
| 253 |
+
def __init__(self, partial, expected):
|
| 254 |
+
super(IncompleteRead, self).__init__(partial, expected)
|
| 255 |
+
|
| 256 |
+
def __repr__(self):
|
| 257 |
+
return "IncompleteRead(%i bytes read, %i more expected)" % (
|
| 258 |
+
self.partial,
|
| 259 |
+
self.expected,
|
| 260 |
+
)
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
class InvalidChunkLength(HTTPError, httplib_IncompleteRead):
|
| 264 |
+
"""Invalid chunk length in a chunked response."""
|
| 265 |
+
|
| 266 |
+
def __init__(self, response, length):
|
| 267 |
+
super(InvalidChunkLength, self).__init__(
|
| 268 |
+
response.tell(), response.length_remaining
|
| 269 |
+
)
|
| 270 |
+
self.response = response
|
| 271 |
+
self.length = length
|
| 272 |
+
|
| 273 |
+
def __repr__(self):
|
| 274 |
+
return "InvalidChunkLength(got length %r, %i bytes read)" % (
|
| 275 |
+
self.length,
|
| 276 |
+
self.partial,
|
| 277 |
+
)
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
class InvalidHeader(HTTPError):
|
| 281 |
+
"""The header provided was somehow invalid."""
|
| 282 |
+
|
| 283 |
+
pass
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
class ProxySchemeUnknown(AssertionError, URLSchemeUnknown):
|
| 287 |
+
"""ProxyManager does not support the supplied scheme"""
|
| 288 |
+
|
| 289 |
+
# TODO(t-8ch): Stop inheriting from AssertionError in v2.0.
|
| 290 |
+
|
| 291 |
+
def __init__(self, scheme):
|
| 292 |
+
# 'localhost' is here because our URL parser parses
|
| 293 |
+
# localhost:8080 -> scheme=localhost, remove if we fix this.
|
| 294 |
+
if scheme == "localhost":
|
| 295 |
+
scheme = None
|
| 296 |
+
if scheme is None:
|
| 297 |
+
message = "Proxy URL had no scheme, should start with http:// or https://"
|
| 298 |
+
else:
|
| 299 |
+
message = (
|
| 300 |
+
"Proxy URL had unsupported scheme %s, should use http:// or https://"
|
| 301 |
+
% scheme
|
| 302 |
+
)
|
| 303 |
+
super(ProxySchemeUnknown, self).__init__(message)
|
| 304 |
+
|
| 305 |
+
|
| 306 |
+
class ProxySchemeUnsupported(ValueError):
|
| 307 |
+
"""Fetching HTTPS resources through HTTPS proxies is unsupported"""
|
| 308 |
+
|
| 309 |
+
pass
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
class HeaderParsingError(HTTPError):
|
| 313 |
+
"""Raised by assert_header_parsing, but we convert it to a log.warning statement."""
|
| 314 |
+
|
| 315 |
+
def __init__(self, defects, unparsed_data):
|
| 316 |
+
message = "%s, unparsed data: %r" % (defects or "Unknown", unparsed_data)
|
| 317 |
+
super(HeaderParsingError, self).__init__(message)
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
class UnrewindableBodyError(HTTPError):
|
| 321 |
+
"""urllib3 encountered an error when trying to rewind a body"""
|
| 322 |
+
|
| 323 |
+
pass
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/fields.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import email.utils
|
| 4 |
+
import mimetypes
|
| 5 |
+
import re
|
| 6 |
+
|
| 7 |
+
from .packages import six
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def guess_content_type(filename, default="application/octet-stream"):
|
| 11 |
+
"""
|
| 12 |
+
Guess the "Content-Type" of a file.
|
| 13 |
+
|
| 14 |
+
:param filename:
|
| 15 |
+
The filename to guess the "Content-Type" of using :mod:`mimetypes`.
|
| 16 |
+
:param default:
|
| 17 |
+
If no "Content-Type" can be guessed, default to `default`.
|
| 18 |
+
"""
|
| 19 |
+
if filename:
|
| 20 |
+
return mimetypes.guess_type(filename)[0] or default
|
| 21 |
+
return default
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def format_header_param_rfc2231(name, value):
|
| 25 |
+
"""
|
| 26 |
+
Helper function to format and quote a single header parameter using the
|
| 27 |
+
strategy defined in RFC 2231.
|
| 28 |
+
|
| 29 |
+
Particularly useful for header parameters which might contain
|
| 30 |
+
non-ASCII values, like file names. This follows
|
| 31 |
+
`RFC 2388 Section 4.4 <https://tools.ietf.org/html/rfc2388#section-4.4>`_.
|
| 32 |
+
|
| 33 |
+
:param name:
|
| 34 |
+
The name of the parameter, a string expected to be ASCII only.
|
| 35 |
+
:param value:
|
| 36 |
+
The value of the parameter, provided as ``bytes`` or `str``.
|
| 37 |
+
:ret:
|
| 38 |
+
An RFC-2231-formatted unicode string.
|
| 39 |
+
"""
|
| 40 |
+
if isinstance(value, six.binary_type):
|
| 41 |
+
value = value.decode("utf-8")
|
| 42 |
+
|
| 43 |
+
if not any(ch in value for ch in '"\\\r\n'):
|
| 44 |
+
result = u'%s="%s"' % (name, value)
|
| 45 |
+
try:
|
| 46 |
+
result.encode("ascii")
|
| 47 |
+
except (UnicodeEncodeError, UnicodeDecodeError):
|
| 48 |
+
pass
|
| 49 |
+
else:
|
| 50 |
+
return result
|
| 51 |
+
|
| 52 |
+
if six.PY2: # Python 2:
|
| 53 |
+
value = value.encode("utf-8")
|
| 54 |
+
|
| 55 |
+
# encode_rfc2231 accepts an encoded string and returns an ascii-encoded
|
| 56 |
+
# string in Python 2 but accepts and returns unicode strings in Python 3
|
| 57 |
+
value = email.utils.encode_rfc2231(value, "utf-8")
|
| 58 |
+
value = "%s*=%s" % (name, value)
|
| 59 |
+
|
| 60 |
+
if six.PY2: # Python 2:
|
| 61 |
+
value = value.decode("utf-8")
|
| 62 |
+
|
| 63 |
+
return value
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
_HTML5_REPLACEMENTS = {
|
| 67 |
+
u"\u0022": u"%22",
|
| 68 |
+
# Replace "\" with "\\".
|
| 69 |
+
u"\u005C": u"\u005C\u005C",
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
# All control characters from 0x00 to 0x1F *except* 0x1B.
|
| 73 |
+
_HTML5_REPLACEMENTS.update(
|
| 74 |
+
{
|
| 75 |
+
six.unichr(cc): u"%{:02X}".format(cc)
|
| 76 |
+
for cc in range(0x00, 0x1F + 1)
|
| 77 |
+
if cc not in (0x1B,)
|
| 78 |
+
}
|
| 79 |
+
)
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def _replace_multiple(value, needles_and_replacements):
|
| 83 |
+
def replacer(match):
|
| 84 |
+
return needles_and_replacements[match.group(0)]
|
| 85 |
+
|
| 86 |
+
pattern = re.compile(
|
| 87 |
+
r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()])
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
result = pattern.sub(replacer, value)
|
| 91 |
+
|
| 92 |
+
return result
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
def format_header_param_html5(name, value):
|
| 96 |
+
"""
|
| 97 |
+
Helper function to format and quote a single header parameter using the
|
| 98 |
+
HTML5 strategy.
|
| 99 |
+
|
| 100 |
+
Particularly useful for header parameters which might contain
|
| 101 |
+
non-ASCII values, like file names. This follows the `HTML5 Working Draft
|
| 102 |
+
Section 4.10.22.7`_ and matches the behavior of curl and modern browsers.
|
| 103 |
+
|
| 104 |
+
.. _HTML5 Working Draft Section 4.10.22.7:
|
| 105 |
+
https://w3c.github.io/html/sec-forms.html#multipart-form-data
|
| 106 |
+
|
| 107 |
+
:param name:
|
| 108 |
+
The name of the parameter, a string expected to be ASCII only.
|
| 109 |
+
:param value:
|
| 110 |
+
The value of the parameter, provided as ``bytes`` or `str``.
|
| 111 |
+
:ret:
|
| 112 |
+
A unicode string, stripped of troublesome characters.
|
| 113 |
+
"""
|
| 114 |
+
if isinstance(value, six.binary_type):
|
| 115 |
+
value = value.decode("utf-8")
|
| 116 |
+
|
| 117 |
+
value = _replace_multiple(value, _HTML5_REPLACEMENTS)
|
| 118 |
+
|
| 119 |
+
return u'%s="%s"' % (name, value)
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
# For backwards-compatibility.
|
| 123 |
+
format_header_param = format_header_param_html5
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
class RequestField(object):
|
| 127 |
+
"""
|
| 128 |
+
A data container for request body parameters.
|
| 129 |
+
|
| 130 |
+
:param name:
|
| 131 |
+
The name of this request field. Must be unicode.
|
| 132 |
+
:param data:
|
| 133 |
+
The data/value body.
|
| 134 |
+
:param filename:
|
| 135 |
+
An optional filename of the request field. Must be unicode.
|
| 136 |
+
:param headers:
|
| 137 |
+
An optional dict-like object of headers to initially use for the field.
|
| 138 |
+
:param header_formatter:
|
| 139 |
+
An optional callable that is used to encode and format the headers. By
|
| 140 |
+
default, this is :func:`format_header_param_html5`.
|
| 141 |
+
"""
|
| 142 |
+
|
| 143 |
+
def __init__(
|
| 144 |
+
self,
|
| 145 |
+
name,
|
| 146 |
+
data,
|
| 147 |
+
filename=None,
|
| 148 |
+
headers=None,
|
| 149 |
+
header_formatter=format_header_param_html5,
|
| 150 |
+
):
|
| 151 |
+
self._name = name
|
| 152 |
+
self._filename = filename
|
| 153 |
+
self.data = data
|
| 154 |
+
self.headers = {}
|
| 155 |
+
if headers:
|
| 156 |
+
self.headers = dict(headers)
|
| 157 |
+
self.header_formatter = header_formatter
|
| 158 |
+
|
| 159 |
+
@classmethod
|
| 160 |
+
def from_tuples(cls, fieldname, value, header_formatter=format_header_param_html5):
|
| 161 |
+
"""
|
| 162 |
+
A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters.
|
| 163 |
+
|
| 164 |
+
Supports constructing :class:`~urllib3.fields.RequestField` from
|
| 165 |
+
parameter of key/value strings AND key/filetuple. A filetuple is a
|
| 166 |
+
(filename, data, MIME type) tuple where the MIME type is optional.
|
| 167 |
+
For example::
|
| 168 |
+
|
| 169 |
+
'foo': 'bar',
|
| 170 |
+
'fakefile': ('foofile.txt', 'contents of foofile'),
|
| 171 |
+
'realfile': ('barfile.txt', open('realfile').read()),
|
| 172 |
+
'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'),
|
| 173 |
+
'nonamefile': 'contents of nonamefile field',
|
| 174 |
+
|
| 175 |
+
Field names and filenames must be unicode.
|
| 176 |
+
"""
|
| 177 |
+
if isinstance(value, tuple):
|
| 178 |
+
if len(value) == 3:
|
| 179 |
+
filename, data, content_type = value
|
| 180 |
+
else:
|
| 181 |
+
filename, data = value
|
| 182 |
+
content_type = guess_content_type(filename)
|
| 183 |
+
else:
|
| 184 |
+
filename = None
|
| 185 |
+
content_type = None
|
| 186 |
+
data = value
|
| 187 |
+
|
| 188 |
+
request_param = cls(
|
| 189 |
+
fieldname, data, filename=filename, header_formatter=header_formatter
|
| 190 |
+
)
|
| 191 |
+
request_param.make_multipart(content_type=content_type)
|
| 192 |
+
|
| 193 |
+
return request_param
|
| 194 |
+
|
| 195 |
+
def _render_part(self, name, value):
|
| 196 |
+
"""
|
| 197 |
+
Overridable helper function to format a single header parameter. By
|
| 198 |
+
default, this calls ``self.header_formatter``.
|
| 199 |
+
|
| 200 |
+
:param name:
|
| 201 |
+
The name of the parameter, a string expected to be ASCII only.
|
| 202 |
+
:param value:
|
| 203 |
+
The value of the parameter, provided as a unicode string.
|
| 204 |
+
"""
|
| 205 |
+
|
| 206 |
+
return self.header_formatter(name, value)
|
| 207 |
+
|
| 208 |
+
def _render_parts(self, header_parts):
|
| 209 |
+
"""
|
| 210 |
+
Helper function to format and quote a single header.
|
| 211 |
+
|
| 212 |
+
Useful for single headers that are composed of multiple items. E.g.,
|
| 213 |
+
'Content-Disposition' fields.
|
| 214 |
+
|
| 215 |
+
:param header_parts:
|
| 216 |
+
A sequence of (k, v) tuples or a :class:`dict` of (k, v) to format
|
| 217 |
+
as `k1="v1"; k2="v2"; ...`.
|
| 218 |
+
"""
|
| 219 |
+
parts = []
|
| 220 |
+
iterable = header_parts
|
| 221 |
+
if isinstance(header_parts, dict):
|
| 222 |
+
iterable = header_parts.items()
|
| 223 |
+
|
| 224 |
+
for name, value in iterable:
|
| 225 |
+
if value is not None:
|
| 226 |
+
parts.append(self._render_part(name, value))
|
| 227 |
+
|
| 228 |
+
return u"; ".join(parts)
|
| 229 |
+
|
| 230 |
+
def render_headers(self):
|
| 231 |
+
"""
|
| 232 |
+
Renders the headers for this request field.
|
| 233 |
+
"""
|
| 234 |
+
lines = []
|
| 235 |
+
|
| 236 |
+
sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"]
|
| 237 |
+
for sort_key in sort_keys:
|
| 238 |
+
if self.headers.get(sort_key, False):
|
| 239 |
+
lines.append(u"%s: %s" % (sort_key, self.headers[sort_key]))
|
| 240 |
+
|
| 241 |
+
for header_name, header_value in self.headers.items():
|
| 242 |
+
if header_name not in sort_keys:
|
| 243 |
+
if header_value:
|
| 244 |
+
lines.append(u"%s: %s" % (header_name, header_value))
|
| 245 |
+
|
| 246 |
+
lines.append(u"\r\n")
|
| 247 |
+
return u"\r\n".join(lines)
|
| 248 |
+
|
| 249 |
+
def make_multipart(
|
| 250 |
+
self, content_disposition=None, content_type=None, content_location=None
|
| 251 |
+
):
|
| 252 |
+
"""
|
| 253 |
+
Makes this request field into a multipart request field.
|
| 254 |
+
|
| 255 |
+
This method overrides "Content-Disposition", "Content-Type" and
|
| 256 |
+
"Content-Location" headers to the request parameter.
|
| 257 |
+
|
| 258 |
+
:param content_type:
|
| 259 |
+
The 'Content-Type' of the request body.
|
| 260 |
+
:param content_location:
|
| 261 |
+
The 'Content-Location' of the request body.
|
| 262 |
+
|
| 263 |
+
"""
|
| 264 |
+
self.headers["Content-Disposition"] = content_disposition or u"form-data"
|
| 265 |
+
self.headers["Content-Disposition"] += u"; ".join(
|
| 266 |
+
[
|
| 267 |
+
u"",
|
| 268 |
+
self._render_parts(
|
| 269 |
+
((u"name", self._name), (u"filename", self._filename))
|
| 270 |
+
),
|
| 271 |
+
]
|
| 272 |
+
)
|
| 273 |
+
self.headers["Content-Type"] = content_type
|
| 274 |
+
self.headers["Content-Location"] = content_location
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/filepost.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import binascii
|
| 4 |
+
import codecs
|
| 5 |
+
import os
|
| 6 |
+
from io import BytesIO
|
| 7 |
+
|
| 8 |
+
from .fields import RequestField
|
| 9 |
+
from .packages import six
|
| 10 |
+
from .packages.six import b
|
| 11 |
+
|
| 12 |
+
writer = codecs.lookup("utf-8")[3]
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def choose_boundary():
|
| 16 |
+
"""
|
| 17 |
+
Our embarrassingly-simple replacement for mimetools.choose_boundary.
|
| 18 |
+
"""
|
| 19 |
+
boundary = binascii.hexlify(os.urandom(16))
|
| 20 |
+
if not six.PY2:
|
| 21 |
+
boundary = boundary.decode("ascii")
|
| 22 |
+
return boundary
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def iter_field_objects(fields):
|
| 26 |
+
"""
|
| 27 |
+
Iterate over fields.
|
| 28 |
+
|
| 29 |
+
Supports list of (k, v) tuples and dicts, and lists of
|
| 30 |
+
:class:`~urllib3.fields.RequestField`.
|
| 31 |
+
|
| 32 |
+
"""
|
| 33 |
+
if isinstance(fields, dict):
|
| 34 |
+
i = six.iteritems(fields)
|
| 35 |
+
else:
|
| 36 |
+
i = iter(fields)
|
| 37 |
+
|
| 38 |
+
for field in i:
|
| 39 |
+
if isinstance(field, RequestField):
|
| 40 |
+
yield field
|
| 41 |
+
else:
|
| 42 |
+
yield RequestField.from_tuples(*field)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def iter_fields(fields):
|
| 46 |
+
"""
|
| 47 |
+
.. deprecated:: 1.6
|
| 48 |
+
|
| 49 |
+
Iterate over fields.
|
| 50 |
+
|
| 51 |
+
The addition of :class:`~urllib3.fields.RequestField` makes this function
|
| 52 |
+
obsolete. Instead, use :func:`iter_field_objects`, which returns
|
| 53 |
+
:class:`~urllib3.fields.RequestField` objects.
|
| 54 |
+
|
| 55 |
+
Supports list of (k, v) tuples and dicts.
|
| 56 |
+
"""
|
| 57 |
+
if isinstance(fields, dict):
|
| 58 |
+
return ((k, v) for k, v in six.iteritems(fields))
|
| 59 |
+
|
| 60 |
+
return ((k, v) for k, v in fields)
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def encode_multipart_formdata(fields, boundary=None):
|
| 64 |
+
"""
|
| 65 |
+
Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
|
| 66 |
+
|
| 67 |
+
:param fields:
|
| 68 |
+
Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`).
|
| 69 |
+
|
| 70 |
+
:param boundary:
|
| 71 |
+
If not specified, then a random boundary will be generated using
|
| 72 |
+
:func:`urllib3.filepost.choose_boundary`.
|
| 73 |
+
"""
|
| 74 |
+
body = BytesIO()
|
| 75 |
+
if boundary is None:
|
| 76 |
+
boundary = choose_boundary()
|
| 77 |
+
|
| 78 |
+
for field in iter_field_objects(fields):
|
| 79 |
+
body.write(b("--%s\r\n" % (boundary)))
|
| 80 |
+
|
| 81 |
+
writer(body).write(field.render_headers())
|
| 82 |
+
data = field.data
|
| 83 |
+
|
| 84 |
+
if isinstance(data, int):
|
| 85 |
+
data = str(data) # Backwards compatibility
|
| 86 |
+
|
| 87 |
+
if isinstance(data, six.text_type):
|
| 88 |
+
writer(body).write(data)
|
| 89 |
+
else:
|
| 90 |
+
body.write(data)
|
| 91 |
+
|
| 92 |
+
body.write(b"\r\n")
|
| 93 |
+
|
| 94 |
+
body.write(b("--%s--\r\n" % (boundary)))
|
| 95 |
+
|
| 96 |
+
content_type = str("multipart/form-data; boundary=%s" % boundary)
|
| 97 |
+
|
| 98 |
+
return body.getvalue(), content_type
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/__init__.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
from . import ssl_match_hostname
|
| 4 |
+
|
| 5 |
+
__all__ = ("ssl_match_hostname",)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/packages/six.py
ADDED
|
@@ -0,0 +1,1077 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2010-2020 Benjamin Peterson
|
| 2 |
+
#
|
| 3 |
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 4 |
+
# of this software and associated documentation files (the "Software"), to deal
|
| 5 |
+
# in the Software without restriction, including without limitation the rights
|
| 6 |
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 7 |
+
# copies of the Software, and to permit persons to whom the Software is
|
| 8 |
+
# furnished to do so, subject to the following conditions:
|
| 9 |
+
#
|
| 10 |
+
# The above copyright notice and this permission notice shall be included in all
|
| 11 |
+
# copies or substantial portions of the Software.
|
| 12 |
+
#
|
| 13 |
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 14 |
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 15 |
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 16 |
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 17 |
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 18 |
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 19 |
+
# SOFTWARE.
|
| 20 |
+
|
| 21 |
+
"""Utilities for writing code that runs on Python 2 and 3"""
|
| 22 |
+
|
| 23 |
+
from __future__ import absolute_import
|
| 24 |
+
|
| 25 |
+
import functools
|
| 26 |
+
import itertools
|
| 27 |
+
import operator
|
| 28 |
+
import sys
|
| 29 |
+
import types
|
| 30 |
+
|
| 31 |
+
__author__ = "Benjamin Peterson <benjamin@python.org>"
|
| 32 |
+
__version__ = "1.16.0"
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
# Useful for very coarse version differentiation.
|
| 36 |
+
PY2 = sys.version_info[0] == 2
|
| 37 |
+
PY3 = sys.version_info[0] == 3
|
| 38 |
+
PY34 = sys.version_info[0:2] >= (3, 4)
|
| 39 |
+
|
| 40 |
+
if PY3:
|
| 41 |
+
string_types = (str,)
|
| 42 |
+
integer_types = (int,)
|
| 43 |
+
class_types = (type,)
|
| 44 |
+
text_type = str
|
| 45 |
+
binary_type = bytes
|
| 46 |
+
|
| 47 |
+
MAXSIZE = sys.maxsize
|
| 48 |
+
else:
|
| 49 |
+
string_types = (basestring,)
|
| 50 |
+
integer_types = (int, long)
|
| 51 |
+
class_types = (type, types.ClassType)
|
| 52 |
+
text_type = unicode
|
| 53 |
+
binary_type = str
|
| 54 |
+
|
| 55 |
+
if sys.platform.startswith("java"):
|
| 56 |
+
# Jython always uses 32 bits.
|
| 57 |
+
MAXSIZE = int((1 << 31) - 1)
|
| 58 |
+
else:
|
| 59 |
+
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
|
| 60 |
+
class X(object):
|
| 61 |
+
def __len__(self):
|
| 62 |
+
return 1 << 31
|
| 63 |
+
|
| 64 |
+
try:
|
| 65 |
+
len(X())
|
| 66 |
+
except OverflowError:
|
| 67 |
+
# 32-bit
|
| 68 |
+
MAXSIZE = int((1 << 31) - 1)
|
| 69 |
+
else:
|
| 70 |
+
# 64-bit
|
| 71 |
+
MAXSIZE = int((1 << 63) - 1)
|
| 72 |
+
del X
|
| 73 |
+
|
| 74 |
+
if PY34:
|
| 75 |
+
from importlib.util import spec_from_loader
|
| 76 |
+
else:
|
| 77 |
+
spec_from_loader = None
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def _add_doc(func, doc):
|
| 81 |
+
"""Add documentation to a function."""
|
| 82 |
+
func.__doc__ = doc
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def _import_module(name):
|
| 86 |
+
"""Import module, returning the module after the last dot."""
|
| 87 |
+
__import__(name)
|
| 88 |
+
return sys.modules[name]
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
class _LazyDescr(object):
|
| 92 |
+
def __init__(self, name):
|
| 93 |
+
self.name = name
|
| 94 |
+
|
| 95 |
+
def __get__(self, obj, tp):
|
| 96 |
+
result = self._resolve()
|
| 97 |
+
setattr(obj, self.name, result) # Invokes __set__.
|
| 98 |
+
try:
|
| 99 |
+
# This is a bit ugly, but it avoids running this again by
|
| 100 |
+
# removing this descriptor.
|
| 101 |
+
delattr(obj.__class__, self.name)
|
| 102 |
+
except AttributeError:
|
| 103 |
+
pass
|
| 104 |
+
return result
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
class MovedModule(_LazyDescr):
|
| 108 |
+
def __init__(self, name, old, new=None):
|
| 109 |
+
super(MovedModule, self).__init__(name)
|
| 110 |
+
if PY3:
|
| 111 |
+
if new is None:
|
| 112 |
+
new = name
|
| 113 |
+
self.mod = new
|
| 114 |
+
else:
|
| 115 |
+
self.mod = old
|
| 116 |
+
|
| 117 |
+
def _resolve(self):
|
| 118 |
+
return _import_module(self.mod)
|
| 119 |
+
|
| 120 |
+
def __getattr__(self, attr):
|
| 121 |
+
_module = self._resolve()
|
| 122 |
+
value = getattr(_module, attr)
|
| 123 |
+
setattr(self, attr, value)
|
| 124 |
+
return value
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
class _LazyModule(types.ModuleType):
|
| 128 |
+
def __init__(self, name):
|
| 129 |
+
super(_LazyModule, self).__init__(name)
|
| 130 |
+
self.__doc__ = self.__class__.__doc__
|
| 131 |
+
|
| 132 |
+
def __dir__(self):
|
| 133 |
+
attrs = ["__doc__", "__name__"]
|
| 134 |
+
attrs += [attr.name for attr in self._moved_attributes]
|
| 135 |
+
return attrs
|
| 136 |
+
|
| 137 |
+
# Subclasses should override this
|
| 138 |
+
_moved_attributes = []
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MovedAttribute(_LazyDescr):
|
| 142 |
+
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
|
| 143 |
+
super(MovedAttribute, self).__init__(name)
|
| 144 |
+
if PY3:
|
| 145 |
+
if new_mod is None:
|
| 146 |
+
new_mod = name
|
| 147 |
+
self.mod = new_mod
|
| 148 |
+
if new_attr is None:
|
| 149 |
+
if old_attr is None:
|
| 150 |
+
new_attr = name
|
| 151 |
+
else:
|
| 152 |
+
new_attr = old_attr
|
| 153 |
+
self.attr = new_attr
|
| 154 |
+
else:
|
| 155 |
+
self.mod = old_mod
|
| 156 |
+
if old_attr is None:
|
| 157 |
+
old_attr = name
|
| 158 |
+
self.attr = old_attr
|
| 159 |
+
|
| 160 |
+
def _resolve(self):
|
| 161 |
+
module = _import_module(self.mod)
|
| 162 |
+
return getattr(module, self.attr)
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
class _SixMetaPathImporter(object):
|
| 166 |
+
|
| 167 |
+
"""
|
| 168 |
+
A meta path importer to import six.moves and its submodules.
|
| 169 |
+
|
| 170 |
+
This class implements a PEP302 finder and loader. It should be compatible
|
| 171 |
+
with Python 2.5 and all existing versions of Python3
|
| 172 |
+
"""
|
| 173 |
+
|
| 174 |
+
def __init__(self, six_module_name):
|
| 175 |
+
self.name = six_module_name
|
| 176 |
+
self.known_modules = {}
|
| 177 |
+
|
| 178 |
+
def _add_module(self, mod, *fullnames):
|
| 179 |
+
for fullname in fullnames:
|
| 180 |
+
self.known_modules[self.name + "." + fullname] = mod
|
| 181 |
+
|
| 182 |
+
def _get_module(self, fullname):
|
| 183 |
+
return self.known_modules[self.name + "." + fullname]
|
| 184 |
+
|
| 185 |
+
def find_module(self, fullname, path=None):
|
| 186 |
+
if fullname in self.known_modules:
|
| 187 |
+
return self
|
| 188 |
+
return None
|
| 189 |
+
|
| 190 |
+
def find_spec(self, fullname, path, target=None):
|
| 191 |
+
if fullname in self.known_modules:
|
| 192 |
+
return spec_from_loader(fullname, self)
|
| 193 |
+
return None
|
| 194 |
+
|
| 195 |
+
def __get_module(self, fullname):
|
| 196 |
+
try:
|
| 197 |
+
return self.known_modules[fullname]
|
| 198 |
+
except KeyError:
|
| 199 |
+
raise ImportError("This loader does not know module " + fullname)
|
| 200 |
+
|
| 201 |
+
def load_module(self, fullname):
|
| 202 |
+
try:
|
| 203 |
+
# in case of a reload
|
| 204 |
+
return sys.modules[fullname]
|
| 205 |
+
except KeyError:
|
| 206 |
+
pass
|
| 207 |
+
mod = self.__get_module(fullname)
|
| 208 |
+
if isinstance(mod, MovedModule):
|
| 209 |
+
mod = mod._resolve()
|
| 210 |
+
else:
|
| 211 |
+
mod.__loader__ = self
|
| 212 |
+
sys.modules[fullname] = mod
|
| 213 |
+
return mod
|
| 214 |
+
|
| 215 |
+
def is_package(self, fullname):
|
| 216 |
+
"""
|
| 217 |
+
Return true, if the named module is a package.
|
| 218 |
+
|
| 219 |
+
We need this method to get correct spec objects with
|
| 220 |
+
Python 3.4 (see PEP451)
|
| 221 |
+
"""
|
| 222 |
+
return hasattr(self.__get_module(fullname), "__path__")
|
| 223 |
+
|
| 224 |
+
def get_code(self, fullname):
|
| 225 |
+
"""Return None
|
| 226 |
+
|
| 227 |
+
Required, if is_package is implemented"""
|
| 228 |
+
self.__get_module(fullname) # eventually raises ImportError
|
| 229 |
+
return None
|
| 230 |
+
|
| 231 |
+
get_source = get_code # same as get_code
|
| 232 |
+
|
| 233 |
+
def create_module(self, spec):
|
| 234 |
+
return self.load_module(spec.name)
|
| 235 |
+
|
| 236 |
+
def exec_module(self, module):
|
| 237 |
+
pass
|
| 238 |
+
|
| 239 |
+
|
| 240 |
+
_importer = _SixMetaPathImporter(__name__)
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
class _MovedItems(_LazyModule):
|
| 244 |
+
|
| 245 |
+
"""Lazy loading of moved objects"""
|
| 246 |
+
|
| 247 |
+
__path__ = [] # mark as package
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
_moved_attributes = [
|
| 251 |
+
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
|
| 252 |
+
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
|
| 253 |
+
MovedAttribute(
|
| 254 |
+
"filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"
|
| 255 |
+
),
|
| 256 |
+
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
|
| 257 |
+
MovedAttribute("intern", "__builtin__", "sys"),
|
| 258 |
+
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
|
| 259 |
+
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
|
| 260 |
+
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
|
| 261 |
+
MovedAttribute("getoutput", "commands", "subprocess"),
|
| 262 |
+
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
|
| 263 |
+
MovedAttribute(
|
| 264 |
+
"reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"
|
| 265 |
+
),
|
| 266 |
+
MovedAttribute("reduce", "__builtin__", "functools"),
|
| 267 |
+
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
|
| 268 |
+
MovedAttribute("StringIO", "StringIO", "io"),
|
| 269 |
+
MovedAttribute("UserDict", "UserDict", "collections"),
|
| 270 |
+
MovedAttribute("UserList", "UserList", "collections"),
|
| 271 |
+
MovedAttribute("UserString", "UserString", "collections"),
|
| 272 |
+
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
|
| 273 |
+
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
|
| 274 |
+
MovedAttribute(
|
| 275 |
+
"zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"
|
| 276 |
+
),
|
| 277 |
+
MovedModule("builtins", "__builtin__"),
|
| 278 |
+
MovedModule("configparser", "ConfigParser"),
|
| 279 |
+
MovedModule(
|
| 280 |
+
"collections_abc",
|
| 281 |
+
"collections",
|
| 282 |
+
"collections.abc" if sys.version_info >= (3, 3) else "collections",
|
| 283 |
+
),
|
| 284 |
+
MovedModule("copyreg", "copy_reg"),
|
| 285 |
+
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
|
| 286 |
+
MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
|
| 287 |
+
MovedModule(
|
| 288 |
+
"_dummy_thread",
|
| 289 |
+
"dummy_thread",
|
| 290 |
+
"_dummy_thread" if sys.version_info < (3, 9) else "_thread",
|
| 291 |
+
),
|
| 292 |
+
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
|
| 293 |
+
MovedModule("http_cookies", "Cookie", "http.cookies"),
|
| 294 |
+
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
|
| 295 |
+
MovedModule("html_parser", "HTMLParser", "html.parser"),
|
| 296 |
+
MovedModule("http_client", "httplib", "http.client"),
|
| 297 |
+
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
|
| 298 |
+
MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
|
| 299 |
+
MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
|
| 300 |
+
MovedModule(
|
| 301 |
+
"email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"
|
| 302 |
+
),
|
| 303 |
+
MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
|
| 304 |
+
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
|
| 305 |
+
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
|
| 306 |
+
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
|
| 307 |
+
MovedModule("cPickle", "cPickle", "pickle"),
|
| 308 |
+
MovedModule("queue", "Queue"),
|
| 309 |
+
MovedModule("reprlib", "repr"),
|
| 310 |
+
MovedModule("socketserver", "SocketServer"),
|
| 311 |
+
MovedModule("_thread", "thread", "_thread"),
|
| 312 |
+
MovedModule("tkinter", "Tkinter"),
|
| 313 |
+
MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"),
|
| 314 |
+
MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"),
|
| 315 |
+
MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"),
|
| 316 |
+
MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"),
|
| 317 |
+
MovedModule("tkinter_tix", "Tix", "tkinter.tix"),
|
| 318 |
+
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
|
| 319 |
+
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
|
| 320 |
+
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
|
| 321 |
+
MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"),
|
| 322 |
+
MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"),
|
| 323 |
+
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
|
| 324 |
+
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
|
| 325 |
+
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
|
| 326 |
+
MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"),
|
| 327 |
+
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
|
| 328 |
+
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
|
| 329 |
+
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
|
| 330 |
+
MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"),
|
| 331 |
+
MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"),
|
| 332 |
+
MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"),
|
| 333 |
+
]
|
| 334 |
+
# Add windows specific modules.
|
| 335 |
+
if sys.platform == "win32":
|
| 336 |
+
_moved_attributes += [
|
| 337 |
+
MovedModule("winreg", "_winreg"),
|
| 338 |
+
]
|
| 339 |
+
|
| 340 |
+
for attr in _moved_attributes:
|
| 341 |
+
setattr(_MovedItems, attr.name, attr)
|
| 342 |
+
if isinstance(attr, MovedModule):
|
| 343 |
+
_importer._add_module(attr, "moves." + attr.name)
|
| 344 |
+
del attr
|
| 345 |
+
|
| 346 |
+
_MovedItems._moved_attributes = _moved_attributes
|
| 347 |
+
|
| 348 |
+
moves = _MovedItems(__name__ + ".moves")
|
| 349 |
+
_importer._add_module(moves, "moves")
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
class Module_six_moves_urllib_parse(_LazyModule):
|
| 353 |
+
|
| 354 |
+
"""Lazy loading of moved objects in six.moves.urllib_parse"""
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
_urllib_parse_moved_attributes = [
|
| 358 |
+
MovedAttribute("ParseResult", "urlparse", "urllib.parse"),
|
| 359 |
+
MovedAttribute("SplitResult", "urlparse", "urllib.parse"),
|
| 360 |
+
MovedAttribute("parse_qs", "urlparse", "urllib.parse"),
|
| 361 |
+
MovedAttribute("parse_qsl", "urlparse", "urllib.parse"),
|
| 362 |
+
MovedAttribute("urldefrag", "urlparse", "urllib.parse"),
|
| 363 |
+
MovedAttribute("urljoin", "urlparse", "urllib.parse"),
|
| 364 |
+
MovedAttribute("urlparse", "urlparse", "urllib.parse"),
|
| 365 |
+
MovedAttribute("urlsplit", "urlparse", "urllib.parse"),
|
| 366 |
+
MovedAttribute("urlunparse", "urlparse", "urllib.parse"),
|
| 367 |
+
MovedAttribute("urlunsplit", "urlparse", "urllib.parse"),
|
| 368 |
+
MovedAttribute("quote", "urllib", "urllib.parse"),
|
| 369 |
+
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
|
| 370 |
+
MovedAttribute("unquote", "urllib", "urllib.parse"),
|
| 371 |
+
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
|
| 372 |
+
MovedAttribute(
|
| 373 |
+
"unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"
|
| 374 |
+
),
|
| 375 |
+
MovedAttribute("urlencode", "urllib", "urllib.parse"),
|
| 376 |
+
MovedAttribute("splitquery", "urllib", "urllib.parse"),
|
| 377 |
+
MovedAttribute("splittag", "urllib", "urllib.parse"),
|
| 378 |
+
MovedAttribute("splituser", "urllib", "urllib.parse"),
|
| 379 |
+
MovedAttribute("splitvalue", "urllib", "urllib.parse"),
|
| 380 |
+
MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
|
| 381 |
+
MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
|
| 382 |
+
MovedAttribute("uses_params", "urlparse", "urllib.parse"),
|
| 383 |
+
MovedAttribute("uses_query", "urlparse", "urllib.parse"),
|
| 384 |
+
MovedAttribute("uses_relative", "urlparse", "urllib.parse"),
|
| 385 |
+
]
|
| 386 |
+
for attr in _urllib_parse_moved_attributes:
|
| 387 |
+
setattr(Module_six_moves_urllib_parse, attr.name, attr)
|
| 388 |
+
del attr
|
| 389 |
+
|
| 390 |
+
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
|
| 391 |
+
|
| 392 |
+
_importer._add_module(
|
| 393 |
+
Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
|
| 394 |
+
"moves.urllib_parse",
|
| 395 |
+
"moves.urllib.parse",
|
| 396 |
+
)
|
| 397 |
+
|
| 398 |
+
|
| 399 |
+
class Module_six_moves_urllib_error(_LazyModule):
|
| 400 |
+
|
| 401 |
+
"""Lazy loading of moved objects in six.moves.urllib_error"""
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
_urllib_error_moved_attributes = [
|
| 405 |
+
MovedAttribute("URLError", "urllib2", "urllib.error"),
|
| 406 |
+
MovedAttribute("HTTPError", "urllib2", "urllib.error"),
|
| 407 |
+
MovedAttribute("ContentTooShortError", "urllib", "urllib.error"),
|
| 408 |
+
]
|
| 409 |
+
for attr in _urllib_error_moved_attributes:
|
| 410 |
+
setattr(Module_six_moves_urllib_error, attr.name, attr)
|
| 411 |
+
del attr
|
| 412 |
+
|
| 413 |
+
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
|
| 414 |
+
|
| 415 |
+
_importer._add_module(
|
| 416 |
+
Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
|
| 417 |
+
"moves.urllib_error",
|
| 418 |
+
"moves.urllib.error",
|
| 419 |
+
)
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
class Module_six_moves_urllib_request(_LazyModule):
|
| 423 |
+
|
| 424 |
+
"""Lazy loading of moved objects in six.moves.urllib_request"""
|
| 425 |
+
|
| 426 |
+
|
| 427 |
+
_urllib_request_moved_attributes = [
|
| 428 |
+
MovedAttribute("urlopen", "urllib2", "urllib.request"),
|
| 429 |
+
MovedAttribute("install_opener", "urllib2", "urllib.request"),
|
| 430 |
+
MovedAttribute("build_opener", "urllib2", "urllib.request"),
|
| 431 |
+
MovedAttribute("pathname2url", "urllib", "urllib.request"),
|
| 432 |
+
MovedAttribute("url2pathname", "urllib", "urllib.request"),
|
| 433 |
+
MovedAttribute("getproxies", "urllib", "urllib.request"),
|
| 434 |
+
MovedAttribute("Request", "urllib2", "urllib.request"),
|
| 435 |
+
MovedAttribute("OpenerDirector", "urllib2", "urllib.request"),
|
| 436 |
+
MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"),
|
| 437 |
+
MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"),
|
| 438 |
+
MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"),
|
| 439 |
+
MovedAttribute("ProxyHandler", "urllib2", "urllib.request"),
|
| 440 |
+
MovedAttribute("BaseHandler", "urllib2", "urllib.request"),
|
| 441 |
+
MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"),
|
| 442 |
+
MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"),
|
| 443 |
+
MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"),
|
| 444 |
+
MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"),
|
| 445 |
+
MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"),
|
| 446 |
+
MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"),
|
| 447 |
+
MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"),
|
| 448 |
+
MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"),
|
| 449 |
+
MovedAttribute("HTTPHandler", "urllib2", "urllib.request"),
|
| 450 |
+
MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"),
|
| 451 |
+
MovedAttribute("FileHandler", "urllib2", "urllib.request"),
|
| 452 |
+
MovedAttribute("FTPHandler", "urllib2", "urllib.request"),
|
| 453 |
+
MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"),
|
| 454 |
+
MovedAttribute("UnknownHandler", "urllib2", "urllib.request"),
|
| 455 |
+
MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"),
|
| 456 |
+
MovedAttribute("urlretrieve", "urllib", "urllib.request"),
|
| 457 |
+
MovedAttribute("urlcleanup", "urllib", "urllib.request"),
|
| 458 |
+
MovedAttribute("URLopener", "urllib", "urllib.request"),
|
| 459 |
+
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
|
| 460 |
+
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
|
| 461 |
+
MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
|
| 462 |
+
MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
|
| 463 |
+
]
|
| 464 |
+
for attr in _urllib_request_moved_attributes:
|
| 465 |
+
setattr(Module_six_moves_urllib_request, attr.name, attr)
|
| 466 |
+
del attr
|
| 467 |
+
|
| 468 |
+
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
|
| 469 |
+
|
| 470 |
+
_importer._add_module(
|
| 471 |
+
Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
|
| 472 |
+
"moves.urllib_request",
|
| 473 |
+
"moves.urllib.request",
|
| 474 |
+
)
|
| 475 |
+
|
| 476 |
+
|
| 477 |
+
class Module_six_moves_urllib_response(_LazyModule):
|
| 478 |
+
|
| 479 |
+
"""Lazy loading of moved objects in six.moves.urllib_response"""
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
_urllib_response_moved_attributes = [
|
| 483 |
+
MovedAttribute("addbase", "urllib", "urllib.response"),
|
| 484 |
+
MovedAttribute("addclosehook", "urllib", "urllib.response"),
|
| 485 |
+
MovedAttribute("addinfo", "urllib", "urllib.response"),
|
| 486 |
+
MovedAttribute("addinfourl", "urllib", "urllib.response"),
|
| 487 |
+
]
|
| 488 |
+
for attr in _urllib_response_moved_attributes:
|
| 489 |
+
setattr(Module_six_moves_urllib_response, attr.name, attr)
|
| 490 |
+
del attr
|
| 491 |
+
|
| 492 |
+
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
|
| 493 |
+
|
| 494 |
+
_importer._add_module(
|
| 495 |
+
Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
|
| 496 |
+
"moves.urllib_response",
|
| 497 |
+
"moves.urllib.response",
|
| 498 |
+
)
|
| 499 |
+
|
| 500 |
+
|
| 501 |
+
class Module_six_moves_urllib_robotparser(_LazyModule):
|
| 502 |
+
|
| 503 |
+
"""Lazy loading of moved objects in six.moves.urllib_robotparser"""
|
| 504 |
+
|
| 505 |
+
|
| 506 |
+
_urllib_robotparser_moved_attributes = [
|
| 507 |
+
MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
|
| 508 |
+
]
|
| 509 |
+
for attr in _urllib_robotparser_moved_attributes:
|
| 510 |
+
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
|
| 511 |
+
del attr
|
| 512 |
+
|
| 513 |
+
Module_six_moves_urllib_robotparser._moved_attributes = (
|
| 514 |
+
_urllib_robotparser_moved_attributes
|
| 515 |
+
)
|
| 516 |
+
|
| 517 |
+
_importer._add_module(
|
| 518 |
+
Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
|
| 519 |
+
"moves.urllib_robotparser",
|
| 520 |
+
"moves.urllib.robotparser",
|
| 521 |
+
)
|
| 522 |
+
|
| 523 |
+
|
| 524 |
+
class Module_six_moves_urllib(types.ModuleType):
|
| 525 |
+
|
| 526 |
+
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
|
| 527 |
+
|
| 528 |
+
__path__ = [] # mark as package
|
| 529 |
+
parse = _importer._get_module("moves.urllib_parse")
|
| 530 |
+
error = _importer._get_module("moves.urllib_error")
|
| 531 |
+
request = _importer._get_module("moves.urllib_request")
|
| 532 |
+
response = _importer._get_module("moves.urllib_response")
|
| 533 |
+
robotparser = _importer._get_module("moves.urllib_robotparser")
|
| 534 |
+
|
| 535 |
+
def __dir__(self):
|
| 536 |
+
return ["parse", "error", "request", "response", "robotparser"]
|
| 537 |
+
|
| 538 |
+
|
| 539 |
+
_importer._add_module(
|
| 540 |
+
Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib"
|
| 541 |
+
)
|
| 542 |
+
|
| 543 |
+
|
| 544 |
+
def add_move(move):
|
| 545 |
+
"""Add an item to six.moves."""
|
| 546 |
+
setattr(_MovedItems, move.name, move)
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
def remove_move(name):
|
| 550 |
+
"""Remove item from six.moves."""
|
| 551 |
+
try:
|
| 552 |
+
delattr(_MovedItems, name)
|
| 553 |
+
except AttributeError:
|
| 554 |
+
try:
|
| 555 |
+
del moves.__dict__[name]
|
| 556 |
+
except KeyError:
|
| 557 |
+
raise AttributeError("no such move, %r" % (name,))
|
| 558 |
+
|
| 559 |
+
|
| 560 |
+
if PY3:
|
| 561 |
+
_meth_func = "__func__"
|
| 562 |
+
_meth_self = "__self__"
|
| 563 |
+
|
| 564 |
+
_func_closure = "__closure__"
|
| 565 |
+
_func_code = "__code__"
|
| 566 |
+
_func_defaults = "__defaults__"
|
| 567 |
+
_func_globals = "__globals__"
|
| 568 |
+
else:
|
| 569 |
+
_meth_func = "im_func"
|
| 570 |
+
_meth_self = "im_self"
|
| 571 |
+
|
| 572 |
+
_func_closure = "func_closure"
|
| 573 |
+
_func_code = "func_code"
|
| 574 |
+
_func_defaults = "func_defaults"
|
| 575 |
+
_func_globals = "func_globals"
|
| 576 |
+
|
| 577 |
+
|
| 578 |
+
try:
|
| 579 |
+
advance_iterator = next
|
| 580 |
+
except NameError:
|
| 581 |
+
|
| 582 |
+
def advance_iterator(it):
|
| 583 |
+
return it.next()
|
| 584 |
+
|
| 585 |
+
|
| 586 |
+
next = advance_iterator
|
| 587 |
+
|
| 588 |
+
|
| 589 |
+
try:
|
| 590 |
+
callable = callable
|
| 591 |
+
except NameError:
|
| 592 |
+
|
| 593 |
+
def callable(obj):
|
| 594 |
+
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
|
| 595 |
+
|
| 596 |
+
|
| 597 |
+
if PY3:
|
| 598 |
+
|
| 599 |
+
def get_unbound_function(unbound):
|
| 600 |
+
return unbound
|
| 601 |
+
|
| 602 |
+
create_bound_method = types.MethodType
|
| 603 |
+
|
| 604 |
+
def create_unbound_method(func, cls):
|
| 605 |
+
return func
|
| 606 |
+
|
| 607 |
+
Iterator = object
|
| 608 |
+
else:
|
| 609 |
+
|
| 610 |
+
def get_unbound_function(unbound):
|
| 611 |
+
return unbound.im_func
|
| 612 |
+
|
| 613 |
+
def create_bound_method(func, obj):
|
| 614 |
+
return types.MethodType(func, obj, obj.__class__)
|
| 615 |
+
|
| 616 |
+
def create_unbound_method(func, cls):
|
| 617 |
+
return types.MethodType(func, None, cls)
|
| 618 |
+
|
| 619 |
+
class Iterator(object):
|
| 620 |
+
def next(self):
|
| 621 |
+
return type(self).__next__(self)
|
| 622 |
+
|
| 623 |
+
callable = callable
|
| 624 |
+
_add_doc(
|
| 625 |
+
get_unbound_function, """Get the function out of a possibly unbound function"""
|
| 626 |
+
)
|
| 627 |
+
|
| 628 |
+
|
| 629 |
+
get_method_function = operator.attrgetter(_meth_func)
|
| 630 |
+
get_method_self = operator.attrgetter(_meth_self)
|
| 631 |
+
get_function_closure = operator.attrgetter(_func_closure)
|
| 632 |
+
get_function_code = operator.attrgetter(_func_code)
|
| 633 |
+
get_function_defaults = operator.attrgetter(_func_defaults)
|
| 634 |
+
get_function_globals = operator.attrgetter(_func_globals)
|
| 635 |
+
|
| 636 |
+
|
| 637 |
+
if PY3:
|
| 638 |
+
|
| 639 |
+
def iterkeys(d, **kw):
|
| 640 |
+
return iter(d.keys(**kw))
|
| 641 |
+
|
| 642 |
+
def itervalues(d, **kw):
|
| 643 |
+
return iter(d.values(**kw))
|
| 644 |
+
|
| 645 |
+
def iteritems(d, **kw):
|
| 646 |
+
return iter(d.items(**kw))
|
| 647 |
+
|
| 648 |
+
def iterlists(d, **kw):
|
| 649 |
+
return iter(d.lists(**kw))
|
| 650 |
+
|
| 651 |
+
viewkeys = operator.methodcaller("keys")
|
| 652 |
+
|
| 653 |
+
viewvalues = operator.methodcaller("values")
|
| 654 |
+
|
| 655 |
+
viewitems = operator.methodcaller("items")
|
| 656 |
+
else:
|
| 657 |
+
|
| 658 |
+
def iterkeys(d, **kw):
|
| 659 |
+
return d.iterkeys(**kw)
|
| 660 |
+
|
| 661 |
+
def itervalues(d, **kw):
|
| 662 |
+
return d.itervalues(**kw)
|
| 663 |
+
|
| 664 |
+
def iteritems(d, **kw):
|
| 665 |
+
return d.iteritems(**kw)
|
| 666 |
+
|
| 667 |
+
def iterlists(d, **kw):
|
| 668 |
+
return d.iterlists(**kw)
|
| 669 |
+
|
| 670 |
+
viewkeys = operator.methodcaller("viewkeys")
|
| 671 |
+
|
| 672 |
+
viewvalues = operator.methodcaller("viewvalues")
|
| 673 |
+
|
| 674 |
+
viewitems = operator.methodcaller("viewitems")
|
| 675 |
+
|
| 676 |
+
_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
|
| 677 |
+
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
|
| 678 |
+
_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.")
|
| 679 |
+
_add_doc(
|
| 680 |
+
iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary."
|
| 681 |
+
)
|
| 682 |
+
|
| 683 |
+
|
| 684 |
+
if PY3:
|
| 685 |
+
|
| 686 |
+
def b(s):
|
| 687 |
+
return s.encode("latin-1")
|
| 688 |
+
|
| 689 |
+
def u(s):
|
| 690 |
+
return s
|
| 691 |
+
|
| 692 |
+
unichr = chr
|
| 693 |
+
import struct
|
| 694 |
+
|
| 695 |
+
int2byte = struct.Struct(">B").pack
|
| 696 |
+
del struct
|
| 697 |
+
byte2int = operator.itemgetter(0)
|
| 698 |
+
indexbytes = operator.getitem
|
| 699 |
+
iterbytes = iter
|
| 700 |
+
import io
|
| 701 |
+
|
| 702 |
+
StringIO = io.StringIO
|
| 703 |
+
BytesIO = io.BytesIO
|
| 704 |
+
del io
|
| 705 |
+
_assertCountEqual = "assertCountEqual"
|
| 706 |
+
if sys.version_info[1] <= 1:
|
| 707 |
+
_assertRaisesRegex = "assertRaisesRegexp"
|
| 708 |
+
_assertRegex = "assertRegexpMatches"
|
| 709 |
+
_assertNotRegex = "assertNotRegexpMatches"
|
| 710 |
+
else:
|
| 711 |
+
_assertRaisesRegex = "assertRaisesRegex"
|
| 712 |
+
_assertRegex = "assertRegex"
|
| 713 |
+
_assertNotRegex = "assertNotRegex"
|
| 714 |
+
else:
|
| 715 |
+
|
| 716 |
+
def b(s):
|
| 717 |
+
return s
|
| 718 |
+
|
| 719 |
+
# Workaround for standalone backslash
|
| 720 |
+
|
| 721 |
+
def u(s):
|
| 722 |
+
return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape")
|
| 723 |
+
|
| 724 |
+
unichr = unichr
|
| 725 |
+
int2byte = chr
|
| 726 |
+
|
| 727 |
+
def byte2int(bs):
|
| 728 |
+
return ord(bs[0])
|
| 729 |
+
|
| 730 |
+
def indexbytes(buf, i):
|
| 731 |
+
return ord(buf[i])
|
| 732 |
+
|
| 733 |
+
iterbytes = functools.partial(itertools.imap, ord)
|
| 734 |
+
import StringIO
|
| 735 |
+
|
| 736 |
+
StringIO = BytesIO = StringIO.StringIO
|
| 737 |
+
_assertCountEqual = "assertItemsEqual"
|
| 738 |
+
_assertRaisesRegex = "assertRaisesRegexp"
|
| 739 |
+
_assertRegex = "assertRegexpMatches"
|
| 740 |
+
_assertNotRegex = "assertNotRegexpMatches"
|
| 741 |
+
_add_doc(b, """Byte literal""")
|
| 742 |
+
_add_doc(u, """Text literal""")
|
| 743 |
+
|
| 744 |
+
|
| 745 |
+
def assertCountEqual(self, *args, **kwargs):
|
| 746 |
+
return getattr(self, _assertCountEqual)(*args, **kwargs)
|
| 747 |
+
|
| 748 |
+
|
| 749 |
+
def assertRaisesRegex(self, *args, **kwargs):
|
| 750 |
+
return getattr(self, _assertRaisesRegex)(*args, **kwargs)
|
| 751 |
+
|
| 752 |
+
|
| 753 |
+
def assertRegex(self, *args, **kwargs):
|
| 754 |
+
return getattr(self, _assertRegex)(*args, **kwargs)
|
| 755 |
+
|
| 756 |
+
|
| 757 |
+
def assertNotRegex(self, *args, **kwargs):
|
| 758 |
+
return getattr(self, _assertNotRegex)(*args, **kwargs)
|
| 759 |
+
|
| 760 |
+
|
| 761 |
+
if PY3:
|
| 762 |
+
exec_ = getattr(moves.builtins, "exec")
|
| 763 |
+
|
| 764 |
+
def reraise(tp, value, tb=None):
|
| 765 |
+
try:
|
| 766 |
+
if value is None:
|
| 767 |
+
value = tp()
|
| 768 |
+
if value.__traceback__ is not tb:
|
| 769 |
+
raise value.with_traceback(tb)
|
| 770 |
+
raise value
|
| 771 |
+
finally:
|
| 772 |
+
value = None
|
| 773 |
+
tb = None
|
| 774 |
+
|
| 775 |
+
|
| 776 |
+
else:
|
| 777 |
+
|
| 778 |
+
def exec_(_code_, _globs_=None, _locs_=None):
|
| 779 |
+
"""Execute code in a namespace."""
|
| 780 |
+
if _globs_ is None:
|
| 781 |
+
frame = sys._getframe(1)
|
| 782 |
+
_globs_ = frame.f_globals
|
| 783 |
+
if _locs_ is None:
|
| 784 |
+
_locs_ = frame.f_locals
|
| 785 |
+
del frame
|
| 786 |
+
elif _locs_ is None:
|
| 787 |
+
_locs_ = _globs_
|
| 788 |
+
exec ("""exec _code_ in _globs_, _locs_""")
|
| 789 |
+
|
| 790 |
+
exec_(
|
| 791 |
+
"""def reraise(tp, value, tb=None):
|
| 792 |
+
try:
|
| 793 |
+
raise tp, value, tb
|
| 794 |
+
finally:
|
| 795 |
+
tb = None
|
| 796 |
+
"""
|
| 797 |
+
)
|
| 798 |
+
|
| 799 |
+
|
| 800 |
+
if sys.version_info[:2] > (3,):
|
| 801 |
+
exec_(
|
| 802 |
+
"""def raise_from(value, from_value):
|
| 803 |
+
try:
|
| 804 |
+
raise value from from_value
|
| 805 |
+
finally:
|
| 806 |
+
value = None
|
| 807 |
+
"""
|
| 808 |
+
)
|
| 809 |
+
else:
|
| 810 |
+
|
| 811 |
+
def raise_from(value, from_value):
|
| 812 |
+
raise value
|
| 813 |
+
|
| 814 |
+
|
| 815 |
+
print_ = getattr(moves.builtins, "print", None)
|
| 816 |
+
if print_ is None:
|
| 817 |
+
|
| 818 |
+
def print_(*args, **kwargs):
|
| 819 |
+
"""The new-style print function for Python 2.4 and 2.5."""
|
| 820 |
+
fp = kwargs.pop("file", sys.stdout)
|
| 821 |
+
if fp is None:
|
| 822 |
+
return
|
| 823 |
+
|
| 824 |
+
def write(data):
|
| 825 |
+
if not isinstance(data, basestring):
|
| 826 |
+
data = str(data)
|
| 827 |
+
# If the file has an encoding, encode unicode with it.
|
| 828 |
+
if (
|
| 829 |
+
isinstance(fp, file)
|
| 830 |
+
and isinstance(data, unicode)
|
| 831 |
+
and fp.encoding is not None
|
| 832 |
+
):
|
| 833 |
+
errors = getattr(fp, "errors", None)
|
| 834 |
+
if errors is None:
|
| 835 |
+
errors = "strict"
|
| 836 |
+
data = data.encode(fp.encoding, errors)
|
| 837 |
+
fp.write(data)
|
| 838 |
+
|
| 839 |
+
want_unicode = False
|
| 840 |
+
sep = kwargs.pop("sep", None)
|
| 841 |
+
if sep is not None:
|
| 842 |
+
if isinstance(sep, unicode):
|
| 843 |
+
want_unicode = True
|
| 844 |
+
elif not isinstance(sep, str):
|
| 845 |
+
raise TypeError("sep must be None or a string")
|
| 846 |
+
end = kwargs.pop("end", None)
|
| 847 |
+
if end is not None:
|
| 848 |
+
if isinstance(end, unicode):
|
| 849 |
+
want_unicode = True
|
| 850 |
+
elif not isinstance(end, str):
|
| 851 |
+
raise TypeError("end must be None or a string")
|
| 852 |
+
if kwargs:
|
| 853 |
+
raise TypeError("invalid keyword arguments to print()")
|
| 854 |
+
if not want_unicode:
|
| 855 |
+
for arg in args:
|
| 856 |
+
if isinstance(arg, unicode):
|
| 857 |
+
want_unicode = True
|
| 858 |
+
break
|
| 859 |
+
if want_unicode:
|
| 860 |
+
newline = unicode("\n")
|
| 861 |
+
space = unicode(" ")
|
| 862 |
+
else:
|
| 863 |
+
newline = "\n"
|
| 864 |
+
space = " "
|
| 865 |
+
if sep is None:
|
| 866 |
+
sep = space
|
| 867 |
+
if end is None:
|
| 868 |
+
end = newline
|
| 869 |
+
for i, arg in enumerate(args):
|
| 870 |
+
if i:
|
| 871 |
+
write(sep)
|
| 872 |
+
write(arg)
|
| 873 |
+
write(end)
|
| 874 |
+
|
| 875 |
+
|
| 876 |
+
if sys.version_info[:2] < (3, 3):
|
| 877 |
+
_print = print_
|
| 878 |
+
|
| 879 |
+
def print_(*args, **kwargs):
|
| 880 |
+
fp = kwargs.get("file", sys.stdout)
|
| 881 |
+
flush = kwargs.pop("flush", False)
|
| 882 |
+
_print(*args, **kwargs)
|
| 883 |
+
if flush and fp is not None:
|
| 884 |
+
fp.flush()
|
| 885 |
+
|
| 886 |
+
|
| 887 |
+
_add_doc(reraise, """Reraise an exception.""")
|
| 888 |
+
|
| 889 |
+
if sys.version_info[0:2] < (3, 4):
|
| 890 |
+
# This does exactly the same what the :func:`py3:functools.update_wrapper`
|
| 891 |
+
# function does on Python versions after 3.2. It sets the ``__wrapped__``
|
| 892 |
+
# attribute on ``wrapper`` object and it doesn't raise an error if any of
|
| 893 |
+
# the attributes mentioned in ``assigned`` and ``updated`` are missing on
|
| 894 |
+
# ``wrapped`` object.
|
| 895 |
+
def _update_wrapper(
|
| 896 |
+
wrapper,
|
| 897 |
+
wrapped,
|
| 898 |
+
assigned=functools.WRAPPER_ASSIGNMENTS,
|
| 899 |
+
updated=functools.WRAPPER_UPDATES,
|
| 900 |
+
):
|
| 901 |
+
for attr in assigned:
|
| 902 |
+
try:
|
| 903 |
+
value = getattr(wrapped, attr)
|
| 904 |
+
except AttributeError:
|
| 905 |
+
continue
|
| 906 |
+
else:
|
| 907 |
+
setattr(wrapper, attr, value)
|
| 908 |
+
for attr in updated:
|
| 909 |
+
getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
|
| 910 |
+
wrapper.__wrapped__ = wrapped
|
| 911 |
+
return wrapper
|
| 912 |
+
|
| 913 |
+
_update_wrapper.__doc__ = functools.update_wrapper.__doc__
|
| 914 |
+
|
| 915 |
+
def wraps(
|
| 916 |
+
wrapped,
|
| 917 |
+
assigned=functools.WRAPPER_ASSIGNMENTS,
|
| 918 |
+
updated=functools.WRAPPER_UPDATES,
|
| 919 |
+
):
|
| 920 |
+
return functools.partial(
|
| 921 |
+
_update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated
|
| 922 |
+
)
|
| 923 |
+
|
| 924 |
+
wraps.__doc__ = functools.wraps.__doc__
|
| 925 |
+
|
| 926 |
+
else:
|
| 927 |
+
wraps = functools.wraps
|
| 928 |
+
|
| 929 |
+
|
| 930 |
+
def with_metaclass(meta, *bases):
|
| 931 |
+
"""Create a base class with a metaclass."""
|
| 932 |
+
# This requires a bit of explanation: the basic idea is to make a dummy
|
| 933 |
+
# metaclass for one level of class instantiation that replaces itself with
|
| 934 |
+
# the actual metaclass.
|
| 935 |
+
class metaclass(type):
|
| 936 |
+
def __new__(cls, name, this_bases, d):
|
| 937 |
+
if sys.version_info[:2] >= (3, 7):
|
| 938 |
+
# This version introduced PEP 560 that requires a bit
|
| 939 |
+
# of extra care (we mimic what is done by __build_class__).
|
| 940 |
+
resolved_bases = types.resolve_bases(bases)
|
| 941 |
+
if resolved_bases is not bases:
|
| 942 |
+
d["__orig_bases__"] = bases
|
| 943 |
+
else:
|
| 944 |
+
resolved_bases = bases
|
| 945 |
+
return meta(name, resolved_bases, d)
|
| 946 |
+
|
| 947 |
+
@classmethod
|
| 948 |
+
def __prepare__(cls, name, this_bases):
|
| 949 |
+
return meta.__prepare__(name, bases)
|
| 950 |
+
|
| 951 |
+
return type.__new__(metaclass, "temporary_class", (), {})
|
| 952 |
+
|
| 953 |
+
|
| 954 |
+
def add_metaclass(metaclass):
|
| 955 |
+
"""Class decorator for creating a class with a metaclass."""
|
| 956 |
+
|
| 957 |
+
def wrapper(cls):
|
| 958 |
+
orig_vars = cls.__dict__.copy()
|
| 959 |
+
slots = orig_vars.get("__slots__")
|
| 960 |
+
if slots is not None:
|
| 961 |
+
if isinstance(slots, str):
|
| 962 |
+
slots = [slots]
|
| 963 |
+
for slots_var in slots:
|
| 964 |
+
orig_vars.pop(slots_var)
|
| 965 |
+
orig_vars.pop("__dict__", None)
|
| 966 |
+
orig_vars.pop("__weakref__", None)
|
| 967 |
+
if hasattr(cls, "__qualname__"):
|
| 968 |
+
orig_vars["__qualname__"] = cls.__qualname__
|
| 969 |
+
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
| 970 |
+
|
| 971 |
+
return wrapper
|
| 972 |
+
|
| 973 |
+
|
| 974 |
+
def ensure_binary(s, encoding="utf-8", errors="strict"):
|
| 975 |
+
"""Coerce **s** to six.binary_type.
|
| 976 |
+
|
| 977 |
+
For Python 2:
|
| 978 |
+
- `unicode` -> encoded to `str`
|
| 979 |
+
- `str` -> `str`
|
| 980 |
+
|
| 981 |
+
For Python 3:
|
| 982 |
+
- `str` -> encoded to `bytes`
|
| 983 |
+
- `bytes` -> `bytes`
|
| 984 |
+
"""
|
| 985 |
+
if isinstance(s, binary_type):
|
| 986 |
+
return s
|
| 987 |
+
if isinstance(s, text_type):
|
| 988 |
+
return s.encode(encoding, errors)
|
| 989 |
+
raise TypeError("not expecting type '%s'" % type(s))
|
| 990 |
+
|
| 991 |
+
|
| 992 |
+
def ensure_str(s, encoding="utf-8", errors="strict"):
|
| 993 |
+
"""Coerce *s* to `str`.
|
| 994 |
+
|
| 995 |
+
For Python 2:
|
| 996 |
+
- `unicode` -> encoded to `str`
|
| 997 |
+
- `str` -> `str`
|
| 998 |
+
|
| 999 |
+
For Python 3:
|
| 1000 |
+
- `str` -> `str`
|
| 1001 |
+
- `bytes` -> decoded to `str`
|
| 1002 |
+
"""
|
| 1003 |
+
# Optimization: Fast return for the common case.
|
| 1004 |
+
if type(s) is str:
|
| 1005 |
+
return s
|
| 1006 |
+
if PY2 and isinstance(s, text_type):
|
| 1007 |
+
return s.encode(encoding, errors)
|
| 1008 |
+
elif PY3 and isinstance(s, binary_type):
|
| 1009 |
+
return s.decode(encoding, errors)
|
| 1010 |
+
elif not isinstance(s, (text_type, binary_type)):
|
| 1011 |
+
raise TypeError("not expecting type '%s'" % type(s))
|
| 1012 |
+
return s
|
| 1013 |
+
|
| 1014 |
+
|
| 1015 |
+
def ensure_text(s, encoding="utf-8", errors="strict"):
|
| 1016 |
+
"""Coerce *s* to six.text_type.
|
| 1017 |
+
|
| 1018 |
+
For Python 2:
|
| 1019 |
+
- `unicode` -> `unicode`
|
| 1020 |
+
- `str` -> `unicode`
|
| 1021 |
+
|
| 1022 |
+
For Python 3:
|
| 1023 |
+
- `str` -> `str`
|
| 1024 |
+
- `bytes` -> decoded to `str`
|
| 1025 |
+
"""
|
| 1026 |
+
if isinstance(s, binary_type):
|
| 1027 |
+
return s.decode(encoding, errors)
|
| 1028 |
+
elif isinstance(s, text_type):
|
| 1029 |
+
return s
|
| 1030 |
+
else:
|
| 1031 |
+
raise TypeError("not expecting type '%s'" % type(s))
|
| 1032 |
+
|
| 1033 |
+
|
| 1034 |
+
def python_2_unicode_compatible(klass):
|
| 1035 |
+
"""
|
| 1036 |
+
A class decorator that defines __unicode__ and __str__ methods under Python 2.
|
| 1037 |
+
Under Python 3 it does nothing.
|
| 1038 |
+
|
| 1039 |
+
To support Python 2 and 3 with a single code base, define a __str__ method
|
| 1040 |
+
returning text and apply this decorator to the class.
|
| 1041 |
+
"""
|
| 1042 |
+
if PY2:
|
| 1043 |
+
if "__str__" not in klass.__dict__:
|
| 1044 |
+
raise ValueError(
|
| 1045 |
+
"@python_2_unicode_compatible cannot be applied "
|
| 1046 |
+
"to %s because it doesn't define __str__()." % klass.__name__
|
| 1047 |
+
)
|
| 1048 |
+
klass.__unicode__ = klass.__str__
|
| 1049 |
+
klass.__str__ = lambda self: self.__unicode__().encode("utf-8")
|
| 1050 |
+
return klass
|
| 1051 |
+
|
| 1052 |
+
|
| 1053 |
+
# Complete the moves implementation.
|
| 1054 |
+
# This code is at the end of this module to speed up module loading.
|
| 1055 |
+
# Turn this module into a package.
|
| 1056 |
+
__path__ = [] # required for PEP 302 and PEP 451
|
| 1057 |
+
__package__ = __name__ # see PEP 366 @ReservedAssignment
|
| 1058 |
+
if globals().get("__spec__") is not None:
|
| 1059 |
+
__spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable
|
| 1060 |
+
# Remove other six meta path importers, since they cause problems. This can
|
| 1061 |
+
# happen if six is removed from sys.modules and then reloaded. (Setuptools does
|
| 1062 |
+
# this for some reason.)
|
| 1063 |
+
if sys.meta_path:
|
| 1064 |
+
for i, importer in enumerate(sys.meta_path):
|
| 1065 |
+
# Here's some real nastiness: Another "instance" of the six module might
|
| 1066 |
+
# be floating around. Therefore, we can't use isinstance() to check for
|
| 1067 |
+
# the six meta path importer, since the other six instance will have
|
| 1068 |
+
# inserted an importer with different class.
|
| 1069 |
+
if (
|
| 1070 |
+
type(importer).__name__ == "_SixMetaPathImporter"
|
| 1071 |
+
and importer.name == __name__
|
| 1072 |
+
):
|
| 1073 |
+
del sys.meta_path[i]
|
| 1074 |
+
break
|
| 1075 |
+
del i, importer
|
| 1076 |
+
# Finally, add the importer to the meta path import hook.
|
| 1077 |
+
sys.meta_path.append(_importer)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/poolmanager.py
ADDED
|
@@ -0,0 +1,536 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import collections
|
| 4 |
+
import functools
|
| 5 |
+
import logging
|
| 6 |
+
|
| 7 |
+
from ._collections import RecentlyUsedContainer
|
| 8 |
+
from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme
|
| 9 |
+
from .exceptions import (
|
| 10 |
+
LocationValueError,
|
| 11 |
+
MaxRetryError,
|
| 12 |
+
ProxySchemeUnknown,
|
| 13 |
+
ProxySchemeUnsupported,
|
| 14 |
+
URLSchemeUnknown,
|
| 15 |
+
)
|
| 16 |
+
from .packages import six
|
| 17 |
+
from .packages.six.moves.urllib.parse import urljoin
|
| 18 |
+
from .request import RequestMethods
|
| 19 |
+
from .util.proxy import connection_requires_http_tunnel
|
| 20 |
+
from .util.retry import Retry
|
| 21 |
+
from .util.url import parse_url
|
| 22 |
+
|
| 23 |
+
__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"]
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
log = logging.getLogger(__name__)
|
| 27 |
+
|
| 28 |
+
SSL_KEYWORDS = (
|
| 29 |
+
"key_file",
|
| 30 |
+
"cert_file",
|
| 31 |
+
"cert_reqs",
|
| 32 |
+
"ca_certs",
|
| 33 |
+
"ssl_version",
|
| 34 |
+
"ca_cert_dir",
|
| 35 |
+
"ssl_context",
|
| 36 |
+
"key_password",
|
| 37 |
+
)
|
| 38 |
+
|
| 39 |
+
# All known keyword arguments that could be provided to the pool manager, its
|
| 40 |
+
# pools, or the underlying connections. This is used to construct a pool key.
|
| 41 |
+
_key_fields = (
|
| 42 |
+
"key_scheme", # str
|
| 43 |
+
"key_host", # str
|
| 44 |
+
"key_port", # int
|
| 45 |
+
"key_timeout", # int or float or Timeout
|
| 46 |
+
"key_retries", # int or Retry
|
| 47 |
+
"key_strict", # bool
|
| 48 |
+
"key_block", # bool
|
| 49 |
+
"key_source_address", # str
|
| 50 |
+
"key_key_file", # str
|
| 51 |
+
"key_key_password", # str
|
| 52 |
+
"key_cert_file", # str
|
| 53 |
+
"key_cert_reqs", # str
|
| 54 |
+
"key_ca_certs", # str
|
| 55 |
+
"key_ssl_version", # str
|
| 56 |
+
"key_ca_cert_dir", # str
|
| 57 |
+
"key_ssl_context", # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext
|
| 58 |
+
"key_maxsize", # int
|
| 59 |
+
"key_headers", # dict
|
| 60 |
+
"key__proxy", # parsed proxy url
|
| 61 |
+
"key__proxy_headers", # dict
|
| 62 |
+
"key__proxy_config", # class
|
| 63 |
+
"key_socket_options", # list of (level (int), optname (int), value (int or str)) tuples
|
| 64 |
+
"key__socks_options", # dict
|
| 65 |
+
"key_assert_hostname", # bool or string
|
| 66 |
+
"key_assert_fingerprint", # str
|
| 67 |
+
"key_server_hostname", # str
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
#: The namedtuple class used to construct keys for the connection pool.
|
| 71 |
+
#: All custom key schemes should include the fields in this key at a minimum.
|
| 72 |
+
PoolKey = collections.namedtuple("PoolKey", _key_fields)
|
| 73 |
+
|
| 74 |
+
_proxy_config_fields = ("ssl_context", "use_forwarding_for_https")
|
| 75 |
+
ProxyConfig = collections.namedtuple("ProxyConfig", _proxy_config_fields)
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def _default_key_normalizer(key_class, request_context):
|
| 79 |
+
"""
|
| 80 |
+
Create a pool key out of a request context dictionary.
|
| 81 |
+
|
| 82 |
+
According to RFC 3986, both the scheme and host are case-insensitive.
|
| 83 |
+
Therefore, this function normalizes both before constructing the pool
|
| 84 |
+
key for an HTTPS request. If you wish to change this behaviour, provide
|
| 85 |
+
alternate callables to ``key_fn_by_scheme``.
|
| 86 |
+
|
| 87 |
+
:param key_class:
|
| 88 |
+
The class to use when constructing the key. This should be a namedtuple
|
| 89 |
+
with the ``scheme`` and ``host`` keys at a minimum.
|
| 90 |
+
:type key_class: namedtuple
|
| 91 |
+
:param request_context:
|
| 92 |
+
A dictionary-like object that contain the context for a request.
|
| 93 |
+
:type request_context: dict
|
| 94 |
+
|
| 95 |
+
:return: A namedtuple that can be used as a connection pool key.
|
| 96 |
+
:rtype: PoolKey
|
| 97 |
+
"""
|
| 98 |
+
# Since we mutate the dictionary, make a copy first
|
| 99 |
+
context = request_context.copy()
|
| 100 |
+
context["scheme"] = context["scheme"].lower()
|
| 101 |
+
context["host"] = context["host"].lower()
|
| 102 |
+
|
| 103 |
+
# These are both dictionaries and need to be transformed into frozensets
|
| 104 |
+
for key in ("headers", "_proxy_headers", "_socks_options"):
|
| 105 |
+
if key in context and context[key] is not None:
|
| 106 |
+
context[key] = frozenset(context[key].items())
|
| 107 |
+
|
| 108 |
+
# The socket_options key may be a list and needs to be transformed into a
|
| 109 |
+
# tuple.
|
| 110 |
+
socket_opts = context.get("socket_options")
|
| 111 |
+
if socket_opts is not None:
|
| 112 |
+
context["socket_options"] = tuple(socket_opts)
|
| 113 |
+
|
| 114 |
+
# Map the kwargs to the names in the namedtuple - this is necessary since
|
| 115 |
+
# namedtuples can't have fields starting with '_'.
|
| 116 |
+
for key in list(context.keys()):
|
| 117 |
+
context["key_" + key] = context.pop(key)
|
| 118 |
+
|
| 119 |
+
# Default to ``None`` for keys missing from the context
|
| 120 |
+
for field in key_class._fields:
|
| 121 |
+
if field not in context:
|
| 122 |
+
context[field] = None
|
| 123 |
+
|
| 124 |
+
return key_class(**context)
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
#: A dictionary that maps a scheme to a callable that creates a pool key.
|
| 128 |
+
#: This can be used to alter the way pool keys are constructed, if desired.
|
| 129 |
+
#: Each PoolManager makes a copy of this dictionary so they can be configured
|
| 130 |
+
#: globally here, or individually on the instance.
|
| 131 |
+
key_fn_by_scheme = {
|
| 132 |
+
"http": functools.partial(_default_key_normalizer, PoolKey),
|
| 133 |
+
"https": functools.partial(_default_key_normalizer, PoolKey),
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool}
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
class PoolManager(RequestMethods):
|
| 140 |
+
"""
|
| 141 |
+
Allows for arbitrary requests while transparently keeping track of
|
| 142 |
+
necessary connection pools for you.
|
| 143 |
+
|
| 144 |
+
:param num_pools:
|
| 145 |
+
Number of connection pools to cache before discarding the least
|
| 146 |
+
recently used pool.
|
| 147 |
+
|
| 148 |
+
:param headers:
|
| 149 |
+
Headers to include with all requests, unless other headers are given
|
| 150 |
+
explicitly.
|
| 151 |
+
|
| 152 |
+
:param \\**connection_pool_kw:
|
| 153 |
+
Additional parameters are used to create fresh
|
| 154 |
+
:class:`urllib3.connectionpool.ConnectionPool` instances.
|
| 155 |
+
|
| 156 |
+
Example::
|
| 157 |
+
|
| 158 |
+
>>> manager = PoolManager(num_pools=2)
|
| 159 |
+
>>> r = manager.request('GET', 'http://google.com/')
|
| 160 |
+
>>> r = manager.request('GET', 'http://google.com/mail')
|
| 161 |
+
>>> r = manager.request('GET', 'http://yahoo.com/')
|
| 162 |
+
>>> len(manager.pools)
|
| 163 |
+
2
|
| 164 |
+
|
| 165 |
+
"""
|
| 166 |
+
|
| 167 |
+
proxy = None
|
| 168 |
+
proxy_config = None
|
| 169 |
+
|
| 170 |
+
def __init__(self, num_pools=10, headers=None, **connection_pool_kw):
|
| 171 |
+
RequestMethods.__init__(self, headers)
|
| 172 |
+
self.connection_pool_kw = connection_pool_kw
|
| 173 |
+
self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close())
|
| 174 |
+
|
| 175 |
+
# Locally set the pool classes and keys so other PoolManagers can
|
| 176 |
+
# override them.
|
| 177 |
+
self.pool_classes_by_scheme = pool_classes_by_scheme
|
| 178 |
+
self.key_fn_by_scheme = key_fn_by_scheme.copy()
|
| 179 |
+
|
| 180 |
+
def __enter__(self):
|
| 181 |
+
return self
|
| 182 |
+
|
| 183 |
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
| 184 |
+
self.clear()
|
| 185 |
+
# Return False to re-raise any potential exceptions
|
| 186 |
+
return False
|
| 187 |
+
|
| 188 |
+
def _new_pool(self, scheme, host, port, request_context=None):
|
| 189 |
+
"""
|
| 190 |
+
Create a new :class:`urllib3.connectionpool.ConnectionPool` based on host, port, scheme, and
|
| 191 |
+
any additional pool keyword arguments.
|
| 192 |
+
|
| 193 |
+
If ``request_context`` is provided, it is provided as keyword arguments
|
| 194 |
+
to the pool class used. This method is used to actually create the
|
| 195 |
+
connection pools handed out by :meth:`connection_from_url` and
|
| 196 |
+
companion methods. It is intended to be overridden for customization.
|
| 197 |
+
"""
|
| 198 |
+
pool_cls = self.pool_classes_by_scheme[scheme]
|
| 199 |
+
if request_context is None:
|
| 200 |
+
request_context = self.connection_pool_kw.copy()
|
| 201 |
+
|
| 202 |
+
# Although the context has everything necessary to create the pool,
|
| 203 |
+
# this function has historically only used the scheme, host, and port
|
| 204 |
+
# in the positional args. When an API change is acceptable these can
|
| 205 |
+
# be removed.
|
| 206 |
+
for key in ("scheme", "host", "port"):
|
| 207 |
+
request_context.pop(key, None)
|
| 208 |
+
|
| 209 |
+
if scheme == "http":
|
| 210 |
+
for kw in SSL_KEYWORDS:
|
| 211 |
+
request_context.pop(kw, None)
|
| 212 |
+
|
| 213 |
+
return pool_cls(host, port, **request_context)
|
| 214 |
+
|
| 215 |
+
def clear(self):
|
| 216 |
+
"""
|
| 217 |
+
Empty our store of pools and direct them all to close.
|
| 218 |
+
|
| 219 |
+
This will not affect in-flight connections, but they will not be
|
| 220 |
+
re-used after completion.
|
| 221 |
+
"""
|
| 222 |
+
self.pools.clear()
|
| 223 |
+
|
| 224 |
+
def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None):
|
| 225 |
+
"""
|
| 226 |
+
Get a :class:`urllib3.connectionpool.ConnectionPool` based on the host, port, and scheme.
|
| 227 |
+
|
| 228 |
+
If ``port`` isn't given, it will be derived from the ``scheme`` using
|
| 229 |
+
``urllib3.connectionpool.port_by_scheme``. If ``pool_kwargs`` is
|
| 230 |
+
provided, it is merged with the instance's ``connection_pool_kw``
|
| 231 |
+
variable and used to create the new connection pool, if one is
|
| 232 |
+
needed.
|
| 233 |
+
"""
|
| 234 |
+
|
| 235 |
+
if not host:
|
| 236 |
+
raise LocationValueError("No host specified.")
|
| 237 |
+
|
| 238 |
+
request_context = self._merge_pool_kwargs(pool_kwargs)
|
| 239 |
+
request_context["scheme"] = scheme or "http"
|
| 240 |
+
if not port:
|
| 241 |
+
port = port_by_scheme.get(request_context["scheme"].lower(), 80)
|
| 242 |
+
request_context["port"] = port
|
| 243 |
+
request_context["host"] = host
|
| 244 |
+
|
| 245 |
+
return self.connection_from_context(request_context)
|
| 246 |
+
|
| 247 |
+
def connection_from_context(self, request_context):
|
| 248 |
+
"""
|
| 249 |
+
Get a :class:`urllib3.connectionpool.ConnectionPool` based on the request context.
|
| 250 |
+
|
| 251 |
+
``request_context`` must at least contain the ``scheme`` key and its
|
| 252 |
+
value must be a key in ``key_fn_by_scheme`` instance variable.
|
| 253 |
+
"""
|
| 254 |
+
scheme = request_context["scheme"].lower()
|
| 255 |
+
pool_key_constructor = self.key_fn_by_scheme.get(scheme)
|
| 256 |
+
if not pool_key_constructor:
|
| 257 |
+
raise URLSchemeUnknown(scheme)
|
| 258 |
+
pool_key = pool_key_constructor(request_context)
|
| 259 |
+
|
| 260 |
+
return self.connection_from_pool_key(pool_key, request_context=request_context)
|
| 261 |
+
|
| 262 |
+
def connection_from_pool_key(self, pool_key, request_context=None):
|
| 263 |
+
"""
|
| 264 |
+
Get a :class:`urllib3.connectionpool.ConnectionPool` based on the provided pool key.
|
| 265 |
+
|
| 266 |
+
``pool_key`` should be a namedtuple that only contains immutable
|
| 267 |
+
objects. At a minimum it must have the ``scheme``, ``host``, and
|
| 268 |
+
``port`` fields.
|
| 269 |
+
"""
|
| 270 |
+
with self.pools.lock:
|
| 271 |
+
# If the scheme, host, or port doesn't match existing open
|
| 272 |
+
# connections, open a new ConnectionPool.
|
| 273 |
+
pool = self.pools.get(pool_key)
|
| 274 |
+
if pool:
|
| 275 |
+
return pool
|
| 276 |
+
|
| 277 |
+
# Make a fresh ConnectionPool of the desired type
|
| 278 |
+
scheme = request_context["scheme"]
|
| 279 |
+
host = request_context["host"]
|
| 280 |
+
port = request_context["port"]
|
| 281 |
+
pool = self._new_pool(scheme, host, port, request_context=request_context)
|
| 282 |
+
self.pools[pool_key] = pool
|
| 283 |
+
|
| 284 |
+
return pool
|
| 285 |
+
|
| 286 |
+
def connection_from_url(self, url, pool_kwargs=None):
|
| 287 |
+
"""
|
| 288 |
+
Similar to :func:`urllib3.connectionpool.connection_from_url`.
|
| 289 |
+
|
| 290 |
+
If ``pool_kwargs`` is not provided and a new pool needs to be
|
| 291 |
+
constructed, ``self.connection_pool_kw`` is used to initialize
|
| 292 |
+
the :class:`urllib3.connectionpool.ConnectionPool`. If ``pool_kwargs``
|
| 293 |
+
is provided, it is used instead. Note that if a new pool does not
|
| 294 |
+
need to be created for the request, the provided ``pool_kwargs`` are
|
| 295 |
+
not used.
|
| 296 |
+
"""
|
| 297 |
+
u = parse_url(url)
|
| 298 |
+
return self.connection_from_host(
|
| 299 |
+
u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs
|
| 300 |
+
)
|
| 301 |
+
|
| 302 |
+
def _merge_pool_kwargs(self, override):
|
| 303 |
+
"""
|
| 304 |
+
Merge a dictionary of override values for self.connection_pool_kw.
|
| 305 |
+
|
| 306 |
+
This does not modify self.connection_pool_kw and returns a new dict.
|
| 307 |
+
Any keys in the override dictionary with a value of ``None`` are
|
| 308 |
+
removed from the merged dictionary.
|
| 309 |
+
"""
|
| 310 |
+
base_pool_kwargs = self.connection_pool_kw.copy()
|
| 311 |
+
if override:
|
| 312 |
+
for key, value in override.items():
|
| 313 |
+
if value is None:
|
| 314 |
+
try:
|
| 315 |
+
del base_pool_kwargs[key]
|
| 316 |
+
except KeyError:
|
| 317 |
+
pass
|
| 318 |
+
else:
|
| 319 |
+
base_pool_kwargs[key] = value
|
| 320 |
+
return base_pool_kwargs
|
| 321 |
+
|
| 322 |
+
def _proxy_requires_url_absolute_form(self, parsed_url):
|
| 323 |
+
"""
|
| 324 |
+
Indicates if the proxy requires the complete destination URL in the
|
| 325 |
+
request. Normally this is only needed when not using an HTTP CONNECT
|
| 326 |
+
tunnel.
|
| 327 |
+
"""
|
| 328 |
+
if self.proxy is None:
|
| 329 |
+
return False
|
| 330 |
+
|
| 331 |
+
return not connection_requires_http_tunnel(
|
| 332 |
+
self.proxy, self.proxy_config, parsed_url.scheme
|
| 333 |
+
)
|
| 334 |
+
|
| 335 |
+
def _validate_proxy_scheme_url_selection(self, url_scheme):
|
| 336 |
+
"""
|
| 337 |
+
Validates that were not attempting to do TLS in TLS connections on
|
| 338 |
+
Python2 or with unsupported SSL implementations.
|
| 339 |
+
"""
|
| 340 |
+
if self.proxy is None or url_scheme != "https":
|
| 341 |
+
return
|
| 342 |
+
|
| 343 |
+
if self.proxy.scheme != "https":
|
| 344 |
+
return
|
| 345 |
+
|
| 346 |
+
if six.PY2 and not self.proxy_config.use_forwarding_for_https:
|
| 347 |
+
raise ProxySchemeUnsupported(
|
| 348 |
+
"Contacting HTTPS destinations through HTTPS proxies "
|
| 349 |
+
"'via CONNECT tunnels' is not supported in Python 2"
|
| 350 |
+
)
|
| 351 |
+
|
| 352 |
+
def urlopen(self, method, url, redirect=True, **kw):
|
| 353 |
+
"""
|
| 354 |
+
Same as :meth:`urllib3.HTTPConnectionPool.urlopen`
|
| 355 |
+
with custom cross-host redirect logic and only sends the request-uri
|
| 356 |
+
portion of the ``url``.
|
| 357 |
+
|
| 358 |
+
The given ``url`` parameter must be absolute, such that an appropriate
|
| 359 |
+
:class:`urllib3.connectionpool.ConnectionPool` can be chosen for it.
|
| 360 |
+
"""
|
| 361 |
+
u = parse_url(url)
|
| 362 |
+
self._validate_proxy_scheme_url_selection(u.scheme)
|
| 363 |
+
|
| 364 |
+
conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme)
|
| 365 |
+
|
| 366 |
+
kw["assert_same_host"] = False
|
| 367 |
+
kw["redirect"] = False
|
| 368 |
+
|
| 369 |
+
if "headers" not in kw:
|
| 370 |
+
kw["headers"] = self.headers.copy()
|
| 371 |
+
|
| 372 |
+
if self._proxy_requires_url_absolute_form(u):
|
| 373 |
+
response = conn.urlopen(method, url, **kw)
|
| 374 |
+
else:
|
| 375 |
+
response = conn.urlopen(method, u.request_uri, **kw)
|
| 376 |
+
|
| 377 |
+
redirect_location = redirect and response.get_redirect_location()
|
| 378 |
+
if not redirect_location:
|
| 379 |
+
return response
|
| 380 |
+
|
| 381 |
+
# Support relative URLs for redirecting.
|
| 382 |
+
redirect_location = urljoin(url, redirect_location)
|
| 383 |
+
|
| 384 |
+
# RFC 7231, Section 6.4.4
|
| 385 |
+
if response.status == 303:
|
| 386 |
+
method = "GET"
|
| 387 |
+
|
| 388 |
+
retries = kw.get("retries")
|
| 389 |
+
if not isinstance(retries, Retry):
|
| 390 |
+
retries = Retry.from_int(retries, redirect=redirect)
|
| 391 |
+
|
| 392 |
+
# Strip headers marked as unsafe to forward to the redirected location.
|
| 393 |
+
# Check remove_headers_on_redirect to avoid a potential network call within
|
| 394 |
+
# conn.is_same_host() which may use socket.gethostbyname() in the future.
|
| 395 |
+
if retries.remove_headers_on_redirect and not conn.is_same_host(
|
| 396 |
+
redirect_location
|
| 397 |
+
):
|
| 398 |
+
headers = list(six.iterkeys(kw["headers"]))
|
| 399 |
+
for header in headers:
|
| 400 |
+
if header.lower() in retries.remove_headers_on_redirect:
|
| 401 |
+
kw["headers"].pop(header, None)
|
| 402 |
+
|
| 403 |
+
try:
|
| 404 |
+
retries = retries.increment(method, url, response=response, _pool=conn)
|
| 405 |
+
except MaxRetryError:
|
| 406 |
+
if retries.raise_on_redirect:
|
| 407 |
+
response.drain_conn()
|
| 408 |
+
raise
|
| 409 |
+
return response
|
| 410 |
+
|
| 411 |
+
kw["retries"] = retries
|
| 412 |
+
kw["redirect"] = redirect
|
| 413 |
+
|
| 414 |
+
log.info("Redirecting %s -> %s", url, redirect_location)
|
| 415 |
+
|
| 416 |
+
response.drain_conn()
|
| 417 |
+
return self.urlopen(method, redirect_location, **kw)
|
| 418 |
+
|
| 419 |
+
|
| 420 |
+
class ProxyManager(PoolManager):
|
| 421 |
+
"""
|
| 422 |
+
Behaves just like :class:`PoolManager`, but sends all requests through
|
| 423 |
+
the defined proxy, using the CONNECT method for HTTPS URLs.
|
| 424 |
+
|
| 425 |
+
:param proxy_url:
|
| 426 |
+
The URL of the proxy to be used.
|
| 427 |
+
|
| 428 |
+
:param proxy_headers:
|
| 429 |
+
A dictionary containing headers that will be sent to the proxy. In case
|
| 430 |
+
of HTTP they are being sent with each request, while in the
|
| 431 |
+
HTTPS/CONNECT case they are sent only once. Could be used for proxy
|
| 432 |
+
authentication.
|
| 433 |
+
|
| 434 |
+
:param proxy_ssl_context:
|
| 435 |
+
The proxy SSL context is used to establish the TLS connection to the
|
| 436 |
+
proxy when using HTTPS proxies.
|
| 437 |
+
|
| 438 |
+
:param use_forwarding_for_https:
|
| 439 |
+
(Defaults to False) If set to True will forward requests to the HTTPS
|
| 440 |
+
proxy to be made on behalf of the client instead of creating a TLS
|
| 441 |
+
tunnel via the CONNECT method. **Enabling this flag means that request
|
| 442 |
+
and response headers and content will be visible from the HTTPS proxy**
|
| 443 |
+
whereas tunneling keeps request and response headers and content
|
| 444 |
+
private. IP address, target hostname, SNI, and port are always visible
|
| 445 |
+
to an HTTPS proxy even when this flag is disabled.
|
| 446 |
+
|
| 447 |
+
Example:
|
| 448 |
+
>>> proxy = urllib3.ProxyManager('http://localhost:3128/')
|
| 449 |
+
>>> r1 = proxy.request('GET', 'http://google.com/')
|
| 450 |
+
>>> r2 = proxy.request('GET', 'http://httpbin.org/')
|
| 451 |
+
>>> len(proxy.pools)
|
| 452 |
+
1
|
| 453 |
+
>>> r3 = proxy.request('GET', 'https://httpbin.org/')
|
| 454 |
+
>>> r4 = proxy.request('GET', 'https://twitter.com/')
|
| 455 |
+
>>> len(proxy.pools)
|
| 456 |
+
3
|
| 457 |
+
|
| 458 |
+
"""
|
| 459 |
+
|
| 460 |
+
def __init__(
|
| 461 |
+
self,
|
| 462 |
+
proxy_url,
|
| 463 |
+
num_pools=10,
|
| 464 |
+
headers=None,
|
| 465 |
+
proxy_headers=None,
|
| 466 |
+
proxy_ssl_context=None,
|
| 467 |
+
use_forwarding_for_https=False,
|
| 468 |
+
**connection_pool_kw
|
| 469 |
+
):
|
| 470 |
+
|
| 471 |
+
if isinstance(proxy_url, HTTPConnectionPool):
|
| 472 |
+
proxy_url = "%s://%s:%i" % (
|
| 473 |
+
proxy_url.scheme,
|
| 474 |
+
proxy_url.host,
|
| 475 |
+
proxy_url.port,
|
| 476 |
+
)
|
| 477 |
+
proxy = parse_url(proxy_url)
|
| 478 |
+
|
| 479 |
+
if proxy.scheme not in ("http", "https"):
|
| 480 |
+
raise ProxySchemeUnknown(proxy.scheme)
|
| 481 |
+
|
| 482 |
+
if not proxy.port:
|
| 483 |
+
port = port_by_scheme.get(proxy.scheme, 80)
|
| 484 |
+
proxy = proxy._replace(port=port)
|
| 485 |
+
|
| 486 |
+
self.proxy = proxy
|
| 487 |
+
self.proxy_headers = proxy_headers or {}
|
| 488 |
+
self.proxy_ssl_context = proxy_ssl_context
|
| 489 |
+
self.proxy_config = ProxyConfig(proxy_ssl_context, use_forwarding_for_https)
|
| 490 |
+
|
| 491 |
+
connection_pool_kw["_proxy"] = self.proxy
|
| 492 |
+
connection_pool_kw["_proxy_headers"] = self.proxy_headers
|
| 493 |
+
connection_pool_kw["_proxy_config"] = self.proxy_config
|
| 494 |
+
|
| 495 |
+
super(ProxyManager, self).__init__(num_pools, headers, **connection_pool_kw)
|
| 496 |
+
|
| 497 |
+
def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None):
|
| 498 |
+
if scheme == "https":
|
| 499 |
+
return super(ProxyManager, self).connection_from_host(
|
| 500 |
+
host, port, scheme, pool_kwargs=pool_kwargs
|
| 501 |
+
)
|
| 502 |
+
|
| 503 |
+
return super(ProxyManager, self).connection_from_host(
|
| 504 |
+
self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs
|
| 505 |
+
)
|
| 506 |
+
|
| 507 |
+
def _set_proxy_headers(self, url, headers=None):
|
| 508 |
+
"""
|
| 509 |
+
Sets headers needed by proxies: specifically, the Accept and Host
|
| 510 |
+
headers. Only sets headers not provided by the user.
|
| 511 |
+
"""
|
| 512 |
+
headers_ = {"Accept": "*/*"}
|
| 513 |
+
|
| 514 |
+
netloc = parse_url(url).netloc
|
| 515 |
+
if netloc:
|
| 516 |
+
headers_["Host"] = netloc
|
| 517 |
+
|
| 518 |
+
if headers:
|
| 519 |
+
headers_.update(headers)
|
| 520 |
+
return headers_
|
| 521 |
+
|
| 522 |
+
def urlopen(self, method, url, redirect=True, **kw):
|
| 523 |
+
"Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute."
|
| 524 |
+
u = parse_url(url)
|
| 525 |
+
if not connection_requires_http_tunnel(self.proxy, self.proxy_config, u.scheme):
|
| 526 |
+
# For connections using HTTP CONNECT, httplib sets the necessary
|
| 527 |
+
# headers on the CONNECT to the proxy. If we're not using CONNECT,
|
| 528 |
+
# we'll definitely need to set 'Host' at the very least.
|
| 529 |
+
headers = kw.get("headers", self.headers)
|
| 530 |
+
kw["headers"] = self._set_proxy_headers(url, headers)
|
| 531 |
+
|
| 532 |
+
return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw)
|
| 533 |
+
|
| 534 |
+
|
| 535 |
+
def proxy_from_url(url, **kw):
|
| 536 |
+
return ProxyManager(proxy_url=url, **kw)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/request.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
from .filepost import encode_multipart_formdata
|
| 4 |
+
from .packages.six.moves.urllib.parse import urlencode
|
| 5 |
+
|
| 6 |
+
__all__ = ["RequestMethods"]
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class RequestMethods(object):
|
| 10 |
+
"""
|
| 11 |
+
Convenience mixin for classes who implement a :meth:`urlopen` method, such
|
| 12 |
+
as :class:`urllib3.HTTPConnectionPool` and
|
| 13 |
+
:class:`urllib3.PoolManager`.
|
| 14 |
+
|
| 15 |
+
Provides behavior for making common types of HTTP request methods and
|
| 16 |
+
decides which type of request field encoding to use.
|
| 17 |
+
|
| 18 |
+
Specifically,
|
| 19 |
+
|
| 20 |
+
:meth:`.request_encode_url` is for sending requests whose fields are
|
| 21 |
+
encoded in the URL (such as GET, HEAD, DELETE).
|
| 22 |
+
|
| 23 |
+
:meth:`.request_encode_body` is for sending requests whose fields are
|
| 24 |
+
encoded in the *body* of the request using multipart or www-form-urlencoded
|
| 25 |
+
(such as for POST, PUT, PATCH).
|
| 26 |
+
|
| 27 |
+
:meth:`.request` is for making any kind of request, it will look up the
|
| 28 |
+
appropriate encoding format and use one of the above two methods to make
|
| 29 |
+
the request.
|
| 30 |
+
|
| 31 |
+
Initializer parameters:
|
| 32 |
+
|
| 33 |
+
:param headers:
|
| 34 |
+
Headers to include with all requests, unless other headers are given
|
| 35 |
+
explicitly.
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
_encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"}
|
| 39 |
+
|
| 40 |
+
def __init__(self, headers=None):
|
| 41 |
+
self.headers = headers or {}
|
| 42 |
+
|
| 43 |
+
def urlopen(
|
| 44 |
+
self,
|
| 45 |
+
method,
|
| 46 |
+
url,
|
| 47 |
+
body=None,
|
| 48 |
+
headers=None,
|
| 49 |
+
encode_multipart=True,
|
| 50 |
+
multipart_boundary=None,
|
| 51 |
+
**kw
|
| 52 |
+
): # Abstract
|
| 53 |
+
raise NotImplementedError(
|
| 54 |
+
"Classes extending RequestMethods must implement "
|
| 55 |
+
"their own ``urlopen`` method."
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
def request(self, method, url, fields=None, headers=None, **urlopen_kw):
|
| 59 |
+
"""
|
| 60 |
+
Make a request using :meth:`urlopen` with the appropriate encoding of
|
| 61 |
+
``fields`` based on the ``method`` used.
|
| 62 |
+
|
| 63 |
+
This is a convenience method that requires the least amount of manual
|
| 64 |
+
effort. It can be used in most situations, while still having the
|
| 65 |
+
option to drop down to more specific methods when necessary, such as
|
| 66 |
+
:meth:`request_encode_url`, :meth:`request_encode_body`,
|
| 67 |
+
or even the lowest level :meth:`urlopen`.
|
| 68 |
+
"""
|
| 69 |
+
method = method.upper()
|
| 70 |
+
|
| 71 |
+
urlopen_kw["request_url"] = url
|
| 72 |
+
|
| 73 |
+
if method in self._encode_url_methods:
|
| 74 |
+
return self.request_encode_url(
|
| 75 |
+
method, url, fields=fields, headers=headers, **urlopen_kw
|
| 76 |
+
)
|
| 77 |
+
else:
|
| 78 |
+
return self.request_encode_body(
|
| 79 |
+
method, url, fields=fields, headers=headers, **urlopen_kw
|
| 80 |
+
)
|
| 81 |
+
|
| 82 |
+
def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw):
|
| 83 |
+
"""
|
| 84 |
+
Make a request using :meth:`urlopen` with the ``fields`` encoded in
|
| 85 |
+
the url. This is useful for request methods like GET, HEAD, DELETE, etc.
|
| 86 |
+
"""
|
| 87 |
+
if headers is None:
|
| 88 |
+
headers = self.headers
|
| 89 |
+
|
| 90 |
+
extra_kw = {"headers": headers}
|
| 91 |
+
extra_kw.update(urlopen_kw)
|
| 92 |
+
|
| 93 |
+
if fields:
|
| 94 |
+
url += "?" + urlencode(fields)
|
| 95 |
+
|
| 96 |
+
return self.urlopen(method, url, **extra_kw)
|
| 97 |
+
|
| 98 |
+
def request_encode_body(
|
| 99 |
+
self,
|
| 100 |
+
method,
|
| 101 |
+
url,
|
| 102 |
+
fields=None,
|
| 103 |
+
headers=None,
|
| 104 |
+
encode_multipart=True,
|
| 105 |
+
multipart_boundary=None,
|
| 106 |
+
**urlopen_kw
|
| 107 |
+
):
|
| 108 |
+
"""
|
| 109 |
+
Make a request using :meth:`urlopen` with the ``fields`` encoded in
|
| 110 |
+
the body. This is useful for request methods like POST, PUT, PATCH, etc.
|
| 111 |
+
|
| 112 |
+
When ``encode_multipart=True`` (default), then
|
| 113 |
+
:func:`urllib3.encode_multipart_formdata` is used to encode
|
| 114 |
+
the payload with the appropriate content type. Otherwise
|
| 115 |
+
:func:`urllib.parse.urlencode` is used with the
|
| 116 |
+
'application/x-www-form-urlencoded' content type.
|
| 117 |
+
|
| 118 |
+
Multipart encoding must be used when posting files, and it's reasonably
|
| 119 |
+
safe to use it in other times too. However, it may break request
|
| 120 |
+
signing, such as with OAuth.
|
| 121 |
+
|
| 122 |
+
Supports an optional ``fields`` parameter of key/value strings AND
|
| 123 |
+
key/filetuple. A filetuple is a (filename, data, MIME type) tuple where
|
| 124 |
+
the MIME type is optional. For example::
|
| 125 |
+
|
| 126 |
+
fields = {
|
| 127 |
+
'foo': 'bar',
|
| 128 |
+
'fakefile': ('foofile.txt', 'contents of foofile'),
|
| 129 |
+
'realfile': ('barfile.txt', open('realfile').read()),
|
| 130 |
+
'typedfile': ('bazfile.bin', open('bazfile').read(),
|
| 131 |
+
'image/jpeg'),
|
| 132 |
+
'nonamefile': 'contents of nonamefile field',
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
When uploading a file, providing a filename (the first parameter of the
|
| 136 |
+
tuple) is optional but recommended to best mimic behavior of browsers.
|
| 137 |
+
|
| 138 |
+
Note that if ``headers`` are supplied, the 'Content-Type' header will
|
| 139 |
+
be overwritten because it depends on the dynamic random boundary string
|
| 140 |
+
which is used to compose the body of the request. The random boundary
|
| 141 |
+
string can be explicitly set with the ``multipart_boundary`` parameter.
|
| 142 |
+
"""
|
| 143 |
+
if headers is None:
|
| 144 |
+
headers = self.headers
|
| 145 |
+
|
| 146 |
+
extra_kw = {"headers": {}}
|
| 147 |
+
|
| 148 |
+
if fields:
|
| 149 |
+
if "body" in urlopen_kw:
|
| 150 |
+
raise TypeError(
|
| 151 |
+
"request got values for both 'fields' and 'body', can only specify one."
|
| 152 |
+
)
|
| 153 |
+
|
| 154 |
+
if encode_multipart:
|
| 155 |
+
body, content_type = encode_multipart_formdata(
|
| 156 |
+
fields, boundary=multipart_boundary
|
| 157 |
+
)
|
| 158 |
+
else:
|
| 159 |
+
body, content_type = (
|
| 160 |
+
urlencode(fields),
|
| 161 |
+
"application/x-www-form-urlencoded",
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
extra_kw["body"] = body
|
| 165 |
+
extra_kw["headers"] = {"Content-Type": content_type}
|
| 166 |
+
|
| 167 |
+
extra_kw["headers"].update(headers)
|
| 168 |
+
extra_kw.update(urlopen_kw)
|
| 169 |
+
|
| 170 |
+
return self.urlopen(method, url, **extra_kw)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/response.py
ADDED
|
@@ -0,0 +1,821 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import io
|
| 4 |
+
import logging
|
| 5 |
+
import zlib
|
| 6 |
+
from contextlib import contextmanager
|
| 7 |
+
from socket import error as SocketError
|
| 8 |
+
from socket import timeout as SocketTimeout
|
| 9 |
+
|
| 10 |
+
try:
|
| 11 |
+
import brotli
|
| 12 |
+
except ImportError:
|
| 13 |
+
brotli = None
|
| 14 |
+
|
| 15 |
+
from ._collections import HTTPHeaderDict
|
| 16 |
+
from .connection import BaseSSLError, HTTPException
|
| 17 |
+
from .exceptions import (
|
| 18 |
+
BodyNotHttplibCompatible,
|
| 19 |
+
DecodeError,
|
| 20 |
+
HTTPError,
|
| 21 |
+
IncompleteRead,
|
| 22 |
+
InvalidChunkLength,
|
| 23 |
+
InvalidHeader,
|
| 24 |
+
ProtocolError,
|
| 25 |
+
ReadTimeoutError,
|
| 26 |
+
ResponseNotChunked,
|
| 27 |
+
SSLError,
|
| 28 |
+
)
|
| 29 |
+
from .packages import six
|
| 30 |
+
from .util.response import is_fp_closed, is_response_to_head
|
| 31 |
+
|
| 32 |
+
log = logging.getLogger(__name__)
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class DeflateDecoder(object):
|
| 36 |
+
def __init__(self):
|
| 37 |
+
self._first_try = True
|
| 38 |
+
self._data = b""
|
| 39 |
+
self._obj = zlib.decompressobj()
|
| 40 |
+
|
| 41 |
+
def __getattr__(self, name):
|
| 42 |
+
return getattr(self._obj, name)
|
| 43 |
+
|
| 44 |
+
def decompress(self, data):
|
| 45 |
+
if not data:
|
| 46 |
+
return data
|
| 47 |
+
|
| 48 |
+
if not self._first_try:
|
| 49 |
+
return self._obj.decompress(data)
|
| 50 |
+
|
| 51 |
+
self._data += data
|
| 52 |
+
try:
|
| 53 |
+
decompressed = self._obj.decompress(data)
|
| 54 |
+
if decompressed:
|
| 55 |
+
self._first_try = False
|
| 56 |
+
self._data = None
|
| 57 |
+
return decompressed
|
| 58 |
+
except zlib.error:
|
| 59 |
+
self._first_try = False
|
| 60 |
+
self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
|
| 61 |
+
try:
|
| 62 |
+
return self.decompress(self._data)
|
| 63 |
+
finally:
|
| 64 |
+
self._data = None
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
class GzipDecoderState(object):
|
| 68 |
+
|
| 69 |
+
FIRST_MEMBER = 0
|
| 70 |
+
OTHER_MEMBERS = 1
|
| 71 |
+
SWALLOW_DATA = 2
|
| 72 |
+
|
| 73 |
+
|
| 74 |
+
class GzipDecoder(object):
|
| 75 |
+
def __init__(self):
|
| 76 |
+
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
| 77 |
+
self._state = GzipDecoderState.FIRST_MEMBER
|
| 78 |
+
|
| 79 |
+
def __getattr__(self, name):
|
| 80 |
+
return getattr(self._obj, name)
|
| 81 |
+
|
| 82 |
+
def decompress(self, data):
|
| 83 |
+
ret = bytearray()
|
| 84 |
+
if self._state == GzipDecoderState.SWALLOW_DATA or not data:
|
| 85 |
+
return bytes(ret)
|
| 86 |
+
while True:
|
| 87 |
+
try:
|
| 88 |
+
ret += self._obj.decompress(data)
|
| 89 |
+
except zlib.error:
|
| 90 |
+
previous_state = self._state
|
| 91 |
+
# Ignore data after the first error
|
| 92 |
+
self._state = GzipDecoderState.SWALLOW_DATA
|
| 93 |
+
if previous_state == GzipDecoderState.OTHER_MEMBERS:
|
| 94 |
+
# Allow trailing garbage acceptable in other gzip clients
|
| 95 |
+
return bytes(ret)
|
| 96 |
+
raise
|
| 97 |
+
data = self._obj.unused_data
|
| 98 |
+
if not data:
|
| 99 |
+
return bytes(ret)
|
| 100 |
+
self._state = GzipDecoderState.OTHER_MEMBERS
|
| 101 |
+
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
if brotli is not None:
|
| 105 |
+
|
| 106 |
+
class BrotliDecoder(object):
|
| 107 |
+
# Supports both 'brotlipy' and 'Brotli' packages
|
| 108 |
+
# since they share an import name. The top branches
|
| 109 |
+
# are for 'brotlipy' and bottom branches for 'Brotli'
|
| 110 |
+
def __init__(self):
|
| 111 |
+
self._obj = brotli.Decompressor()
|
| 112 |
+
if hasattr(self._obj, "decompress"):
|
| 113 |
+
self.decompress = self._obj.decompress
|
| 114 |
+
else:
|
| 115 |
+
self.decompress = self._obj.process
|
| 116 |
+
|
| 117 |
+
def flush(self):
|
| 118 |
+
if hasattr(self._obj, "flush"):
|
| 119 |
+
return self._obj.flush()
|
| 120 |
+
return b""
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
class MultiDecoder(object):
|
| 124 |
+
"""
|
| 125 |
+
From RFC7231:
|
| 126 |
+
If one or more encodings have been applied to a representation, the
|
| 127 |
+
sender that applied the encodings MUST generate a Content-Encoding
|
| 128 |
+
header field that lists the content codings in the order in which
|
| 129 |
+
they were applied.
|
| 130 |
+
"""
|
| 131 |
+
|
| 132 |
+
def __init__(self, modes):
|
| 133 |
+
self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
|
| 134 |
+
|
| 135 |
+
def flush(self):
|
| 136 |
+
return self._decoders[0].flush()
|
| 137 |
+
|
| 138 |
+
def decompress(self, data):
|
| 139 |
+
for d in reversed(self._decoders):
|
| 140 |
+
data = d.decompress(data)
|
| 141 |
+
return data
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
def _get_decoder(mode):
|
| 145 |
+
if "," in mode:
|
| 146 |
+
return MultiDecoder(mode)
|
| 147 |
+
|
| 148 |
+
if mode == "gzip":
|
| 149 |
+
return GzipDecoder()
|
| 150 |
+
|
| 151 |
+
if brotli is not None and mode == "br":
|
| 152 |
+
return BrotliDecoder()
|
| 153 |
+
|
| 154 |
+
return DeflateDecoder()
|
| 155 |
+
|
| 156 |
+
|
| 157 |
+
class HTTPResponse(io.IOBase):
|
| 158 |
+
"""
|
| 159 |
+
HTTP Response container.
|
| 160 |
+
|
| 161 |
+
Backwards-compatible with :class:`http.client.HTTPResponse` but the response ``body`` is
|
| 162 |
+
loaded and decoded on-demand when the ``data`` property is accessed. This
|
| 163 |
+
class is also compatible with the Python standard library's :mod:`io`
|
| 164 |
+
module, and can hence be treated as a readable object in the context of that
|
| 165 |
+
framework.
|
| 166 |
+
|
| 167 |
+
Extra parameters for behaviour not present in :class:`http.client.HTTPResponse`:
|
| 168 |
+
|
| 169 |
+
:param preload_content:
|
| 170 |
+
If True, the response's body will be preloaded during construction.
|
| 171 |
+
|
| 172 |
+
:param decode_content:
|
| 173 |
+
If True, will attempt to decode the body based on the
|
| 174 |
+
'content-encoding' header.
|
| 175 |
+
|
| 176 |
+
:param original_response:
|
| 177 |
+
When this HTTPResponse wrapper is generated from an :class:`http.client.HTTPResponse`
|
| 178 |
+
object, it's convenient to include the original for debug purposes. It's
|
| 179 |
+
otherwise unused.
|
| 180 |
+
|
| 181 |
+
:param retries:
|
| 182 |
+
The retries contains the last :class:`~urllib3.util.retry.Retry` that
|
| 183 |
+
was used during the request.
|
| 184 |
+
|
| 185 |
+
:param enforce_content_length:
|
| 186 |
+
Enforce content length checking. Body returned by server must match
|
| 187 |
+
value of Content-Length header, if present. Otherwise, raise error.
|
| 188 |
+
"""
|
| 189 |
+
|
| 190 |
+
CONTENT_DECODERS = ["gzip", "deflate"]
|
| 191 |
+
if brotli is not None:
|
| 192 |
+
CONTENT_DECODERS += ["br"]
|
| 193 |
+
REDIRECT_STATUSES = [301, 302, 303, 307, 308]
|
| 194 |
+
|
| 195 |
+
def __init__(
|
| 196 |
+
self,
|
| 197 |
+
body="",
|
| 198 |
+
headers=None,
|
| 199 |
+
status=0,
|
| 200 |
+
version=0,
|
| 201 |
+
reason=None,
|
| 202 |
+
strict=0,
|
| 203 |
+
preload_content=True,
|
| 204 |
+
decode_content=True,
|
| 205 |
+
original_response=None,
|
| 206 |
+
pool=None,
|
| 207 |
+
connection=None,
|
| 208 |
+
msg=None,
|
| 209 |
+
retries=None,
|
| 210 |
+
enforce_content_length=False,
|
| 211 |
+
request_method=None,
|
| 212 |
+
request_url=None,
|
| 213 |
+
auto_close=True,
|
| 214 |
+
):
|
| 215 |
+
|
| 216 |
+
if isinstance(headers, HTTPHeaderDict):
|
| 217 |
+
self.headers = headers
|
| 218 |
+
else:
|
| 219 |
+
self.headers = HTTPHeaderDict(headers)
|
| 220 |
+
self.status = status
|
| 221 |
+
self.version = version
|
| 222 |
+
self.reason = reason
|
| 223 |
+
self.strict = strict
|
| 224 |
+
self.decode_content = decode_content
|
| 225 |
+
self.retries = retries
|
| 226 |
+
self.enforce_content_length = enforce_content_length
|
| 227 |
+
self.auto_close = auto_close
|
| 228 |
+
|
| 229 |
+
self._decoder = None
|
| 230 |
+
self._body = None
|
| 231 |
+
self._fp = None
|
| 232 |
+
self._original_response = original_response
|
| 233 |
+
self._fp_bytes_read = 0
|
| 234 |
+
self.msg = msg
|
| 235 |
+
self._request_url = request_url
|
| 236 |
+
|
| 237 |
+
if body and isinstance(body, (six.string_types, bytes)):
|
| 238 |
+
self._body = body
|
| 239 |
+
|
| 240 |
+
self._pool = pool
|
| 241 |
+
self._connection = connection
|
| 242 |
+
|
| 243 |
+
if hasattr(body, "read"):
|
| 244 |
+
self._fp = body
|
| 245 |
+
|
| 246 |
+
# Are we using the chunked-style of transfer encoding?
|
| 247 |
+
self.chunked = False
|
| 248 |
+
self.chunk_left = None
|
| 249 |
+
tr_enc = self.headers.get("transfer-encoding", "").lower()
|
| 250 |
+
# Don't incur the penalty of creating a list and then discarding it
|
| 251 |
+
encodings = (enc.strip() for enc in tr_enc.split(","))
|
| 252 |
+
if "chunked" in encodings:
|
| 253 |
+
self.chunked = True
|
| 254 |
+
|
| 255 |
+
# Determine length of response
|
| 256 |
+
self.length_remaining = self._init_length(request_method)
|
| 257 |
+
|
| 258 |
+
# If requested, preload the body.
|
| 259 |
+
if preload_content and not self._body:
|
| 260 |
+
self._body = self.read(decode_content=decode_content)
|
| 261 |
+
|
| 262 |
+
def get_redirect_location(self):
|
| 263 |
+
"""
|
| 264 |
+
Should we redirect and where to?
|
| 265 |
+
|
| 266 |
+
:returns: Truthy redirect location string if we got a redirect status
|
| 267 |
+
code and valid location. ``None`` if redirect status and no
|
| 268 |
+
location. ``False`` if not a redirect status code.
|
| 269 |
+
"""
|
| 270 |
+
if self.status in self.REDIRECT_STATUSES:
|
| 271 |
+
return self.headers.get("location")
|
| 272 |
+
|
| 273 |
+
return False
|
| 274 |
+
|
| 275 |
+
def release_conn(self):
|
| 276 |
+
if not self._pool or not self._connection:
|
| 277 |
+
return
|
| 278 |
+
|
| 279 |
+
self._pool._put_conn(self._connection)
|
| 280 |
+
self._connection = None
|
| 281 |
+
|
| 282 |
+
def drain_conn(self):
|
| 283 |
+
"""
|
| 284 |
+
Read and discard any remaining HTTP response data in the response connection.
|
| 285 |
+
|
| 286 |
+
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
|
| 287 |
+
"""
|
| 288 |
+
try:
|
| 289 |
+
self.read()
|
| 290 |
+
except (HTTPError, SocketError, BaseSSLError, HTTPException):
|
| 291 |
+
pass
|
| 292 |
+
|
| 293 |
+
@property
|
| 294 |
+
def data(self):
|
| 295 |
+
# For backwards-compat with earlier urllib3 0.4 and earlier.
|
| 296 |
+
if self._body:
|
| 297 |
+
return self._body
|
| 298 |
+
|
| 299 |
+
if self._fp:
|
| 300 |
+
return self.read(cache_content=True)
|
| 301 |
+
|
| 302 |
+
@property
|
| 303 |
+
def connection(self):
|
| 304 |
+
return self._connection
|
| 305 |
+
|
| 306 |
+
def isclosed(self):
|
| 307 |
+
return is_fp_closed(self._fp)
|
| 308 |
+
|
| 309 |
+
def tell(self):
|
| 310 |
+
"""
|
| 311 |
+
Obtain the number of bytes pulled over the wire so far. May differ from
|
| 312 |
+
the amount of content returned by :meth:``urllib3.response.HTTPResponse.read``
|
| 313 |
+
if bytes are encoded on the wire (e.g, compressed).
|
| 314 |
+
"""
|
| 315 |
+
return self._fp_bytes_read
|
| 316 |
+
|
| 317 |
+
def _init_length(self, request_method):
|
| 318 |
+
"""
|
| 319 |
+
Set initial length value for Response content if available.
|
| 320 |
+
"""
|
| 321 |
+
length = self.headers.get("content-length")
|
| 322 |
+
|
| 323 |
+
if length is not None:
|
| 324 |
+
if self.chunked:
|
| 325 |
+
# This Response will fail with an IncompleteRead if it can't be
|
| 326 |
+
# received as chunked. This method falls back to attempt reading
|
| 327 |
+
# the response before raising an exception.
|
| 328 |
+
log.warning(
|
| 329 |
+
"Received response with both Content-Length and "
|
| 330 |
+
"Transfer-Encoding set. This is expressly forbidden "
|
| 331 |
+
"by RFC 7230 sec 3.3.2. Ignoring Content-Length and "
|
| 332 |
+
"attempting to process response as Transfer-Encoding: "
|
| 333 |
+
"chunked."
|
| 334 |
+
)
|
| 335 |
+
return None
|
| 336 |
+
|
| 337 |
+
try:
|
| 338 |
+
# RFC 7230 section 3.3.2 specifies multiple content lengths can
|
| 339 |
+
# be sent in a single Content-Length header
|
| 340 |
+
# (e.g. Content-Length: 42, 42). This line ensures the values
|
| 341 |
+
# are all valid ints and that as long as the `set` length is 1,
|
| 342 |
+
# all values are the same. Otherwise, the header is invalid.
|
| 343 |
+
lengths = set([int(val) for val in length.split(",")])
|
| 344 |
+
if len(lengths) > 1:
|
| 345 |
+
raise InvalidHeader(
|
| 346 |
+
"Content-Length contained multiple "
|
| 347 |
+
"unmatching values (%s)" % length
|
| 348 |
+
)
|
| 349 |
+
length = lengths.pop()
|
| 350 |
+
except ValueError:
|
| 351 |
+
length = None
|
| 352 |
+
else:
|
| 353 |
+
if length < 0:
|
| 354 |
+
length = None
|
| 355 |
+
|
| 356 |
+
# Convert status to int for comparison
|
| 357 |
+
# In some cases, httplib returns a status of "_UNKNOWN"
|
| 358 |
+
try:
|
| 359 |
+
status = int(self.status)
|
| 360 |
+
except ValueError:
|
| 361 |
+
status = 0
|
| 362 |
+
|
| 363 |
+
# Check for responses that shouldn't include a body
|
| 364 |
+
if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD":
|
| 365 |
+
length = 0
|
| 366 |
+
|
| 367 |
+
return length
|
| 368 |
+
|
| 369 |
+
def _init_decoder(self):
|
| 370 |
+
"""
|
| 371 |
+
Set-up the _decoder attribute if necessary.
|
| 372 |
+
"""
|
| 373 |
+
# Note: content-encoding value should be case-insensitive, per RFC 7230
|
| 374 |
+
# Section 3.2
|
| 375 |
+
content_encoding = self.headers.get("content-encoding", "").lower()
|
| 376 |
+
if self._decoder is None:
|
| 377 |
+
if content_encoding in self.CONTENT_DECODERS:
|
| 378 |
+
self._decoder = _get_decoder(content_encoding)
|
| 379 |
+
elif "," in content_encoding:
|
| 380 |
+
encodings = [
|
| 381 |
+
e.strip()
|
| 382 |
+
for e in content_encoding.split(",")
|
| 383 |
+
if e.strip() in self.CONTENT_DECODERS
|
| 384 |
+
]
|
| 385 |
+
if len(encodings):
|
| 386 |
+
self._decoder = _get_decoder(content_encoding)
|
| 387 |
+
|
| 388 |
+
DECODER_ERROR_CLASSES = (IOError, zlib.error)
|
| 389 |
+
if brotli is not None:
|
| 390 |
+
DECODER_ERROR_CLASSES += (brotli.error,)
|
| 391 |
+
|
| 392 |
+
def _decode(self, data, decode_content, flush_decoder):
|
| 393 |
+
"""
|
| 394 |
+
Decode the data passed in and potentially flush the decoder.
|
| 395 |
+
"""
|
| 396 |
+
if not decode_content:
|
| 397 |
+
return data
|
| 398 |
+
|
| 399 |
+
try:
|
| 400 |
+
if self._decoder:
|
| 401 |
+
data = self._decoder.decompress(data)
|
| 402 |
+
except self.DECODER_ERROR_CLASSES as e:
|
| 403 |
+
content_encoding = self.headers.get("content-encoding", "").lower()
|
| 404 |
+
raise DecodeError(
|
| 405 |
+
"Received response with content-encoding: %s, but "
|
| 406 |
+
"failed to decode it." % content_encoding,
|
| 407 |
+
e,
|
| 408 |
+
)
|
| 409 |
+
if flush_decoder:
|
| 410 |
+
data += self._flush_decoder()
|
| 411 |
+
|
| 412 |
+
return data
|
| 413 |
+
|
| 414 |
+
def _flush_decoder(self):
|
| 415 |
+
"""
|
| 416 |
+
Flushes the decoder. Should only be called if the decoder is actually
|
| 417 |
+
being used.
|
| 418 |
+
"""
|
| 419 |
+
if self._decoder:
|
| 420 |
+
buf = self._decoder.decompress(b"")
|
| 421 |
+
return buf + self._decoder.flush()
|
| 422 |
+
|
| 423 |
+
return b""
|
| 424 |
+
|
| 425 |
+
@contextmanager
|
| 426 |
+
def _error_catcher(self):
|
| 427 |
+
"""
|
| 428 |
+
Catch low-level python exceptions, instead re-raising urllib3
|
| 429 |
+
variants, so that low-level exceptions are not leaked in the
|
| 430 |
+
high-level api.
|
| 431 |
+
|
| 432 |
+
On exit, release the connection back to the pool.
|
| 433 |
+
"""
|
| 434 |
+
clean_exit = False
|
| 435 |
+
|
| 436 |
+
try:
|
| 437 |
+
try:
|
| 438 |
+
yield
|
| 439 |
+
|
| 440 |
+
except SocketTimeout:
|
| 441 |
+
# FIXME: Ideally we'd like to include the url in the ReadTimeoutError but
|
| 442 |
+
# there is yet no clean way to get at it from this context.
|
| 443 |
+
raise ReadTimeoutError(self._pool, None, "Read timed out.")
|
| 444 |
+
|
| 445 |
+
except BaseSSLError as e:
|
| 446 |
+
# FIXME: Is there a better way to differentiate between SSLErrors?
|
| 447 |
+
if "read operation timed out" not in str(e):
|
| 448 |
+
# SSL errors related to framing/MAC get wrapped and reraised here
|
| 449 |
+
raise SSLError(e)
|
| 450 |
+
|
| 451 |
+
raise ReadTimeoutError(self._pool, None, "Read timed out.")
|
| 452 |
+
|
| 453 |
+
except (HTTPException, SocketError) as e:
|
| 454 |
+
# This includes IncompleteRead.
|
| 455 |
+
raise ProtocolError("Connection broken: %r" % e, e)
|
| 456 |
+
|
| 457 |
+
# If no exception is thrown, we should avoid cleaning up
|
| 458 |
+
# unnecessarily.
|
| 459 |
+
clean_exit = True
|
| 460 |
+
finally:
|
| 461 |
+
# If we didn't terminate cleanly, we need to throw away our
|
| 462 |
+
# connection.
|
| 463 |
+
if not clean_exit:
|
| 464 |
+
# The response may not be closed but we're not going to use it
|
| 465 |
+
# anymore so close it now to ensure that the connection is
|
| 466 |
+
# released back to the pool.
|
| 467 |
+
if self._original_response:
|
| 468 |
+
self._original_response.close()
|
| 469 |
+
|
| 470 |
+
# Closing the response may not actually be sufficient to close
|
| 471 |
+
# everything, so if we have a hold of the connection close that
|
| 472 |
+
# too.
|
| 473 |
+
if self._connection:
|
| 474 |
+
self._connection.close()
|
| 475 |
+
|
| 476 |
+
# If we hold the original response but it's closed now, we should
|
| 477 |
+
# return the connection back to the pool.
|
| 478 |
+
if self._original_response and self._original_response.isclosed():
|
| 479 |
+
self.release_conn()
|
| 480 |
+
|
| 481 |
+
def read(self, amt=None, decode_content=None, cache_content=False):
|
| 482 |
+
"""
|
| 483 |
+
Similar to :meth:`http.client.HTTPResponse.read`, but with two additional
|
| 484 |
+
parameters: ``decode_content`` and ``cache_content``.
|
| 485 |
+
|
| 486 |
+
:param amt:
|
| 487 |
+
How much of the content to read. If specified, caching is skipped
|
| 488 |
+
because it doesn't make sense to cache partial content as the full
|
| 489 |
+
response.
|
| 490 |
+
|
| 491 |
+
:param decode_content:
|
| 492 |
+
If True, will attempt to decode the body based on the
|
| 493 |
+
'content-encoding' header.
|
| 494 |
+
|
| 495 |
+
:param cache_content:
|
| 496 |
+
If True, will save the returned data such that the same result is
|
| 497 |
+
returned despite of the state of the underlying file object. This
|
| 498 |
+
is useful if you want the ``.data`` property to continue working
|
| 499 |
+
after having ``.read()`` the file object. (Overridden if ``amt`` is
|
| 500 |
+
set.)
|
| 501 |
+
"""
|
| 502 |
+
self._init_decoder()
|
| 503 |
+
if decode_content is None:
|
| 504 |
+
decode_content = self.decode_content
|
| 505 |
+
|
| 506 |
+
if self._fp is None:
|
| 507 |
+
return
|
| 508 |
+
|
| 509 |
+
flush_decoder = False
|
| 510 |
+
fp_closed = getattr(self._fp, "closed", False)
|
| 511 |
+
|
| 512 |
+
with self._error_catcher():
|
| 513 |
+
if amt is None:
|
| 514 |
+
# cStringIO doesn't like amt=None
|
| 515 |
+
data = self._fp.read() if not fp_closed else b""
|
| 516 |
+
flush_decoder = True
|
| 517 |
+
else:
|
| 518 |
+
cache_content = False
|
| 519 |
+
data = self._fp.read(amt) if not fp_closed else b""
|
| 520 |
+
if (
|
| 521 |
+
amt != 0 and not data
|
| 522 |
+
): # Platform-specific: Buggy versions of Python.
|
| 523 |
+
# Close the connection when no data is returned
|
| 524 |
+
#
|
| 525 |
+
# This is redundant to what httplib/http.client _should_
|
| 526 |
+
# already do. However, versions of python released before
|
| 527 |
+
# December 15, 2012 (http://bugs.python.org/issue16298) do
|
| 528 |
+
# not properly close the connection in all cases. There is
|
| 529 |
+
# no harm in redundantly calling close.
|
| 530 |
+
self._fp.close()
|
| 531 |
+
flush_decoder = True
|
| 532 |
+
if self.enforce_content_length and self.length_remaining not in (
|
| 533 |
+
0,
|
| 534 |
+
None,
|
| 535 |
+
):
|
| 536 |
+
# This is an edge case that httplib failed to cover due
|
| 537 |
+
# to concerns of backward compatibility. We're
|
| 538 |
+
# addressing it here to make sure IncompleteRead is
|
| 539 |
+
# raised during streaming, so all calls with incorrect
|
| 540 |
+
# Content-Length are caught.
|
| 541 |
+
raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
|
| 542 |
+
|
| 543 |
+
if data:
|
| 544 |
+
self._fp_bytes_read += len(data)
|
| 545 |
+
if self.length_remaining is not None:
|
| 546 |
+
self.length_remaining -= len(data)
|
| 547 |
+
|
| 548 |
+
data = self._decode(data, decode_content, flush_decoder)
|
| 549 |
+
|
| 550 |
+
if cache_content:
|
| 551 |
+
self._body = data
|
| 552 |
+
|
| 553 |
+
return data
|
| 554 |
+
|
| 555 |
+
def stream(self, amt=2 ** 16, decode_content=None):
|
| 556 |
+
"""
|
| 557 |
+
A generator wrapper for the read() method. A call will block until
|
| 558 |
+
``amt`` bytes have been read from the connection or until the
|
| 559 |
+
connection is closed.
|
| 560 |
+
|
| 561 |
+
:param amt:
|
| 562 |
+
How much of the content to read. The generator will return up to
|
| 563 |
+
much data per iteration, but may return less. This is particularly
|
| 564 |
+
likely when using compressed data. However, the empty string will
|
| 565 |
+
never be returned.
|
| 566 |
+
|
| 567 |
+
:param decode_content:
|
| 568 |
+
If True, will attempt to decode the body based on the
|
| 569 |
+
'content-encoding' header.
|
| 570 |
+
"""
|
| 571 |
+
if self.chunked and self.supports_chunked_reads():
|
| 572 |
+
for line in self.read_chunked(amt, decode_content=decode_content):
|
| 573 |
+
yield line
|
| 574 |
+
else:
|
| 575 |
+
while not is_fp_closed(self._fp):
|
| 576 |
+
data = self.read(amt=amt, decode_content=decode_content)
|
| 577 |
+
|
| 578 |
+
if data:
|
| 579 |
+
yield data
|
| 580 |
+
|
| 581 |
+
@classmethod
|
| 582 |
+
def from_httplib(ResponseCls, r, **response_kw):
|
| 583 |
+
"""
|
| 584 |
+
Given an :class:`http.client.HTTPResponse` instance ``r``, return a
|
| 585 |
+
corresponding :class:`urllib3.response.HTTPResponse` object.
|
| 586 |
+
|
| 587 |
+
Remaining parameters are passed to the HTTPResponse constructor, along
|
| 588 |
+
with ``original_response=r``.
|
| 589 |
+
"""
|
| 590 |
+
headers = r.msg
|
| 591 |
+
|
| 592 |
+
if not isinstance(headers, HTTPHeaderDict):
|
| 593 |
+
if six.PY2:
|
| 594 |
+
# Python 2.7
|
| 595 |
+
headers = HTTPHeaderDict.from_httplib(headers)
|
| 596 |
+
else:
|
| 597 |
+
headers = HTTPHeaderDict(headers.items())
|
| 598 |
+
|
| 599 |
+
# HTTPResponse objects in Python 3 don't have a .strict attribute
|
| 600 |
+
strict = getattr(r, "strict", 0)
|
| 601 |
+
resp = ResponseCls(
|
| 602 |
+
body=r,
|
| 603 |
+
headers=headers,
|
| 604 |
+
status=r.status,
|
| 605 |
+
version=r.version,
|
| 606 |
+
reason=r.reason,
|
| 607 |
+
strict=strict,
|
| 608 |
+
original_response=r,
|
| 609 |
+
**response_kw
|
| 610 |
+
)
|
| 611 |
+
return resp
|
| 612 |
+
|
| 613 |
+
# Backwards-compatibility methods for http.client.HTTPResponse
|
| 614 |
+
def getheaders(self):
|
| 615 |
+
return self.headers
|
| 616 |
+
|
| 617 |
+
def getheader(self, name, default=None):
|
| 618 |
+
return self.headers.get(name, default)
|
| 619 |
+
|
| 620 |
+
# Backwards compatibility for http.cookiejar
|
| 621 |
+
def info(self):
|
| 622 |
+
return self.headers
|
| 623 |
+
|
| 624 |
+
# Overrides from io.IOBase
|
| 625 |
+
def close(self):
|
| 626 |
+
if not self.closed:
|
| 627 |
+
self._fp.close()
|
| 628 |
+
|
| 629 |
+
if self._connection:
|
| 630 |
+
self._connection.close()
|
| 631 |
+
|
| 632 |
+
if not self.auto_close:
|
| 633 |
+
io.IOBase.close(self)
|
| 634 |
+
|
| 635 |
+
@property
|
| 636 |
+
def closed(self):
|
| 637 |
+
if not self.auto_close:
|
| 638 |
+
return io.IOBase.closed.__get__(self)
|
| 639 |
+
elif self._fp is None:
|
| 640 |
+
return True
|
| 641 |
+
elif hasattr(self._fp, "isclosed"):
|
| 642 |
+
return self._fp.isclosed()
|
| 643 |
+
elif hasattr(self._fp, "closed"):
|
| 644 |
+
return self._fp.closed
|
| 645 |
+
else:
|
| 646 |
+
return True
|
| 647 |
+
|
| 648 |
+
def fileno(self):
|
| 649 |
+
if self._fp is None:
|
| 650 |
+
raise IOError("HTTPResponse has no file to get a fileno from")
|
| 651 |
+
elif hasattr(self._fp, "fileno"):
|
| 652 |
+
return self._fp.fileno()
|
| 653 |
+
else:
|
| 654 |
+
raise IOError(
|
| 655 |
+
"The file-like object this HTTPResponse is wrapped "
|
| 656 |
+
"around has no file descriptor"
|
| 657 |
+
)
|
| 658 |
+
|
| 659 |
+
def flush(self):
|
| 660 |
+
if (
|
| 661 |
+
self._fp is not None
|
| 662 |
+
and hasattr(self._fp, "flush")
|
| 663 |
+
and not getattr(self._fp, "closed", False)
|
| 664 |
+
):
|
| 665 |
+
return self._fp.flush()
|
| 666 |
+
|
| 667 |
+
def readable(self):
|
| 668 |
+
# This method is required for `io` module compatibility.
|
| 669 |
+
return True
|
| 670 |
+
|
| 671 |
+
def readinto(self, b):
|
| 672 |
+
# This method is required for `io` module compatibility.
|
| 673 |
+
temp = self.read(len(b))
|
| 674 |
+
if len(temp) == 0:
|
| 675 |
+
return 0
|
| 676 |
+
else:
|
| 677 |
+
b[: len(temp)] = temp
|
| 678 |
+
return len(temp)
|
| 679 |
+
|
| 680 |
+
def supports_chunked_reads(self):
|
| 681 |
+
"""
|
| 682 |
+
Checks if the underlying file-like object looks like a
|
| 683 |
+
:class:`http.client.HTTPResponse` object. We do this by testing for
|
| 684 |
+
the fp attribute. If it is present we assume it returns raw chunks as
|
| 685 |
+
processed by read_chunked().
|
| 686 |
+
"""
|
| 687 |
+
return hasattr(self._fp, "fp")
|
| 688 |
+
|
| 689 |
+
def _update_chunk_length(self):
|
| 690 |
+
# First, we'll figure out length of a chunk and then
|
| 691 |
+
# we'll try to read it from socket.
|
| 692 |
+
if self.chunk_left is not None:
|
| 693 |
+
return
|
| 694 |
+
line = self._fp.fp.readline()
|
| 695 |
+
line = line.split(b";", 1)[0]
|
| 696 |
+
try:
|
| 697 |
+
self.chunk_left = int(line, 16)
|
| 698 |
+
except ValueError:
|
| 699 |
+
# Invalid chunked protocol response, abort.
|
| 700 |
+
self.close()
|
| 701 |
+
raise InvalidChunkLength(self, line)
|
| 702 |
+
|
| 703 |
+
def _handle_chunk(self, amt):
|
| 704 |
+
returned_chunk = None
|
| 705 |
+
if amt is None:
|
| 706 |
+
chunk = self._fp._safe_read(self.chunk_left)
|
| 707 |
+
returned_chunk = chunk
|
| 708 |
+
self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
|
| 709 |
+
self.chunk_left = None
|
| 710 |
+
elif amt < self.chunk_left:
|
| 711 |
+
value = self._fp._safe_read(amt)
|
| 712 |
+
self.chunk_left = self.chunk_left - amt
|
| 713 |
+
returned_chunk = value
|
| 714 |
+
elif amt == self.chunk_left:
|
| 715 |
+
value = self._fp._safe_read(amt)
|
| 716 |
+
self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
|
| 717 |
+
self.chunk_left = None
|
| 718 |
+
returned_chunk = value
|
| 719 |
+
else: # amt > self.chunk_left
|
| 720 |
+
returned_chunk = self._fp._safe_read(self.chunk_left)
|
| 721 |
+
self._fp._safe_read(2) # Toss the CRLF at the end of the chunk.
|
| 722 |
+
self.chunk_left = None
|
| 723 |
+
return returned_chunk
|
| 724 |
+
|
| 725 |
+
def read_chunked(self, amt=None, decode_content=None):
|
| 726 |
+
"""
|
| 727 |
+
Similar to :meth:`HTTPResponse.read`, but with an additional
|
| 728 |
+
parameter: ``decode_content``.
|
| 729 |
+
|
| 730 |
+
:param amt:
|
| 731 |
+
How much of the content to read. If specified, caching is skipped
|
| 732 |
+
because it doesn't make sense to cache partial content as the full
|
| 733 |
+
response.
|
| 734 |
+
|
| 735 |
+
:param decode_content:
|
| 736 |
+
If True, will attempt to decode the body based on the
|
| 737 |
+
'content-encoding' header.
|
| 738 |
+
"""
|
| 739 |
+
self._init_decoder()
|
| 740 |
+
# FIXME: Rewrite this method and make it a class with a better structured logic.
|
| 741 |
+
if not self.chunked:
|
| 742 |
+
raise ResponseNotChunked(
|
| 743 |
+
"Response is not chunked. "
|
| 744 |
+
"Header 'transfer-encoding: chunked' is missing."
|
| 745 |
+
)
|
| 746 |
+
if not self.supports_chunked_reads():
|
| 747 |
+
raise BodyNotHttplibCompatible(
|
| 748 |
+
"Body should be http.client.HTTPResponse like. "
|
| 749 |
+
"It should have have an fp attribute which returns raw chunks."
|
| 750 |
+
)
|
| 751 |
+
|
| 752 |
+
with self._error_catcher():
|
| 753 |
+
# Don't bother reading the body of a HEAD request.
|
| 754 |
+
if self._original_response and is_response_to_head(self._original_response):
|
| 755 |
+
self._original_response.close()
|
| 756 |
+
return
|
| 757 |
+
|
| 758 |
+
# If a response is already read and closed
|
| 759 |
+
# then return immediately.
|
| 760 |
+
if self._fp.fp is None:
|
| 761 |
+
return
|
| 762 |
+
|
| 763 |
+
while True:
|
| 764 |
+
self._update_chunk_length()
|
| 765 |
+
if self.chunk_left == 0:
|
| 766 |
+
break
|
| 767 |
+
chunk = self._handle_chunk(amt)
|
| 768 |
+
decoded = self._decode(
|
| 769 |
+
chunk, decode_content=decode_content, flush_decoder=False
|
| 770 |
+
)
|
| 771 |
+
if decoded:
|
| 772 |
+
yield decoded
|
| 773 |
+
|
| 774 |
+
if decode_content:
|
| 775 |
+
# On CPython and PyPy, we should never need to flush the
|
| 776 |
+
# decoder. However, on Jython we *might* need to, so
|
| 777 |
+
# lets defensively do it anyway.
|
| 778 |
+
decoded = self._flush_decoder()
|
| 779 |
+
if decoded: # Platform-specific: Jython.
|
| 780 |
+
yield decoded
|
| 781 |
+
|
| 782 |
+
# Chunk content ends with \r\n: discard it.
|
| 783 |
+
while True:
|
| 784 |
+
line = self._fp.fp.readline()
|
| 785 |
+
if not line:
|
| 786 |
+
# Some sites may not end with '\r\n'.
|
| 787 |
+
break
|
| 788 |
+
if line == b"\r\n":
|
| 789 |
+
break
|
| 790 |
+
|
| 791 |
+
# We read everything; close the "file".
|
| 792 |
+
if self._original_response:
|
| 793 |
+
self._original_response.close()
|
| 794 |
+
|
| 795 |
+
def geturl(self):
|
| 796 |
+
"""
|
| 797 |
+
Returns the URL that was the source of this response.
|
| 798 |
+
If the request that generated this response redirected, this method
|
| 799 |
+
will return the final redirect location.
|
| 800 |
+
"""
|
| 801 |
+
if self.retries is not None and len(self.retries.history):
|
| 802 |
+
return self.retries.history[-1].redirect_location
|
| 803 |
+
else:
|
| 804 |
+
return self._request_url
|
| 805 |
+
|
| 806 |
+
def __iter__(self):
|
| 807 |
+
buffer = []
|
| 808 |
+
for chunk in self.stream(decode_content=True):
|
| 809 |
+
if b"\n" in chunk:
|
| 810 |
+
chunk = chunk.split(b"\n")
|
| 811 |
+
yield b"".join(buffer) + chunk[0] + b"\n"
|
| 812 |
+
for x in chunk[1:-1]:
|
| 813 |
+
yield x + b"\n"
|
| 814 |
+
if chunk[-1]:
|
| 815 |
+
buffer = [chunk[-1]]
|
| 816 |
+
else:
|
| 817 |
+
buffer = []
|
| 818 |
+
else:
|
| 819 |
+
buffer.append(chunk)
|
| 820 |
+
if buffer:
|
| 821 |
+
yield b"".join(buffer)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/__init__.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
# For backwards compatibility, provide imports that used to be here.
|
| 4 |
+
from .connection import is_connection_dropped
|
| 5 |
+
from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers
|
| 6 |
+
from .response import is_fp_closed
|
| 7 |
+
from .retry import Retry
|
| 8 |
+
from .ssl_ import (
|
| 9 |
+
ALPN_PROTOCOLS,
|
| 10 |
+
HAS_SNI,
|
| 11 |
+
IS_PYOPENSSL,
|
| 12 |
+
IS_SECURETRANSPORT,
|
| 13 |
+
PROTOCOL_TLS,
|
| 14 |
+
SSLContext,
|
| 15 |
+
assert_fingerprint,
|
| 16 |
+
resolve_cert_reqs,
|
| 17 |
+
resolve_ssl_version,
|
| 18 |
+
ssl_wrap_socket,
|
| 19 |
+
)
|
| 20 |
+
from .timeout import Timeout, current_time
|
| 21 |
+
from .url import Url, get_host, parse_url, split_first
|
| 22 |
+
from .wait import wait_for_read, wait_for_write
|
| 23 |
+
|
| 24 |
+
__all__ = (
|
| 25 |
+
"HAS_SNI",
|
| 26 |
+
"IS_PYOPENSSL",
|
| 27 |
+
"IS_SECURETRANSPORT",
|
| 28 |
+
"SSLContext",
|
| 29 |
+
"PROTOCOL_TLS",
|
| 30 |
+
"ALPN_PROTOCOLS",
|
| 31 |
+
"Retry",
|
| 32 |
+
"Timeout",
|
| 33 |
+
"Url",
|
| 34 |
+
"assert_fingerprint",
|
| 35 |
+
"current_time",
|
| 36 |
+
"is_connection_dropped",
|
| 37 |
+
"is_fp_closed",
|
| 38 |
+
"get_host",
|
| 39 |
+
"parse_url",
|
| 40 |
+
"make_headers",
|
| 41 |
+
"resolve_cert_reqs",
|
| 42 |
+
"resolve_ssl_version",
|
| 43 |
+
"split_first",
|
| 44 |
+
"ssl_wrap_socket",
|
| 45 |
+
"wait_for_read",
|
| 46 |
+
"wait_for_write",
|
| 47 |
+
"SKIP_HEADER",
|
| 48 |
+
"SKIPPABLE_HEADERS",
|
| 49 |
+
)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/connection.py
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import socket
|
| 4 |
+
|
| 5 |
+
from pip._vendor.urllib3.exceptions import LocationParseError
|
| 6 |
+
|
| 7 |
+
from ..contrib import _appengine_environ
|
| 8 |
+
from ..packages import six
|
| 9 |
+
from .wait import NoWayToWaitForSocketError, wait_for_read
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def is_connection_dropped(conn): # Platform-specific
|
| 13 |
+
"""
|
| 14 |
+
Returns True if the connection is dropped and should be closed.
|
| 15 |
+
|
| 16 |
+
:param conn:
|
| 17 |
+
:class:`http.client.HTTPConnection` object.
|
| 18 |
+
|
| 19 |
+
Note: For platforms like AppEngine, this will always return ``False`` to
|
| 20 |
+
let the platform handle connection recycling transparently for us.
|
| 21 |
+
"""
|
| 22 |
+
sock = getattr(conn, "sock", False)
|
| 23 |
+
if sock is False: # Platform-specific: AppEngine
|
| 24 |
+
return False
|
| 25 |
+
if sock is None: # Connection already closed (such as by httplib).
|
| 26 |
+
return True
|
| 27 |
+
try:
|
| 28 |
+
# Returns True if readable, which here means it's been dropped
|
| 29 |
+
return wait_for_read(sock, timeout=0.0)
|
| 30 |
+
except NoWayToWaitForSocketError: # Platform-specific: AppEngine
|
| 31 |
+
return False
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
# This function is copied from socket.py in the Python 2.7 standard
|
| 35 |
+
# library test suite. Added to its signature is only `socket_options`.
|
| 36 |
+
# One additional modification is that we avoid binding to IPv6 servers
|
| 37 |
+
# discovered in DNS if the system doesn't have IPv6 functionality.
|
| 38 |
+
def create_connection(
|
| 39 |
+
address,
|
| 40 |
+
timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
|
| 41 |
+
source_address=None,
|
| 42 |
+
socket_options=None,
|
| 43 |
+
):
|
| 44 |
+
"""Connect to *address* and return the socket object.
|
| 45 |
+
|
| 46 |
+
Convenience function. Connect to *address* (a 2-tuple ``(host,
|
| 47 |
+
port)``) and return the socket object. Passing the optional
|
| 48 |
+
*timeout* parameter will set the timeout on the socket instance
|
| 49 |
+
before attempting to connect. If no *timeout* is supplied, the
|
| 50 |
+
global default timeout setting returned by :func:`socket.getdefaulttimeout`
|
| 51 |
+
is used. If *source_address* is set it must be a tuple of (host, port)
|
| 52 |
+
for the socket to bind as a source address before making the connection.
|
| 53 |
+
An host of '' or port 0 tells the OS to use the default.
|
| 54 |
+
"""
|
| 55 |
+
|
| 56 |
+
host, port = address
|
| 57 |
+
if host.startswith("["):
|
| 58 |
+
host = host.strip("[]")
|
| 59 |
+
err = None
|
| 60 |
+
|
| 61 |
+
# Using the value from allowed_gai_family() in the context of getaddrinfo lets
|
| 62 |
+
# us select whether to work with IPv4 DNS records, IPv6 records, or both.
|
| 63 |
+
# The original create_connection function always returns all records.
|
| 64 |
+
family = allowed_gai_family()
|
| 65 |
+
|
| 66 |
+
try:
|
| 67 |
+
host.encode("idna")
|
| 68 |
+
except UnicodeError:
|
| 69 |
+
return six.raise_from(
|
| 70 |
+
LocationParseError(u"'%s', label empty or too long" % host), None
|
| 71 |
+
)
|
| 72 |
+
|
| 73 |
+
for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
|
| 74 |
+
af, socktype, proto, canonname, sa = res
|
| 75 |
+
sock = None
|
| 76 |
+
try:
|
| 77 |
+
sock = socket.socket(af, socktype, proto)
|
| 78 |
+
|
| 79 |
+
# If provided, set socket level options before connecting.
|
| 80 |
+
_set_socket_options(sock, socket_options)
|
| 81 |
+
|
| 82 |
+
if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT:
|
| 83 |
+
sock.settimeout(timeout)
|
| 84 |
+
if source_address:
|
| 85 |
+
sock.bind(source_address)
|
| 86 |
+
sock.connect(sa)
|
| 87 |
+
return sock
|
| 88 |
+
|
| 89 |
+
except socket.error as e:
|
| 90 |
+
err = e
|
| 91 |
+
if sock is not None:
|
| 92 |
+
sock.close()
|
| 93 |
+
sock = None
|
| 94 |
+
|
| 95 |
+
if err is not None:
|
| 96 |
+
raise err
|
| 97 |
+
|
| 98 |
+
raise socket.error("getaddrinfo returns an empty list")
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
def _set_socket_options(sock, options):
|
| 102 |
+
if options is None:
|
| 103 |
+
return
|
| 104 |
+
|
| 105 |
+
for opt in options:
|
| 106 |
+
sock.setsockopt(*opt)
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def allowed_gai_family():
|
| 110 |
+
"""This function is designed to work in the context of
|
| 111 |
+
getaddrinfo, where family=socket.AF_UNSPEC is the default and
|
| 112 |
+
will perform a DNS search for both IPv6 and IPv4 records."""
|
| 113 |
+
|
| 114 |
+
family = socket.AF_INET
|
| 115 |
+
if HAS_IPV6:
|
| 116 |
+
family = socket.AF_UNSPEC
|
| 117 |
+
return family
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def _has_ipv6(host):
|
| 121 |
+
"""Returns True if the system can bind an IPv6 address."""
|
| 122 |
+
sock = None
|
| 123 |
+
has_ipv6 = False
|
| 124 |
+
|
| 125 |
+
# App Engine doesn't support IPV6 sockets and actually has a quota on the
|
| 126 |
+
# number of sockets that can be used, so just early out here instead of
|
| 127 |
+
# creating a socket needlessly.
|
| 128 |
+
# See https://github.com/urllib3/urllib3/issues/1446
|
| 129 |
+
if _appengine_environ.is_appengine_sandbox():
|
| 130 |
+
return False
|
| 131 |
+
|
| 132 |
+
if socket.has_ipv6:
|
| 133 |
+
# has_ipv6 returns true if cPython was compiled with IPv6 support.
|
| 134 |
+
# It does not tell us if the system has IPv6 support enabled. To
|
| 135 |
+
# determine that we must bind to an IPv6 address.
|
| 136 |
+
# https://github.com/urllib3/urllib3/pull/611
|
| 137 |
+
# https://bugs.python.org/issue658327
|
| 138 |
+
try:
|
| 139 |
+
sock = socket.socket(socket.AF_INET6)
|
| 140 |
+
sock.bind((host, 0))
|
| 141 |
+
has_ipv6 = True
|
| 142 |
+
except Exception:
|
| 143 |
+
pass
|
| 144 |
+
|
| 145 |
+
if sock:
|
| 146 |
+
sock.close()
|
| 147 |
+
return has_ipv6
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
HAS_IPV6 = _has_ipv6("::1")
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/proxy.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .ssl_ import create_urllib3_context, resolve_cert_reqs, resolve_ssl_version
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def connection_requires_http_tunnel(
|
| 5 |
+
proxy_url=None, proxy_config=None, destination_scheme=None
|
| 6 |
+
):
|
| 7 |
+
"""
|
| 8 |
+
Returns True if the connection requires an HTTP CONNECT through the proxy.
|
| 9 |
+
|
| 10 |
+
:param URL proxy_url:
|
| 11 |
+
URL of the proxy.
|
| 12 |
+
:param ProxyConfig proxy_config:
|
| 13 |
+
Proxy configuration from poolmanager.py
|
| 14 |
+
:param str destination_scheme:
|
| 15 |
+
The scheme of the destination. (i.e https, http, etc)
|
| 16 |
+
"""
|
| 17 |
+
# If we're not using a proxy, no way to use a tunnel.
|
| 18 |
+
if proxy_url is None:
|
| 19 |
+
return False
|
| 20 |
+
|
| 21 |
+
# HTTP destinations never require tunneling, we always forward.
|
| 22 |
+
if destination_scheme == "http":
|
| 23 |
+
return False
|
| 24 |
+
|
| 25 |
+
# Support for forwarding with HTTPS proxies and HTTPS destinations.
|
| 26 |
+
if (
|
| 27 |
+
proxy_url.scheme == "https"
|
| 28 |
+
and proxy_config
|
| 29 |
+
and proxy_config.use_forwarding_for_https
|
| 30 |
+
):
|
| 31 |
+
return False
|
| 32 |
+
|
| 33 |
+
# Otherwise always use a tunnel.
|
| 34 |
+
return True
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def create_proxy_ssl_context(
|
| 38 |
+
ssl_version, cert_reqs, ca_certs=None, ca_cert_dir=None, ca_cert_data=None
|
| 39 |
+
):
|
| 40 |
+
"""
|
| 41 |
+
Generates a default proxy ssl context if one hasn't been provided by the
|
| 42 |
+
user.
|
| 43 |
+
"""
|
| 44 |
+
ssl_context = create_urllib3_context(
|
| 45 |
+
ssl_version=resolve_ssl_version(ssl_version),
|
| 46 |
+
cert_reqs=resolve_cert_reqs(cert_reqs),
|
| 47 |
+
)
|
| 48 |
+
if (
|
| 49 |
+
not ca_certs
|
| 50 |
+
and not ca_cert_dir
|
| 51 |
+
and not ca_cert_data
|
| 52 |
+
and hasattr(ssl_context, "load_default_certs")
|
| 53 |
+
):
|
| 54 |
+
ssl_context.load_default_certs()
|
| 55 |
+
|
| 56 |
+
return ssl_context
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/queue.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import collections
|
| 2 |
+
|
| 3 |
+
from ..packages import six
|
| 4 |
+
from ..packages.six.moves import queue
|
| 5 |
+
|
| 6 |
+
if six.PY2:
|
| 7 |
+
# Queue is imported for side effects on MS Windows. See issue #229.
|
| 8 |
+
import Queue as _unused_module_Queue # noqa: F401
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class LifoQueue(queue.Queue):
|
| 12 |
+
def _init(self, _):
|
| 13 |
+
self.queue = collections.deque()
|
| 14 |
+
|
| 15 |
+
def _qsize(self, len=len):
|
| 16 |
+
return len(self.queue)
|
| 17 |
+
|
| 18 |
+
def _put(self, item):
|
| 19 |
+
self.queue.append(item)
|
| 20 |
+
|
| 21 |
+
def _get(self):
|
| 22 |
+
return self.queue.pop()
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/request.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
from base64 import b64encode
|
| 4 |
+
|
| 5 |
+
from ..exceptions import UnrewindableBodyError
|
| 6 |
+
from ..packages.six import b, integer_types
|
| 7 |
+
|
| 8 |
+
# Pass as a value within ``headers`` to skip
|
| 9 |
+
# emitting some HTTP headers that are added automatically.
|
| 10 |
+
# The only headers that are supported are ``Accept-Encoding``,
|
| 11 |
+
# ``Host``, and ``User-Agent``.
|
| 12 |
+
SKIP_HEADER = "@@@SKIP_HEADER@@@"
|
| 13 |
+
SKIPPABLE_HEADERS = frozenset(["accept-encoding", "host", "user-agent"])
|
| 14 |
+
|
| 15 |
+
ACCEPT_ENCODING = "gzip,deflate"
|
| 16 |
+
try:
|
| 17 |
+
import brotli as _unused_module_brotli # noqa: F401
|
| 18 |
+
except ImportError:
|
| 19 |
+
pass
|
| 20 |
+
else:
|
| 21 |
+
ACCEPT_ENCODING += ",br"
|
| 22 |
+
|
| 23 |
+
_FAILEDTELL = object()
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def make_headers(
|
| 27 |
+
keep_alive=None,
|
| 28 |
+
accept_encoding=None,
|
| 29 |
+
user_agent=None,
|
| 30 |
+
basic_auth=None,
|
| 31 |
+
proxy_basic_auth=None,
|
| 32 |
+
disable_cache=None,
|
| 33 |
+
):
|
| 34 |
+
"""
|
| 35 |
+
Shortcuts for generating request headers.
|
| 36 |
+
|
| 37 |
+
:param keep_alive:
|
| 38 |
+
If ``True``, adds 'connection: keep-alive' header.
|
| 39 |
+
|
| 40 |
+
:param accept_encoding:
|
| 41 |
+
Can be a boolean, list, or string.
|
| 42 |
+
``True`` translates to 'gzip,deflate'.
|
| 43 |
+
List will get joined by comma.
|
| 44 |
+
String will be used as provided.
|
| 45 |
+
|
| 46 |
+
:param user_agent:
|
| 47 |
+
String representing the user-agent you want, such as
|
| 48 |
+
"python-urllib3/0.6"
|
| 49 |
+
|
| 50 |
+
:param basic_auth:
|
| 51 |
+
Colon-separated username:password string for 'authorization: basic ...'
|
| 52 |
+
auth header.
|
| 53 |
+
|
| 54 |
+
:param proxy_basic_auth:
|
| 55 |
+
Colon-separated username:password string for 'proxy-authorization: basic ...'
|
| 56 |
+
auth header.
|
| 57 |
+
|
| 58 |
+
:param disable_cache:
|
| 59 |
+
If ``True``, adds 'cache-control: no-cache' header.
|
| 60 |
+
|
| 61 |
+
Example::
|
| 62 |
+
|
| 63 |
+
>>> make_headers(keep_alive=True, user_agent="Batman/1.0")
|
| 64 |
+
{'connection': 'keep-alive', 'user-agent': 'Batman/1.0'}
|
| 65 |
+
>>> make_headers(accept_encoding=True)
|
| 66 |
+
{'accept-encoding': 'gzip,deflate'}
|
| 67 |
+
"""
|
| 68 |
+
headers = {}
|
| 69 |
+
if accept_encoding:
|
| 70 |
+
if isinstance(accept_encoding, str):
|
| 71 |
+
pass
|
| 72 |
+
elif isinstance(accept_encoding, list):
|
| 73 |
+
accept_encoding = ",".join(accept_encoding)
|
| 74 |
+
else:
|
| 75 |
+
accept_encoding = ACCEPT_ENCODING
|
| 76 |
+
headers["accept-encoding"] = accept_encoding
|
| 77 |
+
|
| 78 |
+
if user_agent:
|
| 79 |
+
headers["user-agent"] = user_agent
|
| 80 |
+
|
| 81 |
+
if keep_alive:
|
| 82 |
+
headers["connection"] = "keep-alive"
|
| 83 |
+
|
| 84 |
+
if basic_auth:
|
| 85 |
+
headers["authorization"] = "Basic " + b64encode(b(basic_auth)).decode("utf-8")
|
| 86 |
+
|
| 87 |
+
if proxy_basic_auth:
|
| 88 |
+
headers["proxy-authorization"] = "Basic " + b64encode(
|
| 89 |
+
b(proxy_basic_auth)
|
| 90 |
+
).decode("utf-8")
|
| 91 |
+
|
| 92 |
+
if disable_cache:
|
| 93 |
+
headers["cache-control"] = "no-cache"
|
| 94 |
+
|
| 95 |
+
return headers
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def set_file_position(body, pos):
|
| 99 |
+
"""
|
| 100 |
+
If a position is provided, move file to that point.
|
| 101 |
+
Otherwise, we'll attempt to record a position for future use.
|
| 102 |
+
"""
|
| 103 |
+
if pos is not None:
|
| 104 |
+
rewind_body(body, pos)
|
| 105 |
+
elif getattr(body, "tell", None) is not None:
|
| 106 |
+
try:
|
| 107 |
+
pos = body.tell()
|
| 108 |
+
except (IOError, OSError):
|
| 109 |
+
# This differentiates from None, allowing us to catch
|
| 110 |
+
# a failed `tell()` later when trying to rewind the body.
|
| 111 |
+
pos = _FAILEDTELL
|
| 112 |
+
|
| 113 |
+
return pos
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def rewind_body(body, body_pos):
|
| 117 |
+
"""
|
| 118 |
+
Attempt to rewind body to a certain position.
|
| 119 |
+
Primarily used for request redirects and retries.
|
| 120 |
+
|
| 121 |
+
:param body:
|
| 122 |
+
File-like object that supports seek.
|
| 123 |
+
|
| 124 |
+
:param int pos:
|
| 125 |
+
Position to seek to in file.
|
| 126 |
+
"""
|
| 127 |
+
body_seek = getattr(body, "seek", None)
|
| 128 |
+
if body_seek is not None and isinstance(body_pos, integer_types):
|
| 129 |
+
try:
|
| 130 |
+
body_seek(body_pos)
|
| 131 |
+
except (IOError, OSError):
|
| 132 |
+
raise UnrewindableBodyError(
|
| 133 |
+
"An error occurred when rewinding request body for redirect/retry."
|
| 134 |
+
)
|
| 135 |
+
elif body_pos is _FAILEDTELL:
|
| 136 |
+
raise UnrewindableBodyError(
|
| 137 |
+
"Unable to record file position for rewinding "
|
| 138 |
+
"request body during a redirect/retry."
|
| 139 |
+
)
|
| 140 |
+
else:
|
| 141 |
+
raise ValueError(
|
| 142 |
+
"body_pos must be of type integer, instead it was %s." % type(body_pos)
|
| 143 |
+
)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/response.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect
|
| 4 |
+
|
| 5 |
+
from ..exceptions import HeaderParsingError
|
| 6 |
+
from ..packages.six.moves import http_client as httplib
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def is_fp_closed(obj):
|
| 10 |
+
"""
|
| 11 |
+
Checks whether a given file-like object is closed.
|
| 12 |
+
|
| 13 |
+
:param obj:
|
| 14 |
+
The file-like object to check.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
# Check `isclosed()` first, in case Python3 doesn't set `closed`.
|
| 19 |
+
# GH Issue #928
|
| 20 |
+
return obj.isclosed()
|
| 21 |
+
except AttributeError:
|
| 22 |
+
pass
|
| 23 |
+
|
| 24 |
+
try:
|
| 25 |
+
# Check via the official file-like-object way.
|
| 26 |
+
return obj.closed
|
| 27 |
+
except AttributeError:
|
| 28 |
+
pass
|
| 29 |
+
|
| 30 |
+
try:
|
| 31 |
+
# Check if the object is a container for another file-like object that
|
| 32 |
+
# gets released on exhaustion (e.g. HTTPResponse).
|
| 33 |
+
return obj.fp is None
|
| 34 |
+
except AttributeError:
|
| 35 |
+
pass
|
| 36 |
+
|
| 37 |
+
raise ValueError("Unable to determine whether fp is closed.")
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def assert_header_parsing(headers):
|
| 41 |
+
"""
|
| 42 |
+
Asserts whether all headers have been successfully parsed.
|
| 43 |
+
Extracts encountered errors from the result of parsing headers.
|
| 44 |
+
|
| 45 |
+
Only works on Python 3.
|
| 46 |
+
|
| 47 |
+
:param http.client.HTTPMessage headers: Headers to verify.
|
| 48 |
+
|
| 49 |
+
:raises urllib3.exceptions.HeaderParsingError:
|
| 50 |
+
If parsing errors are found.
|
| 51 |
+
"""
|
| 52 |
+
|
| 53 |
+
# This will fail silently if we pass in the wrong kind of parameter.
|
| 54 |
+
# To make debugging easier add an explicit check.
|
| 55 |
+
if not isinstance(headers, httplib.HTTPMessage):
|
| 56 |
+
raise TypeError("expected httplib.Message, got {0}.".format(type(headers)))
|
| 57 |
+
|
| 58 |
+
defects = getattr(headers, "defects", None)
|
| 59 |
+
get_payload = getattr(headers, "get_payload", None)
|
| 60 |
+
|
| 61 |
+
unparsed_data = None
|
| 62 |
+
if get_payload:
|
| 63 |
+
# get_payload is actually email.message.Message.get_payload;
|
| 64 |
+
# we're only interested in the result if it's not a multipart message
|
| 65 |
+
if not headers.is_multipart():
|
| 66 |
+
payload = get_payload()
|
| 67 |
+
|
| 68 |
+
if isinstance(payload, (bytes, str)):
|
| 69 |
+
unparsed_data = payload
|
| 70 |
+
if defects:
|
| 71 |
+
# httplib is assuming a response body is available
|
| 72 |
+
# when parsing headers even when httplib only sends
|
| 73 |
+
# header data to parse_headers() This results in
|
| 74 |
+
# defects on multipart responses in particular.
|
| 75 |
+
# See: https://github.com/urllib3/urllib3/issues/800
|
| 76 |
+
|
| 77 |
+
# So we ignore the following defects:
|
| 78 |
+
# - StartBoundaryNotFoundDefect:
|
| 79 |
+
# The claimed start boundary was never found.
|
| 80 |
+
# - MultipartInvariantViolationDefect:
|
| 81 |
+
# A message claimed to be a multipart but no subparts were found.
|
| 82 |
+
defects = [
|
| 83 |
+
defect
|
| 84 |
+
for defect in defects
|
| 85 |
+
if not isinstance(
|
| 86 |
+
defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect)
|
| 87 |
+
)
|
| 88 |
+
]
|
| 89 |
+
|
| 90 |
+
if defects or unparsed_data:
|
| 91 |
+
raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def is_response_to_head(response):
|
| 95 |
+
"""
|
| 96 |
+
Checks whether the request of a response has been a HEAD-request.
|
| 97 |
+
Handles the quirks of AppEngine.
|
| 98 |
+
|
| 99 |
+
:param http.client.HTTPResponse response:
|
| 100 |
+
Response to check if the originating request
|
| 101 |
+
used 'HEAD' as a method.
|
| 102 |
+
"""
|
| 103 |
+
# FIXME: Can we do this somehow without accessing private httplib _method?
|
| 104 |
+
method = response._method
|
| 105 |
+
if isinstance(method, int): # Platform-specific: Appengine
|
| 106 |
+
return method == 3
|
| 107 |
+
return method.upper() == "HEAD"
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/retry.py
ADDED
|
@@ -0,0 +1,602 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import email
|
| 4 |
+
import logging
|
| 5 |
+
import re
|
| 6 |
+
import time
|
| 7 |
+
import warnings
|
| 8 |
+
from collections import namedtuple
|
| 9 |
+
from itertools import takewhile
|
| 10 |
+
|
| 11 |
+
from ..exceptions import (
|
| 12 |
+
ConnectTimeoutError,
|
| 13 |
+
InvalidHeader,
|
| 14 |
+
MaxRetryError,
|
| 15 |
+
ProtocolError,
|
| 16 |
+
ProxyError,
|
| 17 |
+
ReadTimeoutError,
|
| 18 |
+
ResponseError,
|
| 19 |
+
)
|
| 20 |
+
from ..packages import six
|
| 21 |
+
|
| 22 |
+
log = logging.getLogger(__name__)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
# Data structure for representing the metadata of requests that result in a retry.
|
| 26 |
+
RequestHistory = namedtuple(
|
| 27 |
+
"RequestHistory", ["method", "url", "error", "status", "redirect_location"]
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
# TODO: In v2 we can remove this sentinel and metaclass with deprecated options.
|
| 32 |
+
_Default = object()
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class _RetryMeta(type):
|
| 36 |
+
@property
|
| 37 |
+
def DEFAULT_METHOD_WHITELIST(cls):
|
| 38 |
+
warnings.warn(
|
| 39 |
+
"Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and "
|
| 40 |
+
"will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead",
|
| 41 |
+
DeprecationWarning,
|
| 42 |
+
)
|
| 43 |
+
return cls.DEFAULT_ALLOWED_METHODS
|
| 44 |
+
|
| 45 |
+
@DEFAULT_METHOD_WHITELIST.setter
|
| 46 |
+
def DEFAULT_METHOD_WHITELIST(cls, value):
|
| 47 |
+
warnings.warn(
|
| 48 |
+
"Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and "
|
| 49 |
+
"will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead",
|
| 50 |
+
DeprecationWarning,
|
| 51 |
+
)
|
| 52 |
+
cls.DEFAULT_ALLOWED_METHODS = value
|
| 53 |
+
|
| 54 |
+
@property
|
| 55 |
+
def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls):
|
| 56 |
+
warnings.warn(
|
| 57 |
+
"Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and "
|
| 58 |
+
"will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead",
|
| 59 |
+
DeprecationWarning,
|
| 60 |
+
)
|
| 61 |
+
return cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT
|
| 62 |
+
|
| 63 |
+
@DEFAULT_REDIRECT_HEADERS_BLACKLIST.setter
|
| 64 |
+
def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls, value):
|
| 65 |
+
warnings.warn(
|
| 66 |
+
"Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and "
|
| 67 |
+
"will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead",
|
| 68 |
+
DeprecationWarning,
|
| 69 |
+
)
|
| 70 |
+
cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT = value
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
@six.add_metaclass(_RetryMeta)
|
| 74 |
+
class Retry(object):
|
| 75 |
+
"""Retry configuration.
|
| 76 |
+
|
| 77 |
+
Each retry attempt will create a new Retry object with updated values, so
|
| 78 |
+
they can be safely reused.
|
| 79 |
+
|
| 80 |
+
Retries can be defined as a default for a pool::
|
| 81 |
+
|
| 82 |
+
retries = Retry(connect=5, read=2, redirect=5)
|
| 83 |
+
http = PoolManager(retries=retries)
|
| 84 |
+
response = http.request('GET', 'http://example.com/')
|
| 85 |
+
|
| 86 |
+
Or per-request (which overrides the default for the pool)::
|
| 87 |
+
|
| 88 |
+
response = http.request('GET', 'http://example.com/', retries=Retry(10))
|
| 89 |
+
|
| 90 |
+
Retries can be disabled by passing ``False``::
|
| 91 |
+
|
| 92 |
+
response = http.request('GET', 'http://example.com/', retries=False)
|
| 93 |
+
|
| 94 |
+
Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless
|
| 95 |
+
retries are disabled, in which case the causing exception will be raised.
|
| 96 |
+
|
| 97 |
+
:param int total:
|
| 98 |
+
Total number of retries to allow. Takes precedence over other counts.
|
| 99 |
+
|
| 100 |
+
Set to ``None`` to remove this constraint and fall back on other
|
| 101 |
+
counts.
|
| 102 |
+
|
| 103 |
+
Set to ``0`` to fail on the first retry.
|
| 104 |
+
|
| 105 |
+
Set to ``False`` to disable and imply ``raise_on_redirect=False``.
|
| 106 |
+
|
| 107 |
+
:param int connect:
|
| 108 |
+
How many connection-related errors to retry on.
|
| 109 |
+
|
| 110 |
+
These are errors raised before the request is sent to the remote server,
|
| 111 |
+
which we assume has not triggered the server to process the request.
|
| 112 |
+
|
| 113 |
+
Set to ``0`` to fail on the first retry of this type.
|
| 114 |
+
|
| 115 |
+
:param int read:
|
| 116 |
+
How many times to retry on read errors.
|
| 117 |
+
|
| 118 |
+
These errors are raised after the request was sent to the server, so the
|
| 119 |
+
request may have side-effects.
|
| 120 |
+
|
| 121 |
+
Set to ``0`` to fail on the first retry of this type.
|
| 122 |
+
|
| 123 |
+
:param int redirect:
|
| 124 |
+
How many redirects to perform. Limit this to avoid infinite redirect
|
| 125 |
+
loops.
|
| 126 |
+
|
| 127 |
+
A redirect is a HTTP response with a status code 301, 302, 303, 307 or
|
| 128 |
+
308.
|
| 129 |
+
|
| 130 |
+
Set to ``0`` to fail on the first retry of this type.
|
| 131 |
+
|
| 132 |
+
Set to ``False`` to disable and imply ``raise_on_redirect=False``.
|
| 133 |
+
|
| 134 |
+
:param int status:
|
| 135 |
+
How many times to retry on bad status codes.
|
| 136 |
+
|
| 137 |
+
These are retries made on responses, where status code matches
|
| 138 |
+
``status_forcelist``.
|
| 139 |
+
|
| 140 |
+
Set to ``0`` to fail on the first retry of this type.
|
| 141 |
+
|
| 142 |
+
:param int other:
|
| 143 |
+
How many times to retry on other errors.
|
| 144 |
+
|
| 145 |
+
Other errors are errors that are not connect, read, redirect or status errors.
|
| 146 |
+
These errors might be raised after the request was sent to the server, so the
|
| 147 |
+
request might have side-effects.
|
| 148 |
+
|
| 149 |
+
Set to ``0`` to fail on the first retry of this type.
|
| 150 |
+
|
| 151 |
+
If ``total`` is not set, it's a good idea to set this to 0 to account
|
| 152 |
+
for unexpected edge cases and avoid infinite retry loops.
|
| 153 |
+
|
| 154 |
+
:param iterable allowed_methods:
|
| 155 |
+
Set of uppercased HTTP method verbs that we should retry on.
|
| 156 |
+
|
| 157 |
+
By default, we only retry on methods which are considered to be
|
| 158 |
+
idempotent (multiple requests with the same parameters end with the
|
| 159 |
+
same state). See :attr:`Retry.DEFAULT_ALLOWED_METHODS`.
|
| 160 |
+
|
| 161 |
+
Set to a ``False`` value to retry on any verb.
|
| 162 |
+
|
| 163 |
+
.. warning::
|
| 164 |
+
|
| 165 |
+
Previously this parameter was named ``method_whitelist``, that
|
| 166 |
+
usage is deprecated in v1.26.0 and will be removed in v2.0.
|
| 167 |
+
|
| 168 |
+
:param iterable status_forcelist:
|
| 169 |
+
A set of integer HTTP status codes that we should force a retry on.
|
| 170 |
+
A retry is initiated if the request method is in ``allowed_methods``
|
| 171 |
+
and the response status code is in ``status_forcelist``.
|
| 172 |
+
|
| 173 |
+
By default, this is disabled with ``None``.
|
| 174 |
+
|
| 175 |
+
:param float backoff_factor:
|
| 176 |
+
A backoff factor to apply between attempts after the second try
|
| 177 |
+
(most errors are resolved immediately by a second try without a
|
| 178 |
+
delay). urllib3 will sleep for::
|
| 179 |
+
|
| 180 |
+
{backoff factor} * (2 ** ({number of total retries} - 1))
|
| 181 |
+
|
| 182 |
+
seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep
|
| 183 |
+
for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer
|
| 184 |
+
than :attr:`Retry.BACKOFF_MAX`.
|
| 185 |
+
|
| 186 |
+
By default, backoff is disabled (set to 0).
|
| 187 |
+
|
| 188 |
+
:param bool raise_on_redirect: Whether, if the number of redirects is
|
| 189 |
+
exhausted, to raise a MaxRetryError, or to return a response with a
|
| 190 |
+
response code in the 3xx range.
|
| 191 |
+
|
| 192 |
+
:param bool raise_on_status: Similar meaning to ``raise_on_redirect``:
|
| 193 |
+
whether we should raise an exception, or return a response,
|
| 194 |
+
if status falls in ``status_forcelist`` range and retries have
|
| 195 |
+
been exhausted.
|
| 196 |
+
|
| 197 |
+
:param tuple history: The history of the request encountered during
|
| 198 |
+
each call to :meth:`~Retry.increment`. The list is in the order
|
| 199 |
+
the requests occurred. Each list item is of class :class:`RequestHistory`.
|
| 200 |
+
|
| 201 |
+
:param bool respect_retry_after_header:
|
| 202 |
+
Whether to respect Retry-After header on status codes defined as
|
| 203 |
+
:attr:`Retry.RETRY_AFTER_STATUS_CODES` or not.
|
| 204 |
+
|
| 205 |
+
:param iterable remove_headers_on_redirect:
|
| 206 |
+
Sequence of headers to remove from the request when a response
|
| 207 |
+
indicating a redirect is returned before firing off the redirected
|
| 208 |
+
request.
|
| 209 |
+
"""
|
| 210 |
+
|
| 211 |
+
#: Default methods to be used for ``allowed_methods``
|
| 212 |
+
DEFAULT_ALLOWED_METHODS = frozenset(
|
| 213 |
+
["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"]
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
#: Default status codes to be used for ``status_forcelist``
|
| 217 |
+
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
|
| 218 |
+
|
| 219 |
+
#: Default headers to be used for ``remove_headers_on_redirect``
|
| 220 |
+
DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Authorization"])
|
| 221 |
+
|
| 222 |
+
#: Maximum backoff time.
|
| 223 |
+
BACKOFF_MAX = 120
|
| 224 |
+
|
| 225 |
+
def __init__(
|
| 226 |
+
self,
|
| 227 |
+
total=10,
|
| 228 |
+
connect=None,
|
| 229 |
+
read=None,
|
| 230 |
+
redirect=None,
|
| 231 |
+
status=None,
|
| 232 |
+
other=None,
|
| 233 |
+
allowed_methods=_Default,
|
| 234 |
+
status_forcelist=None,
|
| 235 |
+
backoff_factor=0,
|
| 236 |
+
raise_on_redirect=True,
|
| 237 |
+
raise_on_status=True,
|
| 238 |
+
history=None,
|
| 239 |
+
respect_retry_after_header=True,
|
| 240 |
+
remove_headers_on_redirect=_Default,
|
| 241 |
+
# TODO: Deprecated, remove in v2.0
|
| 242 |
+
method_whitelist=_Default,
|
| 243 |
+
):
|
| 244 |
+
|
| 245 |
+
if method_whitelist is not _Default:
|
| 246 |
+
if allowed_methods is not _Default:
|
| 247 |
+
raise ValueError(
|
| 248 |
+
"Using both 'allowed_methods' and "
|
| 249 |
+
"'method_whitelist' together is not allowed. "
|
| 250 |
+
"Instead only use 'allowed_methods'"
|
| 251 |
+
)
|
| 252 |
+
warnings.warn(
|
| 253 |
+
"Using 'method_whitelist' with Retry is deprecated and "
|
| 254 |
+
"will be removed in v2.0. Use 'allowed_methods' instead",
|
| 255 |
+
DeprecationWarning,
|
| 256 |
+
stacklevel=2,
|
| 257 |
+
)
|
| 258 |
+
allowed_methods = method_whitelist
|
| 259 |
+
if allowed_methods is _Default:
|
| 260 |
+
allowed_methods = self.DEFAULT_ALLOWED_METHODS
|
| 261 |
+
if remove_headers_on_redirect is _Default:
|
| 262 |
+
remove_headers_on_redirect = self.DEFAULT_REMOVE_HEADERS_ON_REDIRECT
|
| 263 |
+
|
| 264 |
+
self.total = total
|
| 265 |
+
self.connect = connect
|
| 266 |
+
self.read = read
|
| 267 |
+
self.status = status
|
| 268 |
+
self.other = other
|
| 269 |
+
|
| 270 |
+
if redirect is False or total is False:
|
| 271 |
+
redirect = 0
|
| 272 |
+
raise_on_redirect = False
|
| 273 |
+
|
| 274 |
+
self.redirect = redirect
|
| 275 |
+
self.status_forcelist = status_forcelist or set()
|
| 276 |
+
self.allowed_methods = allowed_methods
|
| 277 |
+
self.backoff_factor = backoff_factor
|
| 278 |
+
self.raise_on_redirect = raise_on_redirect
|
| 279 |
+
self.raise_on_status = raise_on_status
|
| 280 |
+
self.history = history or tuple()
|
| 281 |
+
self.respect_retry_after_header = respect_retry_after_header
|
| 282 |
+
self.remove_headers_on_redirect = frozenset(
|
| 283 |
+
[h.lower() for h in remove_headers_on_redirect]
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
def new(self, **kw):
|
| 287 |
+
params = dict(
|
| 288 |
+
total=self.total,
|
| 289 |
+
connect=self.connect,
|
| 290 |
+
read=self.read,
|
| 291 |
+
redirect=self.redirect,
|
| 292 |
+
status=self.status,
|
| 293 |
+
other=self.other,
|
| 294 |
+
status_forcelist=self.status_forcelist,
|
| 295 |
+
backoff_factor=self.backoff_factor,
|
| 296 |
+
raise_on_redirect=self.raise_on_redirect,
|
| 297 |
+
raise_on_status=self.raise_on_status,
|
| 298 |
+
history=self.history,
|
| 299 |
+
remove_headers_on_redirect=self.remove_headers_on_redirect,
|
| 300 |
+
respect_retry_after_header=self.respect_retry_after_header,
|
| 301 |
+
)
|
| 302 |
+
|
| 303 |
+
# TODO: If already given in **kw we use what's given to us
|
| 304 |
+
# If not given we need to figure out what to pass. We decide
|
| 305 |
+
# based on whether our class has the 'method_whitelist' property
|
| 306 |
+
# and if so we pass the deprecated 'method_whitelist' otherwise
|
| 307 |
+
# we use 'allowed_methods'. Remove in v2.0
|
| 308 |
+
if "method_whitelist" not in kw and "allowed_methods" not in kw:
|
| 309 |
+
if "method_whitelist" in self.__dict__:
|
| 310 |
+
warnings.warn(
|
| 311 |
+
"Using 'method_whitelist' with Retry is deprecated and "
|
| 312 |
+
"will be removed in v2.0. Use 'allowed_methods' instead",
|
| 313 |
+
DeprecationWarning,
|
| 314 |
+
)
|
| 315 |
+
params["method_whitelist"] = self.allowed_methods
|
| 316 |
+
else:
|
| 317 |
+
params["allowed_methods"] = self.allowed_methods
|
| 318 |
+
|
| 319 |
+
params.update(kw)
|
| 320 |
+
return type(self)(**params)
|
| 321 |
+
|
| 322 |
+
@classmethod
|
| 323 |
+
def from_int(cls, retries, redirect=True, default=None):
|
| 324 |
+
"""Backwards-compatibility for the old retries format."""
|
| 325 |
+
if retries is None:
|
| 326 |
+
retries = default if default is not None else cls.DEFAULT
|
| 327 |
+
|
| 328 |
+
if isinstance(retries, Retry):
|
| 329 |
+
return retries
|
| 330 |
+
|
| 331 |
+
redirect = bool(redirect) and None
|
| 332 |
+
new_retries = cls(retries, redirect=redirect)
|
| 333 |
+
log.debug("Converted retries value: %r -> %r", retries, new_retries)
|
| 334 |
+
return new_retries
|
| 335 |
+
|
| 336 |
+
def get_backoff_time(self):
|
| 337 |
+
"""Formula for computing the current backoff
|
| 338 |
+
|
| 339 |
+
:rtype: float
|
| 340 |
+
"""
|
| 341 |
+
# We want to consider only the last consecutive errors sequence (Ignore redirects).
|
| 342 |
+
consecutive_errors_len = len(
|
| 343 |
+
list(
|
| 344 |
+
takewhile(lambda x: x.redirect_location is None, reversed(self.history))
|
| 345 |
+
)
|
| 346 |
+
)
|
| 347 |
+
if consecutive_errors_len <= 1:
|
| 348 |
+
return 0
|
| 349 |
+
|
| 350 |
+
backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1))
|
| 351 |
+
return min(self.BACKOFF_MAX, backoff_value)
|
| 352 |
+
|
| 353 |
+
def parse_retry_after(self, retry_after):
|
| 354 |
+
# Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4
|
| 355 |
+
if re.match(r"^\s*[0-9]+\s*$", retry_after):
|
| 356 |
+
seconds = int(retry_after)
|
| 357 |
+
else:
|
| 358 |
+
retry_date_tuple = email.utils.parsedate_tz(retry_after)
|
| 359 |
+
if retry_date_tuple is None:
|
| 360 |
+
raise InvalidHeader("Invalid Retry-After header: %s" % retry_after)
|
| 361 |
+
if retry_date_tuple[9] is None: # Python 2
|
| 362 |
+
# Assume UTC if no timezone was specified
|
| 363 |
+
# On Python2.7, parsedate_tz returns None for a timezone offset
|
| 364 |
+
# instead of 0 if no timezone is given, where mktime_tz treats
|
| 365 |
+
# a None timezone offset as local time.
|
| 366 |
+
retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:]
|
| 367 |
+
|
| 368 |
+
retry_date = email.utils.mktime_tz(retry_date_tuple)
|
| 369 |
+
seconds = retry_date - time.time()
|
| 370 |
+
|
| 371 |
+
if seconds < 0:
|
| 372 |
+
seconds = 0
|
| 373 |
+
|
| 374 |
+
return seconds
|
| 375 |
+
|
| 376 |
+
def get_retry_after(self, response):
|
| 377 |
+
"""Get the value of Retry-After in seconds."""
|
| 378 |
+
|
| 379 |
+
retry_after = response.getheader("Retry-After")
|
| 380 |
+
|
| 381 |
+
if retry_after is None:
|
| 382 |
+
return None
|
| 383 |
+
|
| 384 |
+
return self.parse_retry_after(retry_after)
|
| 385 |
+
|
| 386 |
+
def sleep_for_retry(self, response=None):
|
| 387 |
+
retry_after = self.get_retry_after(response)
|
| 388 |
+
if retry_after:
|
| 389 |
+
time.sleep(retry_after)
|
| 390 |
+
return True
|
| 391 |
+
|
| 392 |
+
return False
|
| 393 |
+
|
| 394 |
+
def _sleep_backoff(self):
|
| 395 |
+
backoff = self.get_backoff_time()
|
| 396 |
+
if backoff <= 0:
|
| 397 |
+
return
|
| 398 |
+
time.sleep(backoff)
|
| 399 |
+
|
| 400 |
+
def sleep(self, response=None):
|
| 401 |
+
"""Sleep between retry attempts.
|
| 402 |
+
|
| 403 |
+
This method will respect a server's ``Retry-After`` response header
|
| 404 |
+
and sleep the duration of the time requested. If that is not present, it
|
| 405 |
+
will use an exponential backoff. By default, the backoff factor is 0 and
|
| 406 |
+
this method will return immediately.
|
| 407 |
+
"""
|
| 408 |
+
|
| 409 |
+
if self.respect_retry_after_header and response:
|
| 410 |
+
slept = self.sleep_for_retry(response)
|
| 411 |
+
if slept:
|
| 412 |
+
return
|
| 413 |
+
|
| 414 |
+
self._sleep_backoff()
|
| 415 |
+
|
| 416 |
+
def _is_connection_error(self, err):
|
| 417 |
+
"""Errors when we're fairly sure that the server did not receive the
|
| 418 |
+
request, so it should be safe to retry.
|
| 419 |
+
"""
|
| 420 |
+
if isinstance(err, ProxyError):
|
| 421 |
+
err = err.original_error
|
| 422 |
+
return isinstance(err, ConnectTimeoutError)
|
| 423 |
+
|
| 424 |
+
def _is_read_error(self, err):
|
| 425 |
+
"""Errors that occur after the request has been started, so we should
|
| 426 |
+
assume that the server began processing it.
|
| 427 |
+
"""
|
| 428 |
+
return isinstance(err, (ReadTimeoutError, ProtocolError))
|
| 429 |
+
|
| 430 |
+
def _is_method_retryable(self, method):
|
| 431 |
+
"""Checks if a given HTTP method should be retried upon, depending if
|
| 432 |
+
it is included in the allowed_methods
|
| 433 |
+
"""
|
| 434 |
+
# TODO: For now favor if the Retry implementation sets its own method_whitelist
|
| 435 |
+
# property outside of our constructor to avoid breaking custom implementations.
|
| 436 |
+
if "method_whitelist" in self.__dict__:
|
| 437 |
+
warnings.warn(
|
| 438 |
+
"Using 'method_whitelist' with Retry is deprecated and "
|
| 439 |
+
"will be removed in v2.0. Use 'allowed_methods' instead",
|
| 440 |
+
DeprecationWarning,
|
| 441 |
+
)
|
| 442 |
+
allowed_methods = self.method_whitelist
|
| 443 |
+
else:
|
| 444 |
+
allowed_methods = self.allowed_methods
|
| 445 |
+
|
| 446 |
+
if allowed_methods and method.upper() not in allowed_methods:
|
| 447 |
+
return False
|
| 448 |
+
return True
|
| 449 |
+
|
| 450 |
+
def is_retry(self, method, status_code, has_retry_after=False):
|
| 451 |
+
"""Is this method/status code retryable? (Based on allowlists and control
|
| 452 |
+
variables such as the number of total retries to allow, whether to
|
| 453 |
+
respect the Retry-After header, whether this header is present, and
|
| 454 |
+
whether the returned status code is on the list of status codes to
|
| 455 |
+
be retried upon on the presence of the aforementioned header)
|
| 456 |
+
"""
|
| 457 |
+
if not self._is_method_retryable(method):
|
| 458 |
+
return False
|
| 459 |
+
|
| 460 |
+
if self.status_forcelist and status_code in self.status_forcelist:
|
| 461 |
+
return True
|
| 462 |
+
|
| 463 |
+
return (
|
| 464 |
+
self.total
|
| 465 |
+
and self.respect_retry_after_header
|
| 466 |
+
and has_retry_after
|
| 467 |
+
and (status_code in self.RETRY_AFTER_STATUS_CODES)
|
| 468 |
+
)
|
| 469 |
+
|
| 470 |
+
def is_exhausted(self):
|
| 471 |
+
"""Are we out of retries?"""
|
| 472 |
+
retry_counts = (
|
| 473 |
+
self.total,
|
| 474 |
+
self.connect,
|
| 475 |
+
self.read,
|
| 476 |
+
self.redirect,
|
| 477 |
+
self.status,
|
| 478 |
+
self.other,
|
| 479 |
+
)
|
| 480 |
+
retry_counts = list(filter(None, retry_counts))
|
| 481 |
+
if not retry_counts:
|
| 482 |
+
return False
|
| 483 |
+
|
| 484 |
+
return min(retry_counts) < 0
|
| 485 |
+
|
| 486 |
+
def increment(
|
| 487 |
+
self,
|
| 488 |
+
method=None,
|
| 489 |
+
url=None,
|
| 490 |
+
response=None,
|
| 491 |
+
error=None,
|
| 492 |
+
_pool=None,
|
| 493 |
+
_stacktrace=None,
|
| 494 |
+
):
|
| 495 |
+
"""Return a new Retry object with incremented retry counters.
|
| 496 |
+
|
| 497 |
+
:param response: A response object, or None, if the server did not
|
| 498 |
+
return a response.
|
| 499 |
+
:type response: :class:`~urllib3.response.HTTPResponse`
|
| 500 |
+
:param Exception error: An error encountered during the request, or
|
| 501 |
+
None if the response was received successfully.
|
| 502 |
+
|
| 503 |
+
:return: A new ``Retry`` object.
|
| 504 |
+
"""
|
| 505 |
+
if self.total is False and error:
|
| 506 |
+
# Disabled, indicate to re-raise the error.
|
| 507 |
+
raise six.reraise(type(error), error, _stacktrace)
|
| 508 |
+
|
| 509 |
+
total = self.total
|
| 510 |
+
if total is not None:
|
| 511 |
+
total -= 1
|
| 512 |
+
|
| 513 |
+
connect = self.connect
|
| 514 |
+
read = self.read
|
| 515 |
+
redirect = self.redirect
|
| 516 |
+
status_count = self.status
|
| 517 |
+
other = self.other
|
| 518 |
+
cause = "unknown"
|
| 519 |
+
status = None
|
| 520 |
+
redirect_location = None
|
| 521 |
+
|
| 522 |
+
if error and self._is_connection_error(error):
|
| 523 |
+
# Connect retry?
|
| 524 |
+
if connect is False:
|
| 525 |
+
raise six.reraise(type(error), error, _stacktrace)
|
| 526 |
+
elif connect is not None:
|
| 527 |
+
connect -= 1
|
| 528 |
+
|
| 529 |
+
elif error and self._is_read_error(error):
|
| 530 |
+
# Read retry?
|
| 531 |
+
if read is False or not self._is_method_retryable(method):
|
| 532 |
+
raise six.reraise(type(error), error, _stacktrace)
|
| 533 |
+
elif read is not None:
|
| 534 |
+
read -= 1
|
| 535 |
+
|
| 536 |
+
elif error:
|
| 537 |
+
# Other retry?
|
| 538 |
+
if other is not None:
|
| 539 |
+
other -= 1
|
| 540 |
+
|
| 541 |
+
elif response and response.get_redirect_location():
|
| 542 |
+
# Redirect retry?
|
| 543 |
+
if redirect is not None:
|
| 544 |
+
redirect -= 1
|
| 545 |
+
cause = "too many redirects"
|
| 546 |
+
redirect_location = response.get_redirect_location()
|
| 547 |
+
status = response.status
|
| 548 |
+
|
| 549 |
+
else:
|
| 550 |
+
# Incrementing because of a server error like a 500 in
|
| 551 |
+
# status_forcelist and the given method is in the allowed_methods
|
| 552 |
+
cause = ResponseError.GENERIC_ERROR
|
| 553 |
+
if response and response.status:
|
| 554 |
+
if status_count is not None:
|
| 555 |
+
status_count -= 1
|
| 556 |
+
cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)
|
| 557 |
+
status = response.status
|
| 558 |
+
|
| 559 |
+
history = self.history + (
|
| 560 |
+
RequestHistory(method, url, error, status, redirect_location),
|
| 561 |
+
)
|
| 562 |
+
|
| 563 |
+
new_retry = self.new(
|
| 564 |
+
total=total,
|
| 565 |
+
connect=connect,
|
| 566 |
+
read=read,
|
| 567 |
+
redirect=redirect,
|
| 568 |
+
status=status_count,
|
| 569 |
+
other=other,
|
| 570 |
+
history=history,
|
| 571 |
+
)
|
| 572 |
+
|
| 573 |
+
if new_retry.is_exhausted():
|
| 574 |
+
raise MaxRetryError(_pool, url, error or ResponseError(cause))
|
| 575 |
+
|
| 576 |
+
log.debug("Incremented Retry for (url='%s'): %r", url, new_retry)
|
| 577 |
+
|
| 578 |
+
return new_retry
|
| 579 |
+
|
| 580 |
+
def __repr__(self):
|
| 581 |
+
return (
|
| 582 |
+
"{cls.__name__}(total={self.total}, connect={self.connect}, "
|
| 583 |
+
"read={self.read}, redirect={self.redirect}, status={self.status})"
|
| 584 |
+
).format(cls=type(self), self=self)
|
| 585 |
+
|
| 586 |
+
def __getattr__(self, item):
|
| 587 |
+
if item == "method_whitelist":
|
| 588 |
+
# TODO: Remove this deprecated alias in v2.0
|
| 589 |
+
warnings.warn(
|
| 590 |
+
"Using 'method_whitelist' with Retry is deprecated and "
|
| 591 |
+
"will be removed in v2.0. Use 'allowed_methods' instead",
|
| 592 |
+
DeprecationWarning,
|
| 593 |
+
)
|
| 594 |
+
return self.allowed_methods
|
| 595 |
+
try:
|
| 596 |
+
return getattr(super(Retry, self), item)
|
| 597 |
+
except AttributeError:
|
| 598 |
+
return getattr(Retry, item)
|
| 599 |
+
|
| 600 |
+
|
| 601 |
+
# For backwards compatibility (equivalent to pre-v1.9):
|
| 602 |
+
Retry.DEFAULT = Retry(3)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/ssl_.py
ADDED
|
@@ -0,0 +1,495 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import hmac
|
| 4 |
+
import os
|
| 5 |
+
import sys
|
| 6 |
+
import warnings
|
| 7 |
+
from binascii import hexlify, unhexlify
|
| 8 |
+
from hashlib import md5, sha1, sha256
|
| 9 |
+
|
| 10 |
+
from ..exceptions import (
|
| 11 |
+
InsecurePlatformWarning,
|
| 12 |
+
ProxySchemeUnsupported,
|
| 13 |
+
SNIMissingWarning,
|
| 14 |
+
SSLError,
|
| 15 |
+
)
|
| 16 |
+
from ..packages import six
|
| 17 |
+
from .url import BRACELESS_IPV6_ADDRZ_RE, IPV4_RE
|
| 18 |
+
|
| 19 |
+
SSLContext = None
|
| 20 |
+
SSLTransport = None
|
| 21 |
+
HAS_SNI = False
|
| 22 |
+
IS_PYOPENSSL = False
|
| 23 |
+
IS_SECURETRANSPORT = False
|
| 24 |
+
ALPN_PROTOCOLS = ["http/1.1"]
|
| 25 |
+
|
| 26 |
+
# Maps the length of a digest to a possible hash function producing this digest
|
| 27 |
+
HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256}
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def _const_compare_digest_backport(a, b):
|
| 31 |
+
"""
|
| 32 |
+
Compare two digests of equal length in constant time.
|
| 33 |
+
|
| 34 |
+
The digests must be of type str/bytes.
|
| 35 |
+
Returns True if the digests match, and False otherwise.
|
| 36 |
+
"""
|
| 37 |
+
result = abs(len(a) - len(b))
|
| 38 |
+
for left, right in zip(bytearray(a), bytearray(b)):
|
| 39 |
+
result |= left ^ right
|
| 40 |
+
return result == 0
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
_const_compare_digest = getattr(hmac, "compare_digest", _const_compare_digest_backport)
|
| 44 |
+
|
| 45 |
+
try: # Test for SSL features
|
| 46 |
+
import ssl
|
| 47 |
+
from ssl import CERT_REQUIRED, wrap_socket
|
| 48 |
+
except ImportError:
|
| 49 |
+
pass
|
| 50 |
+
|
| 51 |
+
try:
|
| 52 |
+
from ssl import HAS_SNI # Has SNI?
|
| 53 |
+
except ImportError:
|
| 54 |
+
pass
|
| 55 |
+
|
| 56 |
+
try:
|
| 57 |
+
from .ssltransport import SSLTransport
|
| 58 |
+
except ImportError:
|
| 59 |
+
pass
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
try: # Platform-specific: Python 3.6
|
| 63 |
+
from ssl import PROTOCOL_TLS
|
| 64 |
+
|
| 65 |
+
PROTOCOL_SSLv23 = PROTOCOL_TLS
|
| 66 |
+
except ImportError:
|
| 67 |
+
try:
|
| 68 |
+
from ssl import PROTOCOL_SSLv23 as PROTOCOL_TLS
|
| 69 |
+
|
| 70 |
+
PROTOCOL_SSLv23 = PROTOCOL_TLS
|
| 71 |
+
except ImportError:
|
| 72 |
+
PROTOCOL_SSLv23 = PROTOCOL_TLS = 2
|
| 73 |
+
|
| 74 |
+
try:
|
| 75 |
+
from ssl import PROTOCOL_TLS_CLIENT
|
| 76 |
+
except ImportError:
|
| 77 |
+
PROTOCOL_TLS_CLIENT = PROTOCOL_TLS
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
try:
|
| 81 |
+
from ssl import OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3
|
| 82 |
+
except ImportError:
|
| 83 |
+
OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000
|
| 84 |
+
OP_NO_COMPRESSION = 0x20000
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
try: # OP_NO_TICKET was added in Python 3.6
|
| 88 |
+
from ssl import OP_NO_TICKET
|
| 89 |
+
except ImportError:
|
| 90 |
+
OP_NO_TICKET = 0x4000
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# A secure default.
|
| 94 |
+
# Sources for more information on TLS ciphers:
|
| 95 |
+
#
|
| 96 |
+
# - https://wiki.mozilla.org/Security/Server_Side_TLS
|
| 97 |
+
# - https://www.ssllabs.com/projects/best-practices/index.html
|
| 98 |
+
# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
|
| 99 |
+
#
|
| 100 |
+
# The general intent is:
|
| 101 |
+
# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE),
|
| 102 |
+
# - prefer ECDHE over DHE for better performance,
|
| 103 |
+
# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and
|
| 104 |
+
# security,
|
| 105 |
+
# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common,
|
| 106 |
+
# - disable NULL authentication, MD5 MACs, DSS, and other
|
| 107 |
+
# insecure ciphers for security reasons.
|
| 108 |
+
# - NOTE: TLS 1.3 cipher suites are managed through a different interface
|
| 109 |
+
# not exposed by CPython (yet!) and are enabled by default if they're available.
|
| 110 |
+
DEFAULT_CIPHERS = ":".join(
|
| 111 |
+
[
|
| 112 |
+
"ECDHE+AESGCM",
|
| 113 |
+
"ECDHE+CHACHA20",
|
| 114 |
+
"DHE+AESGCM",
|
| 115 |
+
"DHE+CHACHA20",
|
| 116 |
+
"ECDH+AESGCM",
|
| 117 |
+
"DH+AESGCM",
|
| 118 |
+
"ECDH+AES",
|
| 119 |
+
"DH+AES",
|
| 120 |
+
"RSA+AESGCM",
|
| 121 |
+
"RSA+AES",
|
| 122 |
+
"!aNULL",
|
| 123 |
+
"!eNULL",
|
| 124 |
+
"!MD5",
|
| 125 |
+
"!DSS",
|
| 126 |
+
]
|
| 127 |
+
)
|
| 128 |
+
|
| 129 |
+
try:
|
| 130 |
+
from ssl import SSLContext # Modern SSL?
|
| 131 |
+
except ImportError:
|
| 132 |
+
|
| 133 |
+
class SSLContext(object): # Platform-specific: Python 2
|
| 134 |
+
def __init__(self, protocol_version):
|
| 135 |
+
self.protocol = protocol_version
|
| 136 |
+
# Use default values from a real SSLContext
|
| 137 |
+
self.check_hostname = False
|
| 138 |
+
self.verify_mode = ssl.CERT_NONE
|
| 139 |
+
self.ca_certs = None
|
| 140 |
+
self.options = 0
|
| 141 |
+
self.certfile = None
|
| 142 |
+
self.keyfile = None
|
| 143 |
+
self.ciphers = None
|
| 144 |
+
|
| 145 |
+
def load_cert_chain(self, certfile, keyfile):
|
| 146 |
+
self.certfile = certfile
|
| 147 |
+
self.keyfile = keyfile
|
| 148 |
+
|
| 149 |
+
def load_verify_locations(self, cafile=None, capath=None, cadata=None):
|
| 150 |
+
self.ca_certs = cafile
|
| 151 |
+
|
| 152 |
+
if capath is not None:
|
| 153 |
+
raise SSLError("CA directories not supported in older Pythons")
|
| 154 |
+
|
| 155 |
+
if cadata is not None:
|
| 156 |
+
raise SSLError("CA data not supported in older Pythons")
|
| 157 |
+
|
| 158 |
+
def set_ciphers(self, cipher_suite):
|
| 159 |
+
self.ciphers = cipher_suite
|
| 160 |
+
|
| 161 |
+
def wrap_socket(self, socket, server_hostname=None, server_side=False):
|
| 162 |
+
warnings.warn(
|
| 163 |
+
"A true SSLContext object is not available. This prevents "
|
| 164 |
+
"urllib3 from configuring SSL appropriately and may cause "
|
| 165 |
+
"certain SSL connections to fail. You can upgrade to a newer "
|
| 166 |
+
"version of Python to solve this. For more information, see "
|
| 167 |
+
"https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html"
|
| 168 |
+
"#ssl-warnings",
|
| 169 |
+
InsecurePlatformWarning,
|
| 170 |
+
)
|
| 171 |
+
kwargs = {
|
| 172 |
+
"keyfile": self.keyfile,
|
| 173 |
+
"certfile": self.certfile,
|
| 174 |
+
"ca_certs": self.ca_certs,
|
| 175 |
+
"cert_reqs": self.verify_mode,
|
| 176 |
+
"ssl_version": self.protocol,
|
| 177 |
+
"server_side": server_side,
|
| 178 |
+
}
|
| 179 |
+
return wrap_socket(socket, ciphers=self.ciphers, **kwargs)
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
def assert_fingerprint(cert, fingerprint):
|
| 183 |
+
"""
|
| 184 |
+
Checks if given fingerprint matches the supplied certificate.
|
| 185 |
+
|
| 186 |
+
:param cert:
|
| 187 |
+
Certificate as bytes object.
|
| 188 |
+
:param fingerprint:
|
| 189 |
+
Fingerprint as string of hexdigits, can be interspersed by colons.
|
| 190 |
+
"""
|
| 191 |
+
|
| 192 |
+
fingerprint = fingerprint.replace(":", "").lower()
|
| 193 |
+
digest_length = len(fingerprint)
|
| 194 |
+
hashfunc = HASHFUNC_MAP.get(digest_length)
|
| 195 |
+
if not hashfunc:
|
| 196 |
+
raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint))
|
| 197 |
+
|
| 198 |
+
# We need encode() here for py32; works on py2 and p33.
|
| 199 |
+
fingerprint_bytes = unhexlify(fingerprint.encode())
|
| 200 |
+
|
| 201 |
+
cert_digest = hashfunc(cert).digest()
|
| 202 |
+
|
| 203 |
+
if not _const_compare_digest(cert_digest, fingerprint_bytes):
|
| 204 |
+
raise SSLError(
|
| 205 |
+
'Fingerprints did not match. Expected "{0}", got "{1}".'.format(
|
| 206 |
+
fingerprint, hexlify(cert_digest)
|
| 207 |
+
)
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def resolve_cert_reqs(candidate):
|
| 212 |
+
"""
|
| 213 |
+
Resolves the argument to a numeric constant, which can be passed to
|
| 214 |
+
the wrap_socket function/method from the ssl module.
|
| 215 |
+
Defaults to :data:`ssl.CERT_REQUIRED`.
|
| 216 |
+
If given a string it is assumed to be the name of the constant in the
|
| 217 |
+
:mod:`ssl` module or its abbreviation.
|
| 218 |
+
(So you can specify `REQUIRED` instead of `CERT_REQUIRED`.
|
| 219 |
+
If it's neither `None` nor a string we assume it is already the numeric
|
| 220 |
+
constant which can directly be passed to wrap_socket.
|
| 221 |
+
"""
|
| 222 |
+
if candidate is None:
|
| 223 |
+
return CERT_REQUIRED
|
| 224 |
+
|
| 225 |
+
if isinstance(candidate, str):
|
| 226 |
+
res = getattr(ssl, candidate, None)
|
| 227 |
+
if res is None:
|
| 228 |
+
res = getattr(ssl, "CERT_" + candidate)
|
| 229 |
+
return res
|
| 230 |
+
|
| 231 |
+
return candidate
|
| 232 |
+
|
| 233 |
+
|
| 234 |
+
def resolve_ssl_version(candidate):
|
| 235 |
+
"""
|
| 236 |
+
like resolve_cert_reqs
|
| 237 |
+
"""
|
| 238 |
+
if candidate is None:
|
| 239 |
+
return PROTOCOL_TLS
|
| 240 |
+
|
| 241 |
+
if isinstance(candidate, str):
|
| 242 |
+
res = getattr(ssl, candidate, None)
|
| 243 |
+
if res is None:
|
| 244 |
+
res = getattr(ssl, "PROTOCOL_" + candidate)
|
| 245 |
+
return res
|
| 246 |
+
|
| 247 |
+
return candidate
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def create_urllib3_context(
|
| 251 |
+
ssl_version=None, cert_reqs=None, options=None, ciphers=None
|
| 252 |
+
):
|
| 253 |
+
"""All arguments have the same meaning as ``ssl_wrap_socket``.
|
| 254 |
+
|
| 255 |
+
By default, this function does a lot of the same work that
|
| 256 |
+
``ssl.create_default_context`` does on Python 3.4+. It:
|
| 257 |
+
|
| 258 |
+
- Disables SSLv2, SSLv3, and compression
|
| 259 |
+
- Sets a restricted set of server ciphers
|
| 260 |
+
|
| 261 |
+
If you wish to enable SSLv3, you can do::
|
| 262 |
+
|
| 263 |
+
from pip._vendor.urllib3.util import ssl_
|
| 264 |
+
context = ssl_.create_urllib3_context()
|
| 265 |
+
context.options &= ~ssl_.OP_NO_SSLv3
|
| 266 |
+
|
| 267 |
+
You can do the same to enable compression (substituting ``COMPRESSION``
|
| 268 |
+
for ``SSLv3`` in the last line above).
|
| 269 |
+
|
| 270 |
+
:param ssl_version:
|
| 271 |
+
The desired protocol version to use. This will default to
|
| 272 |
+
PROTOCOL_SSLv23 which will negotiate the highest protocol that both
|
| 273 |
+
the server and your installation of OpenSSL support.
|
| 274 |
+
:param cert_reqs:
|
| 275 |
+
Whether to require the certificate verification. This defaults to
|
| 276 |
+
``ssl.CERT_REQUIRED``.
|
| 277 |
+
:param options:
|
| 278 |
+
Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``,
|
| 279 |
+
``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``.
|
| 280 |
+
:param ciphers:
|
| 281 |
+
Which cipher suites to allow the server to select.
|
| 282 |
+
:returns:
|
| 283 |
+
Constructed SSLContext object with specified options
|
| 284 |
+
:rtype: SSLContext
|
| 285 |
+
"""
|
| 286 |
+
# PROTOCOL_TLS is deprecated in Python 3.10
|
| 287 |
+
if not ssl_version or ssl_version == PROTOCOL_TLS:
|
| 288 |
+
ssl_version = PROTOCOL_TLS_CLIENT
|
| 289 |
+
|
| 290 |
+
context = SSLContext(ssl_version)
|
| 291 |
+
|
| 292 |
+
context.set_ciphers(ciphers or DEFAULT_CIPHERS)
|
| 293 |
+
|
| 294 |
+
# Setting the default here, as we may have no ssl module on import
|
| 295 |
+
cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs
|
| 296 |
+
|
| 297 |
+
if options is None:
|
| 298 |
+
options = 0
|
| 299 |
+
# SSLv2 is easily broken and is considered harmful and dangerous
|
| 300 |
+
options |= OP_NO_SSLv2
|
| 301 |
+
# SSLv3 has several problems and is now dangerous
|
| 302 |
+
options |= OP_NO_SSLv3
|
| 303 |
+
# Disable compression to prevent CRIME attacks for OpenSSL 1.0+
|
| 304 |
+
# (issue #309)
|
| 305 |
+
options |= OP_NO_COMPRESSION
|
| 306 |
+
# TLSv1.2 only. Unless set explicitly, do not request tickets.
|
| 307 |
+
# This may save some bandwidth on wire, and although the ticket is encrypted,
|
| 308 |
+
# there is a risk associated with it being on wire,
|
| 309 |
+
# if the server is not rotating its ticketing keys properly.
|
| 310 |
+
options |= OP_NO_TICKET
|
| 311 |
+
|
| 312 |
+
context.options |= options
|
| 313 |
+
|
| 314 |
+
# Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is
|
| 315 |
+
# necessary for conditional client cert authentication with TLS 1.3.
|
| 316 |
+
# The attribute is None for OpenSSL <= 1.1.0 or does not exist in older
|
| 317 |
+
# versions of Python. We only enable on Python 3.7.4+ or if certificate
|
| 318 |
+
# verification is enabled to work around Python issue #37428
|
| 319 |
+
# See: https://bugs.python.org/issue37428
|
| 320 |
+
if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr(
|
| 321 |
+
context, "post_handshake_auth", None
|
| 322 |
+
) is not None:
|
| 323 |
+
context.post_handshake_auth = True
|
| 324 |
+
|
| 325 |
+
def disable_check_hostname():
|
| 326 |
+
if (
|
| 327 |
+
getattr(context, "check_hostname", None) is not None
|
| 328 |
+
): # Platform-specific: Python 3.2
|
| 329 |
+
# We do our own verification, including fingerprints and alternative
|
| 330 |
+
# hostnames. So disable it here
|
| 331 |
+
context.check_hostname = False
|
| 332 |
+
|
| 333 |
+
# The order of the below lines setting verify_mode and check_hostname
|
| 334 |
+
# matter due to safe-guards SSLContext has to prevent an SSLContext with
|
| 335 |
+
# check_hostname=True, verify_mode=NONE/OPTIONAL. This is made even more
|
| 336 |
+
# complex because we don't know whether PROTOCOL_TLS_CLIENT will be used
|
| 337 |
+
# or not so we don't know the initial state of the freshly created SSLContext.
|
| 338 |
+
if cert_reqs == ssl.CERT_REQUIRED:
|
| 339 |
+
context.verify_mode = cert_reqs
|
| 340 |
+
disable_check_hostname()
|
| 341 |
+
else:
|
| 342 |
+
disable_check_hostname()
|
| 343 |
+
context.verify_mode = cert_reqs
|
| 344 |
+
|
| 345 |
+
# Enable logging of TLS session keys via defacto standard environment variable
|
| 346 |
+
# 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values.
|
| 347 |
+
if hasattr(context, "keylog_filename"):
|
| 348 |
+
sslkeylogfile = os.environ.get("SSLKEYLOGFILE")
|
| 349 |
+
if sslkeylogfile:
|
| 350 |
+
context.keylog_filename = sslkeylogfile
|
| 351 |
+
|
| 352 |
+
return context
|
| 353 |
+
|
| 354 |
+
|
| 355 |
+
def ssl_wrap_socket(
|
| 356 |
+
sock,
|
| 357 |
+
keyfile=None,
|
| 358 |
+
certfile=None,
|
| 359 |
+
cert_reqs=None,
|
| 360 |
+
ca_certs=None,
|
| 361 |
+
server_hostname=None,
|
| 362 |
+
ssl_version=None,
|
| 363 |
+
ciphers=None,
|
| 364 |
+
ssl_context=None,
|
| 365 |
+
ca_cert_dir=None,
|
| 366 |
+
key_password=None,
|
| 367 |
+
ca_cert_data=None,
|
| 368 |
+
tls_in_tls=False,
|
| 369 |
+
):
|
| 370 |
+
"""
|
| 371 |
+
All arguments except for server_hostname, ssl_context, and ca_cert_dir have
|
| 372 |
+
the same meaning as they do when using :func:`ssl.wrap_socket`.
|
| 373 |
+
|
| 374 |
+
:param server_hostname:
|
| 375 |
+
When SNI is supported, the expected hostname of the certificate
|
| 376 |
+
:param ssl_context:
|
| 377 |
+
A pre-made :class:`SSLContext` object. If none is provided, one will
|
| 378 |
+
be created using :func:`create_urllib3_context`.
|
| 379 |
+
:param ciphers:
|
| 380 |
+
A string of ciphers we wish the client to support.
|
| 381 |
+
:param ca_cert_dir:
|
| 382 |
+
A directory containing CA certificates in multiple separate files, as
|
| 383 |
+
supported by OpenSSL's -CApath flag or the capath argument to
|
| 384 |
+
SSLContext.load_verify_locations().
|
| 385 |
+
:param key_password:
|
| 386 |
+
Optional password if the keyfile is encrypted.
|
| 387 |
+
:param ca_cert_data:
|
| 388 |
+
Optional string containing CA certificates in PEM format suitable for
|
| 389 |
+
passing as the cadata parameter to SSLContext.load_verify_locations()
|
| 390 |
+
:param tls_in_tls:
|
| 391 |
+
Use SSLTransport to wrap the existing socket.
|
| 392 |
+
"""
|
| 393 |
+
context = ssl_context
|
| 394 |
+
if context is None:
|
| 395 |
+
# Note: This branch of code and all the variables in it are no longer
|
| 396 |
+
# used by urllib3 itself. We should consider deprecating and removing
|
| 397 |
+
# this code.
|
| 398 |
+
context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers)
|
| 399 |
+
|
| 400 |
+
if ca_certs or ca_cert_dir or ca_cert_data:
|
| 401 |
+
try:
|
| 402 |
+
context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data)
|
| 403 |
+
except (IOError, OSError) as e:
|
| 404 |
+
raise SSLError(e)
|
| 405 |
+
|
| 406 |
+
elif ssl_context is None and hasattr(context, "load_default_certs"):
|
| 407 |
+
# try to load OS default certs; works well on Windows (require Python3.4+)
|
| 408 |
+
context.load_default_certs()
|
| 409 |
+
|
| 410 |
+
# Attempt to detect if we get the goofy behavior of the
|
| 411 |
+
# keyfile being encrypted and OpenSSL asking for the
|
| 412 |
+
# passphrase via the terminal and instead error out.
|
| 413 |
+
if keyfile and key_password is None and _is_key_file_encrypted(keyfile):
|
| 414 |
+
raise SSLError("Client private key is encrypted, password is required")
|
| 415 |
+
|
| 416 |
+
if certfile:
|
| 417 |
+
if key_password is None:
|
| 418 |
+
context.load_cert_chain(certfile, keyfile)
|
| 419 |
+
else:
|
| 420 |
+
context.load_cert_chain(certfile, keyfile, key_password)
|
| 421 |
+
|
| 422 |
+
try:
|
| 423 |
+
if hasattr(context, "set_alpn_protocols"):
|
| 424 |
+
context.set_alpn_protocols(ALPN_PROTOCOLS)
|
| 425 |
+
except NotImplementedError: # Defensive: in CI, we always have set_alpn_protocols
|
| 426 |
+
pass
|
| 427 |
+
|
| 428 |
+
# If we detect server_hostname is an IP address then the SNI
|
| 429 |
+
# extension should not be used according to RFC3546 Section 3.1
|
| 430 |
+
use_sni_hostname = server_hostname and not is_ipaddress(server_hostname)
|
| 431 |
+
# SecureTransport uses server_hostname in certificate verification.
|
| 432 |
+
send_sni = (use_sni_hostname and HAS_SNI) or (
|
| 433 |
+
IS_SECURETRANSPORT and server_hostname
|
| 434 |
+
)
|
| 435 |
+
# Do not warn the user if server_hostname is an invalid SNI hostname.
|
| 436 |
+
if not HAS_SNI and use_sni_hostname:
|
| 437 |
+
warnings.warn(
|
| 438 |
+
"An HTTPS request has been made, but the SNI (Server Name "
|
| 439 |
+
"Indication) extension to TLS is not available on this platform. "
|
| 440 |
+
"This may cause the server to present an incorrect TLS "
|
| 441 |
+
"certificate, which can cause validation failures. You can upgrade to "
|
| 442 |
+
"a newer version of Python to solve this. For more information, see "
|
| 443 |
+
"https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html"
|
| 444 |
+
"#ssl-warnings",
|
| 445 |
+
SNIMissingWarning,
|
| 446 |
+
)
|
| 447 |
+
|
| 448 |
+
if send_sni:
|
| 449 |
+
ssl_sock = _ssl_wrap_socket_impl(
|
| 450 |
+
sock, context, tls_in_tls, server_hostname=server_hostname
|
| 451 |
+
)
|
| 452 |
+
else:
|
| 453 |
+
ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls)
|
| 454 |
+
return ssl_sock
|
| 455 |
+
|
| 456 |
+
|
| 457 |
+
def is_ipaddress(hostname):
|
| 458 |
+
"""Detects whether the hostname given is an IPv4 or IPv6 address.
|
| 459 |
+
Also detects IPv6 addresses with Zone IDs.
|
| 460 |
+
|
| 461 |
+
:param str hostname: Hostname to examine.
|
| 462 |
+
:return: True if the hostname is an IP address, False otherwise.
|
| 463 |
+
"""
|
| 464 |
+
if not six.PY2 and isinstance(hostname, bytes):
|
| 465 |
+
# IDN A-label bytes are ASCII compatible.
|
| 466 |
+
hostname = hostname.decode("ascii")
|
| 467 |
+
return bool(IPV4_RE.match(hostname) or BRACELESS_IPV6_ADDRZ_RE.match(hostname))
|
| 468 |
+
|
| 469 |
+
|
| 470 |
+
def _is_key_file_encrypted(key_file):
|
| 471 |
+
"""Detects if a key file is encrypted or not."""
|
| 472 |
+
with open(key_file, "r") as f:
|
| 473 |
+
for line in f:
|
| 474 |
+
# Look for Proc-Type: 4,ENCRYPTED
|
| 475 |
+
if "ENCRYPTED" in line:
|
| 476 |
+
return True
|
| 477 |
+
|
| 478 |
+
return False
|
| 479 |
+
|
| 480 |
+
|
| 481 |
+
def _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname=None):
|
| 482 |
+
if tls_in_tls:
|
| 483 |
+
if not SSLTransport:
|
| 484 |
+
# Import error, ssl is not available.
|
| 485 |
+
raise ProxySchemeUnsupported(
|
| 486 |
+
"TLS in TLS requires support for the 'ssl' module"
|
| 487 |
+
)
|
| 488 |
+
|
| 489 |
+
SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context)
|
| 490 |
+
return SSLTransport(sock, ssl_context, server_hostname)
|
| 491 |
+
|
| 492 |
+
if server_hostname:
|
| 493 |
+
return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
|
| 494 |
+
else:
|
| 495 |
+
return ssl_context.wrap_socket(sock)
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/ssltransport.py
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import io
|
| 2 |
+
import socket
|
| 3 |
+
import ssl
|
| 4 |
+
|
| 5 |
+
from pip._vendor.urllib3.exceptions import ProxySchemeUnsupported
|
| 6 |
+
from pip._vendor.urllib3.packages import six
|
| 7 |
+
|
| 8 |
+
SSL_BLOCKSIZE = 16384
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class SSLTransport:
|
| 12 |
+
"""
|
| 13 |
+
The SSLTransport wraps an existing socket and establishes an SSL connection.
|
| 14 |
+
|
| 15 |
+
Contrary to Python's implementation of SSLSocket, it allows you to chain
|
| 16 |
+
multiple TLS connections together. It's particularly useful if you need to
|
| 17 |
+
implement TLS within TLS.
|
| 18 |
+
|
| 19 |
+
The class supports most of the socket API operations.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
@staticmethod
|
| 23 |
+
def _validate_ssl_context_for_tls_in_tls(ssl_context):
|
| 24 |
+
"""
|
| 25 |
+
Raises a ProxySchemeUnsupported if the provided ssl_context can't be used
|
| 26 |
+
for TLS in TLS.
|
| 27 |
+
|
| 28 |
+
The only requirement is that the ssl_context provides the 'wrap_bio'
|
| 29 |
+
methods.
|
| 30 |
+
"""
|
| 31 |
+
|
| 32 |
+
if not hasattr(ssl_context, "wrap_bio"):
|
| 33 |
+
if six.PY2:
|
| 34 |
+
raise ProxySchemeUnsupported(
|
| 35 |
+
"TLS in TLS requires SSLContext.wrap_bio() which isn't "
|
| 36 |
+
"supported on Python 2"
|
| 37 |
+
)
|
| 38 |
+
else:
|
| 39 |
+
raise ProxySchemeUnsupported(
|
| 40 |
+
"TLS in TLS requires SSLContext.wrap_bio() which isn't "
|
| 41 |
+
"available on non-native SSLContext"
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
def __init__(
|
| 45 |
+
self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True
|
| 46 |
+
):
|
| 47 |
+
"""
|
| 48 |
+
Create an SSLTransport around socket using the provided ssl_context.
|
| 49 |
+
"""
|
| 50 |
+
self.incoming = ssl.MemoryBIO()
|
| 51 |
+
self.outgoing = ssl.MemoryBIO()
|
| 52 |
+
|
| 53 |
+
self.suppress_ragged_eofs = suppress_ragged_eofs
|
| 54 |
+
self.socket = socket
|
| 55 |
+
|
| 56 |
+
self.sslobj = ssl_context.wrap_bio(
|
| 57 |
+
self.incoming, self.outgoing, server_hostname=server_hostname
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
# Perform initial handshake.
|
| 61 |
+
self._ssl_io_loop(self.sslobj.do_handshake)
|
| 62 |
+
|
| 63 |
+
def __enter__(self):
|
| 64 |
+
return self
|
| 65 |
+
|
| 66 |
+
def __exit__(self, *_):
|
| 67 |
+
self.close()
|
| 68 |
+
|
| 69 |
+
def fileno(self):
|
| 70 |
+
return self.socket.fileno()
|
| 71 |
+
|
| 72 |
+
def read(self, len=1024, buffer=None):
|
| 73 |
+
return self._wrap_ssl_read(len, buffer)
|
| 74 |
+
|
| 75 |
+
def recv(self, len=1024, flags=0):
|
| 76 |
+
if flags != 0:
|
| 77 |
+
raise ValueError("non-zero flags not allowed in calls to recv")
|
| 78 |
+
return self._wrap_ssl_read(len)
|
| 79 |
+
|
| 80 |
+
def recv_into(self, buffer, nbytes=None, flags=0):
|
| 81 |
+
if flags != 0:
|
| 82 |
+
raise ValueError("non-zero flags not allowed in calls to recv_into")
|
| 83 |
+
if buffer and (nbytes is None):
|
| 84 |
+
nbytes = len(buffer)
|
| 85 |
+
elif nbytes is None:
|
| 86 |
+
nbytes = 1024
|
| 87 |
+
return self.read(nbytes, buffer)
|
| 88 |
+
|
| 89 |
+
def sendall(self, data, flags=0):
|
| 90 |
+
if flags != 0:
|
| 91 |
+
raise ValueError("non-zero flags not allowed in calls to sendall")
|
| 92 |
+
count = 0
|
| 93 |
+
with memoryview(data) as view, view.cast("B") as byte_view:
|
| 94 |
+
amount = len(byte_view)
|
| 95 |
+
while count < amount:
|
| 96 |
+
v = self.send(byte_view[count:])
|
| 97 |
+
count += v
|
| 98 |
+
|
| 99 |
+
def send(self, data, flags=0):
|
| 100 |
+
if flags != 0:
|
| 101 |
+
raise ValueError("non-zero flags not allowed in calls to send")
|
| 102 |
+
response = self._ssl_io_loop(self.sslobj.write, data)
|
| 103 |
+
return response
|
| 104 |
+
|
| 105 |
+
def makefile(
|
| 106 |
+
self, mode="r", buffering=None, encoding=None, errors=None, newline=None
|
| 107 |
+
):
|
| 108 |
+
"""
|
| 109 |
+
Python's httpclient uses makefile and buffered io when reading HTTP
|
| 110 |
+
messages and we need to support it.
|
| 111 |
+
|
| 112 |
+
This is unfortunately a copy and paste of socket.py makefile with small
|
| 113 |
+
changes to point to the socket directly.
|
| 114 |
+
"""
|
| 115 |
+
if not set(mode) <= {"r", "w", "b"}:
|
| 116 |
+
raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,))
|
| 117 |
+
|
| 118 |
+
writing = "w" in mode
|
| 119 |
+
reading = "r" in mode or not writing
|
| 120 |
+
assert reading or writing
|
| 121 |
+
binary = "b" in mode
|
| 122 |
+
rawmode = ""
|
| 123 |
+
if reading:
|
| 124 |
+
rawmode += "r"
|
| 125 |
+
if writing:
|
| 126 |
+
rawmode += "w"
|
| 127 |
+
raw = socket.SocketIO(self, rawmode)
|
| 128 |
+
self.socket._io_refs += 1
|
| 129 |
+
if buffering is None:
|
| 130 |
+
buffering = -1
|
| 131 |
+
if buffering < 0:
|
| 132 |
+
buffering = io.DEFAULT_BUFFER_SIZE
|
| 133 |
+
if buffering == 0:
|
| 134 |
+
if not binary:
|
| 135 |
+
raise ValueError("unbuffered streams must be binary")
|
| 136 |
+
return raw
|
| 137 |
+
if reading and writing:
|
| 138 |
+
buffer = io.BufferedRWPair(raw, raw, buffering)
|
| 139 |
+
elif reading:
|
| 140 |
+
buffer = io.BufferedReader(raw, buffering)
|
| 141 |
+
else:
|
| 142 |
+
assert writing
|
| 143 |
+
buffer = io.BufferedWriter(raw, buffering)
|
| 144 |
+
if binary:
|
| 145 |
+
return buffer
|
| 146 |
+
text = io.TextIOWrapper(buffer, encoding, errors, newline)
|
| 147 |
+
text.mode = mode
|
| 148 |
+
return text
|
| 149 |
+
|
| 150 |
+
def unwrap(self):
|
| 151 |
+
self._ssl_io_loop(self.sslobj.unwrap)
|
| 152 |
+
|
| 153 |
+
def close(self):
|
| 154 |
+
self.socket.close()
|
| 155 |
+
|
| 156 |
+
def getpeercert(self, binary_form=False):
|
| 157 |
+
return self.sslobj.getpeercert(binary_form)
|
| 158 |
+
|
| 159 |
+
def version(self):
|
| 160 |
+
return self.sslobj.version()
|
| 161 |
+
|
| 162 |
+
def cipher(self):
|
| 163 |
+
return self.sslobj.cipher()
|
| 164 |
+
|
| 165 |
+
def selected_alpn_protocol(self):
|
| 166 |
+
return self.sslobj.selected_alpn_protocol()
|
| 167 |
+
|
| 168 |
+
def selected_npn_protocol(self):
|
| 169 |
+
return self.sslobj.selected_npn_protocol()
|
| 170 |
+
|
| 171 |
+
def shared_ciphers(self):
|
| 172 |
+
return self.sslobj.shared_ciphers()
|
| 173 |
+
|
| 174 |
+
def compression(self):
|
| 175 |
+
return self.sslobj.compression()
|
| 176 |
+
|
| 177 |
+
def settimeout(self, value):
|
| 178 |
+
self.socket.settimeout(value)
|
| 179 |
+
|
| 180 |
+
def gettimeout(self):
|
| 181 |
+
return self.socket.gettimeout()
|
| 182 |
+
|
| 183 |
+
def _decref_socketios(self):
|
| 184 |
+
self.socket._decref_socketios()
|
| 185 |
+
|
| 186 |
+
def _wrap_ssl_read(self, len, buffer=None):
|
| 187 |
+
try:
|
| 188 |
+
return self._ssl_io_loop(self.sslobj.read, len, buffer)
|
| 189 |
+
except ssl.SSLError as e:
|
| 190 |
+
if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs:
|
| 191 |
+
return 0 # eof, return 0.
|
| 192 |
+
else:
|
| 193 |
+
raise
|
| 194 |
+
|
| 195 |
+
def _ssl_io_loop(self, func, *args):
|
| 196 |
+
"""Performs an I/O loop between incoming/outgoing and the socket."""
|
| 197 |
+
should_loop = True
|
| 198 |
+
ret = None
|
| 199 |
+
|
| 200 |
+
while should_loop:
|
| 201 |
+
errno = None
|
| 202 |
+
try:
|
| 203 |
+
ret = func(*args)
|
| 204 |
+
except ssl.SSLError as e:
|
| 205 |
+
if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE):
|
| 206 |
+
# WANT_READ, and WANT_WRITE are expected, others are not.
|
| 207 |
+
raise e
|
| 208 |
+
errno = e.errno
|
| 209 |
+
|
| 210 |
+
buf = self.outgoing.read()
|
| 211 |
+
self.socket.sendall(buf)
|
| 212 |
+
|
| 213 |
+
if errno is None:
|
| 214 |
+
should_loop = False
|
| 215 |
+
elif errno == ssl.SSL_ERROR_WANT_READ:
|
| 216 |
+
buf = self.socket.recv(SSL_BLOCKSIZE)
|
| 217 |
+
if buf:
|
| 218 |
+
self.incoming.write(buf)
|
| 219 |
+
else:
|
| 220 |
+
self.incoming.write_eof()
|
| 221 |
+
return ret
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/timeout.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import time
|
| 4 |
+
|
| 5 |
+
# The default socket timeout, used by httplib to indicate that no timeout was
|
| 6 |
+
# specified by the user
|
| 7 |
+
from socket import _GLOBAL_DEFAULT_TIMEOUT
|
| 8 |
+
|
| 9 |
+
from ..exceptions import TimeoutStateError
|
| 10 |
+
|
| 11 |
+
# A sentinel value to indicate that no timeout was specified by the user in
|
| 12 |
+
# urllib3
|
| 13 |
+
_Default = object()
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
# Use time.monotonic if available.
|
| 17 |
+
current_time = getattr(time, "monotonic", time.time)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class Timeout(object):
|
| 21 |
+
"""Timeout configuration.
|
| 22 |
+
|
| 23 |
+
Timeouts can be defined as a default for a pool:
|
| 24 |
+
|
| 25 |
+
.. code-block:: python
|
| 26 |
+
|
| 27 |
+
timeout = Timeout(connect=2.0, read=7.0)
|
| 28 |
+
http = PoolManager(timeout=timeout)
|
| 29 |
+
response = http.request('GET', 'http://example.com/')
|
| 30 |
+
|
| 31 |
+
Or per-request (which overrides the default for the pool):
|
| 32 |
+
|
| 33 |
+
.. code-block:: python
|
| 34 |
+
|
| 35 |
+
response = http.request('GET', 'http://example.com/', timeout=Timeout(10))
|
| 36 |
+
|
| 37 |
+
Timeouts can be disabled by setting all the parameters to ``None``:
|
| 38 |
+
|
| 39 |
+
.. code-block:: python
|
| 40 |
+
|
| 41 |
+
no_timeout = Timeout(connect=None, read=None)
|
| 42 |
+
response = http.request('GET', 'http://example.com/, timeout=no_timeout)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
:param total:
|
| 46 |
+
This combines the connect and read timeouts into one; the read timeout
|
| 47 |
+
will be set to the time leftover from the connect attempt. In the
|
| 48 |
+
event that both a connect timeout and a total are specified, or a read
|
| 49 |
+
timeout and a total are specified, the shorter timeout will be applied.
|
| 50 |
+
|
| 51 |
+
Defaults to None.
|
| 52 |
+
|
| 53 |
+
:type total: int, float, or None
|
| 54 |
+
|
| 55 |
+
:param connect:
|
| 56 |
+
The maximum amount of time (in seconds) to wait for a connection
|
| 57 |
+
attempt to a server to succeed. Omitting the parameter will default the
|
| 58 |
+
connect timeout to the system default, probably `the global default
|
| 59 |
+
timeout in socket.py
|
| 60 |
+
<http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_.
|
| 61 |
+
None will set an infinite timeout for connection attempts.
|
| 62 |
+
|
| 63 |
+
:type connect: int, float, or None
|
| 64 |
+
|
| 65 |
+
:param read:
|
| 66 |
+
The maximum amount of time (in seconds) to wait between consecutive
|
| 67 |
+
read operations for a response from the server. Omitting the parameter
|
| 68 |
+
will default the read timeout to the system default, probably `the
|
| 69 |
+
global default timeout in socket.py
|
| 70 |
+
<http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_.
|
| 71 |
+
None will set an infinite timeout.
|
| 72 |
+
|
| 73 |
+
:type read: int, float, or None
|
| 74 |
+
|
| 75 |
+
.. note::
|
| 76 |
+
|
| 77 |
+
Many factors can affect the total amount of time for urllib3 to return
|
| 78 |
+
an HTTP response.
|
| 79 |
+
|
| 80 |
+
For example, Python's DNS resolver does not obey the timeout specified
|
| 81 |
+
on the socket. Other factors that can affect total request time include
|
| 82 |
+
high CPU load, high swap, the program running at a low priority level,
|
| 83 |
+
or other behaviors.
|
| 84 |
+
|
| 85 |
+
In addition, the read and total timeouts only measure the time between
|
| 86 |
+
read operations on the socket connecting the client and the server,
|
| 87 |
+
not the total amount of time for the request to return a complete
|
| 88 |
+
response. For most requests, the timeout is raised because the server
|
| 89 |
+
has not sent the first byte in the specified time. This is not always
|
| 90 |
+
the case; if a server streams one byte every fifteen seconds, a timeout
|
| 91 |
+
of 20 seconds will not trigger, even though the request will take
|
| 92 |
+
several minutes to complete.
|
| 93 |
+
|
| 94 |
+
If your goal is to cut off any request after a set amount of wall clock
|
| 95 |
+
time, consider having a second "watcher" thread to cut off a slow
|
| 96 |
+
request.
|
| 97 |
+
"""
|
| 98 |
+
|
| 99 |
+
#: A sentinel object representing the default timeout value
|
| 100 |
+
DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT
|
| 101 |
+
|
| 102 |
+
def __init__(self, total=None, connect=_Default, read=_Default):
|
| 103 |
+
self._connect = self._validate_timeout(connect, "connect")
|
| 104 |
+
self._read = self._validate_timeout(read, "read")
|
| 105 |
+
self.total = self._validate_timeout(total, "total")
|
| 106 |
+
self._start_connect = None
|
| 107 |
+
|
| 108 |
+
def __repr__(self):
|
| 109 |
+
return "%s(connect=%r, read=%r, total=%r)" % (
|
| 110 |
+
type(self).__name__,
|
| 111 |
+
self._connect,
|
| 112 |
+
self._read,
|
| 113 |
+
self.total,
|
| 114 |
+
)
|
| 115 |
+
|
| 116 |
+
# __str__ provided for backwards compatibility
|
| 117 |
+
__str__ = __repr__
|
| 118 |
+
|
| 119 |
+
@classmethod
|
| 120 |
+
def _validate_timeout(cls, value, name):
|
| 121 |
+
"""Check that a timeout attribute is valid.
|
| 122 |
+
|
| 123 |
+
:param value: The timeout value to validate
|
| 124 |
+
:param name: The name of the timeout attribute to validate. This is
|
| 125 |
+
used to specify in error messages.
|
| 126 |
+
:return: The validated and casted version of the given value.
|
| 127 |
+
:raises ValueError: If it is a numeric value less than or equal to
|
| 128 |
+
zero, or the type is not an integer, float, or None.
|
| 129 |
+
"""
|
| 130 |
+
if value is _Default:
|
| 131 |
+
return cls.DEFAULT_TIMEOUT
|
| 132 |
+
|
| 133 |
+
if value is None or value is cls.DEFAULT_TIMEOUT:
|
| 134 |
+
return value
|
| 135 |
+
|
| 136 |
+
if isinstance(value, bool):
|
| 137 |
+
raise ValueError(
|
| 138 |
+
"Timeout cannot be a boolean value. It must "
|
| 139 |
+
"be an int, float or None."
|
| 140 |
+
)
|
| 141 |
+
try:
|
| 142 |
+
float(value)
|
| 143 |
+
except (TypeError, ValueError):
|
| 144 |
+
raise ValueError(
|
| 145 |
+
"Timeout value %s was %s, but it must be an "
|
| 146 |
+
"int, float or None." % (name, value)
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
try:
|
| 150 |
+
if value <= 0:
|
| 151 |
+
raise ValueError(
|
| 152 |
+
"Attempted to set %s timeout to %s, but the "
|
| 153 |
+
"timeout cannot be set to a value less "
|
| 154 |
+
"than or equal to 0." % (name, value)
|
| 155 |
+
)
|
| 156 |
+
except TypeError:
|
| 157 |
+
# Python 3
|
| 158 |
+
raise ValueError(
|
| 159 |
+
"Timeout value %s was %s, but it must be an "
|
| 160 |
+
"int, float or None." % (name, value)
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
+
return value
|
| 164 |
+
|
| 165 |
+
@classmethod
|
| 166 |
+
def from_float(cls, timeout):
|
| 167 |
+
"""Create a new Timeout from a legacy timeout value.
|
| 168 |
+
|
| 169 |
+
The timeout value used by httplib.py sets the same timeout on the
|
| 170 |
+
connect(), and recv() socket requests. This creates a :class:`Timeout`
|
| 171 |
+
object that sets the individual timeouts to the ``timeout`` value
|
| 172 |
+
passed to this function.
|
| 173 |
+
|
| 174 |
+
:param timeout: The legacy timeout value.
|
| 175 |
+
:type timeout: integer, float, sentinel default object, or None
|
| 176 |
+
:return: Timeout object
|
| 177 |
+
:rtype: :class:`Timeout`
|
| 178 |
+
"""
|
| 179 |
+
return Timeout(read=timeout, connect=timeout)
|
| 180 |
+
|
| 181 |
+
def clone(self):
|
| 182 |
+
"""Create a copy of the timeout object
|
| 183 |
+
|
| 184 |
+
Timeout properties are stored per-pool but each request needs a fresh
|
| 185 |
+
Timeout object to ensure each one has its own start/stop configured.
|
| 186 |
+
|
| 187 |
+
:return: a copy of the timeout object
|
| 188 |
+
:rtype: :class:`Timeout`
|
| 189 |
+
"""
|
| 190 |
+
# We can't use copy.deepcopy because that will also create a new object
|
| 191 |
+
# for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to
|
| 192 |
+
# detect the user default.
|
| 193 |
+
return Timeout(connect=self._connect, read=self._read, total=self.total)
|
| 194 |
+
|
| 195 |
+
def start_connect(self):
|
| 196 |
+
"""Start the timeout clock, used during a connect() attempt
|
| 197 |
+
|
| 198 |
+
:raises urllib3.exceptions.TimeoutStateError: if you attempt
|
| 199 |
+
to start a timer that has been started already.
|
| 200 |
+
"""
|
| 201 |
+
if self._start_connect is not None:
|
| 202 |
+
raise TimeoutStateError("Timeout timer has already been started.")
|
| 203 |
+
self._start_connect = current_time()
|
| 204 |
+
return self._start_connect
|
| 205 |
+
|
| 206 |
+
def get_connect_duration(self):
|
| 207 |
+
"""Gets the time elapsed since the call to :meth:`start_connect`.
|
| 208 |
+
|
| 209 |
+
:return: Elapsed time in seconds.
|
| 210 |
+
:rtype: float
|
| 211 |
+
:raises urllib3.exceptions.TimeoutStateError: if you attempt
|
| 212 |
+
to get duration for a timer that hasn't been started.
|
| 213 |
+
"""
|
| 214 |
+
if self._start_connect is None:
|
| 215 |
+
raise TimeoutStateError(
|
| 216 |
+
"Can't get connect duration for timer that has not started."
|
| 217 |
+
)
|
| 218 |
+
return current_time() - self._start_connect
|
| 219 |
+
|
| 220 |
+
@property
|
| 221 |
+
def connect_timeout(self):
|
| 222 |
+
"""Get the value to use when setting a connection timeout.
|
| 223 |
+
|
| 224 |
+
This will be a positive float or integer, the value None
|
| 225 |
+
(never timeout), or the default system timeout.
|
| 226 |
+
|
| 227 |
+
:return: Connect timeout.
|
| 228 |
+
:rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
|
| 229 |
+
"""
|
| 230 |
+
if self.total is None:
|
| 231 |
+
return self._connect
|
| 232 |
+
|
| 233 |
+
if self._connect is None or self._connect is self.DEFAULT_TIMEOUT:
|
| 234 |
+
return self.total
|
| 235 |
+
|
| 236 |
+
return min(self._connect, self.total)
|
| 237 |
+
|
| 238 |
+
@property
|
| 239 |
+
def read_timeout(self):
|
| 240 |
+
"""Get the value for the read timeout.
|
| 241 |
+
|
| 242 |
+
This assumes some time has elapsed in the connection timeout and
|
| 243 |
+
computes the read timeout appropriately.
|
| 244 |
+
|
| 245 |
+
If self.total is set, the read timeout is dependent on the amount of
|
| 246 |
+
time taken by the connect timeout. If the connection time has not been
|
| 247 |
+
established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be
|
| 248 |
+
raised.
|
| 249 |
+
|
| 250 |
+
:return: Value to use for the read timeout.
|
| 251 |
+
:rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
|
| 252 |
+
:raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect`
|
| 253 |
+
has not yet been called on this object.
|
| 254 |
+
"""
|
| 255 |
+
if (
|
| 256 |
+
self.total is not None
|
| 257 |
+
and self.total is not self.DEFAULT_TIMEOUT
|
| 258 |
+
and self._read is not None
|
| 259 |
+
and self._read is not self.DEFAULT_TIMEOUT
|
| 260 |
+
):
|
| 261 |
+
# In case the connect timeout has not yet been established.
|
| 262 |
+
if self._start_connect is None:
|
| 263 |
+
return self._read
|
| 264 |
+
return max(0, min(self.total - self.get_connect_duration(), self._read))
|
| 265 |
+
elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT:
|
| 266 |
+
return max(0, self.total - self.get_connect_duration())
|
| 267 |
+
else:
|
| 268 |
+
return self._read
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/url.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import absolute_import
|
| 2 |
+
|
| 3 |
+
import re
|
| 4 |
+
from collections import namedtuple
|
| 5 |
+
|
| 6 |
+
from ..exceptions import LocationParseError
|
| 7 |
+
from ..packages import six
|
| 8 |
+
|
| 9 |
+
url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"]
|
| 10 |
+
|
| 11 |
+
# We only want to normalize urls with an HTTP(S) scheme.
|
| 12 |
+
# urllib3 infers URLs without a scheme (None) to be http.
|
| 13 |
+
NORMALIZABLE_SCHEMES = ("http", "https", None)
|
| 14 |
+
|
| 15 |
+
# Almost all of these patterns were derived from the
|
| 16 |
+
# 'rfc3986' module: https://github.com/python-hyper/rfc3986
|
| 17 |
+
PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}")
|
| 18 |
+
SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)")
|
| 19 |
+
URI_RE = re.compile(
|
| 20 |
+
r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?"
|
| 21 |
+
r"(?://([^\\/?#]*))?"
|
| 22 |
+
r"([^?#]*)"
|
| 23 |
+
r"(?:\?([^#]*))?"
|
| 24 |
+
r"(?:#(.*))?$",
|
| 25 |
+
re.UNICODE | re.DOTALL,
|
| 26 |
+
)
|
| 27 |
+
|
| 28 |
+
IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}"
|
| 29 |
+
HEX_PAT = "[0-9A-Fa-f]{1,4}"
|
| 30 |
+
LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT)
|
| 31 |
+
_subs = {"hex": HEX_PAT, "ls32": LS32_PAT}
|
| 32 |
+
_variations = [
|
| 33 |
+
# 6( h16 ":" ) ls32
|
| 34 |
+
"(?:%(hex)s:){6}%(ls32)s",
|
| 35 |
+
# "::" 5( h16 ":" ) ls32
|
| 36 |
+
"::(?:%(hex)s:){5}%(ls32)s",
|
| 37 |
+
# [ h16 ] "::" 4( h16 ":" ) ls32
|
| 38 |
+
"(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s",
|
| 39 |
+
# [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
|
| 40 |
+
"(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s",
|
| 41 |
+
# [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
|
| 42 |
+
"(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s",
|
| 43 |
+
# [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
|
| 44 |
+
"(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s",
|
| 45 |
+
# [ *4( h16 ":" ) h16 ] "::" ls32
|
| 46 |
+
"(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s",
|
| 47 |
+
# [ *5( h16 ":" ) h16 ] "::" h16
|
| 48 |
+
"(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s",
|
| 49 |
+
# [ *6( h16 ":" ) h16 ] "::"
|
| 50 |
+
"(?:(?:%(hex)s:){0,6}%(hex)s)?::",
|
| 51 |
+
]
|
| 52 |
+
|
| 53 |
+
UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._!\-~"
|
| 54 |
+
IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")"
|
| 55 |
+
ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+"
|
| 56 |
+
IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]"
|
| 57 |
+
REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*"
|
| 58 |
+
TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$")
|
| 59 |
+
|
| 60 |
+
IPV4_RE = re.compile("^" + IPV4_PAT + "$")
|
| 61 |
+
IPV6_RE = re.compile("^" + IPV6_PAT + "$")
|
| 62 |
+
IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$")
|
| 63 |
+
BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$")
|
| 64 |
+
ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$")
|
| 65 |
+
|
| 66 |
+
_HOST_PORT_PAT = ("^(%s|%s|%s)(?::([0-9]{0,5}))?$") % (
|
| 67 |
+
REG_NAME_PAT,
|
| 68 |
+
IPV4_PAT,
|
| 69 |
+
IPV6_ADDRZ_PAT,
|
| 70 |
+
)
|
| 71 |
+
_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL)
|
| 72 |
+
|
| 73 |
+
UNRESERVED_CHARS = set(
|
| 74 |
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~"
|
| 75 |
+
)
|
| 76 |
+
SUB_DELIM_CHARS = set("!$&'()*+,;=")
|
| 77 |
+
USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"}
|
| 78 |
+
PATH_CHARS = USERINFO_CHARS | {"@", "/"}
|
| 79 |
+
QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"}
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
class Url(namedtuple("Url", url_attrs)):
|
| 83 |
+
"""
|
| 84 |
+
Data structure for representing an HTTP URL. Used as a return value for
|
| 85 |
+
:func:`parse_url`. Both the scheme and host are normalized as they are
|
| 86 |
+
both case-insensitive according to RFC 3986.
|
| 87 |
+
"""
|
| 88 |
+
|
| 89 |
+
__slots__ = ()
|
| 90 |
+
|
| 91 |
+
def __new__(
|
| 92 |
+
cls,
|
| 93 |
+
scheme=None,
|
| 94 |
+
auth=None,
|
| 95 |
+
host=None,
|
| 96 |
+
port=None,
|
| 97 |
+
path=None,
|
| 98 |
+
query=None,
|
| 99 |
+
fragment=None,
|
| 100 |
+
):
|
| 101 |
+
if path and not path.startswith("/"):
|
| 102 |
+
path = "/" + path
|
| 103 |
+
if scheme is not None:
|
| 104 |
+
scheme = scheme.lower()
|
| 105 |
+
return super(Url, cls).__new__(
|
| 106 |
+
cls, scheme, auth, host, port, path, query, fragment
|
| 107 |
+
)
|
| 108 |
+
|
| 109 |
+
@property
|
| 110 |
+
def hostname(self):
|
| 111 |
+
"""For backwards-compatibility with urlparse. We're nice like that."""
|
| 112 |
+
return self.host
|
| 113 |
+
|
| 114 |
+
@property
|
| 115 |
+
def request_uri(self):
|
| 116 |
+
"""Absolute path including the query string."""
|
| 117 |
+
uri = self.path or "/"
|
| 118 |
+
|
| 119 |
+
if self.query is not None:
|
| 120 |
+
uri += "?" + self.query
|
| 121 |
+
|
| 122 |
+
return uri
|
| 123 |
+
|
| 124 |
+
@property
|
| 125 |
+
def netloc(self):
|
| 126 |
+
"""Network location including host and port"""
|
| 127 |
+
if self.port:
|
| 128 |
+
return "%s:%d" % (self.host, self.port)
|
| 129 |
+
return self.host
|
| 130 |
+
|
| 131 |
+
@property
|
| 132 |
+
def url(self):
|
| 133 |
+
"""
|
| 134 |
+
Convert self into a url
|
| 135 |
+
|
| 136 |
+
This function should more or less round-trip with :func:`.parse_url`. The
|
| 137 |
+
returned url may not be exactly the same as the url inputted to
|
| 138 |
+
:func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls
|
| 139 |
+
with a blank port will have : removed).
|
| 140 |
+
|
| 141 |
+
Example: ::
|
| 142 |
+
|
| 143 |
+
>>> U = parse_url('http://google.com/mail/')
|
| 144 |
+
>>> U.url
|
| 145 |
+
'http://google.com/mail/'
|
| 146 |
+
>>> Url('http', 'username:password', 'host.com', 80,
|
| 147 |
+
... '/path', 'query', 'fragment').url
|
| 148 |
+
'http://username:password@host.com:80/path?query#fragment'
|
| 149 |
+
"""
|
| 150 |
+
scheme, auth, host, port, path, query, fragment = self
|
| 151 |
+
url = u""
|
| 152 |
+
|
| 153 |
+
# We use "is not None" we want things to happen with empty strings (or 0 port)
|
| 154 |
+
if scheme is not None:
|
| 155 |
+
url += scheme + u"://"
|
| 156 |
+
if auth is not None:
|
| 157 |
+
url += auth + u"@"
|
| 158 |
+
if host is not None:
|
| 159 |
+
url += host
|
| 160 |
+
if port is not None:
|
| 161 |
+
url += u":" + str(port)
|
| 162 |
+
if path is not None:
|
| 163 |
+
url += path
|
| 164 |
+
if query is not None:
|
| 165 |
+
url += u"?" + query
|
| 166 |
+
if fragment is not None:
|
| 167 |
+
url += u"#" + fragment
|
| 168 |
+
|
| 169 |
+
return url
|
| 170 |
+
|
| 171 |
+
def __str__(self):
|
| 172 |
+
return self.url
|
| 173 |
+
|
| 174 |
+
|
| 175 |
+
def split_first(s, delims):
|
| 176 |
+
"""
|
| 177 |
+
.. deprecated:: 1.25
|
| 178 |
+
|
| 179 |
+
Given a string and an iterable of delimiters, split on the first found
|
| 180 |
+
delimiter. Return two split parts and the matched delimiter.
|
| 181 |
+
|
| 182 |
+
If not found, then the first part is the full input string.
|
| 183 |
+
|
| 184 |
+
Example::
|
| 185 |
+
|
| 186 |
+
>>> split_first('foo/bar?baz', '?/=')
|
| 187 |
+
('foo', 'bar?baz', '/')
|
| 188 |
+
>>> split_first('foo/bar?baz', '123')
|
| 189 |
+
('foo/bar?baz', '', None)
|
| 190 |
+
|
| 191 |
+
Scales linearly with number of delims. Not ideal for large number of delims.
|
| 192 |
+
"""
|
| 193 |
+
min_idx = None
|
| 194 |
+
min_delim = None
|
| 195 |
+
for d in delims:
|
| 196 |
+
idx = s.find(d)
|
| 197 |
+
if idx < 0:
|
| 198 |
+
continue
|
| 199 |
+
|
| 200 |
+
if min_idx is None or idx < min_idx:
|
| 201 |
+
min_idx = idx
|
| 202 |
+
min_delim = d
|
| 203 |
+
|
| 204 |
+
if min_idx is None or min_idx < 0:
|
| 205 |
+
return s, "", None
|
| 206 |
+
|
| 207 |
+
return s[:min_idx], s[min_idx + 1 :], min_delim
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def _encode_invalid_chars(component, allowed_chars, encoding="utf-8"):
|
| 211 |
+
"""Percent-encodes a URI component without reapplying
|
| 212 |
+
onto an already percent-encoded component.
|
| 213 |
+
"""
|
| 214 |
+
if component is None:
|
| 215 |
+
return component
|
| 216 |
+
|
| 217 |
+
component = six.ensure_text(component)
|
| 218 |
+
|
| 219 |
+
# Normalize existing percent-encoded bytes.
|
| 220 |
+
# Try to see if the component we're encoding is already percent-encoded
|
| 221 |
+
# so we can skip all '%' characters but still encode all others.
|
| 222 |
+
component, percent_encodings = PERCENT_RE.subn(
|
| 223 |
+
lambda match: match.group(0).upper(), component
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
uri_bytes = component.encode("utf-8", "surrogatepass")
|
| 227 |
+
is_percent_encoded = percent_encodings == uri_bytes.count(b"%")
|
| 228 |
+
encoded_component = bytearray()
|
| 229 |
+
|
| 230 |
+
for i in range(0, len(uri_bytes)):
|
| 231 |
+
# Will return a single character bytestring on both Python 2 & 3
|
| 232 |
+
byte = uri_bytes[i : i + 1]
|
| 233 |
+
byte_ord = ord(byte)
|
| 234 |
+
if (is_percent_encoded and byte == b"%") or (
|
| 235 |
+
byte_ord < 128 and byte.decode() in allowed_chars
|
| 236 |
+
):
|
| 237 |
+
encoded_component += byte
|
| 238 |
+
continue
|
| 239 |
+
encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper()))
|
| 240 |
+
|
| 241 |
+
return encoded_component.decode(encoding)
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
def _remove_path_dot_segments(path):
|
| 245 |
+
# See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code
|
| 246 |
+
segments = path.split("/") # Turn the path into a list of segments
|
| 247 |
+
output = [] # Initialize the variable to use to store output
|
| 248 |
+
|
| 249 |
+
for segment in segments:
|
| 250 |
+
# '.' is the current directory, so ignore it, it is superfluous
|
| 251 |
+
if segment == ".":
|
| 252 |
+
continue
|
| 253 |
+
# Anything other than '..', should be appended to the output
|
| 254 |
+
elif segment != "..":
|
| 255 |
+
output.append(segment)
|
| 256 |
+
# In this case segment == '..', if we can, we should pop the last
|
| 257 |
+
# element
|
| 258 |
+
elif output:
|
| 259 |
+
output.pop()
|
| 260 |
+
|
| 261 |
+
# If the path starts with '/' and the output is empty or the first string
|
| 262 |
+
# is non-empty
|
| 263 |
+
if path.startswith("/") and (not output or output[0]):
|
| 264 |
+
output.insert(0, "")
|
| 265 |
+
|
| 266 |
+
# If the path starts with '/.' or '/..' ensure we add one more empty
|
| 267 |
+
# string to add a trailing '/'
|
| 268 |
+
if path.endswith(("/.", "/..")):
|
| 269 |
+
output.append("")
|
| 270 |
+
|
| 271 |
+
return "/".join(output)
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
def _normalize_host(host, scheme):
|
| 275 |
+
if host:
|
| 276 |
+
if isinstance(host, six.binary_type):
|
| 277 |
+
host = six.ensure_str(host)
|
| 278 |
+
|
| 279 |
+
if scheme in NORMALIZABLE_SCHEMES:
|
| 280 |
+
is_ipv6 = IPV6_ADDRZ_RE.match(host)
|
| 281 |
+
if is_ipv6:
|
| 282 |
+
match = ZONE_ID_RE.search(host)
|
| 283 |
+
if match:
|
| 284 |
+
start, end = match.span(1)
|
| 285 |
+
zone_id = host[start:end]
|
| 286 |
+
|
| 287 |
+
if zone_id.startswith("%25") and zone_id != "%25":
|
| 288 |
+
zone_id = zone_id[3:]
|
| 289 |
+
else:
|
| 290 |
+
zone_id = zone_id[1:]
|
| 291 |
+
zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS)
|
| 292 |
+
return host[:start].lower() + zone_id + host[end:]
|
| 293 |
+
else:
|
| 294 |
+
return host.lower()
|
| 295 |
+
elif not IPV4_RE.match(host):
|
| 296 |
+
return six.ensure_str(
|
| 297 |
+
b".".join([_idna_encode(label) for label in host.split(".")])
|
| 298 |
+
)
|
| 299 |
+
return host
|
| 300 |
+
|
| 301 |
+
|
| 302 |
+
def _idna_encode(name):
|
| 303 |
+
if name and any([ord(x) > 128 for x in name]):
|
| 304 |
+
try:
|
| 305 |
+
from pip._vendor import idna
|
| 306 |
+
except ImportError:
|
| 307 |
+
six.raise_from(
|
| 308 |
+
LocationParseError("Unable to parse URL without the 'idna' module"),
|
| 309 |
+
None,
|
| 310 |
+
)
|
| 311 |
+
try:
|
| 312 |
+
return idna.encode(name.lower(), strict=True, std3_rules=True)
|
| 313 |
+
except idna.IDNAError:
|
| 314 |
+
six.raise_from(
|
| 315 |
+
LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None
|
| 316 |
+
)
|
| 317 |
+
return name.lower().encode("ascii")
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
def _encode_target(target):
|
| 321 |
+
"""Percent-encodes a request target so that there are no invalid characters"""
|
| 322 |
+
path, query = TARGET_RE.match(target).groups()
|
| 323 |
+
target = _encode_invalid_chars(path, PATH_CHARS)
|
| 324 |
+
query = _encode_invalid_chars(query, QUERY_CHARS)
|
| 325 |
+
if query is not None:
|
| 326 |
+
target += "?" + query
|
| 327 |
+
return target
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
def parse_url(url):
|
| 331 |
+
"""
|
| 332 |
+
Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
|
| 333 |
+
performed to parse incomplete urls. Fields not provided will be None.
|
| 334 |
+
This parser is RFC 3986 compliant.
|
| 335 |
+
|
| 336 |
+
The parser logic and helper functions are based heavily on
|
| 337 |
+
work done in the ``rfc3986`` module.
|
| 338 |
+
|
| 339 |
+
:param str url: URL to parse into a :class:`.Url` namedtuple.
|
| 340 |
+
|
| 341 |
+
Partly backwards-compatible with :mod:`urlparse`.
|
| 342 |
+
|
| 343 |
+
Example::
|
| 344 |
+
|
| 345 |
+
>>> parse_url('http://google.com/mail/')
|
| 346 |
+
Url(scheme='http', host='google.com', port=None, path='/mail/', ...)
|
| 347 |
+
>>> parse_url('google.com:80')
|
| 348 |
+
Url(scheme=None, host='google.com', port=80, path=None, ...)
|
| 349 |
+
>>> parse_url('/foo?bar')
|
| 350 |
+
Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...)
|
| 351 |
+
"""
|
| 352 |
+
if not url:
|
| 353 |
+
# Empty
|
| 354 |
+
return Url()
|
| 355 |
+
|
| 356 |
+
source_url = url
|
| 357 |
+
if not SCHEME_RE.search(url):
|
| 358 |
+
url = "//" + url
|
| 359 |
+
|
| 360 |
+
try:
|
| 361 |
+
scheme, authority, path, query, fragment = URI_RE.match(url).groups()
|
| 362 |
+
normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES
|
| 363 |
+
|
| 364 |
+
if scheme:
|
| 365 |
+
scheme = scheme.lower()
|
| 366 |
+
|
| 367 |
+
if authority:
|
| 368 |
+
auth, _, host_port = authority.rpartition("@")
|
| 369 |
+
auth = auth or None
|
| 370 |
+
host, port = _HOST_PORT_RE.match(host_port).groups()
|
| 371 |
+
if auth and normalize_uri:
|
| 372 |
+
auth = _encode_invalid_chars(auth, USERINFO_CHARS)
|
| 373 |
+
if port == "":
|
| 374 |
+
port = None
|
| 375 |
+
else:
|
| 376 |
+
auth, host, port = None, None, None
|
| 377 |
+
|
| 378 |
+
if port is not None:
|
| 379 |
+
port = int(port)
|
| 380 |
+
if not (0 <= port <= 65535):
|
| 381 |
+
raise LocationParseError(url)
|
| 382 |
+
|
| 383 |
+
host = _normalize_host(host, scheme)
|
| 384 |
+
|
| 385 |
+
if normalize_uri and path:
|
| 386 |
+
path = _remove_path_dot_segments(path)
|
| 387 |
+
path = _encode_invalid_chars(path, PATH_CHARS)
|
| 388 |
+
if normalize_uri and query:
|
| 389 |
+
query = _encode_invalid_chars(query, QUERY_CHARS)
|
| 390 |
+
if normalize_uri and fragment:
|
| 391 |
+
fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS)
|
| 392 |
+
|
| 393 |
+
except (ValueError, AttributeError):
|
| 394 |
+
return six.raise_from(LocationParseError(source_url), None)
|
| 395 |
+
|
| 396 |
+
# For the sake of backwards compatibility we put empty
|
| 397 |
+
# string values for path if there are any defined values
|
| 398 |
+
# beyond the path in the URL.
|
| 399 |
+
# TODO: Remove this when we break backwards compatibility.
|
| 400 |
+
if not path:
|
| 401 |
+
if query is not None or fragment is not None:
|
| 402 |
+
path = ""
|
| 403 |
+
else:
|
| 404 |
+
path = None
|
| 405 |
+
|
| 406 |
+
# Ensure that each part of the URL is a `str` for
|
| 407 |
+
# backwards compatibility.
|
| 408 |
+
if isinstance(url, six.text_type):
|
| 409 |
+
ensure_func = six.ensure_text
|
| 410 |
+
else:
|
| 411 |
+
ensure_func = six.ensure_str
|
| 412 |
+
|
| 413 |
+
def ensure_type(x):
|
| 414 |
+
return x if x is None else ensure_func(x)
|
| 415 |
+
|
| 416 |
+
return Url(
|
| 417 |
+
scheme=ensure_type(scheme),
|
| 418 |
+
auth=ensure_type(auth),
|
| 419 |
+
host=ensure_type(host),
|
| 420 |
+
port=port,
|
| 421 |
+
path=ensure_type(path),
|
| 422 |
+
query=ensure_type(query),
|
| 423 |
+
fragment=ensure_type(fragment),
|
| 424 |
+
)
|
| 425 |
+
|
| 426 |
+
|
| 427 |
+
def get_host(url):
|
| 428 |
+
"""
|
| 429 |
+
Deprecated. Use :func:`parse_url` instead.
|
| 430 |
+
"""
|
| 431 |
+
p = parse_url(url)
|
| 432 |
+
return p.scheme or "http", p.hostname, p.port
|
astra_scene_test/Scene_04/.venv/lib/python3.9/site-packages/pip/_vendor/urllib3/util/wait.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import errno
|
| 2 |
+
import select
|
| 3 |
+
import sys
|
| 4 |
+
from functools import partial
|
| 5 |
+
|
| 6 |
+
try:
|
| 7 |
+
from time import monotonic
|
| 8 |
+
except ImportError:
|
| 9 |
+
from time import time as monotonic
|
| 10 |
+
|
| 11 |
+
__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"]
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
class NoWayToWaitForSocketError(Exception):
|
| 15 |
+
pass
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
# How should we wait on sockets?
|
| 19 |
+
#
|
| 20 |
+
# There are two types of APIs you can use for waiting on sockets: the fancy
|
| 21 |
+
# modern stateful APIs like epoll/kqueue, and the older stateless APIs like
|
| 22 |
+
# select/poll. The stateful APIs are more efficient when you have a lots of
|
| 23 |
+
# sockets to keep track of, because you can set them up once and then use them
|
| 24 |
+
# lots of times. But we only ever want to wait on a single socket at a time
|
| 25 |
+
# and don't want to keep track of state, so the stateless APIs are actually
|
| 26 |
+
# more efficient. So we want to use select() or poll().
|
| 27 |
+
#
|
| 28 |
+
# Now, how do we choose between select() and poll()? On traditional Unixes,
|
| 29 |
+
# select() has a strange calling convention that makes it slow, or fail
|
| 30 |
+
# altogether, for high-numbered file descriptors. The point of poll() is to fix
|
| 31 |
+
# that, so on Unixes, we prefer poll().
|
| 32 |
+
#
|
| 33 |
+
# On Windows, there is no poll() (or at least Python doesn't provide a wrapper
|
| 34 |
+
# for it), but that's OK, because on Windows, select() doesn't have this
|
| 35 |
+
# strange calling convention; plain select() works fine.
|
| 36 |
+
#
|
| 37 |
+
# So: on Windows we use select(), and everywhere else we use poll(). We also
|
| 38 |
+
# fall back to select() in case poll() is somehow broken or missing.
|
| 39 |
+
|
| 40 |
+
if sys.version_info >= (3, 5):
|
| 41 |
+
# Modern Python, that retries syscalls by default
|
| 42 |
+
def _retry_on_intr(fn, timeout):
|
| 43 |
+
return fn(timeout)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
else:
|
| 47 |
+
# Old and broken Pythons.
|
| 48 |
+
def _retry_on_intr(fn, timeout):
|
| 49 |
+
if timeout is None:
|
| 50 |
+
deadline = float("inf")
|
| 51 |
+
else:
|
| 52 |
+
deadline = monotonic() + timeout
|
| 53 |
+
|
| 54 |
+
while True:
|
| 55 |
+
try:
|
| 56 |
+
return fn(timeout)
|
| 57 |
+
# OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7
|
| 58 |
+
except (OSError, select.error) as e:
|
| 59 |
+
# 'e.args[0]' incantation works for both OSError and select.error
|
| 60 |
+
if e.args[0] != errno.EINTR:
|
| 61 |
+
raise
|
| 62 |
+
else:
|
| 63 |
+
timeout = deadline - monotonic()
|
| 64 |
+
if timeout < 0:
|
| 65 |
+
timeout = 0
|
| 66 |
+
if timeout == float("inf"):
|
| 67 |
+
timeout = None
|
| 68 |
+
continue
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def select_wait_for_socket(sock, read=False, write=False, timeout=None):
|
| 72 |
+
if not read and not write:
|
| 73 |
+
raise RuntimeError("must specify at least one of read=True, write=True")
|
| 74 |
+
rcheck = []
|
| 75 |
+
wcheck = []
|
| 76 |
+
if read:
|
| 77 |
+
rcheck.append(sock)
|
| 78 |
+
if write:
|
| 79 |
+
wcheck.append(sock)
|
| 80 |
+
# When doing a non-blocking connect, most systems signal success by
|
| 81 |
+
# marking the socket writable. Windows, though, signals success by marked
|
| 82 |
+
# it as "exceptional". We paper over the difference by checking the write
|
| 83 |
+
# sockets for both conditions. (The stdlib selectors module does the same
|
| 84 |
+
# thing.)
|
| 85 |
+
fn = partial(select.select, rcheck, wcheck, wcheck)
|
| 86 |
+
rready, wready, xready = _retry_on_intr(fn, timeout)
|
| 87 |
+
return bool(rready or wready or xready)
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def poll_wait_for_socket(sock, read=False, write=False, timeout=None):
|
| 91 |
+
if not read and not write:
|
| 92 |
+
raise RuntimeError("must specify at least one of read=True, write=True")
|
| 93 |
+
mask = 0
|
| 94 |
+
if read:
|
| 95 |
+
mask |= select.POLLIN
|
| 96 |
+
if write:
|
| 97 |
+
mask |= select.POLLOUT
|
| 98 |
+
poll_obj = select.poll()
|
| 99 |
+
poll_obj.register(sock, mask)
|
| 100 |
+
|
| 101 |
+
# For some reason, poll() takes timeout in milliseconds
|
| 102 |
+
def do_poll(t):
|
| 103 |
+
if t is not None:
|
| 104 |
+
t *= 1000
|
| 105 |
+
return poll_obj.poll(t)
|
| 106 |
+
|
| 107 |
+
return bool(_retry_on_intr(do_poll, timeout))
|
| 108 |
+
|
| 109 |
+
|
| 110 |
+
def null_wait_for_socket(*args, **kwargs):
|
| 111 |
+
raise NoWayToWaitForSocketError("no select-equivalent available")
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def _have_working_poll():
|
| 115 |
+
# Apparently some systems have a select.poll that fails as soon as you try
|
| 116 |
+
# to use it, either due to strange configuration or broken monkeypatching
|
| 117 |
+
# from libraries like eventlet/greenlet.
|
| 118 |
+
try:
|
| 119 |
+
poll_obj = select.poll()
|
| 120 |
+
_retry_on_intr(poll_obj.poll, 0)
|
| 121 |
+
except (AttributeError, OSError):
|
| 122 |
+
return False
|
| 123 |
+
else:
|
| 124 |
+
return True
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def wait_for_socket(*args, **kwargs):
|
| 128 |
+
# We delay choosing which implementation to use until the first time we're
|
| 129 |
+
# called. We could do it at import time, but then we might make the wrong
|
| 130 |
+
# decision if someone goes wild with monkeypatching select.poll after
|
| 131 |
+
# we're imported.
|
| 132 |
+
global wait_for_socket
|
| 133 |
+
if _have_working_poll():
|
| 134 |
+
wait_for_socket = poll_wait_for_socket
|
| 135 |
+
elif hasattr(select, "select"):
|
| 136 |
+
wait_for_socket = select_wait_for_socket
|
| 137 |
+
else: # Platform-specific: Appengine.
|
| 138 |
+
wait_for_socket = null_wait_for_socket
|
| 139 |
+
return wait_for_socket(*args, **kwargs)
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def wait_for_read(sock, timeout=None):
|
| 143 |
+
"""Waits for reading to be available on a given socket.
|
| 144 |
+
Returns True if the socket is readable, or False if the timeout expired.
|
| 145 |
+
"""
|
| 146 |
+
return wait_for_socket(sock, read=True, timeout=timeout)
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
def wait_for_write(sock, timeout=None):
|
| 150 |
+
"""Waits for writing to be available on a given socket.
|
| 151 |
+
Returns True if the socket is readable, or False if the timeout expired.
|
| 152 |
+
"""
|
| 153 |
+
return wait_for_socket(sock, write=True, timeout=timeout)
|