[SalesForce] Showing attachments from SOAP Responses

Has anyone worked on multi-part SOAP responses with attachments within apex?

Scenario:

We're trying to retrieve a pdf document from an external site using webservice requests then show the pdf file within Salesforce. Problem is, it's returning a multi-part response with attachment on it in which salesforce doesn't support at the moment(https://help.salesforce.com/apex/HTViewSolution?urlname=System-CalloutException-Web-service-callout-failed-Failed-to-get-next-element&language=en_US).

VF Page

<apex:page controller="GetDocumentvRetrieve" sidebar="false" showHeader="false" contentType="application/pdf">
    <script>
        window.location.href = "data:application/pdf;charset=utf-8;base64,{!data}";
    </script>
</apex:page>

Class

public class GetDocumentvRetrieve {

        public string data {get; set;}


        public GetDocumentvRetrieve () {
            data = retrieveDocument('########');
        }
        public String retrieveDocument(String docID) {
            String strBody ='<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">';
            strBody +=' <soap:Header>';
            strBody +='     <wsse:Security xmlns:wsse=" " xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1">';
            strBody +='         <wsse:UsernameToken wsu:Id="UsernameToken-277573">';
            strBody +='             <wsse:Username>#######</wsse:Username>';
            strBody +='             <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">############</wsse:Password>';
            strBody +='         </wsse:UsernameToken>';
            strBody +='     </wsse:Security>';
            strBody +=' </soap:Header>';
            strBody +=' <soap:Body>';
            strBody += '        <getDocument xmlns="http://www.datamail.co.nz/vretrieve/webservices/">';
            strBody += '            <id>###########</id>';
            strBody += '        </getDocument>';
            strBody +=' </soap:Body>';
            strBody +='</soap:Envelope>';

            HttpRequest request = new HttpRequest();
            request.setEndpoint('https://vr2.datamail.co.nz/vretrieve/webservices/viewdocumentservice');
            request.setMethod('POST');
            request.setHeader('Content-Type', 'application/pdf');
            request.setHeader('SOAPAction', '"" ');
            request.setTimeout(100000);
            request.setBody(strBody);

            Http http = new Http(); 
            system.debug('request===>' +  request.getBody());
            HttpResponse response = http.send(request);
            system.debug('res =======>'+response );
            integer statusCode = response.getStatusCode();
            String statusMessage = response.getStatus();
            String message = response.getBody();

            system.debug('statusCode =======>'+statusCode);
            system.debug('statusMessage =======>'+statusMessage);
            system.debug('message =======>'+message);


            Blob contentData =  response.getBodyAsBlob();
            return EncodingUtil.base64Encode(contentData);
        }

    }

Here's the raw response http://pastebin.com/9mEVV0dg

Already checked the following posts, but it doesn't involve parsing through multi-part SOAP responses:
Display PDF with Visualforce

PDF from Httpresponse

Any workaround on how can I extract the attachment from the SOAP response?

Best Answer

I know it's way too late but i thought I would post our solution incase anyone else has the same issue.

Coincidentally we were having the exact same problem with datamail.co.nz/vretrieve haha.

Basically the problem is that you can't use response.getBody() as it will convert the whole response to a string and corrupt the binary attachment, and you can't just use response.getBodyAsBlob() because the text component of the response will also corrupt the file.

There should be a header in the response called 'Content-Type', which also should have a parameter called 'boundary', this is used to separate the different parts of the response.

What we did was pull out the boundary value and convert it to hex, then convert the whole response to hex and use the boundary to split out the attachment, then convert the separated file back to a blob.

For us, there was still some header information in the section containing the file however that didn't seem to affect the file when it was converted back to a pdf so we left it there, others may need to split that out too.

here's our code,

//read the response header to get the boundary string
String header = res.getHeader('Content-Type');
String boundary = header.split('boundary="')[1].split('"')[0];

//convert the boundary string to Hex so we can split the attachment from the rest of the response
String boundaryHex = EncodingUtil.convertToHex(Blob.valueOf('--'+boundary));

//convert the entire response to Hex
String responseHex = EncodingUtil.convertToHex(res.getBodyAsBlob());

//use the boundaryHex to split out the attachment then convert the file back to a blob
Blob pdf = EncodingUtil.convertFromHex( responseHex.split(boundaryHex)[2] );

//return the blob
return pdf;
Related Topic