0

I am attempting to download a file from SharePoint through their Rest API, and then upload that file to my S3 Bucket. I can "successfully" download the file and upload to S3. The issue is when I then go to my bucket and look at the file it's corrupted.

My code:

public static void uploadFile() {
        AccessTokenResponse accessToken = getAccessToken();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('<Sharepoint path>/_api/Web/GetFileByServerRelativePath(decodedurl=\'/sites/<channelname>/Shared%20Documents/General/TestFile.docx\')//OpenBinaryStream()');
        req.setMethod('GET');
        req.setHeader('Accept', 'application/json;odata=verbose');
        req.setHeader('Authorization', 'Bearer ' + accessToken.access_token);
        Http h = new Http();
        HTTPResponse res = h.send(req);
        uploadToAWS(res.getBody());
}

public static void uploadToAWS(String body) {
       Blob bodyBlob = Blob.valueOf(body);
        String attachmentBody = EncodingUtil.base64Encode(bodyBlob);
        String formattedDateString = Datetime.now().formatGMT('EEE, dd MMM yyyy HH:mm:ss z');
        String key = '<key>';
        String secret = '<secret>';
        String bucketname = '<bucket name>';
        String host = 's3.us-east-1.amazonaws.com';
        String method = 'PUT';
        String filename = 'TestFile.docx';

        HttpRequest req = new HttpRequest();
        req.setMethod(method);
        req.setEndpoint('https://' + bucketname + '.' + host + '/' + filename);
        req.setHeader('Host', bucketname + '.' + host);
        req.setHeader('Content-Length', String.valueOf(attachmentBody.length()));
        req.setHeader('Content-Encoding', 'UTF-8');
        req.setHeader('Content-type', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document');
        req.setHeader('Connection', 'keep-alive');
        req.setHeader('Date', formattedDateString);
        req.setHeader('ACL', 'public-read-write');
        req.setBodyAsBlob(EncodingUtil.base64Decode(attachmentBody));

        String stringToSign = 'PUT\n\napplication/vnd.openxmlformats-officedocument.wordprocessingml.document\n' + formattedDateString + '\n' + '/' + bucketname + '/' + filename;
        String encodedStringToSign = EncodingUtil.urlEncode(stringToSign, 'UTF-8');
        Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(stringToSign),blob.valueof(secret));
        String signedKey  = EncodingUtil.base64Encode(mac);
        String authHeader = 'AWS' + ' ' + key + ':' + signedKey ;
        req.setHeader('Authorization', authHeader);

        Http http = new Http();
        HTTPResponse res = http.send(req);
}

I can go to my bucket in S3 and see that a file was uploaded by that name. When I download the file and try to open it though it says its corrupted. I'm not sure how to debug anymore.

I've tried with both a docx and a pdf, with the same corrupted result.

Any idea on why my file is corrupted, or either what I should be doing to fix it or how I can debug more to understand where things are failing?

4
  • 1
    Can you share the "corrupt" file link? Someone like me could look at it and fairly immediately tell you what's wrong.
    – sfdcfox
    Jun 2, 2022 at 22:16
  • @sfdcfox, that would be awesome! I can't paste the link here because the presigned url is too long. Is there an email or other way I can send you the link?
    – cmptrer
    Jun 2, 2022 at 22:37
  • My contact info is on my profile if you desire.
    – sfdcfox
    Jun 2, 2022 at 23:42
  • Found it! Sent you the link in a private message on twitter
    – cmptrer
    Jun 3, 2022 at 16:09

1 Answer 1

2

First, I took a look at the file in a Text editor, and it started off with PK. So far, so good. I then took a look at the file through a hex editor, and saw it started with 50 4b 03 04, which are the "magic bytes" for a ZIP file (DOCX is fundamentally a ZIP file). However, I then tried to verify the contents:

unzip -t TestFile.docx

And I got the following output:

Archive:  TestFile.docx

caution:  zipfile comment truncated
error [TestFile.docx]:  missing 3316400188 bytes in zipfile
  (attempting to process anyway)
error [TestFile.docx]:  attempt to seek before beginning of zipfile
  (please check that you have transferred or created the zipfile in the
  appropriate BINARY mode and that you have compiled UnZip properly)

In other words, some of the bytes got messed up. That's when I realized you used the wrong method in your Apex code:

    // ...
    uploadToAWS(res.getBody());
}
public static void uploadToAWS(String body) {

Here, you call getBody(), which returns a UTF-8 string. I'm kind of surprised you didn't get an invalid UTF-8 StringException, but this definitely changed some of the bytes. To fix it, get the body as a blob:

    // ...
    uploadToAWS(res.getBodyAsBlob());
}
public static void uploadToAWS(Blob body) {
1
  • Thank you so much!!! That fixed my issue!
    – cmptrer
    Jun 3, 2022 at 18:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .