Mercurial > hg
changeset 19038:36733ab7fa05
http2: sane readline
It turns out that it pays off to read more than a byte at a time with
a select in between :)
author | Brendan Cully <brendan@kublai.com> |
---|---|
date | Fri, 01 Feb 2013 15:00:23 -0800 |
parents | 1fde25ad9396 |
children | 41669a18a7d6 |
files | mercurial/httpclient/__init__.py mercurial/httpclient/_readers.py |
diffstat | 2 files changed, 32 insertions(+), 17 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/httpclient/__init__.py Fri Feb 01 14:41:35 2013 -0800 +++ b/mercurial/httpclient/__init__.py Fri Feb 01 15:00:23 2013 -0800 @@ -125,24 +125,16 @@ This may block until either a line ending is found or the response is complete. """ - # TODO: move this into the reader interface where it can be - # smarter (and probably avoid copies) - bytes = [] - while not bytes: - try: - bytes = [self._reader.read(1)] - except _readers.ReadNotReady: - self._select() - while bytes[-1] != '\n' and not self.complete(): + blocks = [] + while True: + self._reader.readto('\n', blocks) + + if blocks and blocks[-1][-1] == '\n' or self.complete(): + break + self._select() - bytes.append(self._reader.read(1)) - if bytes[-1] != '\n': - next = self._reader.read(1) - while next and next != '\n': - bytes.append(next) - next = self._reader.read(1) - bytes.append(next) - return ''.join(bytes) + + return ''.join(blocks) def read(self, length=None): # if length is None, unbounded read
--- a/mercurial/httpclient/_readers.py Fri Feb 01 14:41:35 2013 -0800 +++ b/mercurial/httpclient/_readers.py Fri Feb 01 15:00:23 2013 -0800 @@ -96,6 +96,29 @@ return result + def readto(self, delimstr, blocks = None): + """return available data chunks up to the first one in which delimstr + occurs. No data will be returned after delimstr -- the chunk in which + it occurs will be split and the remainder pushed back onto the available + data queue. If blocks is supplied chunks will be added to blocks, otherwise + a new list will be allocated. + """ + if blocks is None: + blocks = [] + + while self._done_chunks: + b = self.popchunk() + i = b.find(delimstr) + len(delimstr) + if i: + if i < len(b): + self.pushchunk(b[i:]) + blocks.append(b[:i]) + break + else: + blocks.append(b) + + return blocks + def _load(self, data): # pragma: no cover """Subclasses must implement this.