1 # urllib3/connection.py
2 # Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
4 # This module is part of urllib3 and is released under
5 # the MIT License: http://www.opensource.org/licenses/mit-license.php
8 from socket import timeout as SocketTimeout
11 from http.client import HTTPConnection as _HTTPConnection, HTTPException
13 from httplib import HTTPConnection as _HTTPConnection, HTTPException
15 class DummyConnection(object):
16 "Used to detect a failed ConnectionCls import."
19 try: # Compiled with SSL?
21 HTTPSConnection = DummyConnection
23 class BaseSSLError(BaseException):
27 from http.client import HTTPSConnection as _HTTPSConnection
29 from httplib import HTTPSConnection as _HTTPSConnection
32 BaseSSLError = ssl.SSLError
34 except (ImportError, AttributeError): # Platform-specific: No SSL.
37 from .exceptions import (
40 from .packages.ssl_match_hostname import match_hostname
55 class HTTPConnection(_HTTPConnection, object):
56 default_port = port_by_scheme['http']
58 # By default, disable Nagle's Algorithm.
62 """ Establish a socket connection and set nodelay settings on it
64 :return: a new socket connection
67 conn = socket.create_connection(
68 (self.host, self.port),
72 except AttributeError: # Python 2.6
73 conn = socket.create_connection(
74 (self.host, self.port),
77 conn.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
81 def _prepare_conn(self, conn):
84 # TODO: Fix tunnel so it doesn't depend on self.sock state.
88 conn = self._new_conn()
89 self._prepare_conn(conn)
92 class HTTPSConnection(HTTPConnection):
93 default_port = port_by_scheme['https']
95 def __init__(self, host, port=None, key_file=None, cert_file=None,
96 strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
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
106 conn = self._new_conn()
107 self._prepare_conn(conn)
108 self.sock = ssl.wrap_socket(conn, self.key_file, self.cert_file)
111 class VerifiedHTTPSConnection(HTTPSConnection):
113 Based on httplib.HTTPSConnection but wraps the socket with
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):
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
132 # Add certificate verification
134 sock = socket.create_connection(
135 address=(self.host, self.port),
136 timeout=self.timeout,
138 except SocketTimeout:
139 raise ConnectTimeoutError(
140 self, "Connection to %s timed out. (connect timeout=%s)" %
141 (self.host, self.timeout))
143 sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY,
146 resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs)
147 resolved_ssl_version = resolve_ssl_version(self.ssl_version)
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
152 if getattr(self, '_tunnel_host', None):
154 # Calls self._set_hostport(), so self.host is
155 # self._tunnel_host below.
158 # Wrap socket using verification with the root certs in
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)
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)
176 # Make a copy for testing.
177 UnverifiedHTTPSConnection = HTTPSConnection
178 HTTPSConnection = VerifiedHTTPSConnection