Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

S3 Upload #52

Open
dima-shulga opened this issue Aug 10, 2017 · 8 comments
Open

S3 Upload #52

dima-shulga opened this issue Aug 10, 2017 · 8 comments

Comments

@dima-shulga
Copy link

dima-shulga commented Aug 10, 2017

I've done everything like in your tutorial except your Ruby script. I've used node js aws-sdk:

const aws = require('aws-sdk');
var config = require('../../server/config.json');
aws.config = config.aws;

    const s3 = new aws.S3();
    const s3Params = {
      Bucket: config.aws.bucket,
      Key: instance.filename,
      Expires: 60,
      ACL: 'public-read'
    };

    s3.getSignedUrl('putObject', s3Params, (err, signedUrl) => {
      if(err){
        return next(err);
      }
      instance.uploadUrl = signedUrl;
      next();
    });

So I've got signed URL

Request URL:https://f.workdoer.com.s3.amazonaws.com/IMG_4875.PNG.png?AWSAccessKeyId=AKIAIFVWPIVVIGIONPXA&Expires=1502381111&Signature=Af9meXlMA7qj5HYALs7LzhWaftc%3D&x-amz-acl=public-read

Request headers:
PUT /IMG_4875.PNG.png?AWSAccessKeyId=AKIAIFVWPIVVIGIONPXA&Expires=1502381111&Signature=Af9meXlMA7qj5HYALs7LzhWaftc%3D&x-amz-acl=public-read HTTP/1.1
Host: f.workdoer.com.s3.amazonaws.com
Connection: keep-alive
Content-Length: 130838
Accept: application/json,text/javascript
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarygDui83iohothuh7E
Referer: http://localhost:4200/app/team/1/project/15/list/task/2074
Accept-Encoding: gzip, deflate, br
Accept-Language: ru,en-US;q=0.8,en;q=0.6,uk;q=0.4,it;q=0.2,de;q=0.2
Request Payload:
------WebKitFormBoundarygDui83iohothuh7E
Content-Disposition: form-data; name="Content-Type"

image/png
------WebKitFormBoundarygDui83iohothuh7E
Content-Disposition: form-data; name="file"; filename="IMG_4875.PNG.png"
Content-Type: image/png


------WebKitFormBoundarygDui83iohothuh7E--

And I've got from Amazon:

<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message><AWSAccessKeyId>AKIAIFVWPIVVIGIONPXA</AWSAccessKeyId><StringToSign>PUT

multipart/form-data; boundary=----WebKitFormBoundarygDui83iohothuh7E
1502381111
x-amz-acl:public-read
/f.workdoer.com/IMG_4875.PNG.png</StringToSign><SignatureProvided>Af9meXlMA7qj5HYALs7LzhWaftc=</SignatureProvided>

Something wrong with your request, because when I put it with CURL:

curl -k -X PUT -T "IMG_4875.PNG.png" "https://f.workdoer.com.s3.amazonaws.com/IMG_4875.PNG.png?AWSAccessKeyId=AKIAIFVWPIVVIGIONPXA&Expires=1502381111&Signature=Af9meXlMA7qj5HYALs7LzhWaftc%3D&x-amz-acl=public-read"

It's successfully uploaded. What I'm doing wrong?

Here is my bucket policy:

    {
        "Version": "2008-10-17",
        "Statement": [
            {
                "Sid": "Allow Public Access to All Objects",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "*"
                },
                "Action": [
                    "s3:DeleteObject",
                    "s3:GetObject",
                    "s3:PutObject"
                ],
                "Resource": "arn:aws:s3:::f.workdoer.com/*"
            }
        ]
    }

And cors:


    <?xml version="1.0" encoding="UTF-8"?>
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <ExposeHeader>Location</ExposeHeader>
        <AllowedHeader>Content-Type</AllowedHeader>
        <AllowedHeader>x-amz-acl</AllowedHeader>
        <AllowedHeader>origin</AllowedHeader>
        <AllowedHeader>accept</AllowedHeader>
    </CORSRule>
    </CORSConfiguration>

Thanks for any help.

@RuslanZavacky
Copy link

I actually have the same issue, but I am doing request from PHP. Can someone please verify, that Ruby version in Readme and the latest version of this bundle, actually can upload to S3?

@tim-evans
Copy link
Collaborator

tim-evans commented Aug 31, 2017

Let me look into this and reproduce this so I can debug.

@schleifer-john
Copy link
Contributor

I ran into this same issue. The problem is the S3 example in the README says to use the file.upload method, but that method adds the multipart/form-data content type header which as mentioned here is not compatible with binary uploads to S3: aws/aws-sdk-js#547 (comment)

I saw this solution (#12 (comment)) which mentions there is an alternative method called uploadBinary. As mentioned in the thread, the example in the README needs to be updated to the following for S3 uploads to work:

import Ember from 'ember';

const RSVP = Ember.RSVP;
const set = Ember.set;

export default Ember.Route.extend({
  actions: {
    uploadImage: function (file) {
      let model = this.modelFor(this.routeName);
      RSVP.cast(Ember.$.get('/api/s3_direct')).then(function (response) {
        return file.uploadBinary(response.url, {
          method: 'PUT',
          contentType: file.blob.type,
          data: JSON.stringify(response.credentials),
        });
      }).then(function (response) {
        set(model, 'url', response.headers.Location);
        return model.save();
      });
    }
  }
});

@Parrryy
Copy link

Parrryy commented Mar 15, 2018

Try adding Content-Type to S3Params when getting signed URL.

@jelhan
Copy link
Collaborator

jelhan commented Nov 8, 2019

Current documentation still uses file.upload() and not file.uploadBinary(): https://adopted-ember-addons.github.io/ember-file-upload/docs/aws

@schleifer-john do you have time to provide a pull request fixing that one?

Try adding Content-Type to S3Params when getting signed URL.

@Parrryy Is this something what should be added to our documentation? If so, please feel free to provide a pull request.

@mcfiredrill
Copy link
Contributor

I needed to use uploadBinary or else the formData seems to be concatenated to the beginning of the file. What is the use case for using upload instead of uploadBinary ?

@jelhan
Copy link
Collaborator

jelhan commented Jan 6, 2020

What is the use case for using upload instead of uploadBinary ?

uploadBinary enforces a Content-Type: 'application/octet-stream' which upload does not:

uploadBinary(url, opts) {
opts.contentType = 'application/octet-stream';
return upload(this, url, opts, (request) => {
return request.send(get(this, 'blob'));
});
},

@allthesignals
Copy link

When I specify a contentType for uploadBinary I get an error:

file.js:43 Uncaught (in promise) TypeError: Cannot create property 'Content-Type' on string '{"key":"asdf.jpg"}'

It seems to pass through uploadBinary, then call the regular upload method.

Did something about the API change? I am stringifying the data according to @schleifer-john 's approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants