Skip to content

Commit 8581010

Browse files
SNOW-201003 vendoring requests and urllib3 (snowflakedb#557)
1 parent aaa3a52 commit 8581010

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+15440
-55
lines changed

Diff for: .pre-commit-config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
exclude: '^(.*egg.info.*|.*/parameters.py).*$'
1+
exclude: '^(.*egg.info.*|.*/parameters.py|src/snowflake/connector/vendored/.*/).*$'
22
repos:
33
- repo: https://github.com/asottile/seed-isort-config
44
rev: v1.9.1

Diff for: MANIFEST.in

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
include *.rst
22
recursive-include src/snowflake/connector *.py *.pyx
33
include LICENSE.txt
4+
include NOTICE
45
recursive-include src/snowflake/connector/cpp *.cpp *.hpp
56
prune test

Diff for: NOTICE

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Snowflake Python Connector
2+
Copyright 2020 Snowflake Inc.
3+
4+
This software includes software derived from urllib3, licensed under the MIT license (https://urllib3.readthedocs.io).
5+
Copyright (c) 2008-2020 Andrey Petrov and contributors
6+
7+
This software includes software derived from Requests: HTTP For Humans, licensed under the Apache license, developed by the Python Software Foundation (https://requests.readthedocs.io/)
8+
Requests Copyright 2019 Kenneth Reitz

Diff for: setup.py

+17-4
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,8 @@ def _get_arrow_lib_as_linker_input(self):
195195
'azure-common<2.0.0',
196196
'azure-storage-blob>=12.0.0,<13.0.0',
197197
'boto3>=1.4.4,<2.0.0',
198-
'requests<2.24.0',
199-
'urllib3>=1.20,<1.26.0',
198+
'requests<3.0.0',
199+
'urllib3<2.0.0',
200200
'certifi<2021.0.0',
201201
'pytz<2021.0',
202202
'pycryptodomex>=3.2,!=3.5.0,<4.0.0',
@@ -210,16 +210,29 @@ def _get_arrow_lib_as_linker_input(self):
210210
# required. Python 3.6 was released at the end of 2016. setuptools 34.0.0 was released
211211
# in early 2017, so we pick this version as a reasonably modern base.
212212
'setuptools>34.0.0',
213+
# requests requirements
214+
'chardet>=3.0.2,<4',
215+
'idna>=2.5,<3',
216+
'certifi>=2017.4.17',
213217
],
214218

215219
namespace_packages=['snowflake'],
216220
packages=[
217221
'snowflake.connector',
218222
'snowflake.connector.tool',
223+
224+
'snowflake.connector.vendored',
225+
'snowflake.connector.vendored.requests',
226+
'snowflake.connector.vendored.urllib3',
227+
'snowflake.connector.vendored.urllib3.packages',
228+
'snowflake.connector.vendored.urllib3.packages.ssl_match_hostname',
229+
'snowflake.connector.vendored.urllib3.packages.backports',
230+
'snowflake.connector.vendored.urllib3.contrib',
231+
'snowflake.connector.vendored.urllib3.contrib._securetransport',
232+
'snowflake.connector.vendored.urllib3.util',
219233
],
220234
package_dir={
221-
'snowflake.connector': os.path.join('src', 'snowflake', 'connector'),
222-
'snowflake.connector.tool': os.path.join('src', 'snowflake', 'connector', 'tool'),
235+
'': 'src',
223236
},
224237
package_data={
225238
'snowflake.connector': ['*.pem', '*.json', '*.rst', 'LICENSE.txt'],

Diff for: src/snowflake/connector/gcs_util.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@
1010
from logging import getLogger
1111
from typing import Any, Dict
1212

13-
import requests
14-
1513
from .compat import quote
1614
from .constants import HTTP_HEADER_CONTENT_ENCODING, SHA256_DIGEST, FileHeader, ResultStatus
1715
from .encryption_util import EncryptionMetadata
16+
from .vendored import requests
1817

1918
logger = getLogger(__name__)
2019

Diff for: src/snowflake/connector/gzip_decoder.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from typing import IO
1212

1313
CHUNK_SIZE = 16384
14-
MAGIC_NUMBER = 16 # magic number from requests/packages/urllib3/response.py
14+
MAGIC_NUMBER = 16 # magic number from .vendored.requests/packages/urllib3/response.py
1515

1616
logger = getLogger(__name__)
1717

Diff for: src/snowflake/connector/network.py

+6-8
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@
1717
from threading import Lock
1818

1919
import OpenSSL.SSL
20-
import requests
21-
from requests.adapters import HTTPAdapter
22-
from requests.auth import AuthBase
23-
from requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout, SSLError
24-
from requests.packages.urllib3.exceptions import ProtocolError, ReadTimeoutError
25-
26-
from snowflake.connector.time_util import get_time_millis
2720

2821
from . import ssl_wrap_socket
2922
from .compat import (
@@ -81,8 +74,13 @@
8174
SQLSTATE_IO_ERROR,
8275
)
8376
from .telemetry_oob import TelemetryService
84-
from .time_util import DEFAULT_MASTER_VALIDITY_IN_SECONDS, DecorrelateJitterBackoff
77+
from .time_util import DEFAULT_MASTER_VALIDITY_IN_SECONDS, DecorrelateJitterBackoff, get_time_millis
8578
from .tool.probe_connection import probe_connection
79+
from .vendored import requests
80+
from .vendored.requests.adapters import HTTPAdapter
81+
from .vendored.requests.auth import AuthBase
82+
from .vendored.requests.exceptions import ConnectionError, ConnectTimeout, ReadTimeout, SSLError
83+
from .vendored.urllib3.exceptions import ProtocolError, ReadTimeoutError
8684

8785
logger = logging.getLogger(__name__)
8886

Diff for: src/snowflake/connector/ssl_wrap_socket.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,17 @@
1616
from functools import wraps
1717
from inspect import getfullargspec as get_args
1818
from socket import socket
19+
from typing import Optional
1920

2021
import certifi
2122
import OpenSSL.SSL
22-
import requests.packages.urllib3.connection as connection_
23-
import requests.packages.urllib3.util.ssl_ as ssl_
2423
from urllib3.contrib.pyopenssl import PyOpenSSLContext
2524

2625
from .constants import OCSPMode
2726
from .errorcode import ER_OCSP_RESPONSE_CERT_STATUS_REVOKED
2827
from .errors import OperationalError
28+
from .vendored.urllib3 import connection as connection_
29+
from .vendored.urllib3.util import ssl_ as ssl_
2930

3031
FEATURE_OCSP_MODE = OCSPMode.FAIL_OPEN
3132

@@ -98,7 +99,10 @@ def ssl_wrap_socket_with_ocsp(*args, **kwargs):
9899
return ret
99100

100101

101-
def _openssl_connect(hostname, port=443, max_retry=20):
102+
def _openssl_connect(hostname: str,
103+
port: int = 443,
104+
max_retry: int = 20,
105+
timeout: Optional[int] = None) -> OpenSSL.SSL.Connection:
102106
"""The OpenSSL connection without validating certificates.
103107
104108
This is used to diagnose SSL issues.
@@ -108,10 +112,11 @@ def _openssl_connect(hostname, port=443, max_retry=20):
108112
for _ in range(max_retry):
109113
try:
110114
client = socket()
111-
# client.settimeout(5)
112115
client.connect((hostname, port))
113-
client_ssl = OpenSSL.SSL.Connection(
114-
OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD), client)
116+
context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
117+
if timeout is not None:
118+
context.set_timeout(timeout)
119+
client_ssl = OpenSSL.SSL.Connection(context, client)
115120
client_ssl.set_connect_state()
116121
client_ssl.set_tlsext_host_name(hostname.encode('utf-8'))
117122
client_ssl.do_handshake()

Diff for: src/snowflake/connector/telemetry_oob.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@
1212
from queue import Queue
1313
from typing import Optional
1414

15-
import requests
16-
1715
from .compat import OK
1816
from .description import CLIENT_NAME, SNOWFLAKE_CONNECTOR_VERSION
1917
from .secret_detector import SecretDetector
2018
from .test_util import ENABLE_TELEMETRY_LOG, rt_plain_logger
19+
from .vendored import requests
2120

2221
logger = logging.getLogger(__name__)
2322

Diff for: src/snowflake/connector/vendored/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#
2+
# Copyright (c) 2012-2020 Snowflake Computing Inc. All right reserved.
3+
#
+130
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# -*- coding: utf-8 -*-
2+
3+
# __
4+
# /__) _ _ _ _ _/ _
5+
# / ( (- (/ (/ (- _) / _)
6+
# /
7+
8+
"""
9+
Requests HTTP Library
10+
~~~~~~~~~~~~~~~~~~~~~
11+
12+
Requests is an HTTP library, written in Python, for human beings.
13+
Basic GET usage:
14+
15+
>>> import requests
16+
>>> r = requests.get('https://www.python.org')
17+
>>> r.status_code
18+
200
19+
>>> b'Python is a programming language' in r.content
20+
True
21+
22+
... or POST:
23+
24+
>>> payload = dict(key1='value1', key2='value2')
25+
>>> r = requests.post('https://httpbin.org/post', data=payload)
26+
>>> print(r.text)
27+
{
28+
...
29+
"form": {
30+
"key1": "value1",
31+
"key2": "value2"
32+
},
33+
...
34+
}
35+
36+
The other HTTP methods are supported - see `requests.api`. Full documentation
37+
is at <https://requests.readthedocs.io>.
38+
39+
:copyright: (c) 2017 by Kenneth Reitz.
40+
:license: Apache 2.0, see LICENSE for more details.
41+
"""
42+
43+
from .. import urllib3
44+
import chardet
45+
import warnings
46+
from .exceptions import RequestsDependencyWarning
47+
48+
49+
def check_compatibility(urllib3_version, chardet_version):
50+
urllib3_version = urllib3_version.split('.')
51+
assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git.
52+
53+
# Sometimes, urllib3 only reports its version as 16.1.
54+
if len(urllib3_version) == 2:
55+
urllib3_version.append('0')
56+
57+
# Check urllib3 for compatibility.
58+
major, minor, patch = urllib3_version # noqa: F811
59+
major, minor, patch = int(major), int(minor), int(patch)
60+
# urllib3 >= 1.21.1, <= 1.25
61+
assert major == 1
62+
assert minor >= 21
63+
assert minor <= 25
64+
65+
# Check chardet for compatibility.
66+
major, minor, patch = chardet_version.split('.')[:3]
67+
major, minor, patch = int(major), int(minor), int(patch)
68+
# chardet >= 3.0.2, < 3.1.0
69+
assert major == 3
70+
assert minor < 1
71+
assert patch >= 2
72+
73+
74+
def _check_cryptography(cryptography_version):
75+
# cryptography < 1.3.4
76+
try:
77+
cryptography_version = list(map(int, cryptography_version.split('.')))
78+
except ValueError:
79+
return
80+
81+
if cryptography_version < [1, 3, 4]:
82+
warning = 'Old version of cryptography ({}) may cause slowdown.'.format(cryptography_version)
83+
warnings.warn(warning, RequestsDependencyWarning)
84+
85+
# Check imported dependencies for compatibility.
86+
try:
87+
check_compatibility(urllib3.__version__, chardet.__version__)
88+
except (AssertionError, ValueError):
89+
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
90+
"version!".format(urllib3.__version__, chardet.__version__),
91+
RequestsDependencyWarning)
92+
93+
# Attempt to enable urllib3's SNI support, if possible
94+
try:
95+
from ..urllib3.contrib import pyopenssl
96+
pyopenssl.inject_into_urllib3()
97+
98+
# Check cryptography version
99+
from cryptography import __version__ as cryptography_version
100+
_check_cryptography(cryptography_version)
101+
except ImportError:
102+
pass
103+
104+
# urllib3's DependencyWarnings should be silenced.
105+
from ..urllib3.exceptions import DependencyWarning
106+
warnings.simplefilter('ignore', DependencyWarning)
107+
108+
from .__version__ import __title__, __description__, __url__, __version__
109+
from .__version__ import __build__, __author__, __author_email__, __license__
110+
from .__version__ import __copyright__, __cake__
111+
112+
from . import utils
113+
from .models import Request, Response, PreparedRequest
114+
from .api import request, get, head, post, patch, put, delete, options
115+
from .sessions import session, Session
116+
from .status_codes import codes
117+
from .exceptions import (
118+
RequestException, Timeout, URLRequired,
119+
TooManyRedirects, HTTPError, ConnectionError,
120+
FileModeWarning, ConnectTimeout, ReadTimeout
121+
)
122+
123+
# Set default logging handler to avoid "No handler found" warnings.
124+
import logging
125+
from logging import NullHandler
126+
127+
logging.getLogger(__name__).addHandler(NullHandler())
128+
129+
# FileModeWarnings go off per the default.
130+
warnings.simplefilter('default', FileModeWarning, append=True)
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# .-. .-. .-. . . .-. .-. .-. .-.
2+
# |( |- |.| | | |- `-. | `-.
3+
# ' ' `-' `-`.`-' `-' `-' ' `-'
4+
5+
__title__ = 'requests'
6+
__description__ = 'Python HTTP for Humans.'
7+
__url__ = 'https://requests.readthedocs.io'
8+
__version__ = '2.23.0'
9+
__build__ = 0x022300
10+
__author__ = 'Kenneth Reitz'
11+
__author_email__ = '[email protected]'
12+
__license__ = 'Apache 2.0'
13+
__copyright__ = 'Copyright 2020 Kenneth Reitz'
14+
__cake__ = u'\u2728 \U0001f370 \u2728'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# -*- coding: utf-8 -*-
2+
3+
"""
4+
requests._internal_utils
5+
~~~~~~~~~~~~~~
6+
7+
Provides utility functions that are consumed internally by Requests
8+
which depend on extremely few external helpers (such as compat)
9+
"""
10+
11+
from .compat import is_py2, builtin_str, str
12+
13+
14+
def to_native_string(string, encoding='ascii'):
15+
"""Given a string object, regardless of type, returns a representation of
16+
that string in the native string type, encoding and decoding where
17+
necessary. This assumes ASCII unless told otherwise.
18+
"""
19+
if isinstance(string, builtin_str):
20+
out = string
21+
else:
22+
if is_py2:
23+
out = string.encode(encoding)
24+
else:
25+
out = string.decode(encoding)
26+
27+
return out
28+
29+
30+
def unicode_is_ascii(u_string):
31+
"""Determine if unicode string only contains ASCII characters.
32+
33+
:param str u_string: unicode string to check. Must be unicode
34+
and not Python 2 `str`.
35+
:rtype: bool
36+
"""
37+
assert isinstance(u_string, str)
38+
try:
39+
u_string.encode('ascii')
40+
return True
41+
except UnicodeEncodeError:
42+
return False

0 commit comments

Comments
 (0)