From 5b9911f29a5539bf38eb457616e16595d07fb605 Mon Sep 17 00:00:00 2001 From: davefej Date: Wed, 2 Jun 2021 16:05:00 +0200 Subject: [PATCH 01/11] Add support of MTOM attachments in response --- Readme.md | 3 ++- package-lock.json | 10 ++++++++++ package.json | 2 ++ src/client.ts | 4 +++- src/http.ts | 37 +++++++++++++++++++++++++++++++++-- src/types.ts | 9 +++++++++ src/utils.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 110 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 986c9a07b..5d180f777 100644 --- a/Readme.md +++ b/Readme.md @@ -151,8 +151,9 @@ The `options` argument allows you to customize the client with the following pro - namespaceArrayElements: provides support for nonstandard array semantics. If true, JSON arrays of the form `{list: [{elem: 1}, {elem: 2}]}` are marshalled into xml as `1 2`. If false, marshalls into ` 1 2 `. Default: `true`. - stream: allows using a stream to parse the XML SOAP response. Default: `false` - returnSaxStream: enables the library to return the sax stream, transferring to the end user the responsibility of parsing the XML. It can be used only in combination with *stream* argument set to `true`. Default: `false` +- mtomResponse: Treat response as multipart/related response with MTOM attachment. Reach attachments on the `lastReponseAttachments` property of SoapClient. Default: `false` -Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. +Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. ### soap.listen(*server*, *path*, *services*, *wsdl*, *callback*) - create a new SOAP server that listens on *path* and provides *services*. *server* can be a [http](https://nodejs.org/api/http.html) Server or [express](http://expressjs.com/) framework based server diff --git a/package-lock.json b/package-lock.json index a2b9de15a..17aa2690d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -736,6 +736,11 @@ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", "dev": true }, + "content-type-parser": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", + "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==" + }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -1397,6 +1402,11 @@ "samsam": "~1.1" } }, + "formidable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==" + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", diff --git a/package.json b/package.json index 6d54cdee5..2a5dca4b6 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ }, "author": "Vinay Pulim ", "dependencies": { + "content-type-parser": "^1.0.2", "debug": "^4.1.1", + "formidable": "^1.2.2", "get-stream": "^6.0.0", "httpntlm": "^1.5.2", "lodash": "^4.17.19", diff --git a/src/client.ts b/src/client.ts index e0095e675..190ea2a3b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -12,7 +12,7 @@ import * as _ from 'lodash'; import * as request from 'request'; import { v4 as uuidv4 } from 'uuid'; import { HttpClient, Request } from './http'; -import { IHeaders, IHttpClient, IOptions, ISecurity, SoapMethod, SoapMethodAsync } from './types'; +import { IHeaders, IHttpClient, IMTOMAttachments, IOptions, ISecurity, SoapMethod, SoapMethodAsync } from './types'; import { findPrefix } from './utils'; import { WSDL } from './wsdl'; import { IPort, OperationElement, ServiceElement } from './wsdl/elements'; @@ -67,6 +67,7 @@ export class Client extends EventEmitter { private returnSaxStream: boolean; private normalizeNames: boolean; private overridePromiseSuffix: string; + public lastReponseAttachments: IMTOMAttachments; constructor(wsdl: WSDL, endpoint?: string, options?: IOptions) { super(); @@ -543,6 +544,7 @@ export class Client extends EventEmitter { this.lastResponse = body; this.lastResponseHeaders = response && response.headers; this.lastElapsedTime = response && response.elapsedTime; + this.lastReponseAttachments = response && response.mtomResponseAttachments; this.emit('response', body, response, eid); if (err) { diff --git a/src/http.ts b/src/http.ts index efb4f2f8e..39ffdbca3 100644 --- a/src/http.ts +++ b/src/http.ts @@ -7,8 +7,10 @@ import * as debugBuilder from 'debug'; import * as httpNtlm from 'httpntlm'; import * as req from 'request'; import * as url from 'url'; +import * as contentTypeParser from "content-type-parser"; import {v4 as uuidv4} from 'uuid'; -import { IExOptions, IHeaders, IHttpClient, IOptions } from './types'; +import { IExOptions, IHeaders, IHttpClient, IMTOMAttachments, IOptions } from './types'; +import { parseMTOMResp } from './utils'; const debug = debugBuilder('node-soap'); const VERSION = require('../package.json').version; @@ -31,9 +33,11 @@ export type Request = req.Request; */ export class HttpClient implements IHttpClient { private _request: req.RequestAPI; + private options: IOptions; constructor(options?: IOptions) { options = options || {}; + this.options = options; this._request = options.request || req; } @@ -179,10 +183,39 @@ export class HttpClient implements IHttpClient { callback(null, res, res.body); }); } else { + const _this = this; + if(this.options.mtomResponse){ + options.encoding = null; + } req = this._request(options, (err, res, body) => { if (err) { return callback(err); } + if(_this.options.mtomResponse){ + const isMultipartResp = res.headers['content-type'].toLowerCase().indexOf("multipart/related") > -1; + if(isMultipartResp){ + let boundary; + const parsedContentType = contentTypeParser(res.headers['content-type']); + if(parsedContentType && parsedContentType.parameterList){ + boundary = ((parsedContentType.parameterList as Array).find(item => item.key === "boundary") || {}).value; + } + if(!boundary){ + callback(new Error("Missing boundary from content-type")); + } + const multipartResponse = parseMTOMResp(res.body, boundary); + + //first part is the soap response + const firstPart = multipartResponse.parts.shift(); + body = firstPart.body.toString('utf8'); + + //If clause only to pass previous tests without res + if(res){ + res.mtomResponseAttachments = multipartResponse; + } + }else{ + body = body.toString('utf8'); + } + } body = this.handleResponse(req, res, body); callback(null, res, body); }); @@ -195,4 +228,4 @@ export class HttpClient implements IHttpClient { const options = this.buildRequest(rurl, data, exheaders, exoptions); return this._request(options); } -} +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 670bc00ab..0e3742aba 100644 --- a/src/types.ts +++ b/src/types.ts @@ -132,6 +132,8 @@ export interface IOptions extends IWsdlBaseOptions { overridePromiseSuffix?: string; /** @internal */ WSDL_CACHE?; + /** handle MTOM soapAttachments in response */ + mtomResponse?: boolean; } export interface IOneWayOptions { @@ -151,3 +153,10 @@ export interface IServerOptions extends IWsdlBaseOptions { /** A boolean for controlling chunked transfer encoding in response. Some client (such as Windows 10's MDM enrollment SOAP client) is sensitive to transfer-encoding mode and can't accept chunked response. This option let user disable chunked transfer encoding for such a client. Default to true for backward compatibility. */ enableChunkedEncoding?: boolean; } + +export interface IMTOMAttachments{ + parts: Array<{ + body:Buffer, + headers:{[key: string]: string} + }> +} \ No newline at end of file diff --git a/src/utils.ts b/src/utils.ts index a6904d333..740ff5107 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,7 @@ import * as crypto from 'crypto'; +import { IMTOMAttachments } from './types'; +const MultipartParser = require('formidable/lib/multipart_parser.js').MultipartParser; export function passwordDigest(nonce: string, created: string, password: string): string { // digest = base64 ( sha1 ( nonce + created + password ) ) @@ -64,3 +66,50 @@ export function xmlEscape(obj) { return obj; } + +export function parseMTOMResp(payload: Buffer, boundary: string): IMTOMAttachments{ + const resp: IMTOMAttachments = { + parts:[] + }; + let headerName = "", headerValue = "", data: Buffer; + let partIndex = 0; + const parser = new MultipartParser(); + + + parser.initWithBoundary(boundary) + parser.onPartBegin = function() { + resp.parts[partIndex] = { + body:null, + headers:{} + }; + data = Buffer.from(''); + } + + parser.onHeaderField = function(b: Buffer, start: number, end: number) { + headerName = b.slice(start, end).toString() + }; + + parser.onHeaderValue = function(b: Buffer, start: number, end: number) { + headerValue = b.slice(start, end).toString() + } + + parser.onHeaderEnd = function() { + resp.parts[partIndex].headers[headerName.toLowerCase()] = headerValue; + } + + parser.onHeadersEnd = function() {} + + parser.onPartData = function(b: Buffer, start: number, end: number) { + data = Buffer.concat([data, b.slice(start, end)]); + } + + parser.onPartEnd = function() { + resp.parts[partIndex].body = data; + partIndex++; + } + + parser.onEnd = function() {} + parser.write(payload); + + return resp; +} \ No newline at end of file From d5b3d02521a4f192cc46dff923e933da4b260b1b Mon Sep 17 00:00:00 2001 From: davefej Date: Wed, 2 Jun 2021 23:58:19 +0200 Subject: [PATCH 02/11] create test for MTOM response attachment functionality --- test/request-response-samples-test.js | 36 ++++++++++--- .../attachmentParts.js | 7 +++ .../request.json | 3 ++ .../request.xml | 1 + .../response.json | 1 + .../response.xml | 22 ++++++++ .../responseHttpHeader.json | 3 ++ .../soap.wsdl | 52 +++++++++++++++++++ .../wsdl_options.json | 3 ++ 9 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl create mode 100644 test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json diff --git a/test/request-response-samples-test.js b/test/request-response-samples-test.js index d24e290ad..38146883a 100644 --- a/test/request-response-samples-test.js +++ b/test/request-response-samples-test.js @@ -57,6 +57,11 @@ var requestContext = { assert.equal(actualRequest, expectedRequest); if(!requestContext.responseToSend)return requestContext.doneHandler(); + if(requestContext.responseHttpHeaders){ + for(const headerKey in requestContext.responseHttpHeaders ){ + res.setHeader(headerKey,requestContext.responseHttpHeaders[headerKey]); + } + } res.end(requestContext.responseToSend); requestContext.expectedRequest = null; @@ -81,6 +86,8 @@ tests.forEach(function(test){ var options = path.resolve(test, 'options.json'); var wsdlOptionsFile = path.resolve(test, 'wsdl_options.json'); var wsdlJSOptionsFile = path.resolve(test, 'wsdl_options.js'); + var responseHttpHeaders = path.resolve(test,'responseHttpHeader.json'); + var attachmentParts = path.resolve(test, "attachmentParts.js"); var wsdlOptions = {}; //headerJSON is optional @@ -120,11 +127,20 @@ tests.forEach(function(test){ else if(fs.existsSync(wsdlJSOptionsFile)) wsdlOptions = require(wsdlJSOptionsFile); else wsdlOptions = {}; - generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, false); - generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, true); + + //responseHttpHeaders + if(fs.existsSync(responseHttpHeaders)) responseHttpHeaders = require(responseHttpHeaders) + else responseHttpHeaders = null; + + //attachmentParts + if(fs.existsSync(attachmentParts)) attachmentParts = require(attachmentParts) + else attachmentParts = null; + + generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, false); + generateTest(name, methodName, wsdl, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, true); }); -function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, usePromises){ +function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requestXML, requestJSON, responseXML, responseJSON, responseSoapHeaderJSON, wsdlOptions, options, responseHttpHeaders, attachmentParts, usePromises){ var methodCaller = cbCaller; if (usePromises) { @@ -137,6 +153,7 @@ function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requ if(requestXML) requestContext.expectedRequest = requestXML; if(responseXML) requestContext.responseToSend = responseXML; requestContext.doneHandler = done; + requestContext.responseHttpHeaders = responseHttpHeaders; soap.createClient(wsdlPath, wsdlOptions, function(err, client){ if (headerJSON) { for (var headerKey in headerJSON) { @@ -152,12 +169,12 @@ function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requ throw new Error('method ' + methodName + ' does not exists in wsdl specified in test wsdl: ' + wsdlPath); } - methodCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, done); + methodCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done); }, 'http://localhost:'+port+'/Message/Message.dll?Handler=Default'); }; } -function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, done){ +function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done){ client[methodName](requestJSON, function(err, json, body, soapHeader){ if(requestJSON){ if (err) { @@ -169,14 +186,18 @@ function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHea if(responseSoapHeaderJSON){ assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); } + if(client.lastReponseAttachments){ + assert.deepEqual(client.lastReponseAttachments.parts,attachmentParts) + } } } done(); }, options); } -function promiseCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, done){ +function promiseCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done){ client[methodName](requestJSON).then(function(responseArr){ + const respAttachments = client.lastReponseAttachments; var json = responseArr[0]; var body = responseArr[1]; var soapHeader = responseArr[2]; @@ -187,6 +208,9 @@ function promiseCaller(client, methodName, requestJSON, responseJSON, responseSo if(responseSoapHeaderJSON){ assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); } + if(client.lastReponseAttachments){ + assert.deepEqual(client.lastReponseAttachments.parts,attachmentParts) + } } }).catch(function(err) { if(requestJSON){ diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js b/test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js new file mode 100644 index 000000000..53924a64d --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/attachmentParts.js @@ -0,0 +1,7 @@ +module.exports = [{ + body:Buffer.from("...binary data..."), + headers:{ + "content-type": "image/tiff", + "content-transfer-encoding": "binary" + } +}]; \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json new file mode 100644 index 000000000..f87ce7528 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.json @@ -0,0 +1,3 @@ +{ + "param":"123" +} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml new file mode 100644 index 000000000..575506abc --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/request.xml @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json new file mode 100644 index 000000000..643d28ef9 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.json @@ -0,0 +1 @@ +{"attributes":{"soapenv:encodingStyle":"http://schemas.xmlsoap.org/soap/encoding/"},"attachment1":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:1186818862128"},"attachment2":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:536857424511"}} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml new file mode 100644 index 000000000..50daa98a5 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml @@ -0,0 +1,22 @@ +--MIME_boundary +Content-Type: text/xml; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + + + + + cid:1186818862128 + cid:536857424511 + + + + +--MIME_boundary +Content-Type: image/tiff +Content-Transfer-Encoding: binary + +...binary data... +--MIME_boundary-- + + diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json new file mode 100644 index 000000000..d6739f69a --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/responseHttpHeader.json @@ -0,0 +1,3 @@ +{ + "content-type":"Multipart/Related; boundary=MIME_boundary; type=text/xml;" +} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl b/test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl new file mode 100644 index 000000000..78e87dd5e --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/soap.wsdl @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSDL File for MTOMService + + + + + \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json new file mode 100644 index 000000000..8ea6f5581 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "mtomResponse":true +} \ No newline at end of file From 3a3e11d3f2d8ca8d2ddc6d6006fa994b372876b8 Mon Sep 17 00:00:00 2001 From: davefej Date: Wed, 2 Jun 2021 23:59:26 +0200 Subject: [PATCH 03/11] typo fix lastReponseAttachments --- Readme.md | 2 +- src/client.ts | 4 ++-- test/request-response-samples-test.js | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Readme.md b/Readme.md index 5d180f777..ca14a084b 100644 --- a/Readme.md +++ b/Readme.md @@ -151,7 +151,7 @@ The `options` argument allows you to customize the client with the following pro - namespaceArrayElements: provides support for nonstandard array semantics. If true, JSON arrays of the form `{list: [{elem: 1}, {elem: 2}]}` are marshalled into xml as `1 2`. If false, marshalls into ` 1 2 `. Default: `true`. - stream: allows using a stream to parse the XML SOAP response. Default: `false` - returnSaxStream: enables the library to return the sax stream, transferring to the end user the responsibility of parsing the XML. It can be used only in combination with *stream* argument set to `true`. Default: `false` -- mtomResponse: Treat response as multipart/related response with MTOM attachment. Reach attachments on the `lastReponseAttachments` property of SoapClient. Default: `false` +- mtomResponse: Treat response as multipart/related response with MTOM attachment. Reach attachments on the `lastResponseAttachments` property of SoapClient. Default: `false` Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. diff --git a/src/client.ts b/src/client.ts index 190ea2a3b..bd425fded 100644 --- a/src/client.ts +++ b/src/client.ts @@ -67,7 +67,7 @@ export class Client extends EventEmitter { private returnSaxStream: boolean; private normalizeNames: boolean; private overridePromiseSuffix: string; - public lastReponseAttachments: IMTOMAttachments; + public lastResponseAttachments: IMTOMAttachments; constructor(wsdl: WSDL, endpoint?: string, options?: IOptions) { super(); @@ -544,7 +544,7 @@ export class Client extends EventEmitter { this.lastResponse = body; this.lastResponseHeaders = response && response.headers; this.lastElapsedTime = response && response.elapsedTime; - this.lastReponseAttachments = response && response.mtomResponseAttachments; + this.lastResponseAttachments = response && response.mtomResponseAttachments; this.emit('response', body, response, eid); if (err) { diff --git a/test/request-response-samples-test.js b/test/request-response-samples-test.js index 38146883a..c16b6d988 100644 --- a/test/request-response-samples-test.js +++ b/test/request-response-samples-test.js @@ -186,8 +186,8 @@ function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHea if(responseSoapHeaderJSON){ assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); } - if(client.lastReponseAttachments){ - assert.deepEqual(client.lastReponseAttachments.parts,attachmentParts) + if(client.lastResponseAttachments){ + assert.deepEqual(client.lastResponseAttachments.parts,attachmentParts) } } } @@ -197,7 +197,7 @@ function cbCaller(client, methodName, requestJSON, responseJSON, responseSoapHea function promiseCaller(client, methodName, requestJSON, responseJSON, responseSoapHeaderJSON, options, attachmentParts, done){ client[methodName](requestJSON).then(function(responseArr){ - const respAttachments = client.lastReponseAttachments; + const respAttachments = client.lastResponseAttachments; var json = responseArr[0]; var body = responseArr[1]; var soapHeader = responseArr[2]; @@ -208,8 +208,8 @@ function promiseCaller(client, methodName, requestJSON, responseJSON, responseSo if(responseSoapHeaderJSON){ assert.equal(JSON.stringify(soapHeader), JSON.stringify(responseSoapHeaderJSON)); } - if(client.lastReponseAttachments){ - assert.deepEqual(client.lastReponseAttachments.parts,attachmentParts) + if(client.lastResponseAttachments){ + assert.deepEqual(client.lastResponseAttachments.parts,attachmentParts) } } }).catch(function(err) { From a7642f242ed4da94967b9425650c5e88cd4f33de Mon Sep 17 00:00:00 2001 From: davefej Date: Thu, 3 Jun 2021 10:43:38 +0200 Subject: [PATCH 04/11] fix tests without mocking httpres --- src/http.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http.ts b/src/http.ts index 39ffdbca3..b54178641 100644 --- a/src/http.ts +++ b/src/http.ts @@ -202,7 +202,7 @@ export class HttpClient implements IHttpClient { if(!boundary){ callback(new Error("Missing boundary from content-type")); } - const multipartResponse = parseMTOMResp(res.body, boundary); + const multipartResponse = parseMTOMResp(body, boundary); //first part is the soap response const firstPart = multipartResponse.parts.shift(); From 0fd45947ca3f7b6d0db83faa7ffd6acb049b9fcf Mon Sep 17 00:00:00 2001 From: davefej Date: Thu, 3 Jun 2021 11:45:05 +0200 Subject: [PATCH 05/11] lint and coverage fixes --- src/client.ts | 2 +- src/http.ts | 34 +++++++++++++++++----------------- src/types.ts | 10 +++++----- src/utils.ts | 47 ++++++++++++++++++++++++----------------------- 4 files changed, 47 insertions(+), 46 deletions(-) diff --git a/src/client.ts b/src/client.ts index bd425fded..80a6053c8 100644 --- a/src/client.ts +++ b/src/client.ts @@ -54,6 +54,7 @@ export class Client extends EventEmitter { public lastResponse?: any; public lastResponseHeaders?: IncomingHttpHeaders; public lastElapsedTime?: number; + public lastResponseAttachments: IMTOMAttachments; private wsdl: WSDL; private httpClient: IHttpClient; @@ -67,7 +68,6 @@ export class Client extends EventEmitter { private returnSaxStream: boolean; private normalizeNames: boolean; private overridePromiseSuffix: string; - public lastResponseAttachments: IMTOMAttachments; constructor(wsdl: WSDL, endpoint?: string, options?: IOptions) { super(); diff --git a/src/http.ts b/src/http.ts index b54178641..031319b83 100644 --- a/src/http.ts +++ b/src/http.ts @@ -3,11 +3,12 @@ * MIT Licensed */ +import * as contentTypeParser from 'content-type-parser'; import * as debugBuilder from 'debug'; import * as httpNtlm from 'httpntlm'; import * as req from 'request'; import * as url from 'url'; -import * as contentTypeParser from "content-type-parser"; + import {v4 as uuidv4} from 'uuid'; import { IExOptions, IHeaders, IHttpClient, IMTOMAttachments, IOptions } from './types'; import { parseMTOMResp } from './utils'; @@ -184,35 +185,34 @@ export class HttpClient implements IHttpClient { }); } else { const _this = this; - if(this.options.mtomResponse){ + if (this.options.mtomResponse) { options.encoding = null; } req = this._request(options, (err, res, body) => { if (err) { return callback(err); } - if(_this.options.mtomResponse){ - const isMultipartResp = res.headers['content-type'].toLowerCase().indexOf("multipart/related") > -1; - if(isMultipartResp){ + if (_this.options.mtomResponse) { + const isMultipartResp = res.headers['content-type'].toLowerCase().indexOf('multipart/related') > -1; + if (isMultipartResp) { let boundary; const parsedContentType = contentTypeParser(res.headers['content-type']); - if(parsedContentType && parsedContentType.parameterList){ - boundary = ((parsedContentType.parameterList as Array).find(item => item.key === "boundary") || {}).value; + if (parsedContentType && parsedContentType.parameterList) { + boundary = ((parsedContentType.parameterList as any[]).find( (item) => item.key === 'boundary') || {}).value; } - if(!boundary){ - callback(new Error("Missing boundary from content-type")); + if (!boundary) { + return callback(new Error('Missing boundary from content-type')); } const multipartResponse = parseMTOMResp(body, boundary); - //first part is the soap response + // first part is the soap response const firstPart = multipartResponse.parts.shift(); - body = firstPart.body.toString('utf8'); - - //If clause only to pass previous tests without res - if(res){ - res.mtomResponseAttachments = multipartResponse; + if (!firstPart || !firstPart.body) { + return callback(new Error('Cannot parse multipart response')); } - }else{ + body = firstPart.body.toString('utf8'); + res.mtomResponseAttachments = multipartResponse; + } else { body = body.toString('utf8'); } } @@ -228,4 +228,4 @@ export class HttpClient implements IHttpClient { const options = this.buildRequest(rurl, data, exheaders, exoptions); return this._request(options); } -} \ No newline at end of file +} diff --git a/src/types.ts b/src/types.ts index 0e3742aba..5bb1c98a9 100644 --- a/src/types.ts +++ b/src/types.ts @@ -154,9 +154,9 @@ export interface IServerOptions extends IWsdlBaseOptions { enableChunkedEncoding?: boolean; } -export interface IMTOMAttachments{ +export interface IMTOMAttachments { parts: Array<{ - body:Buffer, - headers:{[key: string]: string} - }> -} \ No newline at end of file + body: Buffer, + headers: {[key: string]: string}, + }>; +} diff --git a/src/utils.ts b/src/utils.ts index 740ff5107..f36ab01f5 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -67,49 +67,50 @@ export function xmlEscape(obj) { return obj; } -export function parseMTOMResp(payload: Buffer, boundary: string): IMTOMAttachments{ +export function parseMTOMResp(payload: Buffer, boundary: string): IMTOMAttachments { const resp: IMTOMAttachments = { - parts:[] + parts: [], }; - let headerName = "", headerValue = "", data: Buffer; + let headerName = ''; + let headerValue = ''; + let data: Buffer; let partIndex = 0; const parser = new MultipartParser(); - - parser.initWithBoundary(boundary) - parser.onPartBegin = function() { + parser.initWithBoundary(boundary); + parser.onPartBegin = () => { resp.parts[partIndex] = { - body:null, - headers:{} + body: null, + headers: {}, }; data = Buffer.from(''); - } + }; - parser.onHeaderField = function(b: Buffer, start: number, end: number) { - headerName = b.slice(start, end).toString() + parser.onHeaderField = (b: Buffer, start: number, end: number) => { + headerName = b.slice(start, end).toString(); }; - parser.onHeaderValue = function(b: Buffer, start: number, end: number) { - headerValue = b.slice(start, end).toString() - } + parser.onHeaderValue = (b: Buffer, start: number, end: number) => { + headerValue = b.slice(start, end).toString(); + }; - parser.onHeaderEnd = function() { + parser.onHeaderEnd = () => { resp.parts[partIndex].headers[headerName.toLowerCase()] = headerValue; - } + }; - parser.onHeadersEnd = function() {} + parser.onHeadersEnd = () => {}; - parser.onPartData = function(b: Buffer, start: number, end: number) { + parser.onPartData = (b: Buffer, start: number, end: number) => { data = Buffer.concat([data, b.slice(start, end)]); - } + }; - parser.onPartEnd = function() { + parser.onPartEnd = () => { resp.parts[partIndex].body = data; partIndex++; - } + }; - parser.onEnd = function() {} + parser.onEnd = () => {}; parser.write(payload); return resp; -} \ No newline at end of file +} From f339f78d6841b617065f9004877b1b94c4f1213b Mon Sep 17 00:00:00 2001 From: davefej Date: Thu, 3 Jun 2021 15:58:59 +0200 Subject: [PATCH 06/11] Fix getAttachment test fails on linux (LF to CRLF) --- test/request-response-samples-test.js | 8 +++++++- .../response.xml | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/request-response-samples-test.js b/test/request-response-samples-test.js index c16b6d988..aa3b689cf 100644 --- a/test/request-response-samples-test.js +++ b/test/request-response-samples-test.js @@ -151,7 +151,13 @@ function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requ suite[name] = function(done){ if(requestXML) requestContext.expectedRequest = requestXML; - if(responseXML) requestContext.responseToSend = responseXML; + if (responseXML) { + if (wsdlOptions.mtomResponse) {//all LF to CRLF + responseXML = responseXML.replace(/\r\n/g, "\n"); + responseXML = responseXML.replace(/\n/g, "\r\n"); + } + requestContext.responseToSend = responseXML; + } requestContext.doneHandler = done; requestContext.responseHttpHeaders = responseHttpHeaders; soap.createClient(wsdlPath, wsdlOptions, function(err, client){ diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml index 50daa98a5..7c394452f 100644 --- a/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/response.xml @@ -1,3 +1,4 @@ + --MIME_boundary Content-Type: text/xml; charset=UTF-8 Content-Transfer-Encoding: 8bit From c585fd2fcd089c8f05dbf3c886f60479d0a3c2eb Mon Sep 17 00:00:00 2001 From: davefej Date: Thu, 3 Jun 2021 20:35:04 +0200 Subject: [PATCH 07/11] improve code coverage and minor fixes --- src/http.ts | 2 +- src/utils.ts | 2 +- .../request.json | 3 ++ .../request.xml | 1 + .../response.json | 1 + .../response.xml | 9 ++++ .../soap.wsdl | 52 +++++++++++++++++++ .../wsdl_options.json | 3 ++ 8 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl create mode 100644 test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json diff --git a/src/http.ts b/src/http.ts index 031319b83..f84a7f481 100644 --- a/src/http.ts +++ b/src/http.ts @@ -193,7 +193,7 @@ export class HttpClient implements IHttpClient { return callback(err); } if (_this.options.mtomResponse) { - const isMultipartResp = res.headers['content-type'].toLowerCase().indexOf('multipart/related') > -1; + const isMultipartResp = res.headers['content-type'] && res.headers['content-type'].toLowerCase().indexOf('multipart/related') > -1; if (isMultipartResp) { let boundary; const parsedContentType = contentTypeParser(res.headers['content-type']); diff --git a/src/utils.ts b/src/utils.ts index f36ab01f5..469099c72 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,7 +1,7 @@ import * as crypto from 'crypto'; +import { MultipartParser } from 'formidable/lib/multipart_parser.js'; import { IMTOMAttachments } from './types'; -const MultipartParser = require('formidable/lib/multipart_parser.js').MultipartParser; export function passwordDigest(nonce: string, created: string, password: string): string { // digest = base64 ( sha1 ( nonce + created + password ) ) diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json new file mode 100644 index 000000000..f87ce7528 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.json @@ -0,0 +1,3 @@ +{ + "param":"123" +} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml new file mode 100644 index 000000000..575506abc --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/request.xml @@ -0,0 +1 @@ +123 \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json new file mode 100644 index 000000000..643d28ef9 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.json @@ -0,0 +1 @@ +{"attributes":{"soapenv:encodingStyle":"http://schemas.xmlsoap.org/soap/encoding/"},"attachment1":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:1186818862128"},"attachment2":{"attributes":{"xsi:type":"xsd:base64Binary"},"$value":"cid:536857424511"}} \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml new file mode 100644 index 000000000..01e4eb62d --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/response.xml @@ -0,0 +1,9 @@ + + + + + cid:1186818862128 + cid:536857424511 + + + \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl new file mode 100644 index 000000000..78e87dd5e --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/soap.wsdl @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WSDL File for MTOMService + + + + + \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json new file mode 100644 index 000000000..8ea6f5581 --- /dev/null +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json @@ -0,0 +1,3 @@ +{ + "mtomResponse":true +} \ No newline at end of file From d3e8954dc72d81ed62189c53ff3517dac8d75744 Mon Sep 17 00:00:00 2001 From: davefej Date: Fri, 4 Jun 2021 11:24:27 +0200 Subject: [PATCH 08/11] Rename option mtomResponse to parseReponseAttachments --- Readme.md | 2 +- src/http.ts | 4 ++-- src/types.ts | 2 +- test/request-response-samples-test.js | 2 +- .../wsdl_options.json | 2 +- .../wsdl_options.json | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Readme.md b/Readme.md index ca14a084b..23c3285d4 100644 --- a/Readme.md +++ b/Readme.md @@ -151,7 +151,7 @@ The `options` argument allows you to customize the client with the following pro - namespaceArrayElements: provides support for nonstandard array semantics. If true, JSON arrays of the form `{list: [{elem: 1}, {elem: 2}]}` are marshalled into xml as `1 2`. If false, marshalls into ` 1 2 `. Default: `true`. - stream: allows using a stream to parse the XML SOAP response. Default: `false` - returnSaxStream: enables the library to return the sax stream, transferring to the end user the responsibility of parsing the XML. It can be used only in combination with *stream* argument set to `true`. Default: `false` -- mtomResponse: Treat response as multipart/related response with MTOM attachment. Reach attachments on the `lastResponseAttachments` property of SoapClient. Default: `false` +- parseReponseAttachments: Treat response as multipart/related response with MTOM attachment. Reach attachments on the `lastResponseAttachments` property of SoapClient. Default: `false` Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses. diff --git a/src/http.ts b/src/http.ts index f84a7f481..5b9cbb340 100644 --- a/src/http.ts +++ b/src/http.ts @@ -185,14 +185,14 @@ export class HttpClient implements IHttpClient { }); } else { const _this = this; - if (this.options.mtomResponse) { + if (this.options.parseReponseAttachments) { options.encoding = null; } req = this._request(options, (err, res, body) => { if (err) { return callback(err); } - if (_this.options.mtomResponse) { + if (_this.options.parseReponseAttachments) { const isMultipartResp = res.headers['content-type'] && res.headers['content-type'].toLowerCase().indexOf('multipart/related') > -1; if (isMultipartResp) { let boundary; diff --git a/src/types.ts b/src/types.ts index 5bb1c98a9..f05ecb6cc 100644 --- a/src/types.ts +++ b/src/types.ts @@ -133,7 +133,7 @@ export interface IOptions extends IWsdlBaseOptions { /** @internal */ WSDL_CACHE?; /** handle MTOM soapAttachments in response */ - mtomResponse?: boolean; + parseReponseAttachments?: boolean; } export interface IOneWayOptions { diff --git a/test/request-response-samples-test.js b/test/request-response-samples-test.js index aa3b689cf..e6c1dd134 100644 --- a/test/request-response-samples-test.js +++ b/test/request-response-samples-test.js @@ -152,7 +152,7 @@ function generateTest(name, methodName, wsdlPath, headerJSON, securityJSON, requ suite[name] = function(done){ if(requestXML) requestContext.expectedRequest = requestXML; if (responseXML) { - if (wsdlOptions.mtomResponse) {//all LF to CRLF + if (wsdlOptions.parseReponseAttachments) {//all LF to CRLF responseXML = responseXML.replace(/\r\n/g, "\n"); responseXML = responseXML.replace(/\n/g, "\r\n"); } diff --git a/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json b/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json index 8ea6f5581..88a84c3d2 100644 --- a/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json +++ b/test/request-response-samples/getAttachments__should_handle_MTOM_response/wsdl_options.json @@ -1,3 +1,3 @@ { - "mtomResponse":true + "parseReponseAttachments":true } \ No newline at end of file diff --git a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json index 8ea6f5581..88a84c3d2 100644 --- a/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json +++ b/test/request-response-samples/getAttachments__should_handle_not_MTOM_response/wsdl_options.json @@ -1,3 +1,3 @@ { - "mtomResponse":true + "parseReponseAttachments":true } \ No newline at end of file From 3de5eba8bd82ae19e1cc9fd1f7bcc6b07d89f1fd Mon Sep 17 00:00:00 2001 From: David Polidario-Maddock Date: Tue, 29 Jun 2021 11:54:53 +0100 Subject: [PATCH 09/11] feat: add mtomAttachments to result --- src/client.ts | 59 ++++++++++++++++++++++++++------------------------- src/types.ts | 7 +++--- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/client.ts b/src/client.ts index 80a6053c8..beb0b075a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -232,11 +232,12 @@ export class Client extends EventEmitter { rawResponse: any, soapHeader: any, rawRequest: any, + mtomAttachments: any ) => { if (err) { reject(err); } else { - resolve([result, rawResponse, soapHeader, rawRequest]); + resolve([result, rawResponse, soapHeader, rawRequest, mtomAttachments]); } }; method( @@ -265,31 +266,31 @@ export class Client extends EventEmitter { extraHeaders = options; options = temp; } - this._invoke(method, args, location, (error, result, rawResponse, soapHeader, rawRequest) => { - callback(error, result, rawResponse, soapHeader, rawRequest); + this._invoke(method, args, location, (error, result, rawResponse, soapHeader, rawRequest, mtomAttachments) => { + callback(error, result, rawResponse, soapHeader, rawRequest, mtomAttachments); }, options, extraHeaders); }; } private _processSoapHeader(soapHeader, name, namespace, xmlns) { switch (typeof soapHeader) { - case 'object': - return this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); - case 'function': - const _this = this; - // arrow function does not support arguments variable - // tslint:disable-next-line - return function() { - const result = soapHeader.apply(null, arguments); - - if (typeof result === 'object') { - return _this.wsdl.objectToXML(result, name, namespace, xmlns, true); - } else { - return result; - } - }; - default: - return soapHeader; + case 'object': + return this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true); + case 'function': + const _this = this; + // arrow function does not support arguments variable + // tslint:disable-next-line + return function () { + const result = soapHeader.apply(null, arguments); + + if (typeof result === 'object') { + return _this.wsdl.objectToXML(result, name, namespace, xmlns, true); + } else { + return result; + } + }; + default: + return soapHeader; } } @@ -317,7 +318,7 @@ export class Client extends EventEmitter { if (!output) { // one-way, no output expected - return callback(null, null, body, obj.Header, xml); + return callback(null, null, body, obj.Header, xml, response.mtomResponseAttachments); } // If it's not HTML and Soap Body is empty @@ -332,7 +333,7 @@ export class Client extends EventEmitter { return callback(null, obj, body, obj.Header); } - if ( typeof obj.Body !== 'object' ) { + if (typeof obj.Body !== 'object') { const error: ISoapError = new Error('Cannot parse response'); error.response = response; error.body = body; @@ -354,7 +355,7 @@ export class Client extends EventEmitter { }); } - callback(null, result, body, obj.Header, xml); + callback(null, result, body, obj.Header, xml, response.mtomResponseAttachments); }; const parseSync = (body, response) => { @@ -375,7 +376,7 @@ export class Client extends EventEmitter { error.response = response; error.body = body; this.emit('soapError', error, eid); - return callback(error, response, body, undefined, xml); + return callback(error, response, body, undefined, xml, response.mtomResponseAttachments); } return finish(obj, body, response); }; @@ -401,7 +402,7 @@ export class Client extends EventEmitter { if (this.httpHeaders === null) { headers = {}; } else { - for (const header in this.httpHeaders) { headers[header] = this.httpHeaders[header]; } + for (const header in this.httpHeaders) { headers[header] = this.httpHeaders[header]; } for (const attr in extraHeaders) { headers[attr] = extraHeaders[attr]; } } @@ -413,9 +414,9 @@ export class Client extends EventEmitter { this.security.addOptions(options); } - if ((style === 'rpc') && ( ( input.parts || input.name === 'element' ) || args === null) ) { + if ((style === 'rpc') && ((input.parts || input.name === 'element') || args === null)) { assert.ok(!style || style === 'rpc', 'invalid message definition for document style binding'); - message = this.wsdl.objectToRpcXML(name, args, alias, ns, (input.name !== 'element' )); + message = this.wsdl.objectToRpcXML(name, args, alias, ns, (input.name !== 'element')); (method.inputSoap === 'encoded') && (encoding = 'soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" '); } else { assert.ok(!style || style === 'document', 'invalid message definition for rpc style binding'); @@ -448,8 +449,8 @@ export class Client extends EventEmitter { '' ) : - '' - ) + + '' + ) + '<' + envelopeKey + ':Body' + (this.bodyAttributes ? this.bodyAttributes.join(' ') : '') + (this.security && this.security.postProcess ? ' Id="_0"' : '') + diff --git a/src/types.ts b/src/types.ts index f05ecb6cc..da9cb0866 100644 --- a/src/types.ts +++ b/src/types.ts @@ -18,16 +18,17 @@ export interface IHttpClient { export type ISoapMethod = SoapMethod; export type SoapMethod = ( args: any, - callback: (err: any, result: any, rawResponse: any, soapHeader: any, rawRequest: any) => void, + callback: (err: any, result: any, rawResponse: any, soapHeader: any, rawRequest: any, mtomAttachments?: IMTOMAttachments) => void, options?: any, extraHeaders?: any, + mtomAttachments?: IMTOMAttachments ) => void; export type SoapMethodAsync = ( args: any, options?: any, extraHeaders?: any, -) => Promise<[any, any, any, any]>; +) => Promise<[any, any, any, any, IMTOMAttachments?]>; export type ISoapServiceMethod = (args: any, callback?: (data: any) => void, headers?: any, req?: any, res?: any, sender?: any) => any; @@ -157,6 +158,6 @@ export interface IServerOptions extends IWsdlBaseOptions { export interface IMTOMAttachments { parts: Array<{ body: Buffer, - headers: {[key: string]: string}, + headers: { [key: string]: string }, }>; } From 9caad1a9afdca33b935eb4ecbbb84c54efa74f94 Mon Sep 17 00:00:00 2001 From: "david.varga" Date: Wed, 7 Jul 2021 11:25:32 +0200 Subject: [PATCH 10/11] lint fix --- src/http.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/http.ts b/src/http.ts index 9c2eb5059..3a98aa665 100644 --- a/src/http.ts +++ b/src/http.ts @@ -175,7 +175,6 @@ export class HttpClient implements IHttpClient { if (this.options.parseReponseAttachments) { options.responseType = 'arraybuffer'; options.responseEncoding = 'binary'; - //options.encoding = null; } req = this._request(options); } From 73a2b481a0d1e79f3ef57eba1eac781526b036e7 Mon Sep 17 00:00:00 2001 From: David Polidario-Maddock Date: Wed, 7 Jul 2021 10:43:15 +0100 Subject: [PATCH 11/11] remove accidentally re-added request package --- package-lock.json | 19 ++++++ package.json | 158 +++++++++++++++++++++++----------------------- 2 files changed, 97 insertions(+), 80 deletions(-) diff --git a/package-lock.json b/package-lock.json index b052b9bbe..d0bf4f51b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1677,6 +1677,20 @@ "sshpk": "^1.7.0" } }, + "httpntlm": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.7.7.tgz", + "integrity": "sha512-Pv2Rvrz8H0qv1Dne5mAdZ9JegG1uc6Vu5lwLflIY6s8RKHdZQbW39L4dYswSgqMDT0pkJILUTKjeyU0VPNRZjA==", + "requires": { + "httpreq": ">=0.4.22", + "underscore": "~1.12.1" + } + }, + "httpreq": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.5.2.tgz", + "integrity": "sha512-2Jm+x9WkExDOeFRrdBCBSpLPT5SokTcRHkunV3pjKmX/cx6av8zQ0WtHUMDrYb6O4hBFzNU6sxJEypvRUVYKnw==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -3568,6 +3582,11 @@ } } }, + "underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" + }, "unherit": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz", diff --git a/package.json b/package.json index 56242fde2..ed3b57d79 100644 --- a/package.json +++ b/package.json @@ -1,82 +1,80 @@ { - "name": "soap", - "version": "0.40.0", - "description": "A minimal node SOAP client", - "engines": { - "node": ">=10.0.0" - }, - "author": "Vinay Pulim ", - "dependencies": { - "content-type-parser": "^1.0.2", - "formidable": "^1.2.2", - "httpntlm": "^1.5.2", - "request": ">=2.9.0", - "axios": "^0.21.1", - "axios-ntlm": "^1.1.6", - "debug": "^4.3.1", - "get-stream": "^6.0.1", - "lodash": "^4.17.21", - "sax": ">=0.6", - "strip-bom": "^3.0.0", - "uuid": "^8.3.2", - "xml-crypto": "^2.1.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/vpulim/node-soap.git" - }, - "main": "./index.js", - "types": "./lib/soap.d.ts", - "directories": { - "lib": "./lib", - "test": "./test" - }, - "scripts": { - "prepare": "npm run build", - "build": "tsc -p .", - "clean": "rm -rf lib", - "watch": "tsc -w -p .", - "lint": "tslint -p tsconfig.json", - "toc": "./node_modules/.bin/doctoc Readme.md --github --maxlevel 3", - "cover": "nyc --extension=.ts --reporter=lcov --reporter=html --reporter=text mocha --timeout 15000 --exit test/*-test.js test/security/*.js", - "coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js -v", - "docs": "typedoc --out docs", - "test": "mocha --timeout 15000 --bail --exit test/*-test.js test/security/*.js" - }, - "keywords": [ - "soap" - ], - "license": "MIT", - "devDependencies": { - "@types/debug": "^4.1.2", - "@types/express": "^4.16.1", - "@types/lodash": "^4.14.169", - "@types/node": "^11.15.54", - "@types/request": "^2.48.1", - "@types/sax": "^1.0.1", - "@types/uuid": "^8.3.0", - "body-parser": "^1.15.2", - "colors": "^1.3.3", - "coveralls": "^3.0.5", - "diff": "^4.0.1", - "doctoc": "^1.4.0", - "duplexer": "~0.1.1", - "express": "^4.16.4", - "finalhandler": "^1.1.1", - "glob": "^7.1.7", - "jshint": "^2.10.1", - "mocha": "^6.1.4", - "nyc": "^14.1.1", - "readable-stream": "~2.0.2", - "semver": "^5.6.0", - "serve-static": "^1.14.1", - "should": "^13.2.3", - "sinon": "^1.17.7", - "source-map-support": "^0.5.10", - "timekeeper": "^2.1.2", - "tslint": "^5.18.0", - "typedoc": "^0.20.36", - "typescript": "^3.3.3333" - } + "name": "soap", + "version": "0.40.0", + "description": "A minimal node SOAP client", + "engines": { + "node": ">=10.0.0" + }, + "author": "Vinay Pulim ", + "dependencies": { + "axios": "^0.21.1", + "axios-ntlm": "^1.1.6", + "content-type-parser": "^1.0.2", + "debug": "^4.3.1", + "formidable": "^1.2.2", + "get-stream": "^6.0.1", + "httpntlm": "^1.5.2", + "lodash": "^4.17.21", + "sax": ">=0.6", + "strip-bom": "^3.0.0", + "uuid": "^8.3.2", + "xml-crypto": "^2.1.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/vpulim/node-soap.git" + }, + "main": "./index.js", + "types": "./lib/soap.d.ts", + "directories": { + "lib": "./lib", + "test": "./test" + }, + "scripts": { + "prepare": "npm run build", + "build": "tsc -p .", + "clean": "rm -rf lib", + "watch": "tsc -w -p .", + "lint": "tslint -p tsconfig.json", + "toc": "./node_modules/.bin/doctoc Readme.md --github --maxlevel 3", + "cover": "nyc --extension=.ts --reporter=lcov --reporter=html --reporter=text mocha --timeout 15000 --exit test/*-test.js test/security/*.js", + "coveralls": "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js -v", + "docs": "typedoc --out docs", + "test": "mocha --timeout 15000 --bail --exit test/*-test.js test/security/*.js" + }, + "keywords": [ + "soap" + ], + "license": "MIT", + "devDependencies": { + "@types/debug": "^4.1.2", + "@types/express": "^4.16.1", + "@types/lodash": "^4.14.169", + "@types/node": "^11.15.54", + "@types/request": "^2.48.1", + "@types/sax": "^1.0.1", + "@types/uuid": "^8.3.0", + "body-parser": "^1.15.2", + "colors": "^1.3.3", + "coveralls": "^3.0.5", + "diff": "^4.0.1", + "doctoc": "^1.4.0", + "duplexer": "~0.1.1", + "express": "^4.16.4", + "finalhandler": "^1.1.1", + "glob": "^7.1.7", + "jshint": "^2.10.1", + "mocha": "^6.1.4", + "nyc": "^14.1.1", + "readable-stream": "~2.0.2", + "semver": "^5.6.0", + "serve-static": "^1.14.1", + "should": "^13.2.3", + "sinon": "^1.17.7", + "source-map-support": "^0.5.10", + "timekeeper": "^2.1.2", + "tslint": "^5.18.0", + "typedoc": "^0.20.36", + "typescript": "^3.3.3333" } - \ No newline at end of file +}