Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hhhrrrttt222111
GitHub Repository: hhhrrrttt222111/Dorkify
Path: blob/master/venv/Lib/site-packages/urllib3/connection.py
811 views
1
from __future__ import absolute_import
2
import re
3
import datetime
4
import logging
5
import os
6
import socket
7
from socket import error as SocketError, timeout as SocketTimeout
8
import warnings
9
from .packages import six
10
from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection
11
from .packages.six.moves.http_client import HTTPException # noqa: F401
12
13
try: # Compiled with SSL?
14
import ssl
15
16
BaseSSLError = ssl.SSLError
17
except (ImportError, AttributeError): # Platform-specific: No SSL.
18
ssl = None
19
20
class BaseSSLError(BaseException):
21
pass
22
23
24
try:
25
# Python 3: not a no-op, we're adding this to the namespace so it can be imported.
26
ConnectionError = ConnectionError
27
except NameError:
28
# Python 2
29
class ConnectionError(Exception):
30
pass
31
32
33
from .exceptions import (
34
NewConnectionError,
35
ConnectTimeoutError,
36
SubjectAltNameWarning,
37
SystemTimeWarning,
38
)
39
from .packages.ssl_match_hostname import match_hostname, CertificateError
40
41
from .util.ssl_ import (
42
resolve_cert_reqs,
43
resolve_ssl_version,
44
assert_fingerprint,
45
create_urllib3_context,
46
ssl_wrap_socket,
47
)
48
49
50
from .util import connection
51
52
from ._collections import HTTPHeaderDict
53
54
log = logging.getLogger(__name__)
55
56
port_by_scheme = {"http": 80, "https": 443}
57
58
# When it comes time to update this value as a part of regular maintenance
59
# (ie test_recent_date is failing) update it to ~6 months before the current date.
60
RECENT_DATE = datetime.date(2019, 1, 1)
61
62
_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
63
64
65
class DummyConnection(object):
66
"""Used to detect a failed ConnectionCls import."""
67
68
pass
69
70
71
class HTTPConnection(_HTTPConnection, object):
72
"""
73
Based on httplib.HTTPConnection but provides an extra constructor
74
backwards-compatibility layer between older and newer Pythons.
75
76
Additional keyword parameters are used to configure attributes of the connection.
77
Accepted parameters include:
78
79
- ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool`
80
- ``source_address``: Set the source address for the current connection.
81
- ``socket_options``: Set specific options on the underlying socket. If not specified, then
82
defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling
83
Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy.
84
85
For example, if you wish to enable TCP Keep Alive in addition to the defaults,
86
you might pass::
87
88
HTTPConnection.default_socket_options + [
89
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
90
]
91
92
Or you may want to disable the defaults by passing an empty list (e.g., ``[]``).
93
"""
94
95
default_port = port_by_scheme["http"]
96
97
#: Disable Nagle's algorithm by default.
98
#: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]``
99
default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]
100
101
#: Whether this connection verifies the host's certificate.
102
is_verified = False
103
104
def __init__(self, *args, **kw):
105
if not six.PY2:
106
kw.pop("strict", None)
107
108
# Pre-set source_address.
109
self.source_address = kw.get("source_address")
110
111
#: The socket options provided by the user. If no options are
112
#: provided, we use the default options.
113
self.socket_options = kw.pop("socket_options", self.default_socket_options)
114
115
_HTTPConnection.__init__(self, *args, **kw)
116
117
@property
118
def host(self):
119
"""
120
Getter method to remove any trailing dots that indicate the hostname is an FQDN.
121
122
In general, SSL certificates don't include the trailing dot indicating a
123
fully-qualified domain name, and thus, they don't validate properly when
124
checked against a domain name that includes the dot. In addition, some
125
servers may not expect to receive the trailing dot when provided.
126
127
However, the hostname with trailing dot is critical to DNS resolution; doing a
128
lookup with the trailing dot will properly only resolve the appropriate FQDN,
129
whereas a lookup without a trailing dot will search the system's search domain
130
list. Thus, it's important to keep the original host around for use only in
131
those cases where it's appropriate (i.e., when doing DNS lookup to establish the
132
actual TCP connection across which we're going to send HTTP requests).
133
"""
134
return self._dns_host.rstrip(".")
135
136
@host.setter
137
def host(self, value):
138
"""
139
Setter for the `host` property.
140
141
We assume that only urllib3 uses the _dns_host attribute; httplib itself
142
only uses `host`, and it seems reasonable that other libraries follow suit.
143
"""
144
self._dns_host = value
145
146
def _new_conn(self):
147
""" Establish a socket connection and set nodelay settings on it.
148
149
:return: New socket connection.
150
"""
151
extra_kw = {}
152
if self.source_address:
153
extra_kw["source_address"] = self.source_address
154
155
if self.socket_options:
156
extra_kw["socket_options"] = self.socket_options
157
158
try:
159
conn = connection.create_connection(
160
(self._dns_host, self.port), self.timeout, **extra_kw
161
)
162
163
except SocketTimeout:
164
raise ConnectTimeoutError(
165
self,
166
"Connection to %s timed out. (connect timeout=%s)"
167
% (self.host, self.timeout),
168
)
169
170
except SocketError as e:
171
raise NewConnectionError(
172
self, "Failed to establish a new connection: %s" % e
173
)
174
175
return conn
176
177
def _prepare_conn(self, conn):
178
self.sock = conn
179
# Google App Engine's httplib does not define _tunnel_host
180
if getattr(self, "_tunnel_host", None):
181
# TODO: Fix tunnel so it doesn't depend on self.sock state.
182
self._tunnel()
183
# Mark this connection as not reusable
184
self.auto_open = 0
185
186
def connect(self):
187
conn = self._new_conn()
188
self._prepare_conn(conn)
189
190
def putrequest(self, method, url, *args, **kwargs):
191
"""Send a request to the server"""
192
match = _CONTAINS_CONTROL_CHAR_RE.search(method)
193
if match:
194
raise ValueError(
195
"Method cannot contain non-token characters %r (found at least %r)"
196
% (method, match.group())
197
)
198
199
return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)
200
201
def request_chunked(self, method, url, body=None, headers=None):
202
"""
203
Alternative to the common request method, which sends the
204
body with chunked encoding and not as one block
205
"""
206
headers = HTTPHeaderDict(headers if headers is not None else {})
207
skip_accept_encoding = "accept-encoding" in headers
208
skip_host = "host" in headers
209
self.putrequest(
210
method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host
211
)
212
for header, value in headers.items():
213
self.putheader(header, value)
214
if "transfer-encoding" not in headers:
215
self.putheader("Transfer-Encoding", "chunked")
216
self.endheaders()
217
218
if body is not None:
219
stringish_types = six.string_types + (bytes,)
220
if isinstance(body, stringish_types):
221
body = (body,)
222
for chunk in body:
223
if not chunk:
224
continue
225
if not isinstance(chunk, bytes):
226
chunk = chunk.encode("utf8")
227
len_str = hex(len(chunk))[2:]
228
self.send(len_str.encode("utf-8"))
229
self.send(b"\r\n")
230
self.send(chunk)
231
self.send(b"\r\n")
232
233
# After the if clause, to always have a closed body
234
self.send(b"0\r\n\r\n")
235
236
237
class HTTPSConnection(HTTPConnection):
238
default_port = port_by_scheme["https"]
239
240
cert_reqs = None
241
ca_certs = None
242
ca_cert_dir = None
243
ca_cert_data = None
244
ssl_version = None
245
assert_fingerprint = None
246
247
def __init__(
248
self,
249
host,
250
port=None,
251
key_file=None,
252
cert_file=None,
253
key_password=None,
254
strict=None,
255
timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
256
ssl_context=None,
257
server_hostname=None,
258
**kw
259
):
260
261
HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw)
262
263
self.key_file = key_file
264
self.cert_file = cert_file
265
self.key_password = key_password
266
self.ssl_context = ssl_context
267
self.server_hostname = server_hostname
268
269
# Required property for Google AppEngine 1.9.0 which otherwise causes
270
# HTTPS requests to go out as HTTP. (See Issue #356)
271
self._protocol = "https"
272
273
def set_cert(
274
self,
275
key_file=None,
276
cert_file=None,
277
cert_reqs=None,
278
key_password=None,
279
ca_certs=None,
280
assert_hostname=None,
281
assert_fingerprint=None,
282
ca_cert_dir=None,
283
ca_cert_data=None,
284
):
285
"""
286
This method should only be called once, before the connection is used.
287
"""
288
# If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also
289
# have an SSLContext object in which case we'll use its verify_mode.
290
if cert_reqs is None:
291
if self.ssl_context is not None:
292
cert_reqs = self.ssl_context.verify_mode
293
else:
294
cert_reqs = resolve_cert_reqs(None)
295
296
self.key_file = key_file
297
self.cert_file = cert_file
298
self.cert_reqs = cert_reqs
299
self.key_password = key_password
300
self.assert_hostname = assert_hostname
301
self.assert_fingerprint = assert_fingerprint
302
self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
303
self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
304
self.ca_cert_data = ca_cert_data
305
306
def connect(self):
307
# Add certificate verification
308
conn = self._new_conn()
309
hostname = self.host
310
311
# Google App Engine's httplib does not define _tunnel_host
312
if getattr(self, "_tunnel_host", None):
313
self.sock = conn
314
# Calls self._set_hostport(), so self.host is
315
# self._tunnel_host below.
316
self._tunnel()
317
# Mark this connection as not reusable
318
self.auto_open = 0
319
320
# Override the host with the one we're requesting data from.
321
hostname = self._tunnel_host
322
323
server_hostname = hostname
324
if self.server_hostname is not None:
325
server_hostname = self.server_hostname
326
327
is_time_off = datetime.date.today() < RECENT_DATE
328
if is_time_off:
329
warnings.warn(
330
(
331
"System time is way off (before {0}). This will probably "
332
"lead to SSL verification errors"
333
).format(RECENT_DATE),
334
SystemTimeWarning,
335
)
336
337
# Wrap socket using verification with the root certs in
338
# trusted_root_certs
339
default_ssl_context = False
340
if self.ssl_context is None:
341
default_ssl_context = True
342
self.ssl_context = create_urllib3_context(
343
ssl_version=resolve_ssl_version(self.ssl_version),
344
cert_reqs=resolve_cert_reqs(self.cert_reqs),
345
)
346
347
context = self.ssl_context
348
context.verify_mode = resolve_cert_reqs(self.cert_reqs)
349
350
# Try to load OS default certs if none are given.
351
# Works well on Windows (requires Python3.4+)
352
if (
353
not self.ca_certs
354
and not self.ca_cert_dir
355
and not self.ca_cert_data
356
and default_ssl_context
357
and hasattr(context, "load_default_certs")
358
):
359
context.load_default_certs()
360
361
self.sock = ssl_wrap_socket(
362
sock=conn,
363
keyfile=self.key_file,
364
certfile=self.cert_file,
365
key_password=self.key_password,
366
ca_certs=self.ca_certs,
367
ca_cert_dir=self.ca_cert_dir,
368
ca_cert_data=self.ca_cert_data,
369
server_hostname=server_hostname,
370
ssl_context=context,
371
)
372
373
if self.assert_fingerprint:
374
assert_fingerprint(
375
self.sock.getpeercert(binary_form=True), self.assert_fingerprint
376
)
377
elif (
378
context.verify_mode != ssl.CERT_NONE
379
and not getattr(context, "check_hostname", False)
380
and self.assert_hostname is not False
381
):
382
# While urllib3 attempts to always turn off hostname matching from
383
# the TLS library, this cannot always be done. So we check whether
384
# the TLS Library still thinks it's matching hostnames.
385
cert = self.sock.getpeercert()
386
if not cert.get("subjectAltName", ()):
387
warnings.warn(
388
(
389
"Certificate for {0} has no `subjectAltName`, falling back to check for a "
390
"`commonName` for now. This feature is being removed by major browsers and "
391
"deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 "
392
"for details.)".format(hostname)
393
),
394
SubjectAltNameWarning,
395
)
396
_match_hostname(cert, self.assert_hostname or server_hostname)
397
398
self.is_verified = (
399
context.verify_mode == ssl.CERT_REQUIRED
400
or self.assert_fingerprint is not None
401
)
402
403
404
def _match_hostname(cert, asserted_hostname):
405
try:
406
match_hostname(cert, asserted_hostname)
407
except CertificateError as e:
408
log.warning(
409
"Certificate did not match expected hostname: %s. Certificate: %s",
410
asserted_hostname,
411
cert,
412
)
413
# Add cert to exception and reraise so client code can inspect
414
# the cert when catching the exception, if they want to
415
e._peer_cert = cert
416
raise
417
418
419
if not ssl:
420
HTTPSConnection = DummyConnection # noqa: F811
421
422
423
VerifiedHTTPSConnection = HTTPSConnection
424
425