aboutsummaryrefslogtreecommitdiff
path: root/urllib3/util
diff options
context:
space:
mode:
Diffstat (limited to 'urllib3/util')
-rw-r--r--urllib3/util/__init__.py20
-rw-r--r--urllib3/util/connection.py1
-rw-r--r--urllib3/util/request.py1
-rw-r--r--urllib3/util/response.py3
-rw-r--r--urllib3/util/retry.py7
-rw-r--r--urllib3/util/ssl_.py39
-rw-r--r--urllib3/util/timeout.py8
-rw-r--r--urllib3/util/url.py5
8 files changed, 72 insertions, 12 deletions
diff --git a/urllib3/util/__init__.py b/urllib3/util/__init__.py
index 8becc81..c6c6243 100644
--- a/urllib3/util/__init__.py
+++ b/urllib3/util/__init__.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
# For backwards compatibility, provide imports that used to be here.
from .connection import is_connection_dropped
from .request import make_headers
@@ -22,3 +23,22 @@ from .url import (
split_first,
Url,
)
+
+__all__ = (
+ 'HAS_SNI',
+ 'SSLContext',
+ 'Retry',
+ 'Timeout',
+ 'Url',
+ 'assert_fingerprint',
+ 'current_time',
+ 'is_connection_dropped',
+ 'is_fp_closed',
+ 'get_host',
+ 'parse_url',
+ 'make_headers',
+ 'resolve_cert_reqs',
+ 'resolve_ssl_version',
+ 'split_first',
+ 'ssl_wrap_socket',
+)
diff --git a/urllib3/util/connection.py b/urllib3/util/connection.py
index 4f2f0f1..01a4812 100644
--- a/urllib3/util/connection.py
+++ b/urllib3/util/connection.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
import socket
try:
from select import poll, POLLIN
diff --git a/urllib3/util/request.py b/urllib3/util/request.py
index bc64f6b..7377931 100644
--- a/urllib3/util/request.py
+++ b/urllib3/util/request.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
from base64 import b64encode
from ..packages.six import b
diff --git a/urllib3/util/response.py b/urllib3/util/response.py
index 2c1de15..bc72327 100644
--- a/urllib3/util/response.py
+++ b/urllib3/util/response.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
from ..packages.six.moves import http_client as httplib
from ..exceptions import HeaderParsingError
@@ -44,7 +45,7 @@ def assert_header_parsing(headers):
# This will fail silently if we pass in the wrong kind of parameter.
# To make debugging easier add an explicit check.
if not isinstance(headers, httplib.HTTPMessage):
- raise TypeError('expected httplib.Message, got {}.'.format(
+ raise TypeError('expected httplib.Message, got {0}.'.format(
type(headers)))
defects = getattr(headers, 'defects', None)
diff --git a/urllib3/util/retry.py b/urllib3/util/retry.py
index 1fb1f23..03a0124 100644
--- a/urllib3/util/retry.py
+++ b/urllib3/util/retry.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
import time
import logging
@@ -126,7 +127,7 @@ class Retry(object):
self.method_whitelist = method_whitelist
self.backoff_factor = backoff_factor
self.raise_on_redirect = raise_on_redirect
- self._observed_errors = _observed_errors # TODO: use .history instead?
+ self._observed_errors = _observed_errors # TODO: use .history instead?
def new(self, **kw):
params = dict(
@@ -206,7 +207,8 @@ class Retry(object):
return min(retry_counts) < 0
- def increment(self, method=None, url=None, response=None, error=None, _pool=None, _stacktrace=None):
+ def increment(self, method=None, url=None, response=None, error=None,
+ _pool=None, _stacktrace=None):
""" Return a new Retry object with incremented retry counters.
:param response: A response object, or None, if the server did not
@@ -274,7 +276,6 @@ class Retry(object):
return new_retry
-
def __repr__(self):
return ('{cls.__name__}(total={self.total}, connect={self.connect}, '
'read={self.read}, redirect={self.redirect})').format(
diff --git a/urllib3/util/ssl_.py b/urllib3/util/ssl_.py
index 47b817e..67f8344 100644
--- a/urllib3/util/ssl_.py
+++ b/urllib3/util/ssl_.py
@@ -1,7 +1,12 @@
+from __future__ import absolute_import
+import errno
+import warnings
+import hmac
+
from binascii import hexlify, unhexlify
from hashlib import md5, sha1, sha256
-from ..exceptions import SSLError, InsecurePlatformWarning
+from ..exceptions import SSLError, InsecurePlatformWarning, SNIMissingWarning
SSLContext = None
@@ -15,8 +20,23 @@ HASHFUNC_MAP = {
64: sha256,
}
-import errno
-import warnings
+
+def _const_compare_digest_backport(a, b):
+ """
+ Compare two digests of equal length in constant time.
+
+ The digests must be of type str/bytes.
+ Returns True if the digests match, and False otherwise.
+ """
+ result = abs(len(a) - len(b))
+ for l, r in zip(bytearray(a), bytearray(b)):
+ result |= l ^ r
+ return result == 0
+
+
+_const_compare_digest = getattr(hmac, 'compare_digest',
+ _const_compare_digest_backport)
+
try: # Test for SSL features
import ssl
@@ -134,7 +154,7 @@ def assert_fingerprint(cert, fingerprint):
cert_digest = hashfunc(cert).digest()
- if cert_digest != fingerprint_bytes:
+ if not _const_compare_digest(cert_digest, fingerprint_bytes):
raise SSLError('Fingerprints did not match. Expected "{0}", got "{1}".'
.format(fingerprint, hexlify(cert_digest)))
@@ -283,4 +303,15 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
context.load_cert_chain(certfile, keyfile)
if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI
return context.wrap_socket(sock, server_hostname=server_hostname)
+
+ warnings.warn(
+ 'An HTTPS request has been made, but the SNI (Subject Name '
+ 'Indication) extension to TLS is not available on this platform. '
+ 'This may cause the server to present an incorrect TLS '
+ 'certificate, which can cause validation failures. For more '
+ 'information, see '
+ 'https://urllib3.readthedocs.org/en/latest/security.html'
+ '#snimissingwarning.',
+ SNIMissingWarning
+ )
return context.wrap_socket(sock)
diff --git a/urllib3/util/timeout.py b/urllib3/util/timeout.py
index ea7027f..ff62f47 100644
--- a/urllib3/util/timeout.py
+++ b/urllib3/util/timeout.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
# The default socket timeout, used by httplib to indicate that no timeout was
# specified by the user
from socket import _GLOBAL_DEFAULT_TIMEOUT
@@ -9,6 +10,7 @@ from ..exceptions import TimeoutStateError
# urllib3
_Default = object()
+
def current_time():
"""
Retrieve the current time. This function is mocked out in unit testing.
@@ -226,9 +228,9 @@ class Timeout(object):
has not yet been called on this object.
"""
if (self.total is not None and
- self.total is not self.DEFAULT_TIMEOUT and
- self._read is not None and
- self._read is not self.DEFAULT_TIMEOUT):
+ self.total is not self.DEFAULT_TIMEOUT and
+ self._read is not None and
+ self._read is not self.DEFAULT_TIMEOUT):
# In case the connect timeout has not yet been established.
if self._start_connect is None:
return self._read
diff --git a/urllib3/util/url.py b/urllib3/util/url.py
index e58050c..e996204 100644
--- a/urllib3/util/url.py
+++ b/urllib3/util/url.py
@@ -1,3 +1,4 @@
+from __future__ import absolute_import
from collections import namedtuple
from ..exceptions import LocationParseError
@@ -85,6 +86,7 @@ class Url(namedtuple('Url', url_attrs)):
def __str__(self):
return self.url
+
def split_first(s, delims):
"""
Given a string and an iterable of delimiters, split on the first found
@@ -115,7 +117,7 @@ def split_first(s, delims):
if min_idx is None or min_idx < 0:
return s, '', None
- return s[:min_idx], s[min_idx+1:], min_delim
+ return s[:min_idx], s[min_idx + 1:], min_delim
def parse_url(url):
@@ -206,6 +208,7 @@ def parse_url(url):
return Url(scheme, auth, host, port, path, query, fragment)
+
def get_host(url):
"""
Deprecated. Use :func:`.parse_url` instead.