Skip to content

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

Description

@peppies

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.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions