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 Answer 1

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);

You must log in to answer this question.

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