function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Mayukhman Pathak 23Mayukhman Pathak 23 

Amazon S3 Integration

I am trying to PUT a json file from Salesforce to Amazon S3 Bucket using Rest Callout. But I am getting an exception as :
System.CalloutException: Unexpected end of file from server
Can anyone suggest me the issue.

My Code :
public class ProductAmazon_RestClass {
    public void ProductAmazon_RestMethod(string folderName){
        
        string binaryString = ProductAmazonIntegration.ProductAmazonIntegration();
        String key='******************************';
        String secret='******************************';
        String formattedDateString= Datetime.now().formatGMT('EEE,   dd MMM yyyy HH:mm:ss z');
        String bucketname = 'myBucketName';
        String host = 's3-website-us-east-1.amazonaws.com';
        String method = 'PUT';
        String filename = 'Product/Product.json';
        
        //Request starts
        HttpRequest req = new HttpRequest();
        req.setMethod(method);
        req.setEndpoint('https://' + bucketname + '.' + host + '/' + bucketname + '/' + filename);
        req.setHeader('Host', bucketname + '.' + host);
        req.setTimeout(120000);
        req.setHeader('Content-Length', string.valueOf(binaryString.length()));
        req.setHeader('Content-Encoding', 'UTF-8');
        req.setHeader('Content-Type', 'application/json');        
        req.setHeader('Connection','keep-alive');
        req.setHeader('Date', formattedDateString);
        req.setHeader('ACL', 'public-read-write');
        req.setBody(binaryString);     
        String stringToSign = 'PUT\n\n' + 'application/json' + '\n' + '/' + bucketname + '/' + filename;
        String encodedStringToSign = EncodingUtil.urlEncode(stringToSign,'UTF-8'); 
        String signed = createSignature(stringToSign,secret);
        String authHeader = 'AWS' + ' ' + key + ':' + signed;
        req.setHeader('Authorization',authHeader);        
        Http http = new Http();
        try {
            //Execute web service call
            HTTPResponse res = http.send(req);
            System.debug('RESPONSE STRING: ' + res.toString());
            System.debug('RESPONSE STATUS: '+res.getStatus());
            System.debug('STATUS_CODE: '+res.getStatusCode());
            
        } catch(System.CalloutException ae) {
            system.debug('AWS Service Callout Exception: ' + ae);
        }
        
    }
    
    public string createSignature(string canonicalBuffer,String secret){
        string sig;
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(canonicalBuffer),blob.valueof(secret));
        sig = EncodingUtil.base64Encode(mac);        
        return sig;
        
    }
}

 
Best Answer chosen by Mayukhman Pathak 23
NagendraNagendra (Salesforce Developers) 
Hi Pathak,

This is not correct.
String host = ‘s3-website-us-east-1.amazonaws.com’;
That's a website endpoint, so it will not speak HTTPS and it will not accept PUT requests.

If your bucket is in us-east-1, set this to s3.us-east-1.amazonaws.com. (Formerly, you would have needed to use s3.amazonaws.com or s3-external-1.amazonaws.com, and these are still valid but us-east-1 now also supports the standard convention for REST endpoints.)

This is also not correct.

req.setEndpoint(‘https://’ + bucketname + ‘.’ + host + ‘/’ + bucketname + ‘/’ + filename);

Remove bucketname + ‘/’ + before filename.

Hope this helps.

Kindly mark this as solved if the information was helpful.

Thanks,
Nagendra
 

All Answers

NagendraNagendra (Salesforce Developers) 
Hi Pathak,

This is not correct.
String host = ‘s3-website-us-east-1.amazonaws.com’;
That's a website endpoint, so it will not speak HTTPS and it will not accept PUT requests.

If your bucket is in us-east-1, set this to s3.us-east-1.amazonaws.com. (Formerly, you would have needed to use s3.amazonaws.com or s3-external-1.amazonaws.com, and these are still valid but us-east-1 now also supports the standard convention for REST endpoints.)

This is also not correct.

req.setEndpoint(‘https://’ + bucketname + ‘.’ + host + ‘/’ + bucketname + ‘/’ + filename);

Remove bucketname + ‘/’ + before filename.

Hope this helps.

Kindly mark this as solved if the information was helpful.

Thanks,
Nagendra
 
This was selected as the best answer
Mayukhman Pathak 23Mayukhman Pathak 23
@Nagendra thanks for the help. Your suggestion works but I am getting reponse as:
System.HttpResponse[Status=Forbidden, StatusCode=403]