21247745639c5a64e8103033c48c074d636caf8c
[sdc/sdc-distribution-client.git] /
1 # urllib3/connection.py
2 # Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
3 #
4 # This module is part of urllib3 and is released under
5 # the MIT License: http://www.opensource.org/licenses/mit-license.php
6
7 import socket
8 from socket import timeout as SocketTimeout
9
10 try: # Python 3
11     from http.client import HTTPConnection as _HTTPConnection, HTTPException
12 except ImportError:
13     from httplib import HTTPConnection as _HTTPConnection, HTTPException
14
15 class DummyConnection(object):
16     "Used to detect a failed ConnectionCls import."
17     pass
18
19 try: # Compiled with SSL?
20     ssl = None
21     HTTPSConnection = DummyConnection
22
23     class BaseSSLError(BaseException):
24         pass
25
26     try: # Python 3
27         from http.client import HTTPSConnection as _HTTPSConnection
28     except ImportError:
29         from httplib import HTTPSConnection as _HTTPSConnection
30
31     import ssl
32     BaseSSLError = ssl.SSLError
33
34 except (ImportError, AttributeError): # Platform-specific: No SSL.
35     pass
36
37 from .exceptions import (
38     ConnectTimeoutError,
39 )
40 from .packages.ssl_match_hostname import match_hostname
41 from .util import (
42     assert_fingerprint,
43     resolve_cert_reqs,
44     resolve_ssl_version,
45     ssl_wrap_socket,
46 )
47
48
49 port_by_scheme = {
50     'http': 80,
51     'https': 443,
52 }
53
54
55 class HTTPConnection(_HTTPConnection, object):
56     default_port = port_by_scheme['http']
57
58     # By default, disable Nagle's Algorithm.
59     tcp_nodelay = 1
60
61     def _new_conn(self):
62         """ Establish a socket connection and set nodelay settings on it
63
64         :return: a new socket connection
65         """
66         try:
67             conn = socket.create_connection(
68                 (self.host, self.port),
69                 self.timeout,
70                 self.source_address,
71             )
72         except AttributeError: # Python 2.6
73             conn = socket.create_connection(
74                 (self.host, self.port),
75                 self.timeout,
76             )
77         conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
78                         self.tcp_nodelay)
79         return conn
80
81     def _prepare_conn(self, conn):
82         self.sock = conn
83         if self._tunnel_host:
84             # TODO: Fix tunnel so it doesn't depend on self.sock state.
85             self._tunnel()
86
87     def connect(self):
88         conn = self._new_conn()
89         self._prepare_conn(conn)
90
91
92 class HTTPSConnection(HTTPConnection):
93     default_port = port_by_scheme['https']
94
95     def __init__(self, host, port=None, key_file=None, cert_file=None,
96                  strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
97                  source_address=None):
98         try:
99             HTTPConnection.__init__(self, host, port, strict, timeout, source_address)
100         except TypeError: # Python 2.6
101             HTTPConnection.__init__(self, host, port, strict, timeout)
102         self.key_file = key_file
103         self.cert_file = cert_file
104
105     def connect(self):
106         conn = self._new_conn()
107         self._prepare_conn(conn)
108         self.sock = ssl.wrap_socket(conn, self.key_file, self.cert_file)
109
110
111 class VerifiedHTTPSConnection(HTTPSConnection):
112     """
113     Based on httplib.HTTPSConnection but wraps the socket with
114     SSL certification.
115     """
116     cert_reqs = None
117     ca_certs = None
118     ssl_version = None
119
120     def set_cert(self, key_file=None, cert_file=None,
121                  cert_reqs=None, ca_certs=None,
122                  assert_hostname=None, assert_fingerprint=None):
123
124         self.key_file = key_file
125         self.cert_file = cert_file
126         self.cert_reqs = cert_reqs
127         self.ca_certs = ca_certs
128         self.assert_hostname = assert_hostname
129         self.assert_fingerprint = assert_fingerprint
130
131     def connect(self):
132         # Add certificate verification
133         try:
134             sock = socket.create_connection(
135                 address=(self.host, self.port),
136                 timeout=self.timeout,
137             )
138         except SocketTimeout:
139             raise ConnectTimeoutError(
140                 self, "Connection to %s timed out. (connect timeout=%s)" %
141                 (self.host, self.timeout))
142
143         sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
144                         self.tcp_nodelay)
145
146         resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs)
147         resolved_ssl_version = resolve_ssl_version(self.ssl_version)
148
149         # the _tunnel_host attribute was added in python 2.6.3 (via
150         # http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do
151         # not have them.
152         if getattr(self, '_tunnel_host', None):
153             self.sock = sock
154             # Calls self._set_hostport(), so self.host is
155             # self._tunnel_host below.
156             self._tunnel()
157
158         # Wrap socket using verification with the root certs in
159         # trusted_root_certs
160         self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
161                                     cert_reqs=resolved_cert_reqs,
162                                     ca_certs=self.ca_certs,
163                                     server_hostname=self.host,
164                                     ssl_version=resolved_ssl_version)
165
166         if resolved_cert_reqs != ssl.CERT_NONE:
167             if self.assert_fingerprint:
168                 assert_fingerprint(self.sock.getpeercert(binary_form=True),
169                                    self.assert_fingerprint)
170             elif self.assert_hostname is not False:
171                 match_hostname(self.sock.getpeercert(),
172                                self.assert_hostname or self.host)
173
174
175 if ssl:
176     # Make a copy for testing.
177     UnverifiedHTTPSConnection = HTTPSConnection
178     HTTPSConnection = VerifiedHTTPSConnection