changeset 19182:fae47ecaa952

httpclient: upgrade to fe8c09e4db64 of httpplus
author Augie Fackler <raf@durin42.com>
date Sat, 11 May 2013 20:25:15 -0500
parents 8c2fdf7d5645
children 05390cfe678a
files mercurial/httpclient/__init__.py mercurial/httpclient/_readers.py mercurial/httpclient/socketutil.py
diffstat 3 files changed, 79 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/httpclient/__init__.py	Wed May 08 20:55:56 2013 +0200
+++ b/mercurial/httpclient/__init__.py	Sat May 11 20:25:15 2013 -0500
@@ -37,6 +37,9 @@
   * implements ssl inline instead of in a different class
 """
 
+# Many functions in this file have too many arguments.
+# pylint: disable=R0913
+
 import cStringIO
 import errno
 import httplib
@@ -117,6 +120,8 @@
 
     def _close(self):
         if self._reader is not None:
+            # We're a friend of the reader class here.
+            # pylint: disable=W0212
             self._reader._close()
 
     def readline(self):
@@ -137,6 +142,7 @@
         return ''.join(blocks)
 
     def read(self, length=None):
+        """Read data from the response body."""
         # if length is None, unbounded read
         while (not self.complete()  # never select on a finished read
                and (not length  # unbounded, so we wait for complete()
@@ -150,7 +156,8 @@
         return r
 
     def _select(self):
-        r, _, _ = select.select([self.sock], [], [], self._timeout)
+        r, unused_write, unused_err = select.select(
+            [self.sock], [], [], self._timeout)
         if not r:
             # socket was not readable. If the response is not
             # complete, raise a timeout.
@@ -170,13 +177,16 @@
         # raise an exception if this is an invalid situation.
         if not data:
             if self._reader:
+                # We're a friend of the reader class here.
+                # pylint: disable=W0212
                 self._reader._close()
             return False
         else:
             self._load_response(data)
             return True
 
-    def _load_response(self, data):
+    # This method gets replaced by _load later, which confuses pylint.
+    def _load_response(self, data): # pylint: disable=E0202
         # Being here implies we're not at the end of the headers yet,
         # since at the end of this method if headers were completely
         # loaded we replace this method with the load() method of the
@@ -201,7 +211,7 @@
 
         # handle 100-continue response
         hdrs, body = self.raw_response.split(self._end_headers, 1)
-        http_ver, status = hdrs.split(' ', 1)
+        unused_http_ver, status = hdrs.split(' ', 1)
         if status.startswith('100'):
             self.raw_response = body
             self.continued = True
@@ -260,9 +270,13 @@
                 self.will_close = True
 
         if body:
+            # We're a friend of the reader class here.
+            # pylint: disable=W0212
             self._reader._load(body)
         logger.debug('headers complete')
         self.headers = headers
+        # We're a friend of the reader class here.
+        # pylint: disable=W0212
         self._load_response = self._reader._load
 
 
@@ -335,9 +349,9 @@
                                                  self._proxy_port))
             if self.ssl:
                 # TODO proxy header support
-                data = self.buildheaders('CONNECT', '%s:%d' % (self.host,
-                                                               self.port),
-                                         {}, HTTP_VER_1_0)
+                data = self._buildheaders('CONNECT', '%s:%d' % (self.host,
+                                                                self.port),
+                                          {}, HTTP_VER_1_0)
                 sock.send(data)
                 sock.setblocking(0)
                 r = self.response_class(sock, self.timeout, 'CONNECT')
@@ -345,6 +359,9 @@
                     'Timed out waiting for CONNECT response from proxy')
                 while not r.complete():
                     try:
+                        # We're a friend of the response class, so let
+                        # us use the private attribute.
+                        # pylint: disable=W0212
                         if not r._select():
                             if not r.complete():
                                 raise timeout_exc
@@ -376,7 +393,7 @@
         sock.setblocking(0)
         self.sock = sock
 
-    def buildheaders(self, method, path, headers, http_ver):
+    def _buildheaders(self, method, path, headers, http_ver):
         if self.ssl and self.port == 443 or self.port == 80:
             # default port for protocol, so leave it out
             hdrhost = self.host
@@ -437,6 +454,11 @@
             return True
         return False
 
+    def _reconnect(self, where):
+        logger.info('reconnecting during %s', where)
+        self.close()
+        self._connect()
+
     def request(self, method, path, body=None, headers={},
                 expect_continue=False):
         """Send a request to the server.
@@ -474,16 +496,11 @@
                 raise BadRequestData('body has no __len__() nor read()')
 
         self._connect()
-        outgoing_headers = self.buildheaders(
+        outgoing_headers = self._buildheaders(
             method, path, hdrs, self.http_version)
         response = None
         first = True
 
-        def reconnect(where):
-            logger.info('reconnecting during %s', where)
-            self.close()
-            self._connect()
-
         while ((outgoing_headers or body)
                and not (response and response.complete())):
             select_timeout = self.timeout
@@ -523,14 +540,17 @@
                     except socket.sslerror, e:
                         if e.args[0] != socket.SSL_ERROR_WANT_READ:
                             raise
-                        logger.debug(
-                            'SSL_ERROR_WANT_READ while sending data, retrying...')
+                        logger.debug('SSL_ERROR_WANT_READ while sending '
+                                     'data, retrying...')
                         continue
                     if not data:
                         logger.info('socket appears closed in read')
                         self.sock = None
                         self._current_response = None
                         if response is not None:
+                            # We're a friend of the response class, so let
+                            # us use the private attribute.
+                            # pylint: disable=W0212
                             response._close()
                         # This if/elif ladder is a bit subtle,
                         # comments in each branch should help.
@@ -550,7 +570,7 @@
                             logger.info(
                                 'Connection appeared closed in read on first'
                                 ' request loop iteration, will retry.')
-                            reconnect('read')
+                            self._reconnect('read')
                             continue
                         else:
                             # We didn't just send the first data hunk,
@@ -563,7 +583,11 @@
                                 'response was missing or incomplete!')
                     logger.debug('read %d bytes in request()', len(data))
                     if response is None:
-                        response = self.response_class(r[0], self.timeout, method)
+                        response = self.response_class(
+                            r[0], self.timeout, method)
+                    # We're a friend of the response class, so let us
+                    # use the private attribute.
+                    # pylint: disable=W0212
                     response._load_response(data)
                     # Jump to the next select() call so we load more
                     # data if the server is still sending us content.
@@ -576,6 +600,8 @@
             if w and out:
                 try:
                     if getattr(out, 'read', False):
+                        # pylint guesses the type of out incorrectly here
+                        # pylint: disable=E1103
                         data = out.read(OUTGOING_BUFFER_SIZE)
                         if not data:
                             continue
@@ -599,14 +625,10 @@
                     elif (e[0] not in (errno.ECONNRESET, errno.EPIPE)
                           and not first):
                         raise
-                    reconnect('write')
+                    self._reconnect('write')
                     amt = self.sock.send(out)
                 logger.debug('sent %d', amt)
                 first = False
-                # stash data we think we sent in case the socket breaks
-                # when we read from it
-                if was_first:
-                    sent_data = out[:amt]
                 if out is body:
                     body = out[amt:]
                 else:
@@ -616,7 +638,6 @@
         # the whole request
         if response is None:
             response = self.response_class(self.sock, self.timeout, method)
-        complete = response.complete()
         data_left = bool(outgoing_headers or body)
         if data_left:
             logger.info('stopped sending request early, '
@@ -629,10 +650,14 @@
         self._current_response = response
 
     def getresponse(self):
+        """Returns the response to the most recent request."""
         if self._current_response is None:
             raise httplib.ResponseNotReady()
         r = self._current_response
         while r.headers is None:
+            # We're a friend of the response class, so let us use the
+            # private attribute.
+            # pylint: disable=W0212
             if not r._select() and not r.complete():
                 raise _readers.HTTPRemoteClosedError()
         if r.will_close:
--- a/mercurial/httpclient/_readers.py	Wed May 08 20:55:56 2013 +0200
+++ b/mercurial/httpclient/_readers.py	Sat May 11 20:25:15 2013 -0500
@@ -33,7 +33,6 @@
 """
 
 import httplib
-import itertools
 import logging
 
 logger = logging.getLogger(__name__)
@@ -59,33 +58,35 @@
         self._done_chunks = []
         self.available_data = 0
 
-    def addchunk(self, data):
+    def _addchunk(self, data):
         self._done_chunks.append(data)
         self.available_data += len(data)
 
-    def pushchunk(self, data):
+    def _pushchunk(self, data):
         self._done_chunks.insert(0, data)
         self.available_data += len(data)
 
-    def popchunk(self):
+    def _popchunk(self):
         b = self._done_chunks.pop(0)
         self.available_data -= len(b)
 
         return b
 
     def done(self):
+        """Returns true if the response body is entirely read."""
         return self._finished
 
     def read(self, amt):
+        """Read amt bytes from the response body."""
         if self.available_data < amt and not self._finished:
             raise ReadNotReady()
         blocks = []
         need = amt
         while self._done_chunks:
-            b = self.popchunk()
+            b = self._popchunk()
             if len(b) > need:
                 nb = b[:need]
-                self.pushchunk(b[need:])
+                self._pushchunk(b[need:])
                 b = nb
             blocks.append(b)
             need -= len(b)
@@ -107,11 +108,11 @@
             blocks = []
 
         while self._done_chunks:
-            b = self.popchunk()
+            b = self._popchunk()
             i = b.find(delimstr) + len(delimstr)
             if i:
                 if i < len(b):
-                    self.pushchunk(b[i:])
+                    self._pushchunk(b[i:])
                 blocks.append(b[:i])
                 break
             else:
@@ -154,8 +155,9 @@
         if data:
             assert not self._finished, (
                 'tried to add data (%r) to a closed reader!' % data)
-        logger.debug('%s read an additional %d data', self.name, len(data))
-        self.addchunk(data)
+        logger.debug('%s read an additional %d data',
+                     self.name, len(data)) # pylint: disable=E1101
+        self._addchunk(data)
 
 
 class CloseIsEndReader(AbstractSimpleReader):
@@ -172,7 +174,7 @@
     name = 'content-length'
 
     def __init__(self, amount):
-        AbstractReader.__init__(self)
+        AbstractSimpleReader.__init__(self)
         self._amount = amount
         if amount == 0:
             self._finished = True
@@ -199,7 +201,8 @@
         logger.debug('chunked read an additional %d data', len(data))
         position = 0
         if self._leftover_data:
-            logger.debug('chunked reader trying to finish block from leftover data')
+            logger.debug(
+                'chunked reader trying to finish block from leftover data')
             # TODO: avoid this string concatenation if possible
             data = self._leftover_data + data
             position = self._leftover_skip_amt
@@ -224,6 +227,6 @@
                 self._finished = True
                 logger.debug('closing chunked reader due to chunk of length 0')
                 return
-            self.addchunk(data[block_start:block_start + amt])
+            self._addchunk(data[block_start:block_start + amt])
             position = block_start + amt + len(self._eol)
 # no-check-code
--- a/mercurial/httpclient/socketutil.py	Wed May 08 20:55:56 2013 +0200
+++ b/mercurial/httpclient/socketutil.py	Sat May 11 20:25:15 2013 -0500
@@ -39,7 +39,8 @@
 
 try:
     import ssl
-    ssl.wrap_socket  # make demandimporters load the module
+    # make demandimporters load the module
+    ssl.wrap_socket # pylint: disable=W0104
     have_ssl = True
 except ImportError:
     import httplib
@@ -52,12 +53,13 @@
     create_connection = socket.create_connection
 except AttributeError:
     def create_connection(address):
+        """Backport of socket.create_connection from Python 2.6."""
         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
+            af, socktype, proto, unused_canonname, sa = res
             try:
                 sock = socket.socket(af, socktype, proto)
                 logger.info("connect: (%s, %s)", host, port)
@@ -80,8 +82,11 @@
     CERT_REQUIRED = ssl.CERT_REQUIRED
 else:
     class FakeSocket(httplib.FakeSocket):
-        """Socket wrapper that supports SSL.
-        """
+        """Socket wrapper that supports SSL."""
+
+        # Silence lint about this goofy backport class
+        # pylint: disable=W0232,E1101,R0903,R0913,C0111
+
         # 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.
@@ -107,11 +112,16 @@
     CERT_OPTIONAL = 1
     CERT_REQUIRED = 2
 
+    # Disable unused-argument because we're making a dumb wrapper
+    # that's like an upstream method.
+    #
+    # pylint: disable=W0613,R0913
     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):
+        """Backport of ssl.wrap_socket from Python 2.6."""
         if cert_reqs != CERT_NONE and ca_certs:
             raise CertificateValidationUnsupported(
                 'SSL certificate validation requires the ssl module'
@@ -120,6 +130,7 @@
         # borrow httplib's workaround for no ssl.wrap_socket
         sock = FakeSocket(sock, sslob)
         return sock
+    # pylint: enable=W0613,R0913
 
 
 class CertificateValidationUnsupported(Exception):