Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upload jpg to S3: "The request body terminated unexpectedly"

I am facing an issue with S3. After 3h of troubleshooting (in the meantime i learnt about IAM roles & managed to create them) I am stuck trying to upload a fb profile picture to amazon S3.

My code:

if let imageData = NSData(contentsOf: NSURL(string: url) as! URL) {

                            let fileName = ProcessInfo.processInfo.globallyUniqueString + ".jpg"
                            let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
                            let image = UIImage(data: imageData as Data)
                            let imageData = UIImageJPEGRepresentation(image!, 1.0)!
                            do {
                                try imageData.write(to: fileURL! as URL)
                            } catch _ {
                                self.log.error("Could not write to file.")
                            }

                            let transferManager = AWSS3TransferManager.default()
                            let uploadRequest = AWSS3TransferManagerUploadRequest()
                            uploadRequest?.bucket = "app-files"
                            uploadRequest?.key = "user-data/" + awsId! + "_primary_profile_picture.jpg"
                            uploadRequest?.body = fileURL!

                            transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in

                                if let error = task.error as? NSError {
                                    if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
                                        switch code {
                                        case .cancelled, .paused:
                                            break
                                        default:
                                            print("Error uploading: \(uploadRequest?.key) Error: \(error)")
                                        }
                                    } else {
                                        print("Error uploading: \(uploadRequest?.key) Error: \(error)")
                                    }
                                    return nil
                                }

                                let uploadOutput = task.result
                                print("Upload complete for: \(uploadRequest?.key)")
                                return nil
                            })
                        }

**Problem** I am continuously getting a The request body terminated unexpectedly error from S3 which looks like this:

Error uploading: Optional("user-data/eu-west-1:xxxx-xxxx-xxxx-xxxx-xxxxxxxxxx_primary_profile_picture.jpg") 
Error: Error Domain=com.amazonaws.AWSS3ErrorDomain Code=0 "(null)" 
UserInfo={HostId=XXX, 
Message=The request body terminated unexpectedly, 
Code=IncompleteBody, 
RequestId=1485A0FFBD7819D7}

I am not sure what is going wrong, i have debugged, and fileName, fileURL, imageData seem to be fine

like image 351
Sebastian Flückiger Avatar asked Feb 21 '17 12:02

Sebastian Flückiger


People also ask

How to upload an image to Amazon S3 using API?

First Lets focus on uploading an image to S3. For uploading, you will have to configure the API Gateway service by creating a new API. As fig 2 shows, you can create an API by clicking on the Create API button. You will see a new tab opening as fig 3 shows. Fill the name and add a description and Create API.

How to upload image to S3 bucket using lambda proxy?

Bucket is the name of the S3 bucket you need to upload the image to. Key is the location in the bucket with the file name you want to upload to. You need to include the following code to prevent 502 Malformed Lambda proxy response error if you are using Lambda proxy integration in your API

How does a client upload files to S3?

The server relays this request to S3. S3 returns a new pre-signed URL to the server. The server returns the pre-signed URL to the client. The client displays an interface for the user allowing them to select a file for upload.

How do I upload a binary file to an S3 bucket?

To upload a binary file (image) to an S3 bucket using API Gateway, you must enable binary support for your API Gateway API. To allow your API to access your S3 bucket, you must create an AWS Identity and Access Management (IAM) role.


1 Answers

There is a bug with the 2.5.1 SDK, I explain a bit about it here.

Basically, the AWSSignature creates the wrong signature for the upload...

You have two ways to get around it:

1) Revert to using 2.5.0 by declaring all the pods you need explicitly like so: (Edit: I just noticed you can't do that because of the SWIFT problem. Try option 2 maybe)

pod 'AWSCore', '2.5.0'
pod 'AWSCognito', '2.5.0'
pod 'AWSLambda', '2.5.0'
pod 'AWSSNS', '2.5.0'
pod 'AWSS3', '2.5.0'

2) Change the code yourself to fix the problem until Amazon fix it. All you need to do is comment out lines 783-785 in the AWSCore/Authentication/AWSSignature.m file - you should get a message that the file is locked if you try, just unlock it.

if (self.endOfStream) {
    return NO;
}
like image 53
Emmanuel Merali Avatar answered Oct 28 '22 20:10

Emmanuel Merali