Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factor out HTTP(S)Connection -> ConnectionCls, and cleanup. #254

Merged
merged 6 commits into from
Oct 16, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ dev (master)
* Improved url parsing in ``urllib3.util.parse_url`` (properly parse '@' in
username, and blank ports like 'hostname:').

* New `urllib3.connection` module which contains all the HTTPConnection
objects.

* ...


1.7.1 (2013-09-25)
++++++++++++++++++
Expand Down
59 changes: 12 additions & 47 deletions test/with_dummyserver/test_https.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,14 @@ def test_verified(self):
self.assertTrue("doesn't match" in str(e))

def test_no_ssl(self):
import urllib3.connectionpool
OriginalHTTPSConnection = urllib3.connectionpool.HTTPSConnection
OriginalSSL = urllib3.connectionpool.ssl

urllib3.connectionpool.HTTPSConnection = None
urllib3.connectionpool.ssl = None
OriginalConnectionCls = self._pool.ConnectionCls
self._pool.ConnectionCls = None

self.assertRaises(SSLError, self._pool._new_conn)

self.assertRaises(SSLError, self._pool.request, 'GET', '/')

# Undo
urllib3.HTTPSConnection = OriginalHTTPSConnection
urllib3.connectionpool.ssl = OriginalSSL
self._pool.ConnectionCls = OriginalConnectionCls

def test_cert_reqs_as_constant(self):
https_pool = HTTPSConnectionPool(self.host, self.port,
Expand Down Expand Up @@ -223,57 +217,28 @@ def test_tunnel(self):


def test_enhanced_timeout(self):
import urllib3.connectionpool
OriginalHTTPSConnection = urllib3.connectionpool.HTTPSConnection
OriginalSSL = urllib3.connectionpool.ssl
def new_pool(timeout, cert_reqs='CERT_REQUIRED'):
https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port,
timeout=timeout,
cert_reqs=cert_reqs)
return https_pool

urllib3.connectionpool.ssl = None

timeout = Timeout(connect=0.001)
https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port,
timeout=timeout,
cert_reqs='CERT_REQUIRED')
https_pool = new_pool(Timeout(connect=0.001))
conn = https_pool._new_conn()
self.assertEqual(conn.__class__, HTTPSConnection)
self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/')
self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn,
'GET', '/')

timeout = Timeout(connect=5)
https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port,
timeout=timeout,
cert_reqs='CERT_REQUIRED')
https_pool = new_pool(Timeout(connect=5))
self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/',
timeout=Timeout(connect=0.001))

timeout = Timeout(total=None)
https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port,
timeout=timeout,
cert_reqs='CERT_REQUIRED')
t = Timeout(total=None)
https_pool = new_pool(t)
conn = https_pool._new_conn()
self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/',
timeout=Timeout(total=None, connect=0.001))

https_pool = HTTPSConnectionPool(self.host, self.port,
timeout=timeout,
cert_reqs='CERT_NONE')
conn = https_pool._new_conn()
try:
conn.set_tunnel(self.host, self.port)
except AttributeError: # python 2.6
conn._set_tunnel(self.host, self.port)
conn._tunnel = mock.Mock()
try:
https_pool._make_request(conn, 'GET', '/')
except AttributeError:
# wrap_socket unavailable when you mock out ssl
pass
conn._tunnel.assert_called_once_with()

# Undo
urllib3.HTTPSConnection = OriginalHTTPSConnection
urllib3.connectionpool.ssl = OriginalSSL

def test_enhanced_ssl_connection(self):
conn = VerifiedHTTPSConnection(self.host, self.port)
https_pool = HTTPSConnectionPool(self.host, self.port,
Expand Down
107 changes: 107 additions & 0 deletions urllib3/connection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# urllib3/connection.py
# Copyright 2008-2013 Andrey Petrov and contributors (see CONTRIBUTORS.txt)
#
# This module is part of urllib3 and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php

import socket
from socket import timeout as SocketTimeout

try: # Python 3
from http.client import HTTPConnection, HTTPException
except ImportError:
from httplib import HTTPConnection, HTTPException

class DummyConnection(object):
"Used to detect a failed ConnectionCls import."
pass

try: # Compiled with SSL?
ssl = None
HTTPSConnection = DummyConnection

class BaseSSLError(BaseException):
pass

try: # Python 3
from http.client import HTTPSConnection
except ImportError:
from httplib import HTTPSConnection

import ssl
BaseSSLError = ssl.SSLError

except (ImportError, AttributeError): # Platform-specific: No SSL.
pass

from .exceptions import (
ConnectTimeoutError,
)
from .packages.ssl_match_hostname import match_hostname
from .util import (
assert_fingerprint,
resolve_cert_reqs,
resolve_ssl_version,
ssl_wrap_socket,
)

class VerifiedHTTPSConnection(HTTPSConnection):
"""
Based on httplib.HTTPSConnection but wraps the socket with
SSL certification.
"""
cert_reqs = None
ca_certs = None
ssl_version = None

def set_cert(self, key_file=None, cert_file=None,
cert_reqs=None, ca_certs=None,
assert_hostname=None, assert_fingerprint=None):

self.key_file = key_file
self.cert_file = cert_file
self.cert_reqs = cert_reqs
self.ca_certs = ca_certs
self.assert_hostname = assert_hostname
self.assert_fingerprint = assert_fingerprint

def connect(self):
# Add certificate verification
try:
sock = socket.create_connection(
address=(self.host, self.port),
timeout=self.timeout,
)
except SocketTimeout:
raise ConnectTimeoutError(
self, "Connection to %s timed out. (connect timeout=%s)" %
(self.host, self.timeout))

resolved_cert_reqs = resolve_cert_reqs(self.cert_reqs)
resolved_ssl_version = resolve_ssl_version(self.ssl_version)

if self._tunnel_host:
self.sock = sock
# Calls self._set_hostport(), so self.host is
# self._tunnel_host below.
self._tunnel()

# Wrap socket using verification with the root certs in
# trusted_root_certs
self.sock = ssl_wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=resolved_cert_reqs,
ca_certs=self.ca_certs,
server_hostname=self.host,
ssl_version=resolved_ssl_version)

if resolved_cert_reqs != ssl.CERT_NONE:
if self.assert_fingerprint:
assert_fingerprint(self.sock.getpeercert(binary_form=True),
self.assert_fingerprint)
elif self.assert_hostname is not False:
match_hostname(self.sock.getpeercert(),
self.assert_hostname or self.host)


if ssl:
HTTPSConnection = VerifiedHTTPSConnection
Loading