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

Dropzone: How to upload video to S3 using presigned URL and play it in browser? Almost works, but not quite. #2251

Open
peppies opened this issue Aug 21, 2023 · 0 comments

Comments

@peppies
Copy link

peppies commented Aug 21, 2023

Dropzone version: 5.9.3

I have Dropzone set up to allow users to upload videos directly to an S3 presigned URL using the PUT method. Here is my Dropzone script:

var presign = "#";
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("#dropzone", {
  url: presign,
  method: "PUT",
  dictDefaultMessage: "Click Here upload video.",
  maxFilesize: 10000, // MB
  maxFiles: 100,
  addRemoveLinks: true,
  headers: {
    "x-amz-acl": "public-read",
    "Content-Type": "video/mp4"
  },
  init: function() {
    this.on("addedfile", function(file) {
      fileupload_flag = 1;}
    );
    this.on("complete", function (file) {
      fileupload_flag = 0;
    });
    this.on("processing", function (file) {
      this.options.url = presign;
    });
  },
  accept: function(file, done) {
    console.log(file['type']);
    if (file && file['type'].split('/')[0] === 'video') {
      var xhr = new XMLHttpRequest();
      xhr.open("POST", "https://www.example.com/test-getpresign.php");
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.send("mime="+JSON.stringify(file['type']));
      xhr.onreadystatechange = function() {
        if (this.readyState == 4) {
          if(this.status == 200 && this.responseText != '') {
            result = JSON.parse(this.responseText);
            presign = result.url;
            done();
          }
        }
      }
    }
    else { 
      done("Please select only supported picture files."); 
    }
  },
  success: function(file, response){
    this.removeFile(file);
  }     
});

In the "accept" function, which fires before the actual upload, I run an xhr call to a PHP script on my site that generates presigned URLs for my S3, and then returns them to Dropzone and updates the PUT url for where to send the file to. The PHP code for creating the presigned S3 URL is as follows:

    $cdnvideo = new Aws\S3\S3Client([
        'version'     => '2006-03-01',
        'region'      => REGION,
        'endpoint'    => HOST,
            'credentials' => [
            'key'      => AWS_KEY,
            'secret'   => AWS_SECRET_KEY,
        ]
    ]);
    
    $key = 'video.mp4';
    $cmd = $cdnvideo->getCommand('PutObject', [
      'Bucket' => 'bucketname',
      'Key'    => $key,
      'ContentType' => 'video/mp4'
    ]);
    $request = $cdnvideo->createPresignedRequest($cmd, '+720 minutes');
    $url = (string) $request->getUri();

In an example, I attempt to upload a 30-second video 1.5MB in size. It seems that Dropzone sends something to S3. In the bucket list, I am seeing the correct filename at S3, including the correct file size (1.5 MB) and content type "video/mp4'. But when I go to the object URL in my browser to view the actual video, it's a video with 0 seconds, with a 206 HTTP code and apparently 1.1MB downloaded loaded over the network. The video is broken and doesn't load.

Here is the Request in chrome's developer tools:

    Accept: application/json
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.9
    Cache-Control: no-cache
    Connection: keep-alive
    Content-Length: 1570227
    Content-Type: video/mp4
    Host: *****
    Origin: https://www.example.com
    Referer: https://www.example.com/
    Sec-Ch-Ua: "Not/A)Brand";v="99", "Google Chrome";v="115", "Chromium";v="115"
    Sec-Ch-Ua-Mobile: ?0
    Sec-Ch-Ua-Platform: "Windows"
    Sec-Fetch-Dest: empty
    Sec-Fetch-Mode: cors
    Sec-Fetch-Site: cross-site
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36
    X-Amz-Acl: public-read
    X-Requested-With: XMLHttpRequest

PAYLOAD:

    X-Amz-Content-Sha256: UNSIGNED-PAYLOAD
    X-Amz-Algorithm: AWS4-HMAC-SHA256
    X-Amz-Credential: A86SB6NKA1KWC4EF8Z25%2F20230821%2Fus-east-1%2Fs3%2Faws4_request
    X-Amz-Date: 20230821T015024Z
    X-Amz-SignedHeaders: host
    X-Amz-Expires: 43200
    X-Amz-Signature: 2f00a4eff448fc0ba889ed83e207a87d6df42cd0d7b1252f9a68b1056dec8b09
    ------WebKitFormBoundaryfApLoQv4mFg4SHAw
    Content-Disposition: form-data; name="file"; filename="video.mp4"
    Content-Type: video/mp4


    ------WebKitFormBoundaryfApLoQv4mFg4SHAw--

I'm not seeing a Response, not sure if there is supposed to be or not.

What am I doing wrong here? It seems like this is a problem with Dropzone. Although maybe I'm creating the presigned URL incorrectly? My goal is to simply have Dropzone PUT the user's video into S3 and make that object "public-read", so it can immediately play in the browser.

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

No branches or pull requests

1 participant