8
votes

I'm successfully generating a signed url that I can then use for a limited time to download resources from my s3 bucket. However I'm trying to use the ResponseContentDisposition attribute in the params as documented here:

  1. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
  2. http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property

I'm not sure if I'm doing this wrong but for some reason the headers are not being set. For example if I use the url I get back from s3.getSignedUrl:

curl -i "https://foo-dev.s3.amazonaws.com/images/foo.jpg?AWSAccessKeyId=AKIAICBHUC26S6B446PQ&Expires=1468359314&Signature=EeBqx1G83oeusarBl2KUbbCCBgA%3D&response-content-disposition=attachment%3B%20filename%3Ddata.jpg"

the headers are:

x-amz-id-2: SG9rjYQCcuqgKfjBmMbDQC2CNLcnqBAFzP7zINa99VYUwNijPOm5Ea/5fllZ6cnt/Qti7e26hbE=
x-amz-request-id: 2670068008525B1D
Date: Tue, 12 Jul 2016 21:26:16 GMT
Content-Disposition: inline; filename=foo.jpg
Last-Modified: Tue, 12 Jul 2016 00:47:23 GMT
ETag: "2a8e36651b24769170f4faa429f40f54"
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 43373
Server: AmazonS3

I'm setting this, using the javascript s3 sdk like this:

function tempRedirect(req, res) {
    var filename = req.params[0];
    var contentDisposition = 'attachment; filename=data.jpg';
    var params = {
        Bucket: S3_BUCKET,
        ResponseContentDisposition: contentDisposition,
        Key: checkTrailingSlash(getFileKeyDir(req)) + filename
    };
    var s3 = new aws.S3(s3Options);
    s3.getSignedUrl('getObject', params, function(err, url) {
        res.redirect(url);
    });
};

The docs are pretty light and I can only find PHP examples but it does look like I'm setting content disposition correctly.

Anyone know what is going wrong here??

1
You shouldn't need to use ResponseContentDisposition. Make sure you're passing the putObject method a content-type argument (e.g., would be something like contentType: 'image/jpeg') when initially putting the file in your S3 bucket. Then when you download them via a presigned URL, the object already contains the necessary metadata to handle it as a JPG attachment; this means that when you attempt to download the object via presigned URL, it knows to automatically open a file picker asking you where you want to save the appropriately-typed attachment. - Allison

1 Answers

9
votes

According to RFC- 2616, your value is malformed.

The expected format is attachment; filename="funny-cat.jpg". The filename is a quoted string.

And, my original assumption was that S3 was rejecting it as invalid and silently refusing to replace the value.

Subsequent tests reveal unexpected behavior: if Content-Disposition is not stored with the object, then &response-content-disposition=... works as expected, setting the response header. But if there is a header stored with the object, this query string parameter does not have the documented effect of "overriding" that value.

Conversely, &response-content-type=... does override a stored Content-Type: for the object.

That's what a few quick tests revealed for me.

But this appears to be a bug -- or more accurately, some kind of regression -- in S3. According to one support forum post, the behavior is actually inconsistent, sometimes working and sometimes not.

S3 is aware of this issue and we are working to resolve it. (2016-07-12)

https://forums.aws.amazon.com/thread.jspa?threadID=235006