statichttprepo: fix `httprangereader.read()` for py3
It looks like there were a bunch of problems, not all of them py3 related:
1) The signature of BinaryIO.read() is -1, not None
2) The `end` variable can't be bytes and interpolate into str with "%s"
3) The `end` variable can't be an int and interpolate into str with "%s"
4) The result slicing could be out of bounds if more is requested than
returned
I guess if somebody would have called `read(-1)` (either directly or because a
wrapper defaults to that), it wouldn't have been handled correctly. The fact
that it is a valid value meaning to read everything requires some additional
changes later in the method around when it slices the byte string that was read,
but that seems to have already been broken.
--- a/mercurial/statichttprepo.py Wed Sep 25 00:52:44 2024 -0400
+++ b/mercurial/statichttprepo.py Wed Sep 25 01:12:39 2024 -0400
@@ -52,11 +52,14 @@
def seek(self, pos):
self.pos = pos
- def read(self, bytes=None):
+ def read(self, bytes: int = -1):
req = urlreq.request(pycompat.strurl(self.url))
- end = b''
- if bytes:
- end = self.pos + bytes - 1
+ end = ''
+
+ if bytes == 0:
+ return b''
+ elif bytes > 0:
+ end = "%d" % (self.pos + bytes - 1)
if self.pos or end:
req.add_header('Range', 'bytes=%d-%s' % (self.pos, end))
@@ -76,11 +79,13 @@
if code == 200:
# HTTPRangeHandler does nothing if remote does not support
# Range headers and returns the full entity. Let's slice it.
- if bytes:
+ if bytes > 0 and (self.pos + bytes) < len(data):
data = data[self.pos : self.pos + bytes]
+ elif self.pos < len(data):
+ data = data[self.pos :]
else:
- data = data[self.pos :]
- elif bytes:
+ data = b''
+ elif 0 < bytes < len(data):
data = data[:bytes]
self.pos += len(data)
return data