+ Start a Discussion
Henry AkpalaHenry Akpala 

How to pass a Delimiter and a Prefix in a GET request to Amazon S3

I am using Apex REST to call Amazon S3.  I am trying to get the list of the content of a specific folder in a bucket.  The GET request returns all the content of the bucket but I would like to get just the content of a specific bucket.  I think I need to pass a Delimiter and/or a Prefix but not sure how to do this.  I tried this below but doesn't seem to have any effect.
     
       req.setHeader('Prefix','VHUB/INBOX/') ;       
       req.setHeader('Delimiter','/');                        
 
public AWS_Keys__c awsKeySet;
public String bucketname1 = BUCKETNAME; 
public String key1=KEY;
public String secret1=SECRET;
          
// public void readGetFromVirtualS3(){   
         //this is needed for the PUT operation and the generation of the signature.  I use my local time zone.        
        String formattedDateString1 = Datetime.now().format('EEE, dd MMM yyyy HH:mm:ss z','America/Los_Angeles');   
        
        String method1 = 'GET';
        HttpRequest req = new HttpRequest();
        Http http = new Http();
        String filename1 =''; //'500/' ; 
        //String filename = 'VHUB/INBOX/' ;

        req.setEndpoint('https://'+ bucketname1 +'.s3.amazonaws.com' +'/'+ filename1);   
     /********   req.setHeader('Prefix','VHUB/INBOX/') ;		********/
   /********	req.setHeader('Content-Type', ''); 			
  	 		req.setHeader('Delimiter','/');				********/

        req.setMethod(method1);
        req.setHeader('Date', formattedDateString1);
        req.setHeader('Authorization',createAuthHeader(method1,filename1,formattedDateString1,bucketname1,key1,secret1));
         //Execute web service call
            try {
                HTTPResponse res = http.send(req);
                System.debug('MYDEBUG: ' + ' RESPONSE STRING: ' + res.toString());
                System.debug('MYDEBUG: ' + ' RESPONSE STATUS: '+ res.getStatus());
                System.debug('MYDEBUG: ' + ' STATUS_CODE:'+ res.getStatusCode());
                System.debug('MYDEBUG: ' + ' GET_BODY:'+ res.getBody());
                XmlStreamReader reader = res.getXmlStreamReader();
                System.debug(reader.getLocalName());
                
            } catch(System.CalloutException e) {
                system.debug('MYDEBUG: AWS Service Callout Exception on ' + 'ERROR: ' + e.getMessage());
            }
 //   }

  	 //create authorization header for Amazon S3 REST API
    public string createAuthHeader(String method,String filename,String formattedDateString,String bucket,String key,String secret){
        string auth;
        String stringToSign = method+'\n\n\n'+formattedDateString+'\n/'+bucket +'/'+filename;
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
        String sig = EncodingUtil.base64Encode(mac);
        auth = 'AWS' + ' ' + key + ':' + sig;
        return auth;
    }

The code returns all the folders and files in the bucket but I need to pass a parameter to only return the content of one folder.


 
Best Answer chosen by Henry Akpala
pconpcon
According to the documentation [1] the prefix and the delimiter are both suppose to be GET parameters, not header values.  This means you will need to append them as GET params to your URL.
 
Set<String> getParams = new Set<String> {
    'prefix=' + EncodingUtil.urlEncode('VHUB/INBOX/','UTF-8'),
    'delimiter=' + EncodingUtil.urlEncode('/', 'UTF-8')
};

String endpointBase = 'https://' + bucketname1 + '.s3.amazonaws.com/' + filename1;
String params = String.join(getParams, '&');

req.setEndpoint(endpointBase + '?' + params);

You will want to make sure to use the EncodingUtil.urlEncode prior to appending it to your endpoint url.

[1] http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html

All Answers

pconpcon
According to the documentation [1] the prefix and the delimiter are both suppose to be GET parameters, not header values.  This means you will need to append them as GET params to your URL.
 
Set<String> getParams = new Set<String> {
    'prefix=' + EncodingUtil.urlEncode('VHUB/INBOX/','UTF-8'),
    'delimiter=' + EncodingUtil.urlEncode('/', 'UTF-8')
};

String endpointBase = 'https://' + bucketname1 + '.s3.amazonaws.com/' + filename1;
String params = String.join(getParams, '&');

req.setEndpoint(endpointBase + '?' + params);

You will want to make sure to use the EncodingUtil.urlEncode prior to appending it to your endpoint url.

[1] http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGET.html
This was selected as the best answer
Henry AkpalaHenry Akpala
Thanks a lot.  Works like a charm
S3-LinkS3-Link
S3- Link is FREE App for Salesforce - Amazon Connector. Its also available on Appexchange. 

 1. Create Amazon S3 file for standard Salesforce attachment through
    trigger.
 2. Upload attachments on Amazon S3 and create reference in Salesforc to
    access those attachments
 3. Attach file related to any Salesforce object on Amazon.
 4. Unlimited free storage.
 5. Auto backup Event logs / inbound email attachments.
 6. Server Side Encryption: AES-256
 7. No file size limit for upload.
 8. File access control capabiliy.
 9. Track file downloads by users.
 10. File exlorer capability.

https://appexchange.salesforce.com/listingDetail?listingId=a0N3000000CW1OXEA1

Here is our email address. Let us know if you have any query.
support@neiloncloud.com

Thanks.
Karthik ManoKarthik Mano
Henry, Do you have a working sample of the code. I am trying to do the same to get all the objects from a specific folder from a bucket in S3. I always get the 403 Forbidden. PUT Object works good for me.

Thanks
Karthik