By flightblog
Has anyone successfully used AWS S3 iOS SDK to upload to Spaces? I’m using AWSS3 v2.6.10.
In my appDelegate/didFinishLaunchingWithOptions:
let endpoint = AWSEndpoint(urlString: "https://digitaloceanspaces.com")
let credentialsProvider = AWSStaticCredentialsProvider(accessKey:"SPACES_API_ACCESS_KEY", secretKey: "SPACES_API_SECRET_KEY")
let defaultServiceConfiguration = AWSServiceConfiguration(region: AWSRegionType.USEast1, endpoint: endpoint, credentialsProvider: credentialsProvider)
defaultServiceConfiguration?.maxRetryCount = 5
defaultServiceConfiguration?.timeoutIntervalForRequest = 30
AWSServiceManager.default().defaultServiceConfiguration = defaultServiceConfiguration
My AWSS3TransferManagerUploadRequest:
let fileManager = FileManager.default
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("\(newImage).jpeg")
let imageData = UIImageJPEGRepresentation(newImage, 1.0)
fileManager.createFile(atPath: path as String, contents: imageData, attributes: nil)
let fileURL = URL(fileURLWithPath: path)
guard let uploadRequest = AWSS3TransferManagerUploadRequest() else { return }
uploadRequest.bucket = "MY_BUCKET"
uploadRequest.key = "test_key"
uploadRequest.body = fileURL
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest).continueOnSuccessWith { task -> 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: \(String(describing: uploadRequest.key)) Error: \(error)")
}
} else {
print("Error uploading: \(String(describing: uploadRequest.key)) Error: \(error)")
}
return nil
}
let uploadOutput = task.result
print("Upload complete for: \(String(describing: uploadRequest.key))")
print("uploadOutput: \(String(describing: uploadOutput))")
return nil
}
The above configuration times out with the following Request:
content-length:1357634
host:digitaloceanspaces.com
user-agent:aws-sdk-iOS/2.6.10 iOS/11.2 en_US transfer-manager
x-amz-date:20180114T162711Z
content-length;host;user-agent;x-amz-date
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855]
2018-01-14 11:27:11:149 TapRoom[42942:4077877] payload
2018-01-14 11:27:11:149 TapRoom[42942:4077877] AWS4 String to Sign: [AWS4-HMAC-SHA256
20180114T162711Z
20180114/us-east-1/s3/aws4_request
089305745d9bee6d3a57e98683d522f5bf5f8e3b4e9cc6533f021d002d7c6c62]
Authorization = "AWS4-HMAC-SHA256 Credential=SPACES_API_ACCESS_KEY/20180114/us-east-1/s3/aws4_request, SignedHeaders=content-length;host;user-agent;x-amz-date, Signature=d16f6791edd66a6937c50fdc0c8e12bb5e9bc45b1c4b81df4f7413fdd049343e";
"Content-Length" = 1357634;
Host = "digitaloceanspaces.com";
"User-Agent" = "aws-sdk-iOS/2.6.10 iOS/11.2 en_US transfer-manager";
"X-Amz-Date" = 20180114T162743Z;
And error message:
2018-01-14 11:27:43:490 TapRoom[42942:4078252] Session task failed with error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={NSUnderlyingError=0x7b0c000aafa0 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 "(null)" UserInfo={_kCFStreamErrorCodeKey=-2102, _kCFStreamErrorDomainKey=4}}, NSErrorFailingURLStringKey=https://www.digitalocean.com/, NSErrorFailingURLKey=https://www.digitalocean.com/, _kCFStreamErrorDomainKey=4, _kCFStreamErrorCodeKey=-2102, NSLocalizedDescription=The request timed out.}
I’ve tried changing my endpoint from https://digitaloceanspaces.com tohttps://nyc3.digitaloceanspaces.com and I get the following response:
<?xml version="1.0" encoding="UTF-8"?><Error><Code>SignatureDoesNotMatch</Code><RequestId>tx0000000000000000732e6-005a5b86c6-f7aef-nyc3a</RequestId><HostId>f7aef-nyc3a-nyc</HostId></Error>
Any ideas what I’m doing wrong?
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Use the TransferUtility class also you will want to set the endpoint to https://nyc3.digitaloceanspaces.com
NSData *dataToUpload = // The data to upload.
AWSS3TransferUtilityUploadExpression *expression = [AWSS3TransferUtilityUploadExpression new];
expression.uploadProgress = ^(AWSS3TransferUtilityTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
dispatch_async(dispatch_get_main_queue(), ^{
// Do something e.g. Update a progress bar.
});
};
AWSS3TransferUtilityUploadCompletionHandlerBlock completionHandler = ^(AWSS3TransferUtilityUploadTask *task, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
// Do something e.g. Alert a user for transfer completion.
// On failed uploads, `error` contains the error object.
});
};
AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
[[transferUtility uploadFile:fileURL
bucket:@"YourBucketName"
key:@"YourObjectKeyName"
contentType:@"text/plain"
expression:expression
completionHander:completionHandler] continueWithBlock:^id(AWSTask *task) {
if (task.error) {
NSLog(@"Error: %@", task.error);
}
if (task.exception) {
NSLog(@"Exception: %@", task.exception);
}
if (task.result) {
AWSS3TransferUtilityUploadTask *uploadTask = task.result;
// Do something with uploadTask.
}
return nil;
}];
is it work ? i try my ios it does not work
my AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
registerForPushNotifications()
NetworkignService.shared.checkInternetStatus()
UIApplication.shared.statusBarStyle = .lightContent
FBSDKApplicationDelegate.sharedInstance().application(application,
didFinishLaunchingWithOptions: launchOptions)
LocationManager.determineCurrentLocation()
let endpoint = AWSEndpoint(urlString: "https://sgp1.digitaloceanspaces.com")
let credentialsProvider = AWSStaticCredentialsProvider(
accessKey:"XN6NS55KIE5OD6PNYC7R",
secretKey: "LpHUnBsx6MtFsHn59jmUGKt9KCUjqU6+jPY8jG150iE/gBB8"
)
let defaultServiceConfiguration = AWSServiceConfiguration(
region: AWSRegionType.APSoutheast1,
endpoint: endpoint,
credentialsProvider: credentialsProvider
)
defaultServiceConfiguration?.maxRetryCount = 5
defaultServiceConfiguration?.timeoutIntervalForRequest = 10
AWSServiceManager.default().defaultServiceConfiguration = defaultServiceConfiguration
return true
}
@IBAction func uploadImageToAWS(_ sender: Any) {
if profileImage.image == nil {
// Do something to wake up user :)
} else {
let image = profileImage.image!
let fileManager = FileManager.default
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("test3.jpeg")
let imageData = UIImageJPEGRepresentation(image, 0)
fileManager.createFile(atPath: path as String, contents: imageData, attributes: nil)
let fileUrl = NSURL(fileURLWithPath: path)
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = "adda"
uploadRequest?.key = "test"
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = (fileUrl as URL?)!
uploadRequest?.serverSideEncryption = AWSS3ServerSideEncryption.awsKms
uploadRequest?.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
// print("totalBytesSent",totalBytesSent)
// print("totalBytesExpectedToSend",totalBytesExpectedToSend)
// self.amountUploaded = totalBytesSent // To show the updating data status in label.
// self.fileSize = totalBytesExpectedToSend
})
}
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if task.error != nil {
// Error.
print("error", task.error?.localizedDescription)
} else {
// Do something with your result.
print("No error Upload Done")
}
return nil
})
}
Eorror
listObjects failed: [Error Domain=com.amazonaws.AWSServiceErrorDomain Code=3 "(null)" UserInfo={Code=SignatureDoesNotMatch, HostId=1af6c2-sgp1a-sgp, RequestId=tx00000000000000036e4b9-005b596ddb-1af6c2-sgp1a}]
error Optional("The operation couldn’t be completed. (com.amazonaws.AWSServiceErrorDomain error 3.)")```
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Name>addaapi</Name>
<Prefix/>
<Marker/>
<MaxKeys>1000</MaxKeys>
<IsTruncated>false</IsTruncated>
</ListBucketResult>
Fixed the issue!
It had to do with the way the SDK was generating the signatures. I’ve submitted the fix.
https://github.com/aws-amplify/aws-sdk-ios/pull/1114
Here is the following Swift code that will work when the PR is merged. Note: the region doesn’t matter as long as you provide the correct Spaces endpoint and set the service parameter as AWSServiceType.S3.
func setup(accessKey: String, secretKey: String) {
let accessKey = ""
let secretKey = ""
let url = URL(string: "https://nyc3.digitaloceanspaces.com")!
let endpoint = AWSEndpoint(region: AWSRegionType.USEast1, service: AWSServiceType.S3, url: url)
let credProvider = AWSStaticCredentialsProvider(accessKey: accessKey, secretKey: secretKey)
let serviceConfig = AWSServiceConfiguration(region: .USEast1, endpoint: endpoint,
credentialsProvider: credProvider)!
AWSServiceManager.default()!.defaultServiceConfiguration = serviceConfig
}
func upload(key: String, url: URL, contentType: String) {
let utility = AWSS3TransferUtility.default()
let expression = AWSS3TransferUtilityMultiPartUploadExpression()
let completion: AWSS3TransferUtilityMultiPartUploadCompletionHandlerBlock = { (task, error) in
if let error = error {
print(error)
} else {
print("Successfully uploaded!")
}
}
utility.uploadUsingMultiPart(fileURL: url, key: key, contentType: contentType, expression: expression, completionHandler: completion)
}
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.