Overriding file name of an S3 object using pre-signed URL and aws-sdk-go
I’ve been trying to get uploading and downloading of S3 objects working using pre-signed URLs. Once you get the basics sorted around IAM permissions, bucket policies, etc., one final hurdle is downloading the S3 object with a custom name.
Our problem is that we generate and assign a unique ID to the S3 object during file upload and use that ID as the key for the object name. So for instance the user uploads a PDF document named hello-kitty.pdf. We store the original file name in the database, but our actual S3 object key will be something like 12345678987654321.
When you then provide a pre-signed URL to the user for downloading, then the problem is that the user will get a file named 12345678987654321, not hello-kitty.pdf.
When you look at the official AWS documentation for the aws-sdk-go library, then you’ll get something like this (slightly modified):
svc := s3.New(
s3Session.New(
&aws.Config{
Region: aws.String("eu-west-1"),
LogLevel: aws.LogLevel(aws.LogDebug),
},
),
)
req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String("myBucket"),
Key: aws.String("myKey"),
})
str, err := req.Presign(15 * time.Minute)
log.Println("The URL is:", str, " err:", err)The key to override the filename is to use the Content-Disposition header. MDN has the following example:
200 OK
Content-Type: text/html; charset=utf-8
Content-Disposition: attachment; filename="cool.html"
Content-Length: 22
<HTML>Save me!</HTML>I struggled getting the Content-Disposition header added to the pre-signed URL because it turns out that in the API it’s called Response Content-Disposition header. When you add the following line to your request, then it’s all magically working:
req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
Bucket: aws.String("myBucket"),
Key: aws.String("myKey"),
ResponseContentDisposition: aws.String("attachment;filename=hello-kitty.pdf"),
})