Patchwork D3246: keepalive: rewrite readinto() to not use read()

login
register
mail settings
Submitter phabricator
Date April 11, 2018, 7:50 p.m.
Message ID <differential-rev-PHID-DREV-mkvxbahdiychrqtif7j6-req@phab.mercurial-scm.org>
Download mbox | patch
Permalink /patch/30736/
State Superseded
Headers show

Comments

phabricator - April 11, 2018, 7:50 p.m.
durin42 created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  It turns out http.client on Python 3 sometimes uses readinto() in the
  implementation of read().
  
  Subclassing is bad, folks.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3246

AFFECTED FILES
  mercurial/keepalive.py

CHANGE DETAILS




To: durin42, #hg-reviewers
Cc: mercurial-devel
phabricator - April 12, 2018, 3:15 p.m.
indygreg accepted this revision.
indygreg added a comment.
This revision is now accepted and ready to land.


  This is horrible. But this is the world we live in. Everything about the HTTP code terrifies me. That includes both our code and CPython's.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D3246

To: durin42, #hg-reviewers, indygreg
Cc: indygreg, mercurial-devel

Patch

diff --git a/mercurial/keepalive.py b/mercurial/keepalive.py
--- a/mercurial/keepalive.py
+++ b/mercurial/keepalive.py
@@ -384,6 +384,7 @@ 
         self._connection = None # (same)
 
     _raw_read = httplib.HTTPResponse.read
+    _raw_readinto = httplib.HTTPResponse.readinto
 
     def close(self):
         if self.fp:
@@ -523,12 +524,18 @@ 
         return list
 
     def readinto(self, dest):
-        res = self.read(len(dest))
-        if not res:
-            return 0
-
-        dest[0:len(res)] = res
-        return len(res)
+        total = len(dest)
+        have = len(self._rbuf)
+        if have >= total:
+            dest[0:total] = self._rbuf[:total]
+            self._rbuf = self._rbuf[total:]
+            return total
+        mv = memoryview(dest)
+        got = self._raw_readinto(mv[have:total])
+        dest[0:have] = self._rbuf
+        got += len(self._rbuf)
+        self._rbuf = ''
+        return got
 
 def safesend(self, str):
     """Send `str' to the server.