summaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-05-05 10:50:34 +0300
committerrobot-piglet <[email protected]>2025-05-05 11:05:28 +0300
commiteefca8305c6a545cc6b16dca3eb0d91dcef2adcd (patch)
tree374b7f2ed72bd6a9225a1d822492b9bc5e9bba05 /contrib/python
parent74c68d5ada88cc1acc7c521cd2570838fce6607e (diff)
Intermediate changes
commit_hash:fa949e2ff9157e2cc37621d9f6e4f0b54904258b
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/urllib3/py3/.dist-info/METADATA69
-rw-r--r--contrib/python/urllib3/py3/urllib3/_collections.py18
-rw-r--r--contrib/python/urllib3/py3/urllib3/_version.py2
-rw-r--r--contrib/python/urllib3/py3/urllib3/connection.py4
-rw-r--r--contrib/python/urllib3/py3/urllib3/connectionpool.py50
-rw-r--r--contrib/python/urllib3/py3/urllib3/contrib/securetransport.py3
-rw-r--r--contrib/python/urllib3/py3/urllib3/packages/backports/weakref_finalize.py155
-rw-r--r--contrib/python/urllib3/py3/urllib3/poolmanager.py9
-rw-r--r--contrib/python/urllib3/py3/urllib3/request.py21
-rw-r--r--contrib/python/urllib3/py3/urllib3/util/retry.py4
-rw-r--r--contrib/python/urllib3/py3/urllib3/util/ssl_.py17
-rw-r--r--contrib/python/urllib3/py3/ya.make2
12 files changed, 318 insertions, 36 deletions
diff --git a/contrib/python/urllib3/py3/.dist-info/METADATA b/contrib/python/urllib3/py3/.dist-info/METADATA
index 5d2a438fa11..0f21c233a89 100644
--- a/contrib/python/urllib3/py3/.dist-info/METADATA
+++ b/contrib/python/urllib3/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: urllib3
-Version: 1.26.15
+Version: 1.26.20
Summary: HTTP library with thread-safe connection pooling, file post, and more.
Home-page: https://urllib3.readthedocs.io/
Author: Andrey Petrov
@@ -24,6 +24,8 @@ Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Internet :: WWW/HTTP
@@ -32,18 +34,19 @@ Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*
Description-Content-Type: text/x-rst
License-File: LICENSE.txt
Provides-Extra: brotli
-Requires-Dist: brotlicffi (>=0.8.0) ; ((os_name != "nt" or python_version >= "3") and platform_python_implementation != "CPython") and extra == 'brotli'
-Requires-Dist: brotli (>=1.0.9) ; ((os_name != "nt" or python_version >= "3") and platform_python_implementation == "CPython") and extra == 'brotli'
-Requires-Dist: brotlipy (>=0.6.0) ; (os_name == "nt" and python_version < "3") and extra == 'brotli'
+Requires-Dist: brotlicffi>=0.8.0; ((os_name != "nt" or python_version >= "3") and platform_python_implementation != "CPython") and extra == "brotli"
+Requires-Dist: brotli==1.0.9; (os_name != "nt" and python_version < "3" and platform_python_implementation == "CPython") and extra == "brotli"
+Requires-Dist: brotlipy>=0.6.0; (os_name == "nt" and python_version < "3") and extra == "brotli"
+Requires-Dist: brotli>=1.0.9; (python_version >= "3" and platform_python_implementation == "CPython") and extra == "brotli"
Provides-Extra: secure
-Requires-Dist: pyOpenSSL (>=0.14) ; extra == 'secure'
-Requires-Dist: cryptography (>=1.3.4) ; extra == 'secure'
-Requires-Dist: idna (>=2.0.0) ; extra == 'secure'
-Requires-Dist: certifi ; extra == 'secure'
-Requires-Dist: urllib3-secure-extra ; extra == 'secure'
-Requires-Dist: ipaddress ; (python_version == "2.7") and extra == 'secure'
+Requires-Dist: pyOpenSSL>=0.14; extra == "secure"
+Requires-Dist: cryptography>=1.3.4; extra == "secure"
+Requires-Dist: idna>=2.0.0; extra == "secure"
+Requires-Dist: certifi; extra == "secure"
+Requires-Dist: urllib3-secure-extra; extra == "secure"
+Requires-Dist: ipaddress; python_version == "2.7" and extra == "secure"
Provides-Extra: socks
-Requires-Dist: PySocks (!=1.5.7,<2.0,>=1.5.6) ; extra == 'socks'
+Requires-Dist: PySocks!=1.5.7,<2.0,>=1.5.6; extra == "socks"
urllib3 is a powerful, *user-friendly* HTTP client for Python. Much of the
@@ -154,6 +157,48 @@ For Enterprise
Changes
=======
+1.26.20 (2024-08-29)
+--------------------
+
+* Fixed a crash where certain standard library hash functions were absent in
+ FIPS-compliant environments.
+ (`#3432 <https://github.com/urllib3/urllib3/issues/3432>`__)
+* Replaced deprecated dash-separated setuptools entries in ``setup.cfg``.
+ (`#3461 <https://github.com/urllib3/urllib3/pull/3461>`__)
+* Took into account macOS setting ``ECONNRESET`` instead of ``EPROTOTYPE`` in
+ its newer versions.
+ (`#3416 <https://github.com/urllib3/urllib3/pull/3416>`__)
+* Backported changes to our tests and CI configuration from v2.x to support
+ testing with CPython 3.12 and 3.13.
+ (`#3436 <https://github.com/urllib3/urllib3/pull/3436>`__)
+
+
+1.26.19 (2024-06-17)
+--------------------
+
+* Added the ``Proxy-Authorization`` header to the list of headers to strip from requests when redirecting to a different host. As before, different headers can be set via ``Retry.remove_headers_on_redirect``.
+* Fixed handling of OpenSSL 3.2.0 new error message for misconfiguring an HTTP proxy as HTTPS. (`#3405 <https://github.com/urllib3/urllib3/issues/3405>`__)
+
+
+1.26.18 (2023-10-17)
+--------------------
+
+* Made body stripped from HTTP requests changing the request method to GET after HTTP 303 "See Other" redirect responses.
+
+
+1.26.17 (2023-10-02)
+--------------------
+
+* Added the ``Cookie`` header to the list of headers to strip from requests when redirecting to a different host. As before, different headers can be set via ``Retry.remove_headers_on_redirect``.
+
+
+1.26.16 (2023-05-23)
+--------------------
+
+* Fixed thread-safety issue where accessing a ``PoolManager`` with many distinct origins
+ would cause connection pools to be closed while requests are in progress (`#2954 <https://github.com/urllib3/urllib3/pull/2954>`_)
+
+
1.26.15 (2023-03-10)
--------------------
@@ -307,7 +352,7 @@ Changes
* Added default ``User-Agent`` header to every request (Pull #1750)
-* Added ``urllib3.util.SKIP_HEADER`` for skipping ``User-Agent``, ``Accept-Encoding``,
+* Added ``urllib3.util.SKIP_HEADER`` for skipping ``User-Agent``, ``Accept-Encoding``,
and ``Host`` headers from being automatically emitted with requests (Pull #2018)
* Collapse ``transfer-encoding: chunked`` request data and framing into
diff --git a/contrib/python/urllib3/py3/urllib3/_collections.py b/contrib/python/urllib3/py3/urllib3/_collections.py
index da9857e986d..bceb8451f0e 100644
--- a/contrib/python/urllib3/py3/urllib3/_collections.py
+++ b/contrib/python/urllib3/py3/urllib3/_collections.py
@@ -268,6 +268,24 @@ class HTTPHeaderDict(MutableMapping):
else:
return vals[1:]
+ def _prepare_for_method_change(self):
+ """
+ Remove content-specific header fields before changing the request
+ method to GET or HEAD according to RFC 9110, Section 15.4.
+ """
+ content_specific_headers = [
+ "Content-Encoding",
+ "Content-Language",
+ "Content-Location",
+ "Content-Type",
+ "Content-Length",
+ "Digest",
+ "Last-Modified",
+ ]
+ for header in content_specific_headers:
+ self.discard(header)
+ return self
+
# Backwards compatibility for httplib
getheaders = getlist
getallmatchingheaders = getlist
diff --git a/contrib/python/urllib3/py3/urllib3/_version.py b/contrib/python/urllib3/py3/urllib3/_version.py
index e12dd0e7853..d49df2a0c54 100644
--- a/contrib/python/urllib3/py3/urllib3/_version.py
+++ b/contrib/python/urllib3/py3/urllib3/_version.py
@@ -1,2 +1,2 @@
# This file is protected via CODEOWNERS
-__version__ = "1.26.15"
+__version__ = "1.26.20"
diff --git a/contrib/python/urllib3/py3/urllib3/connection.py b/contrib/python/urllib3/py3/urllib3/connection.py
index d8b1f61a550..112a6228db2 100644
--- a/contrib/python/urllib3/py3/urllib3/connection.py
+++ b/contrib/python/urllib3/py3/urllib3/connection.py
@@ -68,7 +68,7 @@ port_by_scheme = {"http": 80, "https": 443}
# When it comes time to update this value as a part of regular maintenance
# (ie test_recent_date is failing) update it to ~6 months before the current date.
-RECENT_DATE = datetime.date(2022, 1, 1)
+RECENT_DATE = datetime.date(2024, 1, 1)
_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
@@ -438,7 +438,7 @@ class HTTPSConnection(HTTPConnection):
and self.ssl_version is None
and hasattr(self.sock, "version")
and self.sock.version() in {"TLSv1", "TLSv1.1"}
- ):
+ ): # Defensive:
warnings.warn(
"Negotiating TLSv1/TLSv1.1 by default is deprecated "
"and will be disabled in urllib3 v2.0.0. Connecting to "
diff --git a/contrib/python/urllib3/py3/urllib3/connectionpool.py b/contrib/python/urllib3/py3/urllib3/connectionpool.py
index c23d736b186..0872ed77011 100644
--- a/contrib/python/urllib3/py3/urllib3/connectionpool.py
+++ b/contrib/python/urllib3/py3/urllib3/connectionpool.py
@@ -9,6 +9,7 @@ import warnings
from socket import error as SocketError
from socket import timeout as SocketTimeout
+from ._collections import HTTPHeaderDict
from .connection import (
BaseSSLError,
BrokenPipeError,
@@ -50,6 +51,13 @@ from .util.url import Url, _encode_target
from .util.url import _normalize_host as normalize_host
from .util.url import get_host, parse_url
+try: # Platform-specific: Python 3
+ import weakref
+
+ weakref_finalize = weakref.finalize
+except AttributeError: # Platform-specific: Python 2
+ from .packages.backports.weakref_finalize import weakref_finalize
+
xrange = six.moves.xrange
log = logging.getLogger(__name__)
@@ -220,6 +228,16 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
self.conn_kw["proxy"] = self.proxy
self.conn_kw["proxy_config"] = self.proxy_config
+ # Do not pass 'self' as callback to 'finalize'.
+ # Then the 'finalize' would keep an endless living (leak) to self.
+ # By just passing a reference to the pool allows the garbage collector
+ # to free self if nobody else has a reference to it.
+ pool = self.pool
+
+ # Close all the HTTPConnections in the pool before the
+ # HTTPConnectionPool object is garbage collected.
+ weakref_finalize(self, _close_pool_connections, pool)
+
def _new_conn(self):
"""
Return a fresh :class:`HTTPConnection`.
@@ -405,12 +423,13 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
pass
except IOError as e:
# Python 2 and macOS/Linux
- # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE is needed on macOS
+ # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE/ECONNRESET are needed on macOS
# https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
if e.errno not in {
errno.EPIPE,
errno.ESHUTDOWN,
errno.EPROTOTYPE,
+ errno.ECONNRESET,
}:
raise
@@ -489,14 +508,8 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
# Disable access to the pool
old_pool, self.pool = self.pool, None
- try:
- while True:
- conn = old_pool.get(block=False)
- if conn:
- conn.close()
-
- except queue.Empty:
- pass # Done.
+ # Close all the HTTPConnections in the pool.
+ _close_pool_connections(old_pool)
def is_same_host(self, url):
"""
@@ -756,7 +769,9 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
# so we try to cover our bases here!
message = " ".join(re.split("[^a-z]", str(ssl_error).lower()))
return (
- "wrong version number" in message or "unknown protocol" in message
+ "wrong version number" in message
+ or "unknown protocol" in message
+ or "record layer failure" in message
)
# Try to detect a common user error with proxies which is to
@@ -832,7 +847,11 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
redirect_location = redirect and response.get_redirect_location()
if redirect_location:
if response.status == 303:
+ # Change the method according to RFC 9110, Section 15.4.4.
method = "GET"
+ # And lose the body not to transfer anything sensitive.
+ body = None
+ headers = HTTPHeaderDict(headers)._prepare_for_method_change()
try:
retries = retries.increment(method, url, response=response, _pool=self)
@@ -1108,3 +1127,14 @@ def _normalize_host(host, scheme):
if host.startswith("[") and host.endswith("]"):
host = host[1:-1]
return host
+
+
+def _close_pool_connections(pool):
+ """Drains a queue of connections and closes each one."""
+ try:
+ while True:
+ conn = pool.get(block=False)
+ if conn:
+ conn.close()
+ except queue.Empty:
+ pass # Done.
diff --git a/contrib/python/urllib3/py3/urllib3/contrib/securetransport.py b/contrib/python/urllib3/py3/urllib3/contrib/securetransport.py
index 6c46a3b9f03..e311c0c899a 100644
--- a/contrib/python/urllib3/py3/urllib3/contrib/securetransport.py
+++ b/contrib/python/urllib3/py3/urllib3/contrib/securetransport.py
@@ -64,9 +64,8 @@ import struct
import threading
import weakref
-import six
-
from .. import util
+from ..packages import six
from ..util.ssl_ import PROTOCOL_TLS_CLIENT
from ._securetransport.bindings import CoreFoundation, Security, SecurityConst
from ._securetransport.low_level import (
diff --git a/contrib/python/urllib3/py3/urllib3/packages/backports/weakref_finalize.py b/contrib/python/urllib3/py3/urllib3/packages/backports/weakref_finalize.py
new file mode 100644
index 00000000000..a2f2966e549
--- /dev/null
+++ b/contrib/python/urllib3/py3/urllib3/packages/backports/weakref_finalize.py
@@ -0,0 +1,155 @@
+# -*- coding: utf-8 -*-
+"""
+backports.weakref_finalize
+~~~~~~~~~~~~~~~~~~
+
+Backports the Python 3 ``weakref.finalize`` method.
+"""
+from __future__ import absolute_import
+
+import itertools
+import sys
+from weakref import ref
+
+__all__ = ["weakref_finalize"]
+
+
+class weakref_finalize(object):
+ """Class for finalization of weakrefable objects
+ finalize(obj, func, *args, **kwargs) returns a callable finalizer
+ object which will be called when obj is garbage collected. The
+ first time the finalizer is called it evaluates func(*arg, **kwargs)
+ and returns the result. After this the finalizer is dead, and
+ calling it just returns None.
+ When the program exits any remaining finalizers for which the
+ atexit attribute is true will be run in reverse order of creation.
+ By default atexit is true.
+ """
+
+ # Finalizer objects don't have any state of their own. They are
+ # just used as keys to lookup _Info objects in the registry. This
+ # ensures that they cannot be part of a ref-cycle.
+
+ __slots__ = ()
+ _registry = {}
+ _shutdown = False
+ _index_iter = itertools.count()
+ _dirty = False
+ _registered_with_atexit = False
+
+ class _Info(object):
+ __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
+
+ def __init__(self, obj, func, *args, **kwargs):
+ if not self._registered_with_atexit:
+ # We may register the exit function more than once because
+ # of a thread race, but that is harmless
+ import atexit
+
+ atexit.register(self._exitfunc)
+ weakref_finalize._registered_with_atexit = True
+ info = self._Info()
+ info.weakref = ref(obj, self)
+ info.func = func
+ info.args = args
+ info.kwargs = kwargs or None
+ info.atexit = True
+ info.index = next(self._index_iter)
+ self._registry[self] = info
+ weakref_finalize._dirty = True
+
+ def __call__(self, _=None):
+ """If alive then mark as dead and return func(*args, **kwargs);
+ otherwise return None"""
+ info = self._registry.pop(self, None)
+ if info and not self._shutdown:
+ return info.func(*info.args, **(info.kwargs or {}))
+
+ def detach(self):
+ """If alive then mark as dead and return (obj, func, args, kwargs);
+ otherwise return None"""
+ info = self._registry.get(self)
+ obj = info and info.weakref()
+ if obj is not None and self._registry.pop(self, None):
+ return (obj, info.func, info.args, info.kwargs or {})
+
+ def peek(self):
+ """If alive then return (obj, func, args, kwargs);
+ otherwise return None"""
+ info = self._registry.get(self)
+ obj = info and info.weakref()
+ if obj is not None:
+ return (obj, info.func, info.args, info.kwargs or {})
+
+ @property
+ def alive(self):
+ """Whether finalizer is alive"""
+ return self in self._registry
+
+ @property
+ def atexit(self):
+ """Whether finalizer should be called at exit"""
+ info = self._registry.get(self)
+ return bool(info) and info.atexit
+
+ @atexit.setter
+ def atexit(self, value):
+ info = self._registry.get(self)
+ if info:
+ info.atexit = bool(value)
+
+ def __repr__(self):
+ info = self._registry.get(self)
+ obj = info and info.weakref()
+ if obj is None:
+ return "<%s object at %#x; dead>" % (type(self).__name__, id(self))
+ else:
+ return "<%s object at %#x; for %r at %#x>" % (
+ type(self).__name__,
+ id(self),
+ type(obj).__name__,
+ id(obj),
+ )
+
+ @classmethod
+ def _select_for_exit(cls):
+ # Return live finalizers marked for exit, oldest first
+ L = [(f, i) for (f, i) in cls._registry.items() if i.atexit]
+ L.sort(key=lambda item: item[1].index)
+ return [f for (f, i) in L]
+
+ @classmethod
+ def _exitfunc(cls):
+ # At shutdown invoke finalizers for which atexit is true.
+ # This is called once all other non-daemonic threads have been
+ # joined.
+ reenable_gc = False
+ try:
+ if cls._registry:
+ import gc
+
+ if gc.isenabled():
+ reenable_gc = True
+ gc.disable()
+ pending = None
+ while True:
+ if pending is None or weakref_finalize._dirty:
+ pending = cls._select_for_exit()
+ weakref_finalize._dirty = False
+ if not pending:
+ break
+ f = pending.pop()
+ try:
+ # gc is disabled, so (assuming no daemonic
+ # threads) the following is the only line in
+ # this function which might trigger creation
+ # of a new finalizer
+ f()
+ except Exception:
+ sys.excepthook(*sys.exc_info())
+ assert f not in cls._registry
+ finally:
+ # prevent any more finalizers from executing during shutdown
+ weakref_finalize._shutdown = True
+ if reenable_gc:
+ gc.enable()
diff --git a/contrib/python/urllib3/py3/urllib3/poolmanager.py b/contrib/python/urllib3/py3/urllib3/poolmanager.py
index ca4ec341184..fb51bf7d96b 100644
--- a/contrib/python/urllib3/py3/urllib3/poolmanager.py
+++ b/contrib/python/urllib3/py3/urllib3/poolmanager.py
@@ -4,7 +4,7 @@ import collections
import functools
import logging
-from ._collections import RecentlyUsedContainer
+from ._collections import HTTPHeaderDict, RecentlyUsedContainer
from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme
from .exceptions import (
LocationValueError,
@@ -171,7 +171,7 @@ class PoolManager(RequestMethods):
def __init__(self, num_pools=10, headers=None, **connection_pool_kw):
RequestMethods.__init__(self, headers)
self.connection_pool_kw = connection_pool_kw
- self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close())
+ self.pools = RecentlyUsedContainer(num_pools)
# Locally set the pool classes and keys so other PoolManagers can
# override them.
@@ -382,9 +382,12 @@ class PoolManager(RequestMethods):
# Support relative URLs for redirecting.
redirect_location = urljoin(url, redirect_location)
- # RFC 7231, Section 6.4.4
if response.status == 303:
+ # Change the method according to RFC 9110, Section 15.4.4.
method = "GET"
+ # And lose the body not to transfer anything sensitive.
+ kw["body"] = None
+ kw["headers"] = HTTPHeaderDict(kw["headers"])._prepare_for_method_change()
retries = kw.get("retries")
if not isinstance(retries, Retry):
diff --git a/contrib/python/urllib3/py3/urllib3/request.py b/contrib/python/urllib3/py3/urllib3/request.py
index 398386a5b9f..3b4cf999225 100644
--- a/contrib/python/urllib3/py3/urllib3/request.py
+++ b/contrib/python/urllib3/py3/urllib3/request.py
@@ -1,6 +1,9 @@
from __future__ import absolute_import
+import sys
+
from .filepost import encode_multipart_formdata
+from .packages import six
from .packages.six.moves.urllib.parse import urlencode
__all__ = ["RequestMethods"]
@@ -168,3 +171,21 @@ class RequestMethods(object):
extra_kw.update(urlopen_kw)
return self.urlopen(method, url, **extra_kw)
+
+
+if not six.PY2:
+
+ class RequestModule(sys.modules[__name__].__class__):
+ def __call__(self, *args, **kwargs):
+ """
+ If user tries to call this module directly urllib3 v2.x style raise an error to the user
+ suggesting they may need urllib3 v2
+ """
+ raise TypeError(
+ "'module' object is not callable\n"
+ "urllib3.request() method is not supported in this release, "
+ "upgrade to urllib3 v2 to use it\n"
+ "see https://urllib3.readthedocs.io/en/stable/v2-migration-guide.html"
+ )
+
+ sys.modules[__name__].__class__ = RequestModule
diff --git a/contrib/python/urllib3/py3/urllib3/util/retry.py b/contrib/python/urllib3/py3/urllib3/util/retry.py
index 2490d5e5b63..9a1e90d0b23 100644
--- a/contrib/python/urllib3/py3/urllib3/util/retry.py
+++ b/contrib/python/urllib3/py3/urllib3/util/retry.py
@@ -235,7 +235,9 @@ class Retry(object):
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
#: Default headers to be used for ``remove_headers_on_redirect``
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Authorization"])
+ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
+ ["Cookie", "Authorization", "Proxy-Authorization"]
+ )
#: Maximum backoff time.
DEFAULT_BACKOFF_MAX = 120
diff --git a/contrib/python/urllib3/py3/urllib3/util/ssl_.py b/contrib/python/urllib3/py3/urllib3/util/ssl_.py
index 8f867812a5e..f26809c766a 100644
--- a/contrib/python/urllib3/py3/urllib3/util/ssl_.py
+++ b/contrib/python/urllib3/py3/urllib3/util/ssl_.py
@@ -1,11 +1,11 @@
from __future__ import absolute_import
+import hashlib
import hmac
import os
import sys
import warnings
from binascii import hexlify, unhexlify
-from hashlib import md5, sha1, sha256
from ..exceptions import (
InsecurePlatformWarning,
@@ -24,7 +24,10 @@ IS_SECURETRANSPORT = False
ALPN_PROTOCOLS = ["http/1.1"]
# Maps the length of a digest to a possible hash function producing this digest
-HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256}
+HASHFUNC_MAP = {
+ length: getattr(hashlib, algorithm, None)
+ for length, algorithm in ((32, "md5"), (40, "sha1"), (64, "sha256"))
+}
def _const_compare_digest_backport(a, b):
@@ -191,9 +194,15 @@ def assert_fingerprint(cert, fingerprint):
fingerprint = fingerprint.replace(":", "").lower()
digest_length = len(fingerprint)
- hashfunc = HASHFUNC_MAP.get(digest_length)
- if not hashfunc:
+ if digest_length not in HASHFUNC_MAP:
raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint))
+ hashfunc = HASHFUNC_MAP.get(digest_length)
+ if hashfunc is None:
+ raise SSLError(
+ "Hash function implementation unavailable for fingerprint length: {0}".format(
+ digest_length
+ )
+ )
# We need encode() here for py32; works on py2 and p33.
fingerprint_bytes = unhexlify(fingerprint.encode())
diff --git a/contrib/python/urllib3/py3/ya.make b/contrib/python/urllib3/py3/ya.make
index bf0f5ec7168..044bf16b232 100644
--- a/contrib/python/urllib3/py3/ya.make
+++ b/contrib/python/urllib3/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(1.26.15)
+VERSION(1.26.20)
LICENSE(MIT)