diff mercurial/httpclient/socketutil.py @ 14243:861f28212398

Import new http library as mercurial.httpclient. This is revision a4229f13c374 of http://py-nonblocking-http.googlecode.com/ with a no-check-code comment added to the end of each file using `for fi in $(hg manifest | grep mercurial/httpclient/) ; echo '# no-check-code' >> $fi`.
author Augie Fackler <durin42@gmail.com>
date Fri, 06 May 2011 09:57:55 -0500
parents
children 494b26ad8736
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/httpclient/socketutil.py	Fri May 06 09:57:55 2011 -0500
@@ -0,0 +1,134 @@
+# Copyright 2010, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""Abstraction to simplify socket use for Python < 2.6
+
+This will attempt to use the ssl module and the new
+socket.create_connection method, but fall back to the old
+methods if those are unavailable.
+"""
+import logging
+import socket
+
+logger = logging.getLogger(__name__)
+
+try:
+    import ssl
+    ssl.wrap_socket  # make demandimporters load the module
+    have_ssl = True
+except ImportError:
+    import httplib
+    import urllib2
+    have_ssl = getattr(urllib2, 'HTTPSHandler', False)
+    ssl = False
+
+
+try:
+    create_connection = socket.create_connection
+except AttributeError:
+    def create_connection(address):
+        host, port = address
+        msg = "getaddrinfo returns an empty list"
+        sock = None
+        for res in socket.getaddrinfo(host, port, 0,
+                                      socket.SOCK_STREAM):
+            af, socktype, proto, _canonname, sa = res
+            try:
+                sock = socket.socket(af, socktype, proto)
+                logger.info("connect: (%s, %s)", host, port)
+                sock.connect(sa)
+            except socket.error, msg:
+                logger.info('connect fail: %s %s', host, port)
+                if sock:
+                    sock.close()
+                sock = None
+                continue
+            break
+        if not sock:
+            raise socket.error, msg
+        return sock
+
+if ssl:
+    wrap_socket = ssl.wrap_socket
+    CERT_NONE = ssl.CERT_NONE
+    CERT_OPTIONAL = ssl.CERT_OPTIONAL
+    CERT_REQUIRED = ssl.CERT_REQUIRED
+    PROTOCOL_SSLv2 = ssl.PROTOCOL_SSLv2
+    PROTOCOL_SSLv3 = ssl.PROTOCOL_SSLv3
+    PROTOCOL_SSLv23 = ssl.PROTOCOL_SSLv23
+    PROTOCOL_TLSv1 = ssl.PROTOCOL_TLSv1
+else:
+    class FakeSocket(httplib.FakeSocket):
+        """Socket wrapper that supports SSL.
+        """
+        # backport the behavior from Python 2.6, which is to busy wait
+        # on the socket instead of anything nice. Sigh.
+        # See http://bugs.python.org/issue3890 for more info.
+        def recv(self, buflen=1024, flags=0):
+            """ssl-aware wrapper around socket.recv
+            """
+            if flags != 0:
+                raise ValueError(
+                    "non-zero flags not allowed in calls to recv() on %s" %
+                    self.__class__)
+            while True:
+                try:
+                    return self._ssl.read(buflen)
+                except socket.sslerror, x:
+                    if x.args[0] == socket.SSL_ERROR_WANT_READ:
+                        continue
+                    else:
+                        raise x
+
+    PROTOCOL_SSLv2 = 0
+    PROTOCOL_SSLv3 = 1
+    PROTOCOL_SSLv23 = 2
+    PROTOCOL_TLSv1 = 3
+
+    CERT_NONE = 0
+    CERT_OPTIONAL = 1
+    CERT_REQUIRED = 2
+
+    def wrap_socket(sock, keyfile=None, certfile=None,
+                server_side=False, cert_reqs=CERT_NONE,
+                ssl_version=PROTOCOL_SSLv23, ca_certs=None,
+                do_handshake_on_connect=True,
+                suppress_ragged_eofs=True):
+        if cert_reqs != CERT_NONE and ca_certs:
+            raise CertificateValidationUnsupported(
+                'SSL certificate validation requires the ssl module'
+                '(included in Python 2.6 and later.)')
+        sslob = socket.ssl(sock)
+        # borrow httplib's workaround for no ssl.wrap_socket
+        sock = FakeSocket(sock, sslob)
+        return sock
+
+
+class CertificateValidationUnsupported(Exception):
+    """Exception raised when cert validation is requested but unavailable."""
+# no-check-code