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
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.
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
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.
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.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With