Search code examples
amazon-web-servicesamazon-s3aws-sdk-js

Why does AWS JS SDK S3::Bucket#upload use unexpected Access-Control-Request-Method


I am seeing a strange problem where CORS requests (OPTIONS, specifically) to AWS S3 intermittently fail (~1/3 tries) with a 403 response code and the following error message:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://s3.amazonaws.com/some-bucket/some-video.mp4?uploads. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

The S3 CORS config should be permissive enough to allow for the use case I'm after (uploading an mp4) and other asset uploads (images, CSS, JS, etc.) to this same bucket, using the same function (which wraps AWS-SDK's Bucket#upload) work without fail.

Does anyone know why this would be happening? Can I prevent the SDK from using the unexpected Access-Control-Request-Method header?

UPDATE: after some more digging, I've come to the conclusion that this is happening because the OPTIONS request is sometimes being sent with an Access-Control-Request-Method: POST header instead of the default Access-Control-Request-Method: PUT. I do not have POST whitelisted in my CORS config and this would seem to be why those requests are failing.

Does anyone know why this would be happening? Is this a bug in the SDK? An oversight in the documentation? The documentation* implies a PUT will be issued, so I'd argue that the two are in conflict.

*From the documentation for this method:

Bucket — (String) Name of the bucket to which the PUT operation was initiated.

Key — (String) Object key for which the PUT operation was initiated.


Solution

  • This is an error in the documentation. The description of upload() contradicts this by implication.

    upload(params = {}, [options], [callback]) ⇒ AWS.S3.ManagedUpload

    Uploads an arbitrarily sized buffer, blob, or stream, using intelligent concurrent handling of parts if the payload is large enough.

    The only way S3 handles "parts" of a file upload is via the multipart API, and POST /...?uploads is a subresource request in the S3 REST API that initiates a multipart upload, which is mandatory on objects > 5 GB and recommended when the file size exceeds some number of MB. Multipart is also the only mechanism by which partially failed uploads can be retried without re-sending the entire file.

    Your CORS policy should allow POST.