Unable to play mp4 video uploaded to AWS S3 using pre-signed URL
Asked Answered
Y

4

7

I'm uploading a mp4 video to AWS S3 using a pre-signed URL, the upload succeeds but when I try to download the video from S3 and play it in a media player (VLC or quickTime), it doesn't play!.

Generated pre-signed URL works fine with mp3 but the same problem as above also occurs for WAV and FLAC.

Code to generate the pre-signed url:

public String getPreSignedS3Url( final String userId, final String fileName )
    {
        Date expiration = new Date();
        long expTimeMillis = expiration.getTime();
        expTimeMillis += urlExpiry;
        expiration.setTime(expTimeMillis);

        String objectKey = StringUtils.getObjectKey( userId, fileName );

        GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(
                recordingBucketName, objectKey)
                .withMethod(HttpMethod.PUT)
                .withExpiration(expiration);

        URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);

        return url.toString();

    }

After I get the pre-signed URL from the method above, I make a HTTP PUT request from Postman with the multipart/form-data in the request body like this:

-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
  -F 'file=@/Users/john/Downloads/sampleDemo.mp4'

pre-signed url looks like this:

https://meeting-recording.s3.eu-west-2.amazonaws.com/331902257/sampleDemo.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=20190720T125751Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3599&X-Amz-Credential=AKIAZDSMLZ3VDKNXQUXH%2F20190720%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Signature=dfb8054f0738e07e925e9880e4a8e5ebba0a1bd3c84a3ec78913239f65221992

I tried to set the content type to mp4 in the getPreSignedS3Url() method using generatePresignedUrlRequest.setContentType( "video/mp4" ); and add Content-Type : "video/mp4" in the HTTP PUT request header but it didn't work and it fails with an error Signature doesn't match.

I'm using S3 as my personal back-up hard-drive, I expect to upload video and audio files to S3 using a pre-signed URL, download them at some point in the future and be able to play them, but I'm unable to play them after I have downloaded them.

Does anyone know what could be causing this?

Yodle answered 20/7, 2019 at 13:17 Comment(0)
C
5

PUT requests to S3 don't support multipart/form-data. The request body needs to contain nothing but the binary object data. If you download your existing file from S3 and open it with a text editor, you'll find that S3 has preserved the multipart form structure inside the file, instead of interpreting it as a wrapper for the actual payload.

Clementina answered 20/7, 2019 at 19:28 Comment(4)
Thanks, I will try that, but why does multipart/form-data work for mp3?Yodle
I can't think of an explanation of why that could work, unless the mp3 player is excessively generous when interpreting the file. Use a tool like md5sum or sha256sum to calculate the checksum of the file before you upload the file and after you download the file and you'll find that uploading this way is in fact corrupting the file. A simpler test, you should also find that the downloaded file is actually larger than the original. If the size and checksums match, then you aren't actually sending multipart/form-data, but that seems unlikely.Clementina
YOU ARE MY HERO. It all makes sense now. THANK YOU.Verecund
so what is the solution?Burgomaster
B
2

To add to the above answer (for future readers), I was using formData() like below to send the put request. Adding the file directly to the payload worked for me.

Don't do this:

var bodyData = new FormData();
bodyData.append('file', video);

axios.put(res?.data?.uploadURL, bodyData, {

Instead, do this:

axios.put(res?.data?.uploadURL, video, {
Bick answered 26/9, 2021 at 16:46 Comment(0)
K
0

1.generatePresignedUrlRequest.setContentType("video/mp4");

2.for your http request, add header, Content-Type:video/mp4 and set your content to binary format

Kwakiutl answered 24/8, 2023 at 8:45 Comment(0)
Z
0

For people struggling with this, don't convert the video or image file to multipart format, instead upload it directly as a File. Make sure the Content-Type on presigned url and frontend request must be similar. For example if its a video it should be video/mp4 on both ends for this to work.

Zipporah answered 28/5, 2024 at 13:49 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.