fix: reject the start-after query in ListObjects (V1)

Fixes #2004
This commit is contained in:
dualfroz
2026-10-10 11:46:12 +02:00
parent e56df2384d
commit 44dc2e71ec
6 changed files with 64 additions and 3 deletions
+10
View File
@@ -22,6 +22,7 @@ import (
"github.com/gofiber/fiber/v3"
"github.com/versity/versitygw/auth"
"github.com/versity/versitygw/s3api/utils"
"github.com/versity/versitygw/s3err"
"github.com/versity/versitygw/s3response"
)
@@ -614,6 +615,15 @@ func (c S3ApiController) ListObjects(ctx fiber.Ctx) (*Response, error) {
region = defaultRegion
}
// start-after is a ListObjectsV2 argument, S3 rejects it on a V1 listing
if ctx.Query("start-after") != "" {
return &Response{
MetaOpts: &MetaOptions{
BucketOwner: parsedAcl.Owner,
},
}, s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, "")
}
err := c.verifyAccess(ctx, auth.AccessOptions{
Acl: parsedAcl,
AclPermission: auth.PermissionRead,
+18
View File
@@ -1195,6 +1195,24 @@ func TestS3ApiController_ListObjects(t *testing.T) {
err: s3err.GetAPIError(s3err.ErrAccessDenied),
},
},
{
name: "start-after is not supported",
input: testInput{
locals: defaultLocals,
beRes: listResult,
queries: map[string]string{
"start-after": "my-key",
},
},
output: testOutput{
response: &Response{
MetaOpts: &MetaOptions{
BucketOwner: "root",
},
},
err: s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, ""),
},
},
{
name: "invalid max keys",
input: testInput{
+5
View File
@@ -26,6 +26,7 @@ type InvalidArgErrorCode int
const (
InvalidArgMaxBuckets InvalidArgErrorCode = iota
InvalidArgNegativeMaxKeys
InvalidArgStartAfter
InvalidArgObjectAttributes
InvalidArgPartNumber
InvalidArgCompleteMpPartNumber
@@ -90,6 +91,10 @@ var invalidArgErrResponses = map[InvalidArgErrorCode]InvalidArgumentError{
Description: "max-keys cannot be negative",
ArgumentName: "maxKeys",
},
InvalidArgStartAfter: {
Description: "startAfter only supported in REST.GET.BUCKET with list-type=2",
ArgumentName: "start-after",
},
InvalidArgObjectAttributes: {
Description: "Invalid attribute name specified.",
ArgumentName: "x-amz-object-attributes",
+29
View File
@@ -17,6 +17,8 @@ package integration
import (
"context"
"fmt"
"net/http"
"time"
"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go-v2/service/s3/types"
@@ -193,6 +195,33 @@ func ListObjects_invalid_max_keys(s *S3Conf) error {
})
}
// start-after belongs to ListObjectsV2, so S3 rejects it on a V1 listing
// instead of ignoring it. The SDK ListObjects input has no StartAfter field,
// so the request is signed and sent by hand.
func ListObjects_start_after(s *S3Conf) error {
testName := "ListObjects_start_after"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
_, err := putObjects(s3client, []string{"bar", "baz", "foo"}, bucket)
if err != nil {
return err
}
req, err := createSignedReq(http.MethodGet, s.endpoint,
fmt.Sprintf("%v?start-after=bar", bucket),
s.awsID, s.awsSecret, "s3", s.awsRegion, "", nil, time.Now(), nil)
if err != nil {
return err
}
resp, err := s.httpClient.Do(req)
if err != nil {
return err
}
return checkHTTPResponseApiErr(resp, s3err.GetInvalidArgumentErr(s3err.InvalidArgStartAfter, ""))
})
}
func ListObjects_max_keys_0(s *S3Conf) error {
testName := "ListObjects_max_keys_0"
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
+2
View File
@@ -314,6 +314,7 @@ func TestListObjects(ts *TestState) {
ts.Run(ListObjects_truncated)
ts.Run(ListObjects_paginated)
ts.Run(ListObjects_invalid_max_keys)
ts.Run(ListObjects_start_after)
ts.Run(ListObjects_max_keys_0)
ts.Run(ListObjects_exceeding_max_keys)
ts.Run(ListObjects_delimiter)
@@ -3153,6 +3154,7 @@ func GetIntTests() IntTests {
"ListObjects_truncated": ListObjects_truncated,
"ListObjects_paginated": ListObjects_paginated,
"ListObjects_invalid_max_keys": ListObjects_invalid_max_keys,
"ListObjects_start_after": ListObjects_start_after,
"ListObjects_max_keys_0": ListObjects_max_keys_0,
"ListObjects_delimiter": ListObjects_delimiter,
"ListObjects_max_keys_none": ListObjects_max_keys_none,
-3
View File
@@ -248,9 +248,6 @@ source ./tests/drivers/objects_and_versions.sh
# tags: curl,ListObjects,start-after,invalid-query
@test "ListObjectsV1 - start-after - error" {
if [ "$DIRECT" != "true" ]; then
skip "https://github.com/versity/versitygw/issues/2004"
fi
run setup_bucket_and_files_v3 "$BUCKET_ONE_NAME" 2
assert_success
read -r bucket_name file_one file_two <<< "$output"