S3 use last Key when there is no Marker element

Fix infinite loop and memory blowup when importing from an unversioned S3
bucket that is large enough to need pagination.

I don't think there actually ever will be a Marker element, a delimiter is
not set.

Probably this code path was never tested with pagination! Also the aws
library's lack of any docs made it easy to mess up.

Versioned buckets seem to not have the same problem. The API docs for
ListObjectVersions say that NextKeyMarker will always be provided when
paginating.
This commit is contained in:
Joey Hess 2024-11-14 16:09:27 -04:00
parent b9b3e1257d
commit 4b87669ae2
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
2 changed files with 19 additions and 8 deletions

View file

@ -11,6 +11,8 @@ git-annex (10.20241032) UNRELEASED; urgency=medium
(Needs aws-0.24.3)
* S3: Send git-annex or other configured User-Agent.
(Needs aws-0.24.3)
* S3: Fix infinite loop and memory blowup when importing from an
unversioned S3 bucket that is large enough to need pagination.
-- Joey Hess <id@joeyh.name> Mon, 11 Nov 2024 12:26:00 -0400

View file

@ -589,14 +589,23 @@ listImportableContentsS3 hv r info c =
continuelistunversioned h [] rsp
continuelistunversioned h l rsp
| S3.gbrIsTruncated rsp = do
| S3.gbrIsTruncated rsp =
let marker =
S3.gbrNextMarker rsp
<|>
(S3.objectKey <$> lastMaybe (S3.gbrContents rsp))
in case marker of
Just _ -> do
rsp' <- sendS3Handle h $
(S3.getBucket (bucket info))
{ S3.gbMarker = S3.gbrNextMarker rsp
{ S3.gbMarker = marker
, S3.gbPrefix = fileprefix
}
continuelistunversioned h (rsp:l) rsp'
| otherwise = return $
Nothing -> nomore
| otherwise = nomore
where
nomore = return $
mkImportableContentsUnversioned info (reverse (rsp:l))
continuelistversioned h l rsp