Skip to content

Commit

Permalink
Upgrade urllib3 to 1.25.9
Browse files Browse the repository at this point in the history
  • Loading branch information
pradyunsg committed Jul 22, 2020
1 parent fe7128c commit 072b70b
Show file tree
Hide file tree
Showing 14 changed files with 122 additions and 58 deletions.
1 change: 1 addition & 0 deletions news/urllib3.vendor
@@ -0,0 +1 @@
Upgrade urllib3 to 1.25.9
2 changes: 1 addition & 1 deletion src/pip/_vendor/urllib3/__init__.py
Expand Up @@ -22,7 +22,7 @@

__author__ = "Andrey Petrov (andrey.petrov@shazow.net)"
__license__ = "MIT"
__version__ = "1.25.8"
__version__ = "1.25.9"

__all__ = (
"HTTPConnectionPool",
Expand Down
47 changes: 28 additions & 19 deletions src/pip/_vendor/urllib3/connection.py
@@ -1,4 +1,5 @@
from __future__ import absolute_import
import re
import datetime
import logging
import os
Expand Down Expand Up @@ -58,6 +59,8 @@ class ConnectionError(Exception):
# (ie test_recent_date is failing) update it to ~6 months before the current date.
RECENT_DATE = datetime.date(2019, 1, 1)

_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")


class DummyConnection(object):
"""Used to detect a failed ConnectionCls import."""
Expand Down Expand Up @@ -184,6 +187,17 @@ def connect(self):
conn = self._new_conn()
self._prepare_conn(conn)

def putrequest(self, method, url, *args, **kwargs):
"""Send a request to the server"""
match = _CONTAINS_CONTROL_CHAR_RE.search(method)
if match:
raise ValueError(
"Method cannot contain non-token characters %r (found at least %r)"
% (method, match.group())
)

return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)

def request_chunked(self, method, url, body=None, headers=None):
"""
Alternative to the common request method, which sends the
Expand Down Expand Up @@ -223,7 +237,12 @@ def request_chunked(self, method, url, body=None, headers=None):
class HTTPSConnection(HTTPConnection):
default_port = port_by_scheme["https"]

cert_reqs = None
ca_certs = None
ca_cert_dir = None
ca_cert_data = None
ssl_version = None
assert_fingerprint = None

def __init__(
self,
Expand Down Expand Up @@ -251,19 +270,6 @@ def __init__(
# HTTPS requests to go out as HTTP. (See Issue #356)
self._protocol = "https"


class VerifiedHTTPSConnection(HTTPSConnection):
"""
Based on httplib.HTTPSConnection but wraps the socket with
SSL certification.
"""

cert_reqs = None
ca_certs = None
ca_cert_dir = None
ssl_version = None
assert_fingerprint = None

def set_cert(
self,
key_file=None,
Expand All @@ -274,6 +280,7 @@ def set_cert(
assert_hostname=None,
assert_fingerprint=None,
ca_cert_dir=None,
ca_cert_data=None,
):
"""
This method should only be called once, before the connection is used.
Expand All @@ -294,6 +301,7 @@ def set_cert(
self.assert_fingerprint = assert_fingerprint
self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
self.ca_cert_data = ca_cert_data

def connect(self):
# Add certificate verification
Expand Down Expand Up @@ -344,6 +352,7 @@ def connect(self):
if (
not self.ca_certs
and not self.ca_cert_dir
and not self.ca_cert_data
and default_ssl_context
and hasattr(context, "load_default_certs")
):
Expand All @@ -356,6 +365,7 @@ def connect(self):
key_password=self.key_password,
ca_certs=self.ca_certs,
ca_cert_dir=self.ca_cert_dir,
ca_cert_data=self.ca_cert_data,
server_hostname=server_hostname,
ssl_context=context,
)
Expand Down Expand Up @@ -406,9 +416,8 @@ def _match_hostname(cert, asserted_hostname):
raise


if ssl:
# Make a copy for testing.
UnverifiedHTTPSConnection = HTTPSConnection
HTTPSConnection = VerifiedHTTPSConnection
else:
HTTPSConnection = DummyConnection
if not ssl:
HTTPSConnection = DummyConnection # noqa: F811


VerifiedHTTPSConnection = HTTPSConnection
36 changes: 9 additions & 27 deletions src/pip/_vendor/urllib3/connectionpool.py
Expand Up @@ -65,6 +65,11 @@ class ConnectionPool(object):
"""
Base class for all connection pools, such as
:class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
.. note::
ConnectionPool.urlopen() does not normalize or percent-encode target URIs
which is useful if your target server doesn't support percent-encoded
target URIs.
"""

scheme = None
Expand Down Expand Up @@ -760,21 +765,6 @@ def urlopen(
**response_kw
)

def drain_and_release_conn(response):
try:
# discard any remaining response body, the connection will be
# released back to the pool once the entire response is read
response.read()
except (
TimeoutError,
HTTPException,
SocketError,
ProtocolError,
BaseSSLError,
SSLError,
):
pass

# Handle redirect?
redirect_location = redirect and response.get_redirect_location()
if redirect_location:
Expand All @@ -785,15 +775,11 @@ def drain_and_release_conn(response):
retries = retries.increment(method, url, response=response, _pool=self)
except MaxRetryError:
if retries.raise_on_redirect:
# Drain and release the connection for this response, since
# we're not returning it to be released manually.
drain_and_release_conn(response)
response.drain_conn()
raise
return response

# drain and return the connection to the pool before recursing
drain_and_release_conn(response)

response.drain_conn()
retries.sleep_for_retry(response)
log.debug("Redirecting %s -> %s", url, redirect_location)
return self.urlopen(
Expand All @@ -819,15 +805,11 @@ def drain_and_release_conn(response):
retries = retries.increment(method, url, response=response, _pool=self)
except MaxRetryError:
if retries.raise_on_status:
# Drain and release the connection for this response, since
# we're not returning it to be released manually.
drain_and_release_conn(response)
response.drain_conn()
raise
return response

# drain and return the connection to the pool before recursing
drain_and_release_conn(response)

response.drain_conn()
retries.sleep(response)
log.debug("Retry: %s", url)
return self.urlopen(
Expand Down
9 changes: 6 additions & 3 deletions src/pip/_vendor/urllib3/contrib/pyopenssl.py
Expand Up @@ -450,9 +450,12 @@ def load_verify_locations(self, cafile=None, capath=None, cadata=None):
cafile = cafile.encode("utf-8")
if capath is not None:
capath = capath.encode("utf-8")
self._ctx.load_verify_locations(cafile, capath)
if cadata is not None:
self._ctx.load_verify_locations(BytesIO(cadata))
try:
self._ctx.load_verify_locations(cafile, capath)
if cadata is not None:
self._ctx.load_verify_locations(BytesIO(cadata))
except OpenSSL.SSL.Error as e:
raise ssl.SSLError("unable to load trusted certificates: %r" % e)

def load_cert_chain(self, certfile, keyfile=None, password=None):
self._ctx.use_certificate_chain_file(certfile)
Expand Down
5 changes: 5 additions & 0 deletions src/pip/_vendor/urllib3/contrib/securetransport.py
Expand Up @@ -819,6 +819,11 @@ def load_verify_locations(self, cafile=None, capath=None, cadata=None):
if capath is not None:
raise ValueError("SecureTransport does not support cert directories")

# Raise if cafile does not exist.
if cafile is not None:
with open(cafile):
pass

self._trust_bundle = cafile or cadata

def load_cert_chain(self, certfile, keyfile=None, password=None):
Expand Down
19 changes: 18 additions & 1 deletion src/pip/_vendor/urllib3/exceptions.py
Expand Up @@ -45,7 +45,10 @@ class SSLError(HTTPError):

class ProxyError(HTTPError):
"Raised when the connection to a proxy fails."
pass

def __init__(self, message, error, *args):
super(ProxyError, self).__init__(message, error, *args)
self.original_error = error


class DecodeError(HTTPError):
Expand Down Expand Up @@ -195,6 +198,20 @@ class DependencyWarning(HTTPWarning):
pass


class InvalidProxyConfigurationWarning(HTTPWarning):
"""
Warned when using an HTTPS proxy and an HTTPS URL. Currently
urllib3 doesn't support HTTPS proxies and the proxy will be
contacted via HTTP instead. This warning can be fixed by
changing your HTTPS proxy URL into an HTTP proxy URL.
If you encounter this warning read this:
https://github.com/urllib3/urllib3/issues/1850
"""

pass


class ResponseNotChunked(ProtocolError, ValueError):
"Response needs to be chunked in order to read it as chunks."
pass
Expand Down
24 changes: 23 additions & 1 deletion src/pip/_vendor/urllib3/poolmanager.py
Expand Up @@ -2,11 +2,17 @@
import collections
import functools
import logging
import warnings

from ._collections import RecentlyUsedContainer
from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool
from .connectionpool import port_by_scheme
from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown
from .exceptions import (
LocationValueError,
MaxRetryError,
ProxySchemeUnknown,
InvalidProxyConfigurationWarning,
)
from .packages import six
from .packages.six.moves.urllib.parse import urljoin
from .request import RequestMethods
Expand Down Expand Up @@ -359,13 +365,16 @@ def urlopen(self, method, url, redirect=True, **kw):
retries = retries.increment(method, url, response=response, _pool=conn)
except MaxRetryError:
if retries.raise_on_redirect:
response.drain_conn()
raise
return response

kw["retries"] = retries
kw["redirect"] = redirect

log.info("Redirecting %s -> %s", url, redirect_location)

response.drain_conn()
return self.urlopen(method, redirect_location, **kw)


Expand Down Expand Up @@ -452,9 +461,22 @@ def _set_proxy_headers(self, url, headers=None):
headers_.update(headers)
return headers_

def _validate_proxy_scheme_url_selection(self, url_scheme):
if url_scheme == "https" and self.proxy.scheme == "https":
warnings.warn(
"Your proxy configuration specified an HTTPS scheme for the proxy. "
"Are you sure you want to use HTTPS to contact the proxy? "
"This most likely indicates an error in your configuration. "
"Read this issue for more info: "
"https://github.com/urllib3/urllib3/issues/1850",
InvalidProxyConfigurationWarning,
stacklevel=3,
)

def urlopen(self, method, url, redirect=True, **kw):
"Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute."
u = parse_url(url)
self._validate_proxy_scheme_url_selection(u.scheme)

if u.scheme == "http":
# For proxied HTTPS requests, httplib sets the necessary headers
Expand Down
12 changes: 12 additions & 0 deletions src/pip/_vendor/urllib3/response.py
Expand Up @@ -20,6 +20,7 @@
ResponseNotChunked,
IncompleteRead,
InvalidHeader,
HTTPError,
)
from .packages.six import string_types as basestring, PY3
from .packages.six.moves import http_client as httplib
Expand Down Expand Up @@ -277,6 +278,17 @@ def release_conn(self):
self._pool._put_conn(self._connection)
self._connection = None

def drain_conn(self):
"""
Read and discard any remaining HTTP response data in the response connection.
Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
"""
try:
self.read()
except (HTTPError, SocketError, BaseSSLError, HTTPException):
pass

@property
def data(self):
# For backwords-compat with earlier urllib3 0.4 and earlier.
Expand Down
3 changes: 3 additions & 0 deletions src/pip/_vendor/urllib3/util/retry.py
Expand Up @@ -13,6 +13,7 @@
ReadTimeoutError,
ResponseError,
InvalidHeader,
ProxyError,
)
from ..packages import six

Expand Down Expand Up @@ -306,6 +307,8 @@ def _is_connection_error(self, err):
""" Errors when we're fairly sure that the server did not receive the
request, so it should be safe to retry.
"""
if isinstance(err, ProxyError):
err = err.original_error
return isinstance(err, ConnectTimeoutError)

def _is_read_error(self, err):
Expand Down

0 comments on commit 072b70b

Please sign in to comment.