| 
						
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -1,5 +1,3 @@
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#!/usr/bin/env python
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				#
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				# Foundation; All Rights Reserved
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -14,13 +12,12 @@ __author__ = "{frew,nick.johnson}@google.com (Fred Wulff and Nick Johnson)"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import base64
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import httplib
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import logging
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import re
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import socket
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import urllib2
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				from urllib import splitpasswd
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				from urllib import splittype
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				from urllib import splituser
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				from urllib import splitpasswd
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				import urllib2
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class InvalidCertificateException(httplib.HTTPException):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  """Raised when a certificate is provided with an invalid hostname."""
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -31,6 +28,7 @@ class InvalidCertificateException(httplib.HTTPException):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    Args:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      host: The hostname the connection was made to.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      cert: The SSL certificate (as a dictionary) the host returned.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      reason: user readable error reason.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    """
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    httplib.HTTPException.__init__(self)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    self.host = host
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -38,21 +36,35 @@ class InvalidCertificateException(httplib.HTTPException):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    self.reason = reason
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  def __str__(self):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return ('Host %s returned an invalid certificate (%s): %s\n'
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            'To learn more, see '
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            'http://code.google.com/appengine/kb/general.html#rpcssl' %
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return ("Host %s returned an invalid certificate (%s): %s\n"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            "To learn more, see "
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            "http://code.google.com/appengine/kb/general.html#rpcssl" %
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            (self.host, self.reason, self.cert))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				try:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  import ssl
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  _CAN_VALIDATE_CERTS = True
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				except ImportError:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  _CAN_VALIDATE_CERTS = False
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				def can_validate_certs():
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  """Return True if we have the SSL package and can validate certificates."""
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  try:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    import ssl
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return True
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  except ImportError:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    return False
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				def _create_fancy_connection(tunnel_host=None, key_file=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                             cert_file=None, ca_certs=None):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return _CAN_VALIDATE_CERTS
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				# Reexport SSLError so clients don't have to to do their own checking for ssl's
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				# existence.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				if can_validate_certs():
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SSLError = ssl.SSLError
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				else:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  SSLError = None
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				def create_fancy_connection(tunnel_host=None, key_file=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            cert_file=None, ca_certs=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                            proxy_authorization=None):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  # This abomination brought to you by the fact that
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  # the HTTPHandler creates the connection instance in the middle
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  # of do_open so we need to add the tunnel host to the class.
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -70,28 +82,64 @@ def _create_fancy_connection(tunnel_host=None, key_file=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self.key_file = key_file
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self.cert_file = cert_file
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self.ca_certs = ca_certs
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      try:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        import ssl
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if can_validate_certs():
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if self.ca_certs:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          self.cert_reqs = ssl.CERT_REQUIRED
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        else:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          self.cert_reqs = ssl.CERT_NONE
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      except ImportError:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        pass
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    def _get_hostport(self, host, port):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # Python 2.7.7rc1 (hg r90728:568041fd8090), 3.4.1 and 3.5 rename
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # _set_hostport to _get_hostport and changes it's functionality.  The
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # Python 2.7.7rc1 version of this method is included here for
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # compatibility with earlier versions of Python.  Without this, HTTPS over
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # HTTP CONNECT proxies cannot be used.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # This method may be removed if compatibility with Python <2.7.7rc1 is not
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # required.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # Python bug: http://bugs.python.org/issue7776
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if port is None:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        i = host.rfind(":")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        j = host.rfind("]")         # ipv6 addresses have [...]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if i > j:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          try:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            port = int(host[i+1:])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          except ValueError:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            if host[i+1:] == "":  # http://foo.com:/ == http://foo.com/
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              port = self.default_port
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            else:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              raise httplib.InvalidURL("nonnumeric port: '%s'" % host[i+1:])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          host = host[:i]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        else:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          port = self.default_port
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if host and host[0] == "[" and host[-1] == "]":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          host = host[1:-1]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return (host, port)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    def _tunnel(self):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self._set_hostport(self._tunnel_host, None)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self.host, self.port = self._get_hostport(self._tunnel_host, None)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      logging.info("Connecting through tunnel to: %s:%d",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                   self.host, self.port)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self.send("CONNECT %s:%d HTTP/1.0\r\n\r\n" % (self.host, self.port))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self.send("CONNECT %s:%d HTTP/1.0\r\n" % (self.host, self.port))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if proxy_authorization:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.send("Proxy-Authorization: %s\r\n" % proxy_authorization)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # blank line
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      self.send("\r\n")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      response = self.response_class(self.sock, strict=self.strict,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                     method=self._method)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # pylint: disable=protected-access
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      (_, code, message) = response._read_status()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if code != 200:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.close()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        raise socket.error, "Tunnel connection failed: %d %s" % (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            code, message.strip())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        raise socket.error("Tunnel connection failed: %d %s" %
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                           (code, message.strip()))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      while True:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        line = response.fp.readline()
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -106,15 +154,15 @@ def _create_fancy_connection(tunnel_host=None, key_file=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      Returns:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        list: A list of valid host globs.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      """
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if 'subjectAltName' in cert:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return [x[1] for x in cert['subjectAltName'] if x[0].lower() == 'dns']
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if "subjectAltName" in cert:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return [x[1] for x in cert["subjectAltName"] if x[0].lower() == "dns"]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      else:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        # Return a list of commonName fields
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return [x[0][1] for x in cert['subject']
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                if x[0][0].lower() == 'commonname']
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        return [x[0][1] for x in cert["subject"]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                if x[0][0].lower() == "commonname"]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    def _validate_certificate_hostname(self, cert, hostname):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      """Validates that a given hostname is valid for an SSL certificate.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      """Perform RFC2818/6125 validation against a cert and hostname.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      Args:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        cert: A dictionary representing an SSL certificate.
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -124,14 +172,19 @@ def _create_fancy_connection(tunnel_host=None, key_file=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      """
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      hosts = self._get_valid_hosts_for_cert(cert)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      for host in hosts:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        # Convert the glob-style hostname expression (eg, '*.google.com') into a
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        # valid regular expression.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        host_re = host.replace('.', '\.').replace('*', '[^.]*')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if re.search('^%s$' % (host_re,), hostname, re.I):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        # Wildcards are only valid when the * exists at the end of the last
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        # (left-most) label, and there are at least 3 labels in the expression.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if ("*." in host and host.count("*") == 1 and
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            host.count(".") > 1 and "." in hostname):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          left_expected, right_expected = host.split("*.")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          left_hostname, right_hostname = hostname.split(".", 1)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          if (left_hostname.startswith(left_expected) and
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				              right_expected == right_hostname):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            return True
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        elif host == hostname:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          return True
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return False
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    def connect(self):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # TODO(frew): When we drop support for <2.6 (in the far distant future),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # change this to socket.create_connection.
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -141,9 +194,11 @@ def _create_fancy_connection(tunnel_host=None, key_file=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self._tunnel()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # ssl and FakeSocket got deprecated. Try for the new hotness of wrap_ssl,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # with fallback.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      try:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        import ssl
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # with fallback. Note: Since can_validate_certs() just checks for the
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # ssl module, it's equivalent to attempting to import ssl from
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # the function, but doesn't require a dynamic import, which doesn't
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      # play nicely with dev_appserver.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if can_validate_certs():
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.sock = ssl.wrap_socket(self.sock,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                    keyfile=self.key_file,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                    certfile=self.cert_file,
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -152,15 +207,15 @@ def _create_fancy_connection(tunnel_host=None, key_file=None,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        if self.cert_reqs & ssl.CERT_REQUIRED:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          cert = self.sock.getpeercert()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          hostname = self.host.split(':', 0)[0]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          hostname = self.host.split(":", 0)[0]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          if not self._validate_certificate_hostname(cert, hostname):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            raise InvalidCertificateException(hostname, cert,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                              'hostname mismatch')
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      except ImportError:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ssl = socket.ssl(self.sock,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                         keyfile=self.key_file,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                         certfile=self.cert_file)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.sock = httplib.FakeSocket(self.sock, ssl)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                              "hostname mismatch")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      else:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        ssl_socket = socket.ssl(self.sock,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                keyfile=self.key_file,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                certfile=self.cert_file)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        self.sock = httplib.FakeSocket(self.sock, ssl_socket)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  return PresetProxyHTTPSConnection
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -329,17 +384,24 @@ class FancyProxyHandler(urllib2.ProxyHandler):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				class FancyHTTPSHandler(urllib2.HTTPSHandler):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  """An HTTPSHandler that works with CONNECT-enabled proxies."""
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  def do_open(self, http_class, req):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				  def do_open(self, http_class, req, *args, **kwargs):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    proxy_authorization = None
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    for header in req.headers:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      if header.lower() == "proxy-authorization":
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        proxy_authorization = req.headers[header]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        break
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    # Intentionally very specific so as to opt for false negatives
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    # rather than false positives.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    try:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      return urllib2.HTTPSHandler.do_open(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          self,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          _create_fancy_connection(req._tunnel_host,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                   req._key_file,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                   req._cert_file,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                   req._ca_certs),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          req)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          create_fancy_connection(req._tunnel_host,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                  req._key_file,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                  req._cert_file,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                  req._ca_certs,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                  proxy_authorization),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          req, *args, **kwargs)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				    except urllib2.URLError, url_error:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      try:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        import ssl
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -347,7 +409,7 @@ class FancyHTTPSHandler(urllib2.HTTPSHandler):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				            url_error.reason.args[0] == 1):
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          # Display the reason to the user. Need to use args for python2.5
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          # compat.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          raise InvalidCertificateException(req.host, '',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				          raise InvalidCertificateException(req.host, "",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				                                            url_error.reason.args[1])
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				      except ImportError:
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				        pass
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |