gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / requests / packages / urllib3 / connection.py @ 564
History | View | Annotate | Download (10 KB)
1 |
from __future__ import absolute_import |
---|---|
2 |
import datetime |
3 |
import os |
4 |
import sys |
5 |
import socket |
6 |
from socket import error as SocketError, timeout as SocketTimeout |
7 |
import warnings |
8 |
from .packages import six |
9 |
|
10 |
try: # Python 3 |
11 |
from http.client import HTTPConnection as _HTTPConnection |
12 |
from http.client import HTTPException # noqa: unused in this module |
13 |
except ImportError: |
14 |
from httplib import HTTPConnection as _HTTPConnection |
15 |
from httplib import HTTPException # noqa: unused in this module |
16 |
|
17 |
try: # Compiled with SSL? |
18 |
import ssl |
19 |
BaseSSLError = ssl.SSLError |
20 |
except (ImportError, AttributeError): # Platform-specific: No SSL. |
21 |
ssl = None
|
22 |
|
23 |
class BaseSSLError(BaseException): |
24 |
pass
|
25 |
|
26 |
|
27 |
try: # Python 3: |
28 |
# Not a no-op, we're adding this to the namespace so it can be imported.
|
29 |
ConnectionError = ConnectionError |
30 |
except NameError: # Python 2: |
31 |
class ConnectionError(Exception): |
32 |
pass
|
33 |
|
34 |
|
35 |
from .exceptions import ( |
36 |
NewConnectionError, |
37 |
ConnectTimeoutError, |
38 |
SubjectAltNameWarning, |
39 |
SystemTimeWarning, |
40 |
) |
41 |
from .packages.ssl_match_hostname import match_hostname |
42 |
|
43 |
from .util.ssl_ import ( |
44 |
resolve_cert_reqs, |
45 |
resolve_ssl_version, |
46 |
ssl_wrap_socket, |
47 |
assert_fingerprint, |
48 |
) |
49 |
|
50 |
|
51 |
from .util import connection |
52 |
|
53 |
port_by_scheme = { |
54 |
'http': 80, |
55 |
'https': 443, |
56 |
} |
57 |
|
58 |
RECENT_DATE = datetime.date(2014, 1, 1) |
59 |
|
60 |
|
61 |
class DummyConnection(object): |
62 |
"""Used to detect a failed ConnectionCls import."""
|
63 |
pass
|
64 |
|
65 |
|
66 |
class HTTPConnection(_HTTPConnection, object): |
67 |
"""
|
68 |
Based on httplib.HTTPConnection but provides an extra constructor
|
69 |
backwards-compatibility layer between older and newer Pythons.
|
70 |
|
71 |
Additional keyword parameters are used to configure attributes of the connection.
|
72 |
Accepted parameters include:
|
73 |
|
74 |
- ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool`
|
75 |
- ``source_address``: Set the source address for the current connection.
|
76 |
|
77 |
.. note:: This is ignored for Python 2.6. It is only applied for 2.7 and 3.x
|
78 |
|
79 |
- ``socket_options``: Set specific options on the underlying socket. If not specified, then
|
80 |
defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling
|
81 |
Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy.
|
82 |
|
83 |
For example, if you wish to enable TCP Keep Alive in addition to the defaults,
|
84 |
you might pass::
|
85 |
|
86 |
HTTPConnection.default_socket_options + [
|
87 |
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
|
88 |
]
|
89 |
|
90 |
Or you may want to disable the defaults by passing an empty list (e.g., ``[]``).
|
91 |
"""
|
92 |
|
93 |
default_port = port_by_scheme['http']
|
94 |
|
95 |
#: Disable Nagle's algorithm by default.
|
96 |
#: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]``
|
97 |
default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]
|
98 |
|
99 |
#: Whether this connection verifies the host's certificate.
|
100 |
is_verified = False
|
101 |
|
102 |
def __init__(self, *args, **kw): |
103 |
if six.PY3: # Python 3 |
104 |
kw.pop('strict', None) |
105 |
|
106 |
# Pre-set source_address in case we have an older Python like 2.6.
|
107 |
self.source_address = kw.get('source_address') |
108 |
|
109 |
if sys.version_info < (2, 7): # Python 2.6 |
110 |
# _HTTPConnection on Python 2.6 will balk at this keyword arg, but
|
111 |
# not newer versions. We can still use it when creating a
|
112 |
# connection though, so we pop it *after* we have saved it as
|
113 |
# self.source_address.
|
114 |
kw.pop('source_address', None) |
115 |
|
116 |
#: The socket options provided by the user. If no options are
|
117 |
#: provided, we use the default options.
|
118 |
self.socket_options = kw.pop('socket_options', self.default_socket_options) |
119 |
|
120 |
# Superclass also sets self.source_address in Python 2.7+.
|
121 |
_HTTPConnection.__init__(self, *args, **kw)
|
122 |
|
123 |
def _new_conn(self): |
124 |
""" Establish a socket connection and set nodelay settings on it.
|
125 |
|
126 |
:return: New socket connection.
|
127 |
"""
|
128 |
extra_kw = {} |
129 |
if self.source_address: |
130 |
extra_kw['source_address'] = self.source_address |
131 |
|
132 |
if self.socket_options: |
133 |
extra_kw['socket_options'] = self.socket_options |
134 |
|
135 |
try:
|
136 |
conn = connection.create_connection( |
137 |
(self.host, self.port), self.timeout, **extra_kw) |
138 |
|
139 |
except SocketTimeout as e: |
140 |
raise ConnectTimeoutError(
|
141 |
self, "Connection to %s timed out. (connect timeout=%s)" % |
142 |
(self.host, self.timeout)) |
143 |
|
144 |
except SocketError as e: |
145 |
raise NewConnectionError(
|
146 |
self, "Failed to establish a new connection: %s" % e) |
147 |
|
148 |
return conn
|
149 |
|
150 |
def _prepare_conn(self, conn): |
151 |
self.sock = conn
|
152 |
# the _tunnel_host attribute was added in python 2.6.3 (via
|
153 |
# http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do
|
154 |
# not have them.
|
155 |
if getattr(self, '_tunnel_host', None): |
156 |
# TODO: Fix tunnel so it doesn't depend on self.sock state.
|
157 |
self._tunnel()
|
158 |
# Mark this connection as not reusable
|
159 |
self.auto_open = 0 |
160 |
|
161 |
def connect(self): |
162 |
conn = self._new_conn()
|
163 |
self._prepare_conn(conn)
|
164 |
|
165 |
|
166 |
class HTTPSConnection(HTTPConnection): |
167 |
default_port = port_by_scheme['https']
|
168 |
|
169 |
def __init__(self, host, port=None, key_file=None, cert_file=None, |
170 |
strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, **kw):
|
171 |
|
172 |
HTTPConnection.__init__(self, host, port, strict=strict,
|
173 |
timeout=timeout, **kw) |
174 |
|
175 |
self.key_file = key_file
|
176 |
self.cert_file = cert_file
|
177 |
|
178 |
# Required property for Google AppEngine 1.9.0 which otherwise causes
|
179 |
# HTTPS requests to go out as HTTP. (See Issue #356)
|
180 |
self._protocol = 'https' |
181 |
|
182 |
def connect(self): |
183 |
conn = self._new_conn()
|
184 |
self._prepare_conn(conn)
|
185 |
self.sock = ssl.wrap_socket(conn, self.key_file, self.cert_file) |
186 |
|
187 |
|
188 |
class VerifiedHTTPSConnection(HTTPSConnection): |
189 |
"""
|
190 |
Based on httplib.HTTPSConnection but wraps the socket with
|
191 |
SSL certification.
|
192 |
"""
|
193 |
cert_reqs = None
|
194 |
ca_certs = None
|
195 |
ca_cert_dir = None
|
196 |
ssl_version = None
|
197 |
assert_fingerprint = None
|
198 |
|
199 |
def set_cert(self, key_file=None, cert_file=None, |
200 |
cert_reqs=None, ca_certs=None, |
201 |
assert_hostname=None, assert_fingerprint=None, |
202 |
ca_cert_dir=None):
|
203 |
|
204 |
if (ca_certs or ca_cert_dir) and cert_reqs is None: |
205 |
cert_reqs = 'CERT_REQUIRED'
|
206 |
|
207 |
self.key_file = key_file
|
208 |
self.cert_file = cert_file
|
209 |
self.cert_reqs = cert_reqs
|
210 |
self.assert_hostname = assert_hostname
|
211 |
self.assert_fingerprint = assert_fingerprint
|
212 |
self.ca_certs = ca_certs and os.path.expanduser(ca_certs) |
213 |
self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) |
214 |
|
215 |
def connect(self): |
216 |
# Add certificate verification
|
217 |
conn = self._new_conn()
|
218 |
|
219 |
resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs)
|
220 |
resolved_ssl_version = resolve_ssl_version(self.ssl_version)
|
221 |
|
222 |
hostname = self.host
|
223 |
if getattr(self, '_tunnel_host', None): |
224 |
# _tunnel_host was added in Python 2.6.3
|
225 |
# (See: http://hg.python.org/cpython/rev/0f57b30a152f)
|
226 |
|
227 |
self.sock = conn
|
228 |
# Calls self._set_hostport(), so self.host is
|
229 |
# self._tunnel_host below.
|
230 |
self._tunnel()
|
231 |
# Mark this connection as not reusable
|
232 |
self.auto_open = 0 |
233 |
|
234 |
# Override the host with the one we're requesting data from.
|
235 |
hostname = self._tunnel_host
|
236 |
|
237 |
is_time_off = datetime.date.today() < RECENT_DATE |
238 |
if is_time_off:
|
239 |
warnings.warn(( |
240 |
'System time is way off (before {0}). This will probably '
|
241 |
'lead to SSL verification errors').format(RECENT_DATE),
|
242 |
SystemTimeWarning |
243 |
) |
244 |
|
245 |
# Wrap socket using verification with the root certs in
|
246 |
# trusted_root_certs
|
247 |
self.sock = ssl_wrap_socket(conn, self.key_file, self.cert_file, |
248 |
cert_reqs=resolved_cert_reqs, |
249 |
ca_certs=self.ca_certs,
|
250 |
ca_cert_dir=self.ca_cert_dir,
|
251 |
server_hostname=hostname, |
252 |
ssl_version=resolved_ssl_version) |
253 |
|
254 |
if self.assert_fingerprint: |
255 |
assert_fingerprint(self.sock.getpeercert(binary_form=True), |
256 |
self.assert_fingerprint)
|
257 |
elif resolved_cert_reqs != ssl.CERT_NONE \
|
258 |
and self.assert_hostname is not False: |
259 |
cert = self.sock.getpeercert()
|
260 |
if not cert.get('subjectAltName', ()): |
261 |
warnings.warn(( |
262 |
'Certificate for {0} has no `subjectAltName`, falling back to check for a '
|
263 |
'`commonName` for now. This feature is being removed by major browsers and '
|
264 |
'deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 '
|
265 |
'for details.)'.format(hostname)),
|
266 |
SubjectAltNameWarning |
267 |
) |
268 |
|
269 |
# In case the hostname is an IPv6 address, strip the square
|
270 |
# brackets from it before using it to validate. This is because
|
271 |
# a certificate with an IPv6 address in it won't have square
|
272 |
# brackets around that address. Sadly, match_hostname won't do this
|
273 |
# for us: it expects the plain host part without any extra work
|
274 |
# that might have been done to make it palatable to httplib.
|
275 |
asserted_hostname = self.assert_hostname or hostname |
276 |
asserted_hostname = asserted_hostname.strip('[]')
|
277 |
match_hostname(cert, asserted_hostname) |
278 |
|
279 |
self.is_verified = (resolved_cert_reqs == ssl.CERT_REQUIRED or |
280 |
self.assert_fingerprint is not None) |
281 |
|
282 |
|
283 |
if ssl:
|
284 |
# Make a copy for testing.
|
285 |
UnverifiedHTTPSConnection = HTTPSConnection |
286 |
HTTPSConnection = VerifiedHTTPSConnection |
287 |
else:
|
288 |
HTTPSConnection = DummyConnection |