How to generate AWS S3 pre-signed URL request without knowing Content-Type?

13,386

Solution 1

I just ran into this problem, and just got it working. Replace your Upload.http code with the following:

var reader = new FileReader();
var xhr = new XMLHttpRequest();

xhr.open("PUT", $scope.signedUrl);
reader.onload = function(evt) {
  xhr.send(evt.target.result);
};
reader.readAsArrayBuffer($scope.file);

The problem ends up being that S3 is looking for a specific Content-Type (binary/octet-stream), which it infers when you omit the Content-Type header.

Solution 2

The value from the Content-Type header is a mandatory component of the signature. It isn't possible to pre-sign a PUT URL without knowing the value that will be sent.

A POST upload is more flexible, since you can allow any Content-Type in the signed policy.

Share:
13,386
c4k
Author by

c4k

Lead Developer at @holbertonschool, formerly @Veepee_Fr, @car360inc + 🏃🏽‍♂️ + 🚴🏼‍♂️

Updated on July 20, 2022

Comments

  • c4k
    c4k almost 2 years

    I am generating in server side a pre-signed URL request with the following parameters for GeneratePresignedUrlRequest : bucket, key, expiration = in 1 hour and method = PUT.

    In my Angular app, I am uploading the file using ng-file-upload

    Upload.http({
        url: $scope.signedUrl,
        method: "PUT",
        headers : {
            'Content-Type': $scope.file.type
        },
        data: $scope.file
    });
    

    The problem is that I always have a 403 response unless I set the type of the file in GeneratePresignedUrlRequest.contentType.

    The problem is that I can't predict in advance what type of file the user will choose (image/png, image/jpeg, text/plain...).

    How can I generate a pre-signed url that accept all kinds of content-type ? I tried setting it to null, it keeps sending 403 errors.

    Thanks.

  • c4k
    c4k over 8 years
    What do you mean by POST upload ? Get the pre-signed URL with POST, no content-type and POST instead of PUT in my Angular app ?
  • Michael - sqlbot
    Michael - sqlbot over 8 years
    It doesn't particularly matter how you get the authorization from your back-end, but S3 has a very different interface for form-based uploads using a POST from the browser that seems to be a better match for what you are doing, at least in this one sense: docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.h‌​tml
  • Michael - sqlbot
    Michael - sqlbot over 8 years
    Actually, you might start here: docs.aws.amazon.com/AmazonS3/latest/API/…
  • c4k
    c4k over 8 years
    Thanks but I can't use HTML POST form. The form needs to be independant.
  • Michael - sqlbot
    Michael - sqlbot over 8 years
    You technicallyvdon't have to "use" (build, render, or display) a form, you only have to submit the structure of a form back to S3.
  • okigan
    okigan over 4 years
    This does not address core part of the question: cannot predict file type in advance