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
|
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
|
// Build result using S3ListObjectVersionsResult to avoid conflicts with XSD structs
|
||||||
result := &S3ListObjectVersionsResult{
|
result := &S3ListObjectVersionsResult{
|
||||||
Name: bucket,
|
Name: bucket,
|
||||||
|
|||||||
Reference in New Issue
Block a user