~ubuntu-branches/ubuntu/trusty/python-urllib3/trusty-proposed

« back to all changes in this revision

Viewing changes to .pc/01_do-not-use-embedded-python-six.patch/urllib3/connectionpool.py

  • Committer: Package Import Robot
  • Author(s): Daniele Tricoli, Jakub Wilk, Daniele Tricoli
  • Date: 2013-05-11 15:15:38 UTC
  • mfrom: (1.2.1) (4.2.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 8.
  • Revision ID: package-import@ubuntu.com-20130511151538-4dshl34jt0kkpt9i
[ Jakub Wilk ]
* Use canonical URIs for Vcs-* fields.

[ Daniele Tricoli ]
* New upstream release
* Upload to unstable (Closes: #707780)
* debian/control
  - Added python3-six to Build-Depends field
  - Bumped debhelper dependency to 8.1 for build-{arch,indep} support
  - Removed python-setuptools from Build-Depends field
* debian/copyright
  - Updated copyright years
  - Added stanza for urllib3/packages/ordered_dict.py
* debian/patches/01_do-not-use-embedded-python-six.patch
  - Refreshed
* debian/patches/02_require-cert-verification.patch
  - Refreshed
* debian/patches/03_no-setuptools.patch
  - Do not use setuptools
* debian/patches/04_relax_nosetests_options.patch
  - Do not use logging-clear-handlers to see all logging output and
    disabled cover-min-percentage since it require python-nose (>= 1.3):
    this way it will be easier to backport python-urllib3 to Wheezy.
* debian/patches/05_fix_python3_syntax_error_in_ntlmpool.patch
  - Fix syntax error 'unicodeescape' codec can't decode bytes in
    position 130-132 for Python3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# urllib3/connectionpool.py
2
 
# Copyright 2008-2012 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
 
2
# Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
3
3
#
4
4
# This module is part of urllib3 and is released under
5
5
# the MIT License: http://www.opensource.org/licenses/mit-license.php
6
6
 
7
7
import logging
8
8
import socket
 
9
import errno
9
10
 
10
11
from socket import error as SocketError, timeout as SocketTimeout
 
12
from .util import resolve_cert_reqs, resolve_ssl_version, assert_fingerprint
11
13
 
12
 
try:   # Python 3
 
14
try: # Python 3
13
15
    from http.client import HTTPConnection, HTTPException
14
16
    from http.client import HTTP_PORT, HTTPS_PORT
15
17
except ImportError:
16
18
    from httplib import HTTPConnection, HTTPException
17
19
    from httplib import HTTP_PORT, HTTPS_PORT
18
20
 
19
 
try:   # Python 3
 
21
try: # Python 3
20
22
    from queue import LifoQueue, Empty, Full
21
23
except ImportError:
22
24
    from Queue import LifoQueue, Empty, Full
23
25
 
24
26
 
25
 
try:   # Compiled with SSL?
 
27
try: # Compiled with SSL?
26
28
    HTTPSConnection = object
27
29
    BaseSSLError = None
28
30
    ssl = None
29
31
 
30
 
    try:   # Python 3
 
32
    try: # Python 3
31
33
        from http.client import HTTPSConnection
32
34
    except ImportError:
33
35
        from httplib import HTTPSConnection
35
37
    import ssl
36
38
    BaseSSLError = ssl.SSLError
37
39
 
38
 
except (ImportError, AttributeError):
 
40
except (ImportError, AttributeError): # Platform-specific: No SSL.
39
41
    pass
40
42
 
41
43
 
42
44
from .request import RequestMethods
43
45
from .response import HTTPResponse
44
 
from .util import get_host, is_connection_dropped
 
46
from .util import get_host, is_connection_dropped, ssl_wrap_socket
45
47
from .exceptions import (
 
48
    ClosedPoolError,
46
49
    EmptyPoolError,
47
50
    HostChangedError,
48
51
    MaxRetryError,
75
78
    """
76
79
    cert_reqs = None
77
80
    ca_certs = None
 
81
    ssl_version = None
78
82
 
79
83
    def set_cert(self, key_file=None, cert_file=None,
80
 
                 cert_reqs='CERT_NONE', ca_certs=None):
81
 
        ssl_req_scheme = {
82
 
            'CERT_NONE': ssl.CERT_NONE,
83
 
            'CERT_OPTIONAL': ssl.CERT_OPTIONAL,
84
 
            'CERT_REQUIRED': ssl.CERT_REQUIRED
85
 
        }
 
84
                 cert_reqs=None, ca_certs=None,
 
85
                 assert_hostname=None, assert_fingerprint=None):
86
86
 
87
87
        self.key_file = key_file
88
88
        self.cert_file = cert_file
89
 
        self.cert_reqs = ssl_req_scheme.get(cert_reqs) or ssl.CERT_NONE
 
89
        self.cert_reqs = cert_reqs
90
90
        self.ca_certs = ca_certs
 
91
        self.assert_hostname = assert_hostname
 
92
        self.assert_fingerprint = assert_fingerprint
91
93
 
92
94
    def connect(self):
93
95
        # Add certificate verification
94
96
        sock = socket.create_connection((self.host, self.port), self.timeout)
95
97
 
 
98
        resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs)
 
99
        resolved_ssl_version = resolve_ssl_version(self.ssl_version)
 
100
 
96
101
        # Wrap socket using verification with the root certs in
97
102
        # trusted_root_certs
98
 
        self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
99
 
                                    cert_reqs=self.cert_reqs,
100
 
                                    ca_certs=self.ca_certs)
101
 
        if self.ca_certs:
102
 
            match_hostname(self.sock.getpeercert(), self.host)
 
103
        self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
 
104
                                    cert_reqs=resolved_cert_reqs,
 
105
                                    ca_certs=self.ca_certs,
 
106
                                    server_hostname=self.host,
 
107
                                    ssl_version=resolved_ssl_version)
103
108
 
 
109
        if resolved_cert_reqs != ssl.CERT_NONE:
 
110
            if self.assert_fingerprint:
 
111
                assert_fingerprint(self.sock.getpeercert(binary_form=True),
 
112
                                   self.assert_fingerprint)
 
113
            else:
 
114
                match_hostname(self.sock.getpeercert(),
 
115
                               self.assert_hostname or self.host)
104
116
 
105
117
## Pool objects
106
118
 
165
177
 
166
178
    def __init__(self, host, port=None, strict=False, timeout=None, maxsize=1,
167
179
                 block=False, headers=None):
168
 
        super(HTTPConnectionPool, self).__init__(host, port)
 
180
        ConnectionPool.__init__(self, host, port)
 
181
        RequestMethods.__init__(self, headers)
169
182
 
170
183
        self.strict = strict
171
184
        self.timeout = timeout
172
185
        self.pool = self.QueueCls(maxsize)
173
186
        self.block = block
174
 
        self.headers = headers or {}
175
187
 
176
188
        # Fill the queue up so that doing get() on it will block properly
177
189
        for _ in xrange(maxsize):
188
200
        self.num_connections += 1
189
201
        log.info("Starting new HTTP connection (%d): %s" %
190
202
                 (self.num_connections, self.host))
191
 
        return HTTPConnection(host=self.host, port=self.port)
 
203
        return HTTPConnection(host=self.host,
 
204
                              port=self.port,
 
205
                              strict=self.strict)
192
206
 
193
207
    def _get_conn(self, timeout=None):
194
208
        """
206
220
        try:
207
221
            conn = self.pool.get(block=self.block, timeout=timeout)
208
222
 
209
 
            # If this is a persistent connection, check if it got disconnected
210
 
            if conn and is_connection_dropped(conn):
211
 
                log.info("Resetting dropped connection: %s" % self.host)
212
 
                conn.close()
 
223
        except AttributeError: # self.pool is None
 
224
            raise ClosedPoolError(self, "Pool is closed.")
213
225
 
214
226
        except Empty:
215
227
            if self.block:
218
230
                                     "connections are allowed.")
219
231
            pass  # Oh well, we'll create a new connection then
220
232
 
 
233
        # If this is a persistent connection, check if it got disconnected
 
234
        if conn and is_connection_dropped(conn):
 
235
            log.info("Resetting dropped connection: %s" % self.host)
 
236
            conn.close()
 
237
 
221
238
        return conn or self._new_conn()
222
239
 
223
240
    def _put_conn(self, conn):
228
245
            Connection object for the current host and port as returned by
229
246
            :meth:`._new_conn` or :meth:`._get_conn`.
230
247
 
231
 
        If the pool is already full, the connection is discarded because we
232
 
        exceeded maxsize. If connections are discarded frequently, then maxsize
233
 
        should be increased.
 
248
        If the pool is already full, the connection is closed and discarded
 
249
        because we exceeded maxsize. If connections are discarded frequently,
 
250
        then maxsize should be increased.
 
251
 
 
252
        If the pool is closed, then the connection will be closed and discarded.
234
253
        """
235
254
        try:
236
255
            self.pool.put(conn, block=False)
 
256
            return # Everything is dandy, done.
 
257
        except AttributeError:
 
258
            # self.pool is None.
 
259
            pass
237
260
        except Full:
238
261
            # This should never happen if self.block == True
239
262
            log.warning("HttpConnectionPool is full, discarding connection: %s"
240
263
                        % self.host)
241
264
 
 
265
        # Connection never got put back into the pool, close it.
 
266
        conn.close()
 
267
 
242
268
    def _make_request(self, conn, method, url, timeout=_Default,
243
269
                      **httplib_request_kw):
244
270
        """
258
284
        if sock:
259
285
            sock.settimeout(timeout)
260
286
 
261
 
        httplib_response = conn.getresponse()
262
 
 
263
 
        log.debug("\"%s %s %s\" %s %s" %
264
 
                  (method, url,
265
 
                   conn._http_vsn_str, # pylint: disable-msg=W0212
266
 
                   httplib_response.status, httplib_response.length))
267
 
 
 
287
        try: # Python 2.7+, use buffering of HTTP responses
 
288
            httplib_response = conn.getresponse(buffering=True)
 
289
        except TypeError: # Python 2.6 and older
 
290
            httplib_response = conn.getresponse()
 
291
 
 
292
        # AppEngine doesn't have a version attr.
 
293
        http_version = getattr(conn, '_http_vsn_str', 'HTTP/?')
 
294
        log.debug("\"%s %s %s\" %s %s" % (method, url, http_version,
 
295
                                          httplib_response.status,
 
296
                                          httplib_response.length))
268
297
        return httplib_response
269
298
 
 
299
    def close(self):
 
300
        """
 
301
        Close all pooled connections and disable the pool.
 
302
        """
 
303
        # Disable access to the pool
 
304
        old_pool, self.pool = self.pool, None
 
305
 
 
306
        try:
 
307
            while True:
 
308
                conn = old_pool.get(block=False)
 
309
                if conn:
 
310
                    conn.close()
 
311
 
 
312
        except Empty:
 
313
            pass # Done.
270
314
 
271
315
    def is_same_host(self, url):
272
316
        """
273
317
        Check if the given ``url`` is a member of the same host as this
274
318
        connection pool.
275
319
        """
 
320
        if url.startswith('/'):
 
321
            return True
 
322
 
276
323
        # TODO: Add optional support for socket.gethostbyname checking.
277
324
        scheme, host, port = get_host(url)
278
325
 
280
327
            # Use explicit default port for comparison when none is given.
281
328
            port = port_by_scheme.get(scheme)
282
329
 
283
 
        return (url.startswith('/') or
284
 
                (scheme, host, port) == (self.scheme, self.host, self.port))
 
330
        return (scheme, host, port) == (self.scheme, self.host, self.port)
285
331
 
286
332
    def urlopen(self, method, url, body=None, headers=None, retries=3,
287
333
                redirect=True, assert_same_host=True, timeout=_Default,
320
366
            Number of retries to allow before raising a MaxRetryError exception.
321
367
 
322
368
        :param redirect:
323
 
            Automatically handle redirects (status codes 301, 302, 303, 307),
324
 
            each redirect counts as a retry.
 
369
            If True, automatically handle redirects (status codes 301, 302,
 
370
            303, 307). Each redirect counts as a retry.
325
371
 
326
372
        :param assert_same_host:
327
373
            If ``True``, will make sure that the host of the pool requests is
374
420
 
375
421
        try:
376
422
            # Request a connection from the queue
377
 
            # (Could raise SocketError: Bad file descriptor)
378
423
            conn = self._get_conn(timeout=pool_timeout)
379
424
 
380
425
            # Make the request on the httplib connection object
423
468
            # This is necessary so we can access e below
424
469
            err = e
425
470
 
 
471
            if retries == 0:
 
472
                raise MaxRetryError(self, url, e)
 
473
 
426
474
        finally:
427
 
            if conn and release_conn:
428
 
                # Put the connection back to be reused
 
475
            if release_conn:
 
476
                # Put the connection back to be reused. If the connection is
 
477
                # expired then it will be None, which will get replaced with a
 
478
                # fresh connection during _get_conn.
429
479
                self._put_conn(conn)
430
480
 
431
481
        if not conn:
 
482
            # Try again
432
483
            log.warn("Retrying (%d attempts remain) after connection "
433
484
                     "broken by '%r': %s" % (retries, err, url))
434
485
            return self.urlopen(method, url, body, headers, retries - 1,
435
 
                                redirect, assert_same_host)  # Try again
 
486
                                redirect, assert_same_host,
 
487
                                timeout=timeout, pool_timeout=pool_timeout,
 
488
                                release_conn=release_conn, **response_kw)
436
489
 
437
490
        # Handle redirect?
438
491
        redirect_location = redirect and response.get_redirect_location()
439
492
        if redirect_location:
 
493
            if response.status == 303:
 
494
                method = 'GET'
440
495
            log.info("Redirecting %s -> %s" % (url, redirect_location))
441
496
            return self.urlopen(method, redirect_location, body, headers,
442
 
                                retries - 1, redirect, assert_same_host)
 
497
                                retries - 1, redirect, assert_same_host,
 
498
                                timeout=timeout, pool_timeout=pool_timeout,
 
499
                                release_conn=release_conn, **response_kw)
443
500
 
444
501
        return response
445
502
 
450
507
 
451
508
    When Python is compiled with the :mod:`ssl` module, then
452
509
    :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates,
453
 
    instead of :class:httplib.HTTPSConnection`.
454
 
 
455
 
    The ``key_file``, ``cert_file``, ``cert_reqs``, and ``ca_certs`` parameters
456
 
    are only used if :mod:`ssl` is available and are fed into
457
 
    :meth:`ssl.wrap_socket` to upgrade the connection socket into an SSL socket.
 
510
    instead of :class:`httplib.HTTPSConnection`.
 
511
 
 
512
    :class:`.VerifiedHTTPSConnection` uses one of ``assert_fingerprint``,
 
513
    ``assert_hostname`` and ``host`` in this order to verify connections.
 
514
 
 
515
    The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs`` and
 
516
    ``ssl_version`` are only used if :mod:`ssl` is available and are fed into
 
517
    :meth:`urllib3.util.ssl_wrap_socket` to upgrade the connection socket
 
518
    into an SSL socket.
458
519
    """
459
520
 
460
521
    scheme = 'https'
462
523
    def __init__(self, host, port=None,
463
524
                 strict=False, timeout=None, maxsize=1,
464
525
                 block=False, headers=None,
465
 
                 key_file=None, cert_file=None,
466
 
                 cert_reqs='CERT_NONE', ca_certs=None):
 
526
                 key_file=None, cert_file=None, cert_reqs=None,
 
527
                 ca_certs=None, ssl_version=None,
 
528
                 assert_hostname=None, assert_fingerprint=None):
467
529
 
468
 
        super(HTTPSConnectionPool, self).__init__(host, port,
469
 
                                                  strict, timeout, maxsize,
470
 
                                                  block, headers)
 
530
        HTTPConnectionPool.__init__(self, host, port,
 
531
                                    strict, timeout, maxsize,
 
532
                                    block, headers)
471
533
        self.key_file = key_file
472
534
        self.cert_file = cert_file
473
535
        self.cert_reqs = cert_reqs
474
536
        self.ca_certs = ca_certs
 
537
        self.ssl_version = ssl_version
 
538
        self.assert_hostname = assert_hostname
 
539
        self.assert_fingerprint = assert_fingerprint
475
540
 
476
541
    def _new_conn(self):
477
542
        """
481
546
        log.info("Starting new HTTPS connection (%d): %s"
482
547
                 % (self.num_connections, self.host))
483
548
 
484
 
        if not ssl: # Platform-specific: Python compiled without +ssl
 
549
        if not ssl:  # Platform-specific: Python compiled without +ssl
485
550
            if not HTTPSConnection or HTTPSConnection is object:
486
551
                raise SSLError("Can't connect to HTTPS URL because the SSL "
487
552
                               "module is not available.")
488
553
 
489
 
            return HTTPSConnection(host=self.host, port=self.port)
 
554
            return HTTPSConnection(host=self.host,
 
555
                                   port=self.port,
 
556
                                   strict=self.strict)
490
557
 
491
 
        connection = VerifiedHTTPSConnection(host=self.host, port=self.port)
 
558
        connection = VerifiedHTTPSConnection(host=self.host,
 
559
                                             port=self.port,
 
560
                                             strict=self.strict)
492
561
        connection.set_cert(key_file=self.key_file, cert_file=self.cert_file,
493
 
                            cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)
 
562
                            cert_reqs=self.cert_reqs, ca_certs=self.ca_certs,
 
563
                            assert_hostname=self.assert_hostname,
 
564
                            assert_fingerprint=self.assert_fingerprint)
 
565
 
 
566
        connection.ssl_version = self.ssl_version
 
567
 
494
568
        return connection
495
569
 
496
570