diff --git a/s3api/router.go b/s3api/router.go index 9e9a591..ae6e078 100644 --- a/s3api/router.go +++ b/s3api/router.go @@ -1048,6 +1048,12 @@ func (sa *S3ApiRouter) Init(app *fiber.App, be backend.Backend, iam auth.IAMServ controllers.ProcessHandlers(ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrGetUploadsWithKey)), metrics.ActionUndetected, services), ) + // object operation with '?versions' is rejected with a specific error + objectRouter.Get("", + middlewares.MatchQueryArgs("versions"), + controllers.ProcessHandlers(ctrl.HandleErrorRoute(s3err.GetAPIError(s3err.ErrVersionsWithKey)), metrics.ActionUndetected, services), + ) + // object GET operation is not allowed with copy source objectRouter.Get("/", middlewares.MatchHeader("X-Amz-Copy-Source"), diff --git a/s3err/s3err.go b/s3err/s3err.go index 03b68c1..a02aa0b 100644 --- a/s3err/s3err.go +++ b/s3err/s3err.go @@ -127,6 +127,7 @@ const ( ErrRequestNotReadyYet ErrMissingDateHeader ErrGetUploadsWithKey + ErrVersionsWithKey ErrCopySourceNotAllowed ErrInvalidRequest ErrAuthNotSetup @@ -542,6 +543,11 @@ var errorCodeResponse = map[ErrorCode]APIError{ Description: "Key is not expected for the GET method ?uploads subresource", HTTPStatusCode: http.StatusBadRequest, }, + ErrVersionsWithKey: { + Code: "InvalidRequest", + Description: "There is no such thing as the ?versions sub-resource for a key", + HTTPStatusCode: http.StatusBadRequest, + }, ErrCopySourceNotAllowed: { Code: "InvalidArgument", Description: "You can only specify a copy source header for copy requests.", diff --git a/tests/integration/general.go b/tests/integration/general.go index 5bfce5d..f5647b7 100644 --- a/tests/integration/general.go +++ b/tests/integration/general.go @@ -189,6 +189,23 @@ func RouterCopySourceNotAllowed(s *S3Conf) error { }) } +func RouterListVersionsWithKey(s *S3Conf) error { + testName := "RouterListVersionsWithKey" + return actionHandlerNoSetup(s, testName, func(s3client *s3.Client, bucket string) error { + req, err := http.NewRequest(http.MethodGet, s.endpoint+"/bucket/object?versions", nil) + if err != nil { + return err + } + + resp, err := s.httpClient.Do(req) + if err != nil { + return err + } + + return checkHTTPResponseApiErr(resp, s3err.GetAPIError(s3err.ErrVersionsWithKey)) + }) +} + // CORS middleware tests func CORSMiddleware_invalid_method(s *S3Conf) error { testName := "CORSMiddleware_invalid_method" diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index 79a54d4..39be64c 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -1094,6 +1094,7 @@ func TestRouter(ts *TestState) { ts.Run(RouterPUTObjectOnlyUploadId) ts.Run(RouterGetUploadsWithKey) ts.Run(RouterCopySourceNotAllowed) + ts.Run(RouterListVersionsWithKey) } func TestUnsignedStreaminPayloadTrailer(ts *TestState) { @@ -1776,6 +1777,7 @@ func GetIntTests() IntTests { "RouterPUTObjectOnlyUploadId": RouterPUTObjectOnlyUploadId, "RouterGetUploadsWithKey": RouterGetUploadsWithKey, "RouterCopySourceNotAllowed": RouterCopySourceNotAllowed, + "RouterListVersionsWithKey": RouterListVersionsWithKey, "UnsignedStreaminPayloadTrailer_malformed_trailer": UnsignedStreaminPayloadTrailer_malformed_trailer, "UnsignedStreamingPayloadTrailer_missing_invalid_dec_content_length": UnsignedStreamingPayloadTrailer_missing_invalid_dec_content_length, "UnsignedStreamingPayloadTrailer_invalid_trailing_checksum": UnsignedStreamingPayloadTrailer_invalid_trailing_checksum,