Mercurial > hg-stable
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):