Monday 9 November 2020

Pre-signed Post Uploads to S3 fails intermittently in Safari when uploading file via multipart/form-data content type

I've been experiencing pre-signed post upload failures to S3 that I cannot reproduce. The failure happens mostly via Mobile Safari browsers, but my error log has shown that the error occurs on Desktop Safari as well.

When the error occurs, I get the following error back from S3:

<Error>
    <Code>EntityTooSmall</Code>
    <Message>Your proposed upload is smaller than the minimum allowed size</Message> 
    <ProposedSize>0</ProposedSize>
    <MinSizeAllowed>26254270</MinSizeAllowed>
    <...></...>
</error>

The code I'm using to presign the S3 Url and subsequently upload the file works fine in other browsers, e.g. Chrome, Firefox, Brave.

Once I have the pre-signed URL, I'm creating a new FormData object and using the pre-signed fields to construct an object which I then send to S3 from the browser via Axios.

My guess is the error has something to do with Safari incorrectly appending the file data to the FormData object, but since it happens randomly, I can't figure out why.

Safari correctly reads the size of the file, as this value is used to create the presigned url, but when it comes time to attach it to the form data object and upload, something must be going wrong.

The following code is what I use with success on other browsers, and what works most of the time on safari:


<script>

import axios from 'axios'
import getPresignUrl from './presign'

// Vue Component

export default {
  name: 'FinickyOnSafariUploader'
  data: () => ({
    // ...
  }),
  methods: {
    presignAndUpload (file) {
      const fileData = {
        fileName: file.name,
        fileType: file.type,
        fileSize: file.size
      }

      getPresignUrl(fileData)
        .then((resp) => {
          const presignFields = resp.data.presignFields  // Object
          const presignUrl = resp.data.presignUrl  // String
          return this.uploadToS3(file, presignUrl, presignUrl, presignFields)
        })
    },
    uploadToS3 (file, presignUrl, presignFields) {
      formPostData = new FormData()

      // Add Presigned Post Fields for Auth
      for (const field in presignFields) {
        formPostData.append(field, presignFields[field])
      }

      // Add Content-Type & File Data
      formPostData.append('Content-Type', file.type)
      formPostData.append('file', file)

      const req = {
        url: presignUrl,
        method: 'POST',
        headers: { 'Content-Type': 'multipart/form-data' },
        data: formPostData
      }

      return axios.request(req)
    }
  }
}


</script>


Does anyone have any guidance/insight as to why this happens sporadically and only on Safari?



from Pre-signed Post Uploads to S3 fails intermittently in Safari when uploading file via multipart/form-data content type

No comments:

Post a Comment