When using a form POST to upload a file to an S3 bucket, S3 ignores the Content-Type
/MIME type of the file.
The file is uploaded successfully. The file
form data field contains a Blob with a Content-Type
of video/x-matroska;codecs=avc1,pcm
. The key
form data field sets the key of where that file goes in the bucket. But, when I HEAD
or GET
that object later, its Content-Type
is just binary/octet-stream
.
Just for kicks, I added a form field named Content-Type
and duplicated the type of the Blob, but that didn't work. I also tried ContentType
and content_type
, and those didn't work either.
Is it just not possible to set the type via a form upload?
Here's some of the raw request data so you can see that the data is indeed being sent to S3.
------WebKitFormBoundaryJJ9VA3o1bbQ3DIPJ
Content-Disposition: form-data; name="key"
woot/woot/wootwootwoot
------WebKitFormBoundaryJJ9VA3o1bbQ3DIPJ
Content-Disposition: form-data; name="file"; filename="woot/woot/wootwootwoot"
Content-Type: video/x-matroska;codecs=avc1,pcm
Eߣ£BB÷BòBóBmatroskaBBSgÿÿÿÿÿÿÿI©f*×±B@MChromeWAChromeT®kà®±×sÅoù¾¤=ÆA_PCM/FLOAT/IEEEáµG,Dbd ®«×sź<ø
V_MPEG4/ISO/AVCà°º8
------WebKitFormBoundaryJJ9VA3o1bbQ3DIPJ
Content-Disposition: form-data; name="Content-Type"
video/x-matroska;codecs=avc1,pcm
------WebKitFormBoundaryJJ9VA3o1bbQ3DIPJ
Content-Disposition: form-data; name="ContentType"
video/x-matroska;codecs=avc1,pcm
------WebKitFormBoundaryJJ9VA3o1bbQ3DIPJ
Content-Disposition: form-data; name="content_type"
video/x-matroska;codecs=avc1,pcm
------WebKitFormBoundaryJJ9VA3o1bbQ3DIPJ--
This is due to Content-Type
not being set in your Form Data. To do so you need to change your policy to allow Content-Type you wish to pass. In your case a video video/x-matroska
. For that you need to set the policy first. After that specify it on the HTML form data as well.
Refer to the code below and the sample policy:
{
"expiration": "2024-12-30T12:00:00.000Z",
"conditions": [
{"bucket": "your-bucket-name"},
["starts-with", "$key", "uploads/"],
{"acl": "public-read"},
{"success_action_status": "201"},
["starts-with", "$Content-Type", ""],
["content-length-range", 0, 10485760] // Adjust the range as per your need
]
}
Make sure to provide the content type in your template code in the HTML like below:
<form action="https://your-bucket-name.s3.amazonaws.com/" method="post" enctype="multipart/form-data">
<input type="hidden" name="key" value="uploads/${filename}">
<input type="hidden" name="acl" value="public-read">
<input type="hidden" name="Content-Type" value="video/x-matroska;codecs=avc1,pcm"> <!-- Add content type like this -->
<input type="hidden" name="X-Amz-Credential" value="${credentials}">
<input type="hidden" name="X-Amz-Algorithm" value="AWS4-HMAC-SHA256">
<input type="hidden" name="X-Amz-Date" value="${timestamp}">
<input type="hidden" name="Policy" value="${policy}">
<input type="hidden" name="X-Amz-Signature" value="${signature}">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
Note: It is very important that the Content-Type
form field come before the file
field.
Refer the AWS S3 upload official documentation here for more reference.