Skip to content

Commit 0b1d9ce

Browse files
SNOW-3569023: bump vendored urllib3 to 2.7.0 (#2888)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 0708614 commit 0b1d9ce

16 files changed

Lines changed: 135 additions & 160 deletions

File tree

DESCRIPTION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
1111
- Dropped support for Python 3.9. The minimum supported version is now Python 3.10.
1212
- Fixed sdist to only install the minicore binary matching the current platform (SNOW-3526469). Previous 4.x releases copied every platform's minicore `.so`/`.dylib`/`.dll` into the install prefix, breaking downstream packagers (e.g. Homebrew) whose audits reject foreign-arch binaries.
1313
- Added one in-band telemetry record per successful login describing which connection-identifier fields the user supplied (`account_provided`, `account_with_region`, `account_org_provided`, `region_provided`, `host_provided`). No hostname or account value is included. This is gated by the existing server-side `CLIENT_TELEMETRY_ENABLED` parameter and can additionally be disabled locally by setting `SF_TELEMETRY_DISABLE_CONNECTION_SHAPE=true`. The telemetry collection is time-boxed and will be removed in a future release.
14+
- Bumped up vendored `urllib3` to `2.7.0`
1415

1516
- v4.5.0(May 12,2026)
1617
- Fixed `write_pandas` temp stage name collisions (SNOW-3481510). The old PRNG could produce identical name sequences in forked processes (e.g. Notebook kernels), causing `CREATE TEMPORARY STAGE` to fail with "Object already exists".

src/snowflake/connector/vendored/urllib3/_base_connection.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
from .util.timeout import _DEFAULT_TIMEOUT, _TYPE_TIMEOUT
77
from .util.url import Url
88

9-
_TYPE_BODY = typing.Union[bytes, typing.IO[typing.Any], typing.Iterable[bytes], str]
9+
_TYPE_BODY = typing.Union[
10+
bytes, typing.IO[typing.Any], typing.Iterable[bytes | str], str
11+
]
1012

1113

1214
class ProxyConfig(typing.NamedTuple):

src/snowflake/connector/vendored/urllib3/_collections.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ def extend(self, *args: ValidHTTPHeaderSource, **kwargs: str) -> None:
356356
for key, val in other.items():
357357
self.add(key, val)
358358
elif isinstance(other, typing.Iterable):
359-
other = typing.cast(typing.Iterable[tuple[str, str]], other)
360359
for key, value in other:
361360
self.add(key, value)
362361
elif hasattr(other, "keys") and hasattr(other, "__getitem__"):
Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
# file generated by setuptools-scm
1+
# file generated by vcs-versioning
22
# don't change, don't track in version control
3+
from __future__ import annotations
34

45
__all__ = [
56
"__version__",
@@ -10,25 +11,14 @@
1011
"commit_id",
1112
]
1213

13-
TYPE_CHECKING = False
14-
if TYPE_CHECKING:
15-
from typing import Tuple
16-
from typing import Union
17-
18-
VERSION_TUPLE = Tuple[Union[int, str], ...]
19-
COMMIT_ID = Union[str, None]
20-
else:
21-
VERSION_TUPLE = object
22-
COMMIT_ID = object
23-
2414
version: str
2515
__version__: str
26-
__version_tuple__: VERSION_TUPLE
27-
version_tuple: VERSION_TUPLE
28-
commit_id: COMMIT_ID
29-
__commit_id__: COMMIT_ID
16+
__version_tuple__: tuple[int | str, ...]
17+
version_tuple: tuple[int | str, ...]
18+
commit_id: str | None
19+
__commit_id__: str | None
3020

31-
__version__ = version = '2.6.3'
32-
__version_tuple__ = version_tuple = (2, 6, 3)
21+
__version__ = version = '2.7.0'
22+
__version_tuple__ = version_tuple = (2, 7, 0)
3323

3424
__commit_id__ = commit_id = None

src/snowflake/connector/vendored/urllib3/connection.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,8 @@ def request_chunked(
540540
"""
541541
warnings.warn(
542542
"HTTPConnection.request_chunked() is deprecated and will be removed "
543-
"in urllib3 v2.1.0. Instead use HTTPConnection.request(..., chunked=True).",
544-
category=DeprecationWarning,
543+
"in urllib3 v3.0. Instead use HTTPConnection.request(..., chunked=True).",
544+
category=FutureWarning,
545545
stacklevel=2,
546546
)
547547
self.request(method, url, body=body, headers=headers, chunked=True)
@@ -706,9 +706,9 @@ def set_cert(
706706
"""
707707
warnings.warn(
708708
"HTTPSConnection.set_cert() is deprecated and will be removed "
709-
"in urllib3 v2.1.0. Instead provide the parameters to the "
709+
"in urllib3 v3.0. Instead provide the parameters to the "
710710
"HTTPSConnection constructor.",
711-
category=DeprecationWarning,
711+
category=FutureWarning,
712712
stacklevel=2,
713713
)
714714

src/snowflake/connector/vendored/urllib3/connectionpool.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,8 @@ def __init__(
216216

217217
if self.proxy:
218218
# Enable Nagle's algorithm for proxies, to avoid packet fragmentation.
219-
# We cannot know if the user has added default socket options, so we cannot replace the
220-
# list.
219+
# Defaulting `socket_options` to an empty list avoids it defaulting to
220+
# ``HTTPConnection.default_socket_options``.
221221
self.conn_kw.setdefault("socket_options", [])
222222

223223
self.conn_kw["proxy"] = self.proxy
@@ -702,8 +702,15 @@ def urlopen( # type: ignore[override]
702702
redirect. Typically this won't need to be set because urllib3 will
703703
auto-populate the value when needed.
704704
"""
705-
parsed_url = parse_url(url)
706-
destination_scheme = parsed_url.scheme
705+
# Ensure that the URL we're connecting to is properly encoded
706+
if url.startswith("/"):
707+
# URLs starting with / are inherently schemeless.
708+
url = to_str(_encode_target(url))
709+
destination_scheme = None
710+
else:
711+
parsed_url = parse_url(url)
712+
destination_scheme = parsed_url.scheme
713+
url = to_str(parsed_url.url)
707714

708715
if headers is None:
709716
headers = self.headers
@@ -718,12 +725,6 @@ def urlopen( # type: ignore[override]
718725
if assert_same_host and not self.is_same_host(url):
719726
raise HostChangedError(self, url, retries)
720727

721-
# Ensure that the URL we're connecting to is properly encoded
722-
if url.startswith("/"):
723-
url = to_str(_encode_target(url))
724-
else:
725-
url = to_str(parsed_url.url)
726-
727728
conn = None
728729

729730
# Track whether `conn` needs to be released before
@@ -896,6 +897,18 @@ def urlopen( # type: ignore[override]
896897
body = None
897898
headers = HTTPHeaderDict(headers)._prepare_for_method_change()
898899

900+
# Strip headers marked as unsafe to forward to the redirected location.
901+
# Check remove_headers_on_redirect to avoid a potential network call within
902+
# self.is_same_host() which may use socket.gethostbyname() in the future.
903+
if retries.remove_headers_on_redirect and not self.is_same_host(
904+
redirect_location
905+
):
906+
new_headers = headers.copy() # type: ignore[union-attr]
907+
for header in headers:
908+
if header.lower() in retries.remove_headers_on_redirect:
909+
new_headers.pop(header, None)
910+
headers = new_headers
911+
899912
try:
900913
retries = retries.increment(method, url, response=response, _pool=self)
901914
except MaxRetryError:

src/snowflake/connector/vendored/urllib3/contrib/emscripten/response.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ def __init__(
3636
):
3737
self._pool = None # set by pool class
3838
self._body = None
39+
self._uncached_read_occurred = False
3940
self._response = internal_response
4041
self._url = url
4142
self._connection = connection
@@ -160,10 +161,13 @@ def read(
160161
# don't cache partial content
161162
cache_content = False
162163
data = self._response.body.read(amt)
164+
self._uncached_read_occurred = True
163165
else: # read all we can (and cache it)
164166
data = self._response.body.read()
165-
if cache_content:
167+
if cache_content and not self._uncached_read_occurred:
166168
self._body = data
169+
else:
170+
self._uncached_read_occurred = True
167171
if self.length_remaining is not None:
168172
self.length_remaining = max(self.length_remaining - len(data), 0)
169173
if len(data) == 0 or (

src/snowflake/connector/vendored/urllib3/contrib/pyopenssl.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
77
This needs the following packages installed:
88
9-
* `pyOpenSSL`_ (tested with 16.0.0)
10-
* `cryptography`_ (minimum 1.3.4, from pyopenssl)
11-
* `idna`_ (minimum 2.0)
9+
* `pyOpenSSL`_ (tested with 19.0.0)
10+
* `cryptography`_ (minimum 2.3, from pyopenssl)
11+
* `idna`_ (minimum 2.1, from cryptography)
1212
1313
However, pyOpenSSL depends on cryptography, so while we use all three directly here we
1414
end up having relatively few packages required.
@@ -56,7 +56,6 @@ class UnsupportedExtension(Exception): # type: ignore[no-redef]
5656
import typing
5757
from io import BytesIO
5858
from socket import socket as socket_cls
59-
from socket import timeout
6059

6160
from .. import util
6261

@@ -311,7 +310,7 @@ def recv(self, *args: typing.Any, **kwargs: typing.Any) -> bytes:
311310
raise
312311
except OpenSSL.SSL.WantReadError as e:
313312
if not util.wait_for_read(self.socket, self.socket.gettimeout()):
314-
raise timeout("The read operation timed out") from e
313+
raise TimeoutError("The read operation timed out") from e
315314
else:
316315
return self.recv(*args, **kwargs)
317316

@@ -336,7 +335,7 @@ def recv_into(self, *args: typing.Any, **kwargs: typing.Any) -> int:
336335
raise
337336
except OpenSSL.SSL.WantReadError as e:
338337
if not util.wait_for_read(self.socket, self.socket.gettimeout()):
339-
raise timeout("The read operation timed out") from e
338+
raise TimeoutError("The read operation timed out") from e
340339
else:
341340
return self.recv_into(*args, **kwargs)
342341

@@ -353,7 +352,7 @@ def _send_until_done(self, data: bytes) -> int:
353352
return self.connection.send(data) # type: ignore[no-any-return]
354353
except OpenSSL.SSL.WantWriteError as e:
355354
if not util.wait_for_write(self.socket, self.socket.gettimeout()):
356-
raise timeout() from e
355+
raise TimeoutError() from e
357356
continue
358357
except OpenSSL.SSL.SysCallError as e:
359358
raise OSError(e.args[0], str(e)) from e
@@ -520,7 +519,7 @@ def wrap_socket(
520519
cnx.do_handshake()
521520
except OpenSSL.SSL.WantReadError as e:
522521
if not util.wait_for_read(sock, sock.gettimeout()):
523-
raise timeout("select timed out") from e
522+
raise TimeoutError("select timed out") from e
524523
continue
525524
except OpenSSL.SSL.Error as e:
526525
raise ssl.SSLError(f"bad handshake: {e!r}") from e

src/snowflake/connector/vendored/urllib3/contrib/socks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ def _new_conn(self) -> socks.socksocket:
141141
raise NewConnectionError(
142142
self, f"Failed to establish a new connection: {error}"
143143
)
144-
else:
144+
else: # Defensive: see https://github.com/urllib3/urllib3/pull/3728#pullrequestreview-3816302703
145145
raise NewConnectionError(
146146
self, f"Failed to establish a new connection: {e}"
147147
) from e

src/snowflake/connector/vendored/urllib3/exceptions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ def __reduce__(self) -> _TYPE_REDUCE_RESULT:
155155
def pool(self) -> HTTPConnection:
156156
warnings.warn(
157157
"The 'pool' property is deprecated and will be removed "
158-
"in urllib3 v2.1.0. Use 'conn' instead.",
159-
DeprecationWarning,
158+
"in urllib3 v3.0. Use 'conn' instead.",
159+
FutureWarning,
160160
stacklevel=2,
161161
)
162162

0 commit comments

Comments
 (0)