package s3api import ( "fmt" "testing" "github.com/seaweedfs/seaweedfs/weed/filer" "github.com/seaweedfs/seaweedfs/weed/util" ) // TestCopyDestinationPathResolvesBucketCollection guards against server-side // copies routing data into the default collection. // // The filer maps a write to a bucket's collection only when the AssignVolume // Path sits under its buckets folder (/buckets//...). UploadPartCopy // and SSE-C CopyObject used to assign destination volumes against r.URL.Path, // the S3 request URI (e.g. /bucket/key), which never has that prefix; the // copied bytes therefore landed in the default collection instead of the // destination bucket's. The handlers must assign against the real filer path // of the destination. func TestCopyDestinationPathResolvesBucketCollection(t *testing.T) { const bucket = "docker-registry" s3a := &S3ApiServer{option: &S3ApiServerOption{BucketsPath: "/buckets"}} f := &filer.Filer{DirBucketsPath: "/buckets"} // The S3 request URI is not a filer path: the filer cannot derive the // destination bucket from it. This is the shape that caused the leak. if got := f.DetectBucket(util.FullPath("/" + bucket + "/blobs/data")); got != "" { t.Fatalf("S3 request URI unexpectedly mapped to collection %q; the test no longer reproduces the bug", got) } // UploadPartCopy assigns against the destination part path under .uploads. uploadDir, partName := s3a.copyPartLocation(bucket, "uploadid", 1) partPath := uploadDir + "/" + partName if got := f.DetectBucket(util.FullPath(partPath)); got != bucket { t.Fatalf("UploadPartCopy dst path %q resolved to collection %q, want %q", partPath, got, bucket) } // CopyObject (including the SSE-C paths) assigns against the destination // object path. objPath := fmt.Sprintf("%s/%s", s3a.bucketDir(bucket), "blobs/data") if got := f.DetectBucket(util.FullPath(objPath)); got != bucket { t.Fatalf("CopyObject dst path %q resolved to collection %q, want %q", objPath, got, bucket) } }