Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my pdf uploaded using a presigned AWS S3 url does not have the correct content type?

I use AWS S3 with presigned urls both for uploading (putObject) and downloading (getObject).

I noticed that the generated urls to load pdfs are downloaded instead of being displayed in the _blank target. I tracked it down to the fact that my s3 objects have a metadata field ContentType set to application/x-www-form-urlencoded instead of application/pdf as I requested. It works when I manually change the content type metadata on S3.

The code used to generate the presigned putObject url is this:

console.log("presigning with ", fileInput);
/* Will print something like:
presigning with  [Object: null prototype] {
  name: 'myFile.pdf',
  mimetype: 'application/pdf',
  size: 321528
}
*/
const { name, size, mimetype } = fileInput
const signedUrlExpireSeconds = 60 * 60
let data = {}
const key = "articles/" + Date.now().toString() + ".pdf"
let params = {
       Bucket: 'mybucket',
       Key: key,
       Expires: signedUrlExpireSeconds,
       ContentType: mimetype
};
data.url = await uploadToS3(params)// what I will use to upload from the client browser


export const uploadToS3 = (params) => {
    AWS.config.update({
        accessKeyId: process.env.S3ACCESSKEYID,
        secretAccessKey: process.env.S3SECRETACCESSKEY,
        region: process.env.S3REGION
    });
    var s3 = new AWS.S3();
    return s3.getSignedUrlPromise('putObject', params);
}

The generated url contains indeed the content type option like follows (truncated url):

https://mybucket.s3.eu-west-3.amazonaws.com/articles/1582299553999.pdf?Content-Type=application%2Fpdf&X-Amz-Algorithm......

However, when I try to display my pdf in a _blank tab, the browser downloads it because of the faulty application/x-www-form-urlencoded content type set during the S3 upload.

I assume the getObject presigned url is ok since it works when I manually update on S3 the content type of the file.

Am I missing something with the upload?


UPDATE

I wondered if maybe it was related to the axios put request made on the basis of the presigned url. Based on this issue comments, I managed to get the proper content type.

However, The pdf does not load because the favicon is not available... There is 2 network call, one for the pdf that ok with 304, and one for a favicon that gets a 400 bad request on firefox, and a 403 forbidden on chromium. As a consequence (it seems), the pdf file is seen as invalid.

I made the favico file the only public one, but the PDF is still seen as invalid. However, it displays correctly when downloaded.

like image 797
Billybobbonnet Avatar asked Sep 05 '25 02:09

Billybobbonnet


1 Answers

For everyone's future reference, when sending a presigned URL request, you need to provide the Content-Type in the request, in the axios, or whatever is your http client. Otherwise it will be given this application/x-www-form-urlencoded. That's why when you retrieve with .getObject , you see the Content-Type set to application/x-www-form-urlencoded.

like image 125
Renan Cidale Avatar answered Sep 07 '25 22:09

Renan Cidale