Is the AWS S3 iOS SDK compatible with Spaces?

January 14, 2018 825 views
Object Storage FreeBSD

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?

2 Answers

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>
Have another answer? Share your knowledge.