|
7 | 7 | import errno
|
8 | 8 | import httplib
|
9 | 9 | import os
|
| 10 | +import socket |
10 | 11 | import time
|
11 | 12 | import urllib2
|
12 | 13 |
|
@@ -271,23 +272,34 @@ def ConnectionWrapperFactory(parent_class, dns_query):
|
271 | 272 | method uses the dns_query function to resolve the connection host name.
|
272 | 273 | '''
|
273 | 274 | class ConnectionWrapper(parent_class):
|
274 |
| - def connect(self): |
| 275 | + def create_connection(self, address, timeout, source_address): |
| 276 | + ''' |
| 277 | + httplib.HTTP(S)Connection creates a socket connection to |
| 278 | + self.host using _create_connection, which by default is a |
| 279 | + redirect to socket.create_connection(). self._create_connection exists |
| 280 | + on httplib.HTTPConnection as a way of overriding it for unit tests. |
| 281 | + Connections are made to self.host by default. When attempting |
| 282 | + to perform DNS resolution and connecting to an IP address instead |
| 283 | + of hostname, SSL certificate validation is broken in Python 2.7.9+. |
| 284 | + This wrapper allows for a dns query to be made, and socket |
| 285 | + connection made to an IP address while still maintaining self.host |
| 286 | + as the unresolved hostname for validation. |
| 287 | + ''' |
275 | 288 | t0 = time.time()
|
276 |
| - # httplib uses self.host both as the host to connect to and as the |
277 |
| - # Host header, because boto doesn't set that. As it happens, |
278 |
| - # httplib sets the Host header before this method is called, so |
279 |
| - # we can change self.host for use when opening the socket. However, |
280 |
| - # boto reuses HTTP(S)Connection instances, and on the next request, |
281 |
| - # httplib resets the Host header with self.host, so we need to |
282 |
| - # restore it. |
283 |
| - host = self.host |
284 |
| - self.host = dns_query(self.host) |
285 |
| - t1 = time.time() |
| 289 | + host, port = address |
| 290 | + resolvedHost = dns_query(host) |
| 291 | + self._socket_connect_timestamp = t1 = time.time() |
286 | 292 | _last_stats['dns'] = (t1 - t0) * 1000
|
| 293 | + sock = socket.create_connection((resolvedHost, port), |
| 294 | + timeout, source_address) |
| 295 | + return sock |
| 296 | + |
| 297 | + def connect(self): |
| 298 | + self._create_connection = self.create_connection |
287 | 299 | parent_class.connect(self)
|
288 |
| - self.host = host |
289 | 300 | self._connect_time = time.time()
|
290 |
| - _last_stats['connect'] = (self._connect_time - t1) * 1000 |
| 301 | + _last_stats['connect'] = ( |
| 302 | + self._connect_time - self._socket_connect_timestamp) * 1000 |
291 | 303 |
|
292 | 304 | def getresponse(self, buffering=False):
|
293 | 305 | res = parent_class.getresponse(self, buffering)
|
|
0 commit comments