serve s3: forget the metadata of deleted objects

The metadata of every object uploaded was kept in memory for as long as
the server ran, even after the object was deleted, so it grew without
limit and the metadata of a deleted object reappeared on any object
later created at the same key other than through serve s3.

Deleting an object now forgets its metadata.
This commit is contained in:
Nick Craig-Wood committed 2026-09-24 10:35:30 +01:00
1 parent 04697cc02a
commit c350f8ebbf
2 files changed
+33

No files matched your search

+1
View File
@@ -491,6 +491,7 @@ func (b *s3Backend) deleteObject(ctx context.Context, bucketName, objectName str
if err := _vfs.Remove(fp); err != nil && !os.IsNotExist(err) {
return err
}
b.meta.Delete(fp)
// FIXME: unsafe operation
rmdirRecursive(fp, _vfs)
+32
View File
@@ -19,6 +19,7 @@ import (
"github.com/rclone/gofakes3"
"github.com/rclone/rclone/cmd/serve/proxy"
"github.com/rclone/rclone/fs"
"github.com/rclone/rclone/fs/object"
"github.com/rclone/rclone/fstest"
"github.com/rclone/rclone/lib/random"
"github.com/rclone/rclone/vfs"
@@ -222,3 +223,34 @@ func TestPutObjectFailureCached(t *testing.T) {
}
}
}
// TestDeleteObjectForgetsMetadata checks that deleting an object forgets
// its metadata, so it isn't kept in memory and doesn't reappear on a new
// object at the same key.
func TestDeleteObjectForgetsMetadata(t *testing.T) {
b, f, bucket := newPutTestBackend(t, "", nil)
ctx := context.Background()
const key = "meta.txt"
meta := map[string]string{"X-Amz-Meta-Colour": "blue"}
_, err := b.PutObject(ctx, bucket, key, meta, bytes.NewReader([]byte("one")), 3)
require.NoError(t, err)
obj, err := b.HeadObject(ctx, bucket, key)
require.NoError(t, err)
assert.Equal(t, "blue", obj.Metadata["X-Amz-Meta-Colour"])
_, err = b.DeleteObject(ctx, bucket, key)
require.NoError(t, err)
// Recreate the object without going through serve s3.
src := object.NewStaticObjectInfo(path.Join(bucket, key), time.Now(), 3, true, nil, nil)
_, err = f.Put(ctx, bytes.NewReader([]byte("two")), src)
require.NoError(t, err)
_vfs, err := b.s.getVFS(ctx)
require.NoError(t, err)
b.forgetPath(_vfs, path.Join(bucket, key))
obj, err = b.HeadObject(ctx, bucket, key)
require.NoError(t, err)
assert.NotContains(t, obj.Metadata, "X-Amz-Meta-Colour", "metadata of the deleted object reappeared")
}