mirror of
https://github.com/versity/versitygw.git
synced 2026-08-17 12:46:23 +00:00
Merge pull request #2138 from versity/ben/implicit-dir-objs
fix: ignore implicit directories for Get/HeadObject
This commit is contained in:
@@ -4496,6 +4496,19 @@ func (p *Posix) GetObject(ctx context.Context, input *s3.GetObjectInput) (*s3.Ge
|
||||
if !strings.HasSuffix(object, "/") && fid.IsDir() {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if fid.IsDir() {
|
||||
// Only directories explicitly created via S3 (put-object with key ending
|
||||
// in '/') have an etag attribute. Directories created incidentally on the
|
||||
// filesystem or as parent directories during object upload should not be
|
||||
// accessible via get-object.
|
||||
_, derr := p.meta.RetrieveAttribute(nil, bucket, object, etagkey)
|
||||
if errors.Is(derr, meta.ErrNoSuchKey) || errors.Is(derr, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if derr != nil {
|
||||
return nil, fmt.Errorf("get dir etag: %w", derr)
|
||||
}
|
||||
}
|
||||
|
||||
if p.versioningEnabled() {
|
||||
isDelMarker, err := p.isObjDeleteMarker(bucket, object)
|
||||
@@ -4821,6 +4834,19 @@ func (p *Posix) HeadObject(ctx context.Context, input *s3.HeadObjectInput) (*s3.
|
||||
if !strings.HasSuffix(object, "/") && fi.IsDir() {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if fi.IsDir() {
|
||||
// Only directories explicitly created via S3 (put-object with key ending
|
||||
// in '/') have an etag attribute. Directories created incidentally on the
|
||||
// filesystem or as parent directories during object upload should not be
|
||||
// accessible via head-object.
|
||||
_, derr := p.meta.RetrieveAttribute(nil, bucket, object, etagkey)
|
||||
if errors.Is(derr, meta.ErrNoSuchKey) || errors.Is(derr, fs.ErrNotExist) {
|
||||
return nil, s3err.GetAPIError(s3err.ErrNoSuchKey)
|
||||
}
|
||||
if derr != nil {
|
||||
return nil, fmt.Errorf("get dir etag: %w", derr)
|
||||
}
|
||||
}
|
||||
|
||||
if p.versioningEnabled() {
|
||||
isDelMarker, err := p.isObjDeleteMarker(bucket, object)
|
||||
|
||||
@@ -829,6 +829,34 @@ func GetObject_not_enabled_checksum_mode(s *S3Conf) error {
|
||||
})
|
||||
}
|
||||
|
||||
// GetObject_incidental_dir_object verifies that a directory created incidentally
|
||||
// as a parent during object upload (i.e. never explicitly PUT via S3 with a
|
||||
// trailing-slash key) is not accessible via GetObject.
|
||||
func GetObject_incidental_dir_object(s *S3Conf) error {
|
||||
testName := "GetObject_incidental_dir_object"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
// Upload an object under a prefix; this creates the parent directory
|
||||
// incidentally on posix but the directory was never PUT as an S3 object.
|
||||
obj := "my-dir/my-obj"
|
||||
_, err := putObjectWithData(int64(64), &s3.PutObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: &obj,
|
||||
}, s3client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir := "my-dir/"
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
||||
_, err = s3client.GetObject(ctx, &s3.GetObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: &dir,
|
||||
})
|
||||
cancel()
|
||||
return checkSdkApiErr(err, "NoSuchKey")
|
||||
})
|
||||
}
|
||||
|
||||
func GetObject_non_existing_dir_object(s *S3Conf) error {
|
||||
testName := "GetObject_non_existing_dir_object"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
|
||||
@@ -62,6 +62,34 @@ func HeadObject_invalid_part_number(s *S3Conf) error {
|
||||
})
|
||||
}
|
||||
|
||||
// HeadObject_incidental_dir_object verifies that a directory created incidentally
|
||||
// as a parent during object upload (i.e. never explicitly PUT via S3 with a
|
||||
// trailing-slash key) is not accessible via HeadObject.
|
||||
func HeadObject_incidental_dir_object(s *S3Conf) error {
|
||||
testName := "HeadObject_incidental_dir_object"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
// Upload an object under a prefix; this creates the parent directory
|
||||
// incidentally on posix but the directory was never PUT as an S3 object.
|
||||
obj := "my-dir/my-obj"
|
||||
_, err := putObjectWithData(int64(64), &s3.PutObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: &obj,
|
||||
}, s3client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dir := "my-dir/"
|
||||
ctx, cancel := context.WithTimeout(context.Background(), shortTimeout)
|
||||
_, err = s3client.HeadObject(ctx, &s3.HeadObjectInput{
|
||||
Bucket: &bucket,
|
||||
Key: &dir,
|
||||
})
|
||||
cancel()
|
||||
return checkSdkApiErr(err, "NotFound")
|
||||
})
|
||||
}
|
||||
|
||||
func HeadObject_non_existing_dir_object(s *S3Conf) error {
|
||||
testName := "HeadObject_non_existing_dir_object"
|
||||
return actionHandler(s, testName, func(s3client *s3.Client, bucket string) error {
|
||||
|
||||
@@ -205,6 +205,7 @@ func TestHeadObject(ts *TestState) {
|
||||
ts.Run(HeadObject_invalid_part_number)
|
||||
ts.Run(HeadObject_directory_object_noslash)
|
||||
ts.Run(HeadObject_non_existing_dir_object)
|
||||
ts.Run(HeadObject_incidental_dir_object)
|
||||
ts.Run(HeadObject_invalid_parent_dir)
|
||||
ts.Run(HeadObject_with_range)
|
||||
ts.Run(HeadObject_by_range_resp_status)
|
||||
@@ -263,6 +264,7 @@ func TestGetObject(ts *TestState) {
|
||||
ts.Run(GetObject_directory_success)
|
||||
ts.Run(GetObject_by_range_resp_status)
|
||||
ts.Run(GetObject_non_existing_dir_object)
|
||||
ts.Run(GetObject_incidental_dir_object)
|
||||
ts.Run(GetObject_overrides_success)
|
||||
ts.Run(GetObject_overrides_presign_success)
|
||||
ts.Run(GetObject_overrides_fail_public)
|
||||
@@ -1412,6 +1414,7 @@ func GetIntTests() IntTests {
|
||||
"HeadObject_invalid_part_number": HeadObject_invalid_part_number,
|
||||
"HeadObject_directory_object_noslash": HeadObject_directory_object_noslash,
|
||||
"HeadObject_non_existing_dir_object": HeadObject_non_existing_dir_object,
|
||||
"HeadObject_incidental_dir_object": HeadObject_incidental_dir_object,
|
||||
"HeadObject_name_too_long": HeadObject_name_too_long,
|
||||
"HeadObject_invalid_parent_dir": HeadObject_invalid_parent_dir,
|
||||
"HeadObject_with_range": HeadObject_with_range,
|
||||
@@ -1456,6 +1459,7 @@ func GetIntTests() IntTests {
|
||||
"GetObject_directory_success": GetObject_directory_success,
|
||||
"GetObject_by_range_resp_status": GetObject_by_range_resp_status,
|
||||
"GetObject_non_existing_dir_object": GetObject_non_existing_dir_object,
|
||||
"GetObject_incidental_dir_object": GetObject_incidental_dir_object,
|
||||
"GetObject_overrides_success": GetObject_overrides_success,
|
||||
"GetObject_overrides_presign_success": GetObject_overrides_presign_success,
|
||||
"GetObject_overrides_fail_public": GetObject_overrides_fail_public,
|
||||
|
||||
Reference in New Issue
Block a user