package s3 import ( "context" "encoding/xml" "net/http" "net/url" "strings" "time" ) // https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html#API_CopyObject_ResponseSyntax type CopyObjectResponse struct { CopyObjectResult xml.Name `json:"copyObjectResult" xml:"CopyObjectResult"` ETag string `json:"etag" xml:"ETag"` LastModified time.Time `json:"lastModified" xml:"LastModified"` ChecksumType string `json:"checksumType" xml:"ChecksumType"` ChecksumCRC32 string `json:"checksumCRC32" xml:"ChecksumCRC32"` ChecksumCRC32C string `json:"checksumCRC32C" xml:"ChecksumCRC32C"` ChecksumCRC64NVME string `json:"checksumCRC64NVME" xml:"ChecksumCRC64NVME"` ChecksumSHA1 string `json:"checksumSHA1" xml:"ChecksumSHA1"` ChecksumSHA256 string `json:"checksumSHA256" xml:"ChecksumSHA256"` } // CopyObject copies a single object from srcKey to dstKey destination. // (both keys are expected to be operating within the same bucket). // // https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html func (s3 *S3) CopyObject(ctx context.Context, srcKey string, dstKey string, optReqFuncs ...func(*http.Request)) (*CopyObjectResponse, error) { req, err := http.NewRequestWithContext(ctx, http.MethodPut, s3.URL(dstKey), nil) if err != nil { return nil, err } // per the doc the header value must be URL-encoded req.Header.Set("x-amz-copy-source", url.PathEscape(s3.Bucket+"/"+strings.TrimLeft(srcKey, "/"))) // apply optional request funcs for _, fn := range optReqFuncs { if fn != nil { fn(req) } } resp, err := s3.SignAndSend(req) if err != nil { return nil, err } defer resp.Body.Close() result := &CopyObjectResponse{} err = xml.NewDecoder(resp.Body).Decode(result) if err != nil { return nil, err } return result, nil }