Mercurial > public > mercurial-scm > hg-stable
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