10
votes

I am new to AWS and using it for iOS app.

I'm trying to upload images from my iOS app to bucket named, "img.haraj.com.sa". When I upload any image, they aren't shown in bucket. But when I change the target to bucket named "haraj", they are uploaded and shown in the bucket.

Here's the policy:

{
  "Statement": [
    {
      "Sid": "**********hidden**********",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": [
       "arn:aws:s3:::haraj/*"
      ]
    }
  ]
}

I modify this for changing the target bucket. I also created other buckets with name "img1.haraj.com.sa" and tried uploading images and unfortunately they also failed.

It seems there is some problem with having bucket names with dots (.) and without dots. Names of buckets without dots works with iOS app and the names with dots doesn't work. I'm not sure though. But I'm facing this problem. I don't receive any error response in app code.

Here's part of my iOS app implementation:

- (void)postAdButtonPushed:(id)sender
{
    DLog(@"Post Ad")

    AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithAccessKey:AWS_ACCESS_KEY_ID withSecretKey:AWS_SECRET_KEY];
    s3Client.timeout = 240;

    NSString *bucketName = [NSString stringWithFormat:@"img.haraj.com.sa"];
    NSString *imageName = [NSString stringWithFormat:@"testimage.jpg"];

    S3PutObjectRequest *objReq = [[S3PutObjectRequest alloc] initWithKey:imageName inBucket:bucketName];
    objReq.contentType = @"image/jpeg";

    UIImage *testImageToUpload = [self.imagesToUpload objectAtIndex:0];

    NSData *imageData = UIImageJPEGRepresentation(testImageToUpload, 0.8);
    objReq.data = imageData;
    objReq.delegate = self;

    objReq.contentLength = [imageData length];

    [s3Client putObject:objReq];
}

- (void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response
{
    DLog(@"response: %@", response.description)
}

- (void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error
{
    DLog(@"Req failed: %@", error.description)
}

I also created a thread on Amazon Forum at: AWS Upload image to Bucket iOS app

Any help would be appreciated. Thank you!

3
Thanks @Eric. That fix is for the Java version. I'm using AWS SDK in iOS. And I have integrated the framework (not source code of sdk). Lets hope some easy solution comes out, otherwise I will have to work around something with the source code then. :\ - Abdullah Umer

3 Answers

6
votes

I've posted a response to your forum thread here, but to summarize, I believe you've bumped up against a bug in the SDK and will need to explicitly set the S3 endpoint where your bucket is located.

6
votes

Just wanted to weigh in, here is a code snippet that i got working

// #import <AWSS3/AWSS3.h>
// #import <AWSRuntime/AWSRuntime.h>
// then you should implement <AmazonServiceRequestDelegate>
// import those in your .h file and
// add the awss3 and awsruntime framework from the client
// download from Amazon
// myFace is the UIImage object

    AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithAccessKey:@"Key_Goes_here" withSecretKey:@"Secret_Goes_Here"];

    NSString *imageName = [NSString stringWithFormat:@"%@.png", @"cpa"];

    S3PutObjectRequest *objReq = [[S3PutObjectRequest alloc] initWithKey:imageName inBucket:@"bucket_name"];
    objReq.contentType = @"image/png";
    objReq.cannedACL   = [S3CannedACL publicRead];
    objReq.data = UIImagePNGRepresentation(myFace);
    objReq.delegate = self;

    [s3Client putObject:objReq];

here are the delegate methods:

-(void)request:(AmazonServiceRequest *)request didSendData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten totalBytesExpectedToWrite:(long long)totalBytesExpectedToWrite {
}

-(void)request:(AmazonServiceRequest *)request didReceiveResponse:(NSURLResponse *)response {
    NSLog(@"response! %@", response);
}

-(void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response {

}

-(void)request:(AmazonServiceRequest *)request didReceiveData:(NSData *)data {
    NSLog(@"data?");
}

-(void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error {
    [self showAlertMessage:[error.userInfo objectForKey:@"message"] withTitle:@"Upload Error"];
}
0
votes

If you don't want to give public access, you should also define a user in IAM, and put this code in your bucket policy:

{
  "Version": "2012-10-17",
  "Id": "S3AccessPolicy",
  "Statement": [
    {
      "Sid": "GiveGetPutAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:user/YOUR_USER"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::YOUR_BUCKET/*"
    }
  ]
}