in antlir/rpm/repo_server.py [0:0]
def do_GET(self) -> None:
location, obj = self.send_head()
if not obj:
return # Object not found, we already sent an error.
if "content_bytes" in obj:
self.wfile.write(obj["content_bytes"])
return
# This binary blob must be fetched from `self.storage`. We don't
# trust our storage, so we have to verify the checksum before
# sending the entire blob back to the client.
bytes_left = obj["size"]
checksum = Checksum.from_string(obj["checksum"])
# pyre-fixme[16]: `Storage` has no attribute `reader`.
with self.storage.reader(obj["storage_id"]) as input:
log.debug(f"Got storage for {location}")
hash = checksum.hasher()
while True:
chunk = input.read(_CHUNK_SIZE)
log.debug(f"{len(chunk)}-byte chunk for {location}")
bytes_left -= len(chunk)
if not chunk:
if bytes_left != 0: # The client will see an error.
self._memoize_error(
obj,
FileIntegrityError(
location=location,
failed_check="size",
expected=obj["size"],
actual=obj["size"] - bytes_left,
),
)
break
#
# Check for errors **before** sending out more data -- this
# might be the last chunk, and so we signal errors by
# refusing to send the last bit of data.
#
# It's possible that we have a chunk after the last chunk,
# but we don't want to send that last chunk since the client
# might conclude all is well upon receiving enough data.
if bytes_left == 0:
# The next `if` will error if we get a non-empty chunk.
# The error's `actual=` might be an underestimate.
bytes_left -= len(input.read())
if bytes_left < 0:
self._memoize_error(
obj,
FileIntegrityError(
location=location,
failed_check="size",
expected=obj["size"],
actual=obj["size"] - bytes_left,
),
)
break # Incomplete content, client will see an error.
hash.update(chunk)
if bytes_left == 0 and hash.hexdigest() != checksum.hexdigest:
self._memoize_error(
obj,
FileIntegrityError(
location=location,
failed_check=checksum.algorithm,
expected=checksum.hexdigest,
actual=hash.hexdigest(),
),
)
break # Incomplete content, client will see an error.
# If this is the last chunk, the stream was error-free.
self.wfile.write(chunk)
log.debug(f"Normal exit for GET {location}")