mercurial/httpclient/socketutil.py
changeset 19182 fae47ecaa952
parent 18179 f614543733b6
child 19489 42fcb2f7787d
equal deleted inserted replaced
19181:8c2fdf7d5645 19182:fae47ecaa952
    37 
    37 
    38 logger = logging.getLogger(__name__)
    38 logger = logging.getLogger(__name__)
    39 
    39 
    40 try:
    40 try:
    41     import ssl
    41     import ssl
    42     ssl.wrap_socket  # make demandimporters load the module
    42     # make demandimporters load the module
       
    43     ssl.wrap_socket # pylint: disable=W0104
    43     have_ssl = True
    44     have_ssl = True
    44 except ImportError:
    45 except ImportError:
    45     import httplib
    46     import httplib
    46     import urllib2
    47     import urllib2
    47     have_ssl = getattr(urllib2, 'HTTPSHandler', False)
    48     have_ssl = getattr(urllib2, 'HTTPSHandler', False)
    50 
    51 
    51 try:
    52 try:
    52     create_connection = socket.create_connection
    53     create_connection = socket.create_connection
    53 except AttributeError:
    54 except AttributeError:
    54     def create_connection(address):
    55     def create_connection(address):
       
    56         """Backport of socket.create_connection from Python 2.6."""
    55         host, port = address
    57         host, port = address
    56         msg = "getaddrinfo returns an empty list"
    58         msg = "getaddrinfo returns an empty list"
    57         sock = None
    59         sock = None
    58         for res in socket.getaddrinfo(host, port, 0,
    60         for res in socket.getaddrinfo(host, port, 0,
    59                                       socket.SOCK_STREAM):
    61                                       socket.SOCK_STREAM):
    60             af, socktype, proto, _canonname, sa = res
    62             af, socktype, proto, unused_canonname, sa = res
    61             try:
    63             try:
    62                 sock = socket.socket(af, socktype, proto)
    64                 sock = socket.socket(af, socktype, proto)
    63                 logger.info("connect: (%s, %s)", host, port)
    65                 logger.info("connect: (%s, %s)", host, port)
    64                 sock.connect(sa)
    66                 sock.connect(sa)
    65             except socket.error, msg:
    67             except socket.error, msg:
    78     CERT_NONE = ssl.CERT_NONE
    80     CERT_NONE = ssl.CERT_NONE
    79     CERT_OPTIONAL = ssl.CERT_OPTIONAL
    81     CERT_OPTIONAL = ssl.CERT_OPTIONAL
    80     CERT_REQUIRED = ssl.CERT_REQUIRED
    82     CERT_REQUIRED = ssl.CERT_REQUIRED
    81 else:
    83 else:
    82     class FakeSocket(httplib.FakeSocket):
    84     class FakeSocket(httplib.FakeSocket):
    83         """Socket wrapper that supports SSL.
    85         """Socket wrapper that supports SSL."""
    84         """
    86 
       
    87         # Silence lint about this goofy backport class
       
    88         # pylint: disable=W0232,E1101,R0903,R0913,C0111
       
    89 
    85         # backport the behavior from Python 2.6, which is to busy wait
    90         # backport the behavior from Python 2.6, which is to busy wait
    86         # on the socket instead of anything nice. Sigh.
    91         # on the socket instead of anything nice. Sigh.
    87         # See http://bugs.python.org/issue3890 for more info.
    92         # See http://bugs.python.org/issue3890 for more info.
    88         def recv(self, buflen=1024, flags=0):
    93         def recv(self, buflen=1024, flags=0):
    89             """ssl-aware wrapper around socket.recv
    94             """ssl-aware wrapper around socket.recv
   105 
   110 
   106     CERT_NONE = 0
   111     CERT_NONE = 0
   107     CERT_OPTIONAL = 1
   112     CERT_OPTIONAL = 1
   108     CERT_REQUIRED = 2
   113     CERT_REQUIRED = 2
   109 
   114 
       
   115     # Disable unused-argument because we're making a dumb wrapper
       
   116     # that's like an upstream method.
       
   117     #
       
   118     # pylint: disable=W0613,R0913
   110     def wrap_socket(sock, keyfile=None, certfile=None,
   119     def wrap_socket(sock, keyfile=None, certfile=None,
   111                 server_side=False, cert_reqs=CERT_NONE,
   120                 server_side=False, cert_reqs=CERT_NONE,
   112                 ssl_version=_PROTOCOL_SSLv23, ca_certs=None,
   121                 ssl_version=_PROTOCOL_SSLv23, ca_certs=None,
   113                 do_handshake_on_connect=True,
   122                 do_handshake_on_connect=True,
   114                 suppress_ragged_eofs=True):
   123                 suppress_ragged_eofs=True):
       
   124         """Backport of ssl.wrap_socket from Python 2.6."""
   115         if cert_reqs != CERT_NONE and ca_certs:
   125         if cert_reqs != CERT_NONE and ca_certs:
   116             raise CertificateValidationUnsupported(
   126             raise CertificateValidationUnsupported(
   117                 'SSL certificate validation requires the ssl module'
   127                 'SSL certificate validation requires the ssl module'
   118                 '(included in Python 2.6 and later.)')
   128                 '(included in Python 2.6 and later.)')
   119         sslob = socket.ssl(sock)
   129         sslob = socket.ssl(sock)
   120         # borrow httplib's workaround for no ssl.wrap_socket
   130         # borrow httplib's workaround for no ssl.wrap_socket
   121         sock = FakeSocket(sock, sslob)
   131         sock = FakeSocket(sock, sslob)
   122         return sock
   132         return sock
       
   133     # pylint: enable=W0613,R0913
   123 
   134 
   124 
   135 
   125 class CertificateValidationUnsupported(Exception):
   136 class CertificateValidationUnsupported(Exception):
   126     """Exception raised when cert validation is requested but unavailable."""
   137     """Exception raised when cert validation is requested but unavailable."""
   127 # no-check-code
   138 # no-check-code