Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

S3 Presigned Post require specific Content-Type

To start, I'm using ruby's aws-sdk, but what I'm facing seems to be a misunderstanding of S3's presigned posts.


What I want to be able to do is ensure that anything uploaded to S3 with my presigned post is a video.

What I've tried doing is setting content_type_starts_with: "video/" in the presigned_post hash. This causes all uploads to be rejected with Policy Condition failed: ["starts-with", "$Content-Type", "video/"].

I then tried just content_type: "video/mp4", but this causes s3 to allow any file to be uploaded, and then just tags it with Content-Type: "video/mp4" in the metadata.

I then noticed that when I upload a file without a Content-Type constraint, S3 will tag the file as binary/octet-stream. So I tried the first method again, but this time with content_type_starts_with: "binary/". Same results as before, Policy Condition Failed.

How am I supposed to use the Content-Type field? It does't seem to ever do what I want it to do.


Here's a snippet of the code I'm using:

# In the controller

client = Aws::S3::Client.new(region: 'us-east-1')
resource = Aws::S3::Resource.new(client: client)
bucket = resource.bucket("my-bucket")

object_id = SecureRandom.uuid
object = bucket.object(object_id)

@presigned_post = object.presigned_post({
  acl: "private",
  content_length_range: 0..104857600, # 100 MB
  content_type_starts_with: "video/",
})

# In the presigned post erb

<form action="<%= presigned_post.url %>" method="post" enctype="multipart/form-data">
<% presigned_post.fields.each do |name, value| %>
    <input type="hidden" name="<%= name %>" value="<%= value %>"/>
<% end %>
    <input type="file" name="file" accept="*.mp4,*.ogg,video/*" />
    <input type="submit">
</form>
like image 249
Brian Schlenker Avatar asked Nov 08 '22 15:11

Brian Schlenker


1 Answers

I just had a very similar problem and I think I solved it. I hope this helps.

I realised that setting the content_type_starts_with does not actually restrict what type of file is uploaded, but it restricts what the content-type key in your form data actually is, but you'll still need to set the content type that the form is going to post.

Since I'm doing a client-side upload with JavaScript, I just added this to my upload code: formData.set('content-type', file.type) where formData is an instance of a FormData object that I eventually send to the server through an XMLHttpRequest.

After doing this, uploading a pdf will start the upload but not save the file on S3 because the MIME type restriction.

Let me know if you need some more information, I based some of my upload code of this: http://blog.teamtreehouse.com/uploading-files-ajax

like image 184
Thyme Avatar answered Nov 15 '22 10:11

Thyme