Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to consume MTOM SOAP web service in node.js?

I need to download or process a file from a soap based web service in node.js. can someone suggest me on how to handle this in node.js

I tried with 'node-soap' or 'soap' NPM module. it worked for normal soap web service. But, not for binary steam or MTOM based SOAP web service

like image 363
Veer R Avatar asked Jan 31 '26 11:01

Veer R


2 Answers

I want to try to answer this... It's quite interesting that 2 years and 2 months later I can not figure it out how to easily solve the same problem.

I'm trying to get the attachment from a response like:

...

headers: { 'cache-control': 'no-cache="set-cookie"', 'content-type': 'multipart/related;boundary="----=_Part_61_425861994.1525782562904";type="application/xop+xml";start="";start-info="text/xml"',

...

body: '------=_Part_61_425861994.1525782562904\r\nContent-Type: application/xop+xml; charset=utf-8; type="text/xml"\r\nContent-Transfer-Encoding: 8bit\r\nContent-ID: \r\n\r\n....\r\n------=_Part_61_425861994.1525782562904\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\nContent-ID: \r\n\r\n�PNG\r\n\u001a\n\u0000\u0000\u0000\rIHDR\u0000\u0000\u0002,\u0000\u0000\u0005�\b\u0006\u0........binary....

I tried ws.js but no solution.

My solution:

var request = require("request");
var bsplit = require('buffer-split')

// it will extract "----=_Part_61_425861994.1525782562904" from the response
function getBoundaryFromResponse(response) {
    var contentType = response.headers['content-type']
    if (contentType && contentType.indexOf('boundary=') != -1 ) {
        return contentType.split(';')[1].replace('boundary=','').slice(1, -1)
    }
    return null
}


function splitBufferWithPattern(binaryData, boundary) {
    var b = new Buffer(binaryData),
        delim = new Buffer(boundary),
        result = bsplit(b, delim);
    return result
}


var options = {
    method: 'POST',
    url: 'http://bla.blabal.../file',
    gzip: true,
    headers: {
        SOAPAction: 'downloadFile',
        'Content-Type': 'text/xml;charset=UTF-8'
    },
    body: '<soapenv: ... xml request of the file ... elope>'
};

var data = [];
var buffer = null;
var filename = "test.png"

request(options, function (error, response, body) {
        if (error) throw new Error(error);

        if (filename && buffer) {
            console.log("filename: " + filename)
            console.log(buffer.toString('base64'))
            // after this, we can save the file from base64 ...
        }
    })
    .on('data', function (chunk) {
        data.push(chunk)

    })
    .on('end', function () {
        var onlyPayload = splitBufferWithPattern(Buffer.concat(data), '\r\n\r\n') // this will get from PNG
        buffer = onlyPayload[2]
        buffer = splitBufferWithPattern(buffer, '\r\n-')[0]
        console.log('Downloaded.');

    })

I am not sure it will works in most of the cases. It looks like unstable code to my eyes and so I'm looking for something better.

like image 92
mrmcmeg Avatar answered Feb 03 '26 01:02

mrmcmeg


Use ws.js

Here is how to fetch the file attachments:

const ws = require('ws.js')
const { Http, Mtom } = ws

var handlers =  [ new Mtom(), new Http()];
var request = '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' +
                '<s:Body>' +
                  '<EchoFiles xmlns="http://tempuri.org/">' +
                      '<File1 />' +
                  '</EchoFiles>' +
                '</s:Body>' +
              '</s:Envelope>'

var ctx = { request: request
          , contentType: "application/soap+xml"
          , url: "http://localhost:7171/Service/mtom"
          , action: "http://tempuri.org/IService/EchoFiles"
          }

ws.send(handlers, ctx, function(ctx) {
  //read an attachment from the soap response
  var file = ws.getAttachment(ctx, "response", "//*[local-name(.)='File1']")
  // work with the file
  fs.writeFileSync("result.jpg", file)
})

Two limitations:

  • No basic auth provided out-of-box, patch required https://github.com/yaronn/ws.js/pull/40
  • If the file name is an url, you need to apply another patch at mtom.js. Replace:

.

xpath = "//*[@href='cid:" + encodeURIComponent(id) + "']//parent::*"

with:

xpath = "//*[@href='cid:" + id + "']//parent::*"
like image 30
Juan Ignacio Barisich Avatar answered Feb 03 '26 01:02

Juan Ignacio Barisich