6

I have a pre-signed upload URL from AWS S3 to upload a video file to. Testing on Postman the video is successfully uploaded. However i get a 403 returned when implementing in retrofit. I cannot use multipart upload for this task.

service call :

@Headers("Content-Type: video/mp4")
    @PUT
    fun uploadTaskAWS(@Url awsUrl: String, @Body filePart: RequestBody): Call<ResponseBody>

upload:

            val file = File(task.file_path)
            val requestFile = RequestBody.create(MediaType.parse("video/mp4"), file)
            val response = awsTaskUploadService.uploadTaskAWS(task.upload_url, requestFile)

I have ensured the URL is correct. The content type header is added too, postman screenshot attached. Getting 403 Forbidden Error

screenshot of postman

I have found this related question however i'm still getting a 403. Upload a file to AWS S3 pre-signed URL using Retrofit2

Any suggestions?

nt95
  • 455
  • 1
  • 6
  • 21

3 Answers3

7

solution was to include multipart and expect Single response not Call :

  @Multipart
    @PUT
    fun uploadAsset(
        @Header(CONTENT_TYPE) contentType: String,
        @Url uploadUrl: String,
        @Part file: MultipartBody.Part
    ): Single<ResponseBody>

where contentType is passed in

val requestFile = RequestBody.create(MediaType.parse(contentType), file)
val body = MultipartBody.Part.createFormData(mediaType, task.file_name, requestFile)
assetService.uploadAsset(contentType, task.upload_url, body)
nt95
  • 455
  • 1
  • 6
  • 21
1

403 error means the server knows who you are but do not have the authority to perform the desired action.

If the pre-signed URL is correctly generated, you should be able to upload without any authentication.

You can check if postman is by default adding any AWS Authentication to request

Also you need to explicitly set the protocol version while signing requests if uploading to a region that uses only version 4.

Nikhil Sahu
  • 2,463
  • 2
  • 32
  • 48
0

I tried many times with retrofit but no success, finally I can do it using HttpURLConnection

 class UploadImageUsingPreSignedUrl(
    var bitmap: Bitmap?,
    var signedURL: String,
    var imageUploadCallback: ImageUploadCallback
) : AsyncTask<Void?, Void?, Int>() {
    override fun doInBackground(vararg p0: Void?): Int {
        var respCode = -1
        try {
            val url = URL(signedURL)
            val connection = url.openConnection() as HttpURLConnection
            connection.requestMethod = "PUT"
            connection.doOutput = true
            connection.setRequestProperty("Content-Type", "image/png") // your content type
            val outputStream = connection.outputStream
            bitmap?.compress(Bitmap.CompressFormat.PNG, 70, outputStream)
            outputStream.close()
            respCode = connection.responseCode
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return respCode
    }

    override fun onPostExecute(responseCode: Int) {
        super.onPostExecute(responseCode)
        imageUploadCallback.imageUpload(responseCode == 200)
    }
}
Rajesh Satvara
  • 3,842
  • 2
  • 30
  • 50