s3: fix ListObjectVersions pagination by implementing key-marker filtering
The ListObjectVersions API was receiving key-marker and version-id-marker parameters but not using them to filter results. This caused infinite pagination loops when clients tried to paginate through results. Fix by adding filtering logic after sorting: - Skip versions with key < keyMarker (already returned in previous pages) - For key == keyMarker, skip versions with versionId >= versionIdMarker - Include versions with key > keyMarker or (key == keyMarker and versionId < versionIdMarker) This respects the S3 sort order (key ascending, versionId descending for same key) and correctly returns only versions that come AFTER the marker position.
This commit is contained in:
@@ -226,6 +226,38 @@ func (s3a *S3ApiServer) listObjectVersions(bucket, prefix, keyMarker, versionIdM
|
||||
return versionIdI > versionIdJ
|
||||
})
|
||||
|
||||
// Apply key-marker and version-id-marker filtering
|
||||
// S3 pagination: skip versions at or before the marker, return versions AFTER the marker
|
||||
// Versions are sorted: key ascending, then versionId descending (newest first for same key)
|
||||
if keyMarker != "" {
|
||||
filteredVersions := make([]interface{}, 0, len(allVersions))
|
||||
for _, version := range allVersions {
|
||||
var key, versionId string
|
||||
switch v := version.(type) {
|
||||
case *VersionEntry:
|
||||
key = v.Key
|
||||
versionId = v.VersionId
|
||||
case *DeleteMarkerEntry:
|
||||
key = v.Key
|
||||
versionId = v.VersionId
|
||||
}
|
||||
|
||||
// Include this version if it's AFTER the marker
|
||||
// For key > keyMarker: always include
|
||||
// For key == keyMarker: include if versionId < versionIdMarker (since versionIds are descending)
|
||||
// For key < keyMarker: skip (already returned in previous pages)
|
||||
if key > keyMarker {
|
||||
filteredVersions = append(filteredVersions, version)
|
||||
} else if key == keyMarker && versionIdMarker != "" && versionId < versionIdMarker {
|
||||
filteredVersions = append(filteredVersions, version)
|
||||
}
|
||||
// else: skip this version (it was in a previous page)
|
||||
}
|
||||
glog.V(1).Infof("listObjectVersions: after applying markers (key=%s, versionId=%s), %d -> %d versions",
|
||||
keyMarker, versionIdMarker, len(allVersions), len(filteredVersions))
|
||||
allVersions = filteredVersions
|
||||
}
|
||||
|
||||
// Build result using S3ListObjectVersionsResult to avoid conflicts with XSD structs
|
||||
result := &S3ListObjectVersionsResult{
|
||||
Name: bucket,
|
||||
|
||||
Reference in New Issue
Block a user