[SalesForce] Uploading from SF to AWS S3: upload works but all files are empty

I've made a file uploader from SF to AWS S3. Everything works as expected except for the fact that the file itself in S3, despite its size reading correctly, is empty:

public pageReference uploadFromFilesystem() {
    try {
        String fileBody = EncodingUtil.base64Encode(fileBlob);
        String now = Datetime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');

        System.debug('fileBody: ' + fileBody);

        HttpRequest req = new HttpRequest();
        req.setMethod(method);
        req.setEndpoint('https://' + bucketname + '.' + host + '/' +
            lead.Id + '/' + fileName);
        req.setHeader('Host', bucketname + '.' + host);
        req.setHeader('Content-Length', String.valueOf(fileBody.length()));
        req.setHeader('Content-Encoding', 'UTF-8');
        req.setHeader('Content-type', contentType);
        req.setHeader('Connection', 'keep-alive');
        req.setHeader('Date', now);
        req.setHeader('ACL', 'public-read');
        req.setBody(fileBody);

        String stringToSign = 'PUT\n\n' + contentType + '\n' + now + '\n' +
            '/' + bucketname + '/' + lead.Id + '/' + fileName;

        String encodedStringToSign = EncodingUtil.urlEncode(stringToSign, 'UTF-8');
        Blob mac = Crypto.generateMac('HMACSHA1', Blob.valueOf(stringToSign), Blob.valueOf(secret));
        String signed = EncodingUtil.base64Encode(mac);
        String authHeader = 'AWS' + ' ' + key + ':' + signed;
        req.setHeader('Authorization', authHeader);
        String decoded = EncodingUtil.urlDecode(encodedStringToSign , 'UTF-8');

        Http http = new Http();
        HTTPResponse res = http.send(req);
        System.debug('RESPONSE STRING: ' + res.toString());
        System.debug('RESPONSE STATUS: ' + res.getStatus());
        System.debug('STATUS_CODE: ' + res.getStatusCode());

        uploadObjectErrorMsg = null;
    } catch(Exception e) {
        System.debug('EXCEPTION: ' + e);
        uploadObjectErrorMsg = e.getMessage();
    }
    return null;
}

Debugging the fileBody returns a string, the files all appear in S3 as the right size, but either trying to preview them in Amazon or download them locally they are empty. What am I missing?

Here's the debug:

debug

And all the files in S3:

s3

And yet, when they're viewed or downloaded, they're "empty" or corrupted or similar, so it seems like an encoding issue. What am I missing? fileBlob comes from an <apex:inputFile> field.

Best Answer

You should not be setting Content-Encoding. UTF8 is for text, so it'll mess up some bytes in the upload process. Just leave that header out.

Edit: I see you decided to base-64 encode your fileBody. Don't do that, either. Just use req.setBodyAsBlob(fileBlob); instead.