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.