1

I faced issues when tried to send binary data from Salesforce to external web services. To start with, I tried to send binary data from Salesforce to itself.

I am trying to read binary data from valid WordX ContentVersion file and upload it again to Salesforce as a Document.

When I use method Blob b = res0.getBodyAsBlob(); and then concatenate it with other form data through b.toString() method, I receive an error

{
  "column": "1",
  "compileProblem": "",
  "compiled": "true",
  "exceptionMessage": "System.StringException: BLOB is not a valid UTF-8 string",
  "exceptionStackTrace": "Class.BlobNotValidUTF8.<init>: line 43, column 1\nAnonymousBlock: line 2, column 1\nAnonymousBlock: line 2, column 1",
  "line": "43",
  "success": "false"
}

enter image description here The complete code is below.

public with sharing class BlobNotValidUTF8 {
    public BlobNotValidUTF8() {
        ContentVersion cv = [SELECT Title, FileExtension, Description FROM ContentVersion WHERE Id = '0681x000001p65tAAA' ];
        Http h = new Http();
        HttpRequest r0 = new HttpRequest();
        r0.setMethod('GET');
        r0.setEndpoint('https://velocity-computing-3399-dev-ed.cs100.my.salesforce.com/services/data/v47.0/sobjects/ContentVersion/0681x000001p65tAAA/VersionData');
        r0.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        HTTPResponse res0 = h.send(r0);
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res0.getStatus());
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res0.getStatusCode());
        System.debug(LoggingLevel.ERROR, '@@@ : keys' + res0.getHeaderKeys());
        for (String key: res0.getHeaderKeys()) {
            System.debug(LoggingLevel.ERROR, '@@@ : key: ' + key + ' header = ' + res0.getHeader(key));
        }
        System.debug(LoggingLevel.ERROR, '@@@ : ' + res0.getBody());

        Blob b = res0.getBodyAsBlob();        
         
        HttpRequest r = new HttpRequest();
        r.setMethod('POST');
        r.setEndpoint('https://velocity-computing-3399-dev-ed.cs100.my.salesforce.com/services/data/v50.0/sobjects/Document/');
        r.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        r.setHeader('Content-Type', 'multipart/form-data; charset="UTF-8"; boundary=\"boundary_string\"');
        r.setBody('--boundary_string\r\n'+
            'Content-Disposition: form-data; name="entity_document";\r\n'+
            'Content-Type: application/json\r\n'+
            '\r\n'+
            '{  \r\n'+
            '    "Description" : "' + cv.Description + '",\r\n'+
            '    "Keywords" : "",\r\n'+
            '    "FolderId" : "' + UserInfo.getUserId() + '",\r\n'+
            '    "Name" : "' + cv.Title + '",\r\n'+
            '    "Type" : "' + cv.FileExtension + '"\r\n'+
            '}\r\n'+
            '\r\n'+
            '--boundary_string\r\n'+
            'Content-Type: application/word\r\n'+
            'Content-Transfer-Encoding: binary\r\n'+
            'Content-Disposition: form-data; name="Body"; filename="' + cv.Title + '.' + cv.FileExtension + '"\r\n'+
            '\r\n' +
            //res0.getBody()+
            b.toString()+
            '\r\n'+
            '--boundary_string--\r\n'
        );
        HTTPResponse res = h.send(r);
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res.getStatus());
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res.getStatusCode());
        System.debug(LoggingLevel.ERROR, '@@@ : keys' + res.getHeaderKeys());
        for (String key: res.getHeaderKeys()) {
            System.debug(LoggingLevel.ERROR, '@@@ : key: ' + key + ' header = ' + res.getHeader(key));
        }
        System.debug(LoggingLevel.ERROR, '@@@ : ' + res.getBody());
        
        insert new Log__c(Name = r.getEndpoint().left(51) + ' request ' + DateTime.now(), Line__c = r.getBody().left(131072));
        insert new Log__c(Name = r.getEndpoint().left(51) + ' response ' + DateTime.now(), Line__c = res.getBody().left(131072));

        insert new Log__c(Name = r.getEndpoint().left(51) + ' request ' + DateTime.now(), Line__c = r0.getBody().left(131072));
        insert new Log__c(Name = r.getEndpoint().left(51) + ' response ' + DateTime.now(), Line__c = res0.getBody().left(131072));

    }
}

When I use method res0.getBody(), it doesn't file, but the uploaded file is unreadable and Word application says that it is corrupted

public with sharing class BlobNotValidUTF8 {
    public BlobNotValidUTF8() {
        ContentVersion cv = [SELECT Title, FileExtension, Description FROM ContentVersion WHERE Id = '0681x000001p65tAAA' ];
        Http h = new Http();
        HttpRequest r0 = new HttpRequest();
        r0.setMethod('GET');
        r0.setEndpoint('https://velocity-computing-3399-dev-ed.cs100.my.salesforce.com/services/data/v47.0/sobjects/ContentVersion/0681x000001p65tAAA/VersionData');
        r0.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        HTTPResponse res0 = h.send(r0);
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res0.getStatus());
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res0.getStatusCode());
        System.debug(LoggingLevel.ERROR, '@@@ : keys' + res0.getHeaderKeys());
        for (String key: res0.getHeaderKeys()) {
            System.debug(LoggingLevel.ERROR, '@@@ : key: ' + key + ' header = ' + res0.getHeader(key));
        }
        System.debug(LoggingLevel.ERROR, '@@@ : ' + res0.getBody());

        HttpRequest r = new HttpRequest();
        r.setMethod('POST');
        r.setEndpoint('https://velocity-computing-3399-dev-ed.cs100.my.salesforce.com/services/data/v50.0/sobjects/Document/');
        r.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        r.setHeader('Content-Type', 'multipart/form-data; charset="UTF-8"; boundary=\"boundary_string\"');
        r.setBody('--boundary_string\r\n'+
            'Content-Disposition: form-data; name="entity_document";\r\n'+
            'Content-Type: application/json\r\n'+
            '\r\n'+
            '{  \r\n'+
            '    "Description" : "' + cv.Description + '",\r\n'+
            '    "Keywords" : "",\r\n'+
            '    "FolderId" : "' + UserInfo.getUserId() + '",\r\n'+
            '    "Name" : "' + cv.Title + '",\r\n'+
            '    "Type" : "' + cv.FileExtension + '"\r\n'+
            '}\r\n'+
            '\r\n'+
            '--boundary_string\r\n'+
            'Content-Type: application/word\r\n'+
            'Content-Transfer-Encoding: binary\r\n'+
            'Content-Disposition: form-data; name="Body"; filename="' + cv.Title + '.' + cv.FileExtension + '"\r\n'+
            '\r\n' +
            res0.getBody()+
            '\r\n'+
            '--boundary_string--\r\n'
        );
        HTTPResponse res = h.send(r);
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res.getStatus());
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res.getStatusCode());
        System.debug(LoggingLevel.ERROR, '@@@ : keys' + res.getHeaderKeys());
        for (String key: res.getHeaderKeys()) {
            System.debug(LoggingLevel.ERROR, '@@@ : key: ' + key + ' header = ' + res.getHeader(key));
        }
        System.debug(LoggingLevel.ERROR, '@@@ : ' + res.getBody());
        
        insert new Log__c(Name = r.getEndpoint().left(51) + ' request ' + DateTime.now(), Line__c = r.getBody().left(131072));
        insert new Log__c(Name = r.getEndpoint().left(51) + ' response ' + DateTime.now(), Line__c = res.getBody().left(131072));

        insert new Log__c(Name = r.getEndpoint().left(51) + ' request ' + DateTime.now(), Line__c = r0.getBody().left(131072));
        insert new Log__c(Name = r.getEndpoint().left(51) + ' response ' + DateTime.now(), Line__c = res0.getBody().left(131072));

    }
}

enter image description here

How can send binary data in a way it will not become corrupted?

1

It is possible to encode binary data in Base64 format, concatenate it this the other strings and then decode it to Blob again

public with sharing class FileUploadMock {
    public FileUploadMock() {
        ContentVersion cv = [SELECT Title, FileExtension, Description FROM ContentVersion WHERE Id = '0681x000001p65tAAA' ];
        Http h = new Http();
        HttpRequest r0 = new HttpRequest();
        r0.setMethod('GET');
        r0.setEndpoint('https://velocity-computing-3399-dev-ed.cs100.my.salesforce.com/services/data/v47.0/sobjects/ContentVersion/0681x000001p65tAAA/VersionData');
        r0.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        HTTPResponse res0 = h.send(r0);
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res0.getStatus());
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res0.getStatusCode());
        System.debug(LoggingLevel.ERROR, '@@@ : keys' + res0.getHeaderKeys());
        for (String key: res0.getHeaderKeys()) {
            System.debug(LoggingLevel.ERROR, '@@@ : key: ' + key + ' header = ' + res0.getHeader(key));
        }
        System.debug(LoggingLevel.ERROR, '@@@ : ' + res0.getBody());

        Blob b = res0.getBodyAsBlob();
        String s = EncodingUtil.base64Encode(b);
         
        HttpRequest r = new HttpRequest();
        r.setMethod('POST');
        r.setEndpoint('https://velocity-computing-3399-dev-ed.cs100.my.salesforce.com/services/data/v50.0/sobjects/Document/');
        r.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
        r.setHeader('Content-Type', 'multipart/form-data; charset="UTF-8"; boundary=\"boundary_string\"');
        r.setBodyAsBlob(EncodingUtil.base64Decode(EncodingUtil.base64Encode(Blob.valueOf('--boundary_string\r\n'+
            'Content-Disposition: form-data; name="entity_document";\r\n'+
            'Content-Type: application/json\r\n'+
            '\r\n'+
            '{  \r\n'+
            '    "Description" : "' + cv.Description + '",\r\n'+
            '    "Keywords" : "",\r\n'+
            '    "FolderId" : "' + UserInfo.getUserId() + '",\r\n'+
            '    "Name" : "' + cv.Title + '",\r\n'+
            '    "Type" : "' + cv.FileExtension + '"\r\n'+
            '}\r\n'+
            '\r\n'+
            '--boundary_string\r\n'+
            'Content-Type: application/word\r\n'+
            'Content-Transfer-Encoding: binary\r\n'+
            'Content-Disposition: form-data; name="Body"; filename="' + cv.Title + '.' + cv.FileExtension + '"\r\n'+
            '\r\n')) + s +
            EncodingUtil.base64Encode(Blob.valueOf('\r\n'+
            '--boundary_string--\r\n')))
        );
        HTTPResponse res = h.send(r);
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res.getStatus());
        System.debug(LoggingLevel.ERROR, '@@@ : status' + res.getStatusCode());
        System.debug(LoggingLevel.ERROR, '@@@ : keys' + res.getHeaderKeys());
        for (String key: res.getHeaderKeys()) {
            System.debug(LoggingLevel.ERROR, '@@@ : key: ' + key + ' header = ' + res.getHeader(key));
        }
        System.debug(LoggingLevel.ERROR, '@@@ : ' + res.getBody());
        
        insert new Log__c(Name = r.getEndpoint().left(51) + ' request ' + DateTime.now(), Line__c = r.getBody().left(131072));
        insert new Log__c(Name = r.getEndpoint().left(51) + ' response ' + DateTime.now(), Line__c = res.getBody().left(131072));

        insert new Log__c(Name = r.getEndpoint().left(51) + ' request ' + DateTime.now(), Line__c = r0.getBody().left(131072));
        insert new Log__c(Name = r.getEndpoint().left(51) + ' response ' + DateTime.now(), Line__c = res0.getBody().left(131072));
    }
}

I was inspired by this blog post to get this done

However, HttpRequest.getBody() doesn't convert correctly the binary sequence, because the following assert fails

    Blob b = EncodingUtil.base64Decode('CAgIAPhQh1EA');
    HttpRequest r = new HttpRequest();
    r.setBodyAsBlob(b);
    System.debug(LoggingLevel.ERROR, '@@@ b.toString() : ' + r.getBody());
    String s = EncodingUtil.base64Encode(b);
    String sb = EncodingUtil.base64Encode(Blob.valueOf(''+r.getBody()));
    System.debug(LoggingLevel.ERROR, '@@@ s : ' + s);
    System.debug(LoggingLevel.ERROR, '@@@ sb : ' + sb);
    System.assertEquals(s, sb);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.