amazon-web-servicesamazon-s3cloudflareaws-sdk-netcloudflare-r2

Why doesn't CopyObject for CloudFlare R2 not work with the AWS SDK for .NET?


I'm trying to move my object between two buckets.

I execute a CopyRequest, then a DeleteRequest. But when I'm trying to copy the object, I get the following error:

Amazon.S3.AmazonS3Exception: Header 'x-amz-tagging-directive' with value 'COPY' not implemented

I tried to remove the header after creating an instance of CopyObjectRequest, but there is no header with similar name. Also, I saw no configuration for this when creating a new instance of CopyObjectRequest.

using Amazon.S3;
using Amazon.S3.Model;

var client = new AmazonS3Client(config);

var request = new CopyObjectRequest
{
    SourceBucket = originBucket,
    SourceKey = fileIdString,
    DestinationBucket = destinationBucket,
    DestinationKey = fileIdString
};

await client.CopyObjectAsync(request);
// deleting object...

Solution

  • 10/01/2024: CloudFlare support have confirmed to me that the R2 team have filed an internal ticket to track getting this fixed.

    ā€”-

    As per CloudFlare docs, the x-amz-tagging-directive header is still not supported:

    āŒ x-amz-tagging-directive

    The CopyObject API itself doesn't strictly require the x-amz-tagging-directive header as S3 internally defaults to COPY; CloudFlare may just do a no-op behind the scenes if the header is not sent.

    The .NET SDK does not provide a way of omitting this header. It always sets a value for this header, to determine if the tags for the object need to be copied. Other SDKs I've checked i.e. JS, Java, Python also do the same.

    You can see this from the source code:

    if (copyObjectRequest.IsSetTagSet())
    {
        request.Headers.Add(S3Constants.AmzHeaderTagging, AmazonS3Util.TagSetToQueryString(copyObjectRequest.TagSet));
        request.Headers.Add(S3Constants.AmzHeaderTaggingDirective, TaggingDirective.REPLACE.Value);
    }
    else
    {
        request.Headers.Add(S3Constants.AmzHeaderTaggingDirective, TaggingDirective.COPY.Value);
    }
    

    Unfortunately, until CloudFlare support this header, you need to manually do GetObject & then PutObject in order to copy the object across.

    P.S. I will raise this with CloudFlare support