Browse Source

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.
pull/7786/head
chrislu 4 days ago
parent
commit
5dd34e3260
  1. 32
      weed/s3api/s3api_object_versioning.go

32
weed/s3api/s3api_object_versioning.go

@ -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,

Loading…
Cancel
Save