9

I'm trying to upload a file to Amazon S3 using a PUT request. I generate my signed urls using boto. If I do

curl --upload-file test.jpg $SIGNED_URL

then the upload works fine (so there's not an issue with the signed urls). I've also set the referer to various things with curl and it still works, so I don't think there is a CORS issue either. I'm trying to upload a file blob using javascript as follows:

var xmlhttp = new XMLHttpRequest();    
xmlhttp.open("PUT", $SIGNED_URL);
xmlhttp.setRequestHeader('Content-Type', blob.type);
xmlhttp.send(blob);

This always returns a 403 Forbidden error. I'm finding it surprisingly difficult to find any information online about PUTing data to S3 from javascript. I realize now that it's more common to POST form data, but is there any way to modify what I'm doing to also work?

Edit: I've found the body of the error now:

> <Error><Code>SignatureDoesNotMatch</Code> <Message>The request
> signature we calculated does not match the signature you provided.
> Check your key and signing method.</Message>

So it appears that the signing is the issue. Again, the same exact url works when I use it with curl (even after it's failed in javascript).

2 Answers 2

8

The issue was the 'Content-Header' which curl was not sending. Chrome sends this header regardless of whether you add it explicitly. To get a signed url that will work with this header you need to pass headers={'Content-Type':type} to generate_url in boto.

Sign up to request clarification or add additional context in comments.

Comments

0

For me the problem was I was not setting the content-type while generating presigned URL, so added that while generating presigned url

java.util.Date expiration = new java.util.Date();
        long msec = expiration.getTime();
        msec +=  60 * 60 * 1000; // 1 hour.
        expiration.setTime(msec);

        GeneratePresignedUrlRequest generatePresignedUrlRequest =
                new GeneratePresignedUrlRequest("bucket_name", "someRandomKey");
        generatePresignedUrlRequest.setMethod(HttpMethod.PUT); // Default.
        generatePresignedUrlRequest.setExpiration(expiration);
        generatePresignedUrlRequest.setContentType("application/octet-stream");

        URL s = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
        System.out.println("Secure PUT URL is "+s);

And here is the curl

curl -v -X PUT \
  'generated_secure_url' \ 
  -H 'Content-Type:application/octet-stream' \
  --data-binary '@swiggy-hackathon.jpg'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.