Skip to content
This repository was archived by the owner on Aug 3, 2022. It is now read-only.

Commit 82350e1

Browse files
committed
Use TLS SNI extension with pyOpenSSL
Use TLS SNI extension in the client, if pyOpenSSL is available. This fixes resource fetches to https servers that require the extension. These are typically cdn servers. Example of such server, without SNI: $ openssl s_client -connect cdn3.vox-cdn.com:443 CONNECTED(00000003) 140434795792032:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:732: ... With SNI: $ openssl s_client -connect cdn3.vox-cdn.com:443 -servername cdn3.vox-cdn.com CONNECTED(00000003) depth=3 C = US, O = "The Go Daddy Group, Inc.", OU = Go Daddy Class 2 Certification Authority ....
1 parent 3cff84d commit 82350e1

File tree

1 file changed

+40
-4
lines changed

1 file changed

+40
-4
lines changed

Diff for: httpclient.py

+40-4
Original file line numberDiff line numberDiff line change
@@ -174,15 +174,50 @@ class DetailedHTTPConnection(httplib.HTTPConnection):
174174
"""Preserve details relevant to replaying connections."""
175175
response_class = DetailedHTTPResponse
176176

177-
178177
class DetailedHTTPSResponse(DetailedHTTPResponse):
179178
"""Preserve details relevant to replaying SSL responses."""
180179
pass
181180

181+
try:
182+
from OpenSSL import SSL
183+
import OpenSSL.version
184+
from socket import _fileobject
185+
if OpenSSL.version <= (0, 12):
186+
raise ImportError("Need pyOpenSSL > 0.12 for client usage")
187+
188+
SSLConnection = SSL.Connection
182189

183-
class DetailedHTTPSConnection(httplib.HTTPSConnection):
184-
"""Preserve details relevant to replaying SSL connections."""
185-
response_class = DetailedHTTPSResponse
190+
class FOSSLConnection(SSLConnection):
191+
"""A connection object that can be accessed as a file object.
192+
Needed so that httplib can use SSL.Connection.
193+
"""
194+
def makefile(self, mode, bufsize=-1):
195+
return _fileobject(self, mode, bufsize)
196+
197+
class DetailedHTTPSConnection(DetailedHTTPConnection):
198+
"""Preserve details relevant to replaying SSL connections.
199+
A pyOpenSSL implementation of DetailedHTTPConnection. This
200+
supports TLS SNI extension, which is needed for some content
201+
distribution networks."""
202+
response_class = DetailedHTTPSResponse
203+
default_port = httplib.HTTPS_PORT
204+
def __init__(self, host, port):
205+
DetailedHTTPConnection.__init__(self, host, port)
206+
self.context = SSL.Context(SSL.SSLv23_METHOD)
207+
208+
def connect(self):
209+
DetailedHTTPConnection.connect(self)
210+
self.sock = FOSSLConnection(self.context, self.sock)
211+
self.sock.set_connect_state()
212+
self.sock.set_tlsext_host_name(self._host_name)
213+
self.sock.do_handshake()
214+
215+
except ImportError, e:
216+
class DetailedHTTPSConnection(httplib.HTTPSConnection):
217+
"""Preserve details relevant to replaying SSL connections."""
218+
response_class = DetailedHTTPSResponse
219+
def set_host_name(self, dummy):
220+
pass
186221

187222

188223
class RealHttpFetch(object):
@@ -292,6 +327,7 @@ def _get_connection(self, request_host, request_port, is_ssl):
292327

293328
if is_ssl:
294329
connection = DetailedHTTPSConnection(connection_ip, connection_port)
330+
connection.set_host_name(connection_host)
295331
if system_proxy:
296332
connection.set_tunnel(self, request_host, request_port)
297333
else:

0 commit comments

Comments
 (0)