From a6d61e1dde3e7d0e04da7f8e8d000e788d525d51 Mon Sep 17 00:00:00 2001 From: Ben McClelland Date: Mon, 18 Nov 2024 21:15:16 -0800 Subject: [PATCH] fix: listobjects internal server error for prefix not directory We need to treat a prefix that has a parent component as a file instead of a directory in the filesystem as a non existing prefix instead of an internal server error. This error was caused because we were not handling ENOTDIR within the fs walk. Fixes #949 --- backend/walk.go | 3 ++- tests/integration/group-tests.go | 2 ++ tests/integration/tests.go | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/backend/walk.go b/backend/walk.go index 6511ae65..b4365121 100644 --- a/backend/walk.go +++ b/backend/walk.go @@ -21,6 +21,7 @@ import ( "io/fs" "sort" "strings" + "syscall" "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/versity/versitygw/s3response" @@ -231,7 +232,7 @@ func Walk(ctx context.Context, fileSystem fs.FS, prefix, delimiter, marker strin }) if err != nil { // suppress file not found caused by user's prefix - if errors.Is(err, fs.ErrNotExist) { + if errors.Is(err, fs.ErrNotExist) || errors.Is(err, syscall.ENOTDIR) { return WalkResults{}, nil } return WalkResults{}, err diff --git a/tests/integration/group-tests.go b/tests/integration/group-tests.go index 124ea159..7eb963e7 100644 --- a/tests/integration/group-tests.go +++ b/tests/integration/group-tests.go @@ -201,6 +201,7 @@ func TestListObjectsV2(s *S3Conf) { ListObjectsV2_truncated_common_prefixes(s) ListObjectsV2_all_objs_max_keys(s) ListObjectsV2_list_all_objs(s) + ListObjectsV2_invalid_parent_prefix(s) } // VD stands for Versioning Disabled @@ -768,6 +769,7 @@ func GetIntTests() IntTests { "ListObjectsV2_truncated_common_prefixes": ListObjectsV2_truncated_common_prefixes, "ListObjectsV2_all_objs_max_keys": ListObjectsV2_all_objs_max_keys, "ListObjectsV2_list_all_objs": ListObjectsV2_list_all_objs, + "ListObjectsV2_invalid_parent_prefix": ListObjectsV2_invalid_parent_prefix, "ListObjectVersions_VD_success": ListObjectVersions_VD_success, "DeleteObject_non_existing_object": DeleteObject_non_existing_object, "DeleteObject_directory_object_noslash": DeleteObject_directory_object_noslash, diff --git a/tests/integration/tests.go b/tests/integration/tests.go index e9c746c9..1cef2091 100644 --- a/tests/integration/tests.go +++ b/tests/integration/tests.go @@ -4656,6 +4656,45 @@ func ListObjectsV2_list_all_objs(s *S3Conf) error { }) } +func ListObjectsV2_invalid_parent_prefix(s *S3Conf) error { + testName := "ListObjectsV2_invalid_parent_prefix" + return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error { + _, err := putObjects(s3client, []string{"file"}, bucket) + if err != nil { + return err + } + + delim, maxKeys := "/", int32(100) + prefix := "file/file/file" + + ctx, cancel := context.WithTimeout(context.Background(), shortTimeout) + out, err := s3client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ + Bucket: &bucket, + Delimiter: &delim, + MaxKeys: &maxKeys, + Prefix: &prefix, + }) + cancel() + if err != nil { + return err + } + + if len(out.CommonPrefixes) > 0 { + return fmt.Errorf("expected the common prefixes to be %v, instead got %v", []string{""}, out.CommonPrefixes) + } + if *out.MaxKeys != maxKeys { + return fmt.Errorf("expected the max-keys to be %v, instead got %v", maxKeys, *out.MaxKeys) + } + if *out.Delimiter != delim { + return fmt.Errorf("expected the delimiter to be %v, instead got %v", delim, *out.Delimiter) + } + if len(out.Contents) > 0 { + return fmt.Errorf("expected the objects to be %v, instead got %v", []types.Object{}, out.Contents) + } + return nil + }) +} + func ListObjectVersions_VD_success(s *S3Conf) error { testName := "ListObjectVersions_VD_success" return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {