Skip to content

Commit

Permalink
Upgrade to Formidable 3, Node 14, and audit fix (vpulim#1192)
Browse files Browse the repository at this point in the history
  • Loading branch information
benasher44 authored Oct 1, 2022
1 parent ceb2599 commit cded0c3
Show file tree
Hide file tree
Showing 8 changed files with 1,242 additions and 1,146 deletions.
2,217 changes: 1,148 additions & 1,069 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
"version": "0.45.0",
"description": "A minimal node SOAP client",
"engines": {
"node": ">=12.0.0"
"node": ">=14.0.0"
},
"author": "Vinay Pulim <[email protected]>",
"dependencies": {
"axios-ntlm": "^1.2.0",
"debug": "^4.3.2",
"formidable": "^2.0.1",
"formidable": "^3.2.4",
"get-stream": "^6.0.1",
"lodash": "^4.17.21",
"sax": ">=0.6",
Expand All @@ -19,7 +19,7 @@
"xml-crypto": "^2.1.3"
},
"peerDependencies": {
"axios": ">=0.21.1"
"axios": "^0.27.2"
},
"repository": {
"type": "git",
Expand Down Expand Up @@ -78,7 +78,7 @@
"source-map-support": "^0.5.10",
"timekeeper": "^2.1.2",
"tslint": "^5.18.0",
"typedoc": "^0.20.37",
"typescript": "^3.9.10"
"typedoc": "^0.23.10",
"typescript": "^4.7.4"
}
}
41 changes: 23 additions & 18 deletions src/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as url from 'url';
import { v4 as uuidv4 } from 'uuid';
import MIMEType = require('whatwg-mimetype');
import { gzipSync } from 'zlib';
import { IExOptions, IHeaders, IHttpClient, IMTOMAttachments, IOptions } from './types';
import { IExOptions, IHeaders, IHttpClient, IOptions } from './types';
import { parseMTOMResp } from './utils';

const debug = debugBuilder('node-soap');
Expand Down Expand Up @@ -53,8 +53,6 @@ export class HttpClient implements IHttpClient {
public buildRequest(rurl: string, data: any, exheaders?: IHeaders, exoptions: IExOptions = {}): any {
const curl = url.parse(rurl);
const method = data ? 'POST' : 'GET';
const secure = curl.protocol === 'https:';
const path = [curl.pathname || '/', curl.search || '', curl.hash || ''].join('');

const host = curl.hostname;
const port = parseInt(curl.port, 10);
Expand Down Expand Up @@ -206,7 +204,13 @@ export class HttpClient implements IHttpClient {
}
const _this = this;
req.then((res) => {
let body;

const handleBody = (body?: string) => {
res.data = this.handleResponse(req, res, body || res.data);
callback(null, res, res.data);
return res;
};

if (_this.options.parseReponseAttachments) {
const isMultipartResp = res.headers['content-type'] && res.headers['content-type'].toLowerCase().indexOf('multipart/related') > -1;
if (isMultipartResp) {
Expand All @@ -218,23 +222,24 @@ export class HttpClient implements IHttpClient {
if (!boundary) {
return callback(new Error('Missing boundary from content-type'));
}
const multipartResponse = parseMTOMResp(res.data, boundary);

// first part is the soap response
const firstPart = multipartResponse.parts.shift();
if (!firstPart || !firstPart.body) {
return callback(new Error('Cannot parse multipart response'));
}
body = firstPart.body.toString('utf8');
(res as any).mtomResponseAttachments = multipartResponse;
return parseMTOMResp(res.data, boundary, (err, multipartResponse) => {
if (err) {
return callback(err);
}
// first part is the soap response
const firstPart = multipartResponse.parts.shift();
if (!firstPart || !firstPart.body) {
return callback(new Error('Cannot parse multipart response'));
}
(res as any).mtomResponseAttachments = multipartResponse;
return handleBody(firstPart.body.toString('utf8'));
});
} else {
body = res.data.toString('utf8');
return handleBody(res.data.toString('utf8'));
}
} else {
return handleBody();
}

res.data = this.handleResponse(req, res, body || res.data);
callback(null, res, res.data);
return res;
}, (err) => {
return callback(err);
});
Expand Down
89 changes: 46 additions & 43 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

import * as crypto from 'crypto';
import { MultipartParser } from 'formidable';
import { IMTOMAttachments } from './types';

export function passwordDigest(nonce: string, created: string, password: string): string {
Expand Down Expand Up @@ -67,46 +66,50 @@ export function xmlEscape(obj) {
return obj;
}

export function parseMTOMResp(payload: Buffer, boundary: string): IMTOMAttachments {
const resp: IMTOMAttachments = {
parts: [],
};
let headerName = '';
let headerValue = '';
let data: Buffer;
let partIndex = 0;
const parser = new MultipartParser();

parser.initWithBoundary(boundary);
parser.on('data', ({ name, buffer, start, end }) => {
switch (name) {
case 'partBegin':
resp.parts[partIndex] = {
body: null,
headers: {},
};
data = Buffer.from('');
break;
case 'headerField':
headerName = buffer.slice(start, end).toString();
break;
case 'headerValue':
headerValue = buffer.slice(start, end).toString();
break;
case 'headerEnd':
resp.parts[partIndex].headers[headerName.toLowerCase()] = headerValue;
break;
case 'partData':
data = Buffer.concat([data, buffer.slice(start, end)]);
break;
case 'partEnd':
resp.parts[partIndex].body = data;
partIndex++;
break;
}
});

parser.write(payload);

return resp;
export function parseMTOMResp(payload: Buffer, boundary: string, callback: (err?: Error, resp?: IMTOMAttachments) => void) {
return import('formidable')
.then(({ MultipartParser }) => {
const resp: IMTOMAttachments = {
parts: [],
};
let headerName = '';
let headerValue = '';
let data: Buffer;
let partIndex = 0;
const parser = new MultipartParser();

parser.initWithBoundary(boundary);
parser.on('data', ({ name, buffer, start, end }) => {
switch (name) {
case 'partBegin':
resp.parts[partIndex] = {
body: null,
headers: {},
};
data = Buffer.from('');
break;
case 'headerField':
headerName = buffer.slice(start, end).toString();
break;
case 'headerValue':
headerValue = buffer.slice(start, end).toString();
break;
case 'headerEnd':
resp.parts[partIndex].headers[headerName.toLowerCase()] = headerValue;
break;
case 'partData':
data = Buffer.concat([data, buffer.slice(start, end)]);
break;
case 'partEnd':
resp.parts[partIndex].body = data;
partIndex++;
break;
}
});

parser.write(payload);

return callback(null, resp);
})
.catch(callback);
}
4 changes: 4 additions & 0 deletions test/_socketStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ module.exports = function createSocketStream(file, length) {
socketStream.destroy = function() {
};

// axios calls this
socketStream.setKeepAlive = function() {
};

socketStream.req = httpReqStream;
socketStream.res = httpResStream;

Expand Down
14 changes: 9 additions & 5 deletions test/client-customHttp-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,18 @@ it('should allow customization of httpClient and the wsdl file download should p
socketStream.destroy = function() {
};

// axios calls this
socketStream.setKeepAlive = function() {
};

//Custom httpClient
function MyHttpClient (options, socket){
httpClient.call(this,options);
this.agent = new CustomAgent(options, socket);
class MyHttpClient extends httpClient {
constructor(options, socket) {
super(options)
this.agent = new CustomAgent(options, socket);
}
}

util.inherits(MyHttpClient, httpClient);

MyHttpClient.prototype.request = function(rurl, data, callback, exheaders, exoptions) {
var self = this;
var options = self.buildRequest(rurl, data, exheaders, exoptions);
Expand Down
10 changes: 5 additions & 5 deletions test/client-customHttp-xsdinclude-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ it('should allow customization of httpClient, the wsdl file, and associated data
};

//Custom httpClient
function MyHttpClient (options, wsdlSocket, xsdSocket){
httpClient.call(this,options);
this.agent = new CustomAgent(options, wsdlSocket, xsdSocket);
class MyHttpClient extends httpClient {
constructor(options, wsdlSocket, xsdSocket) {
super(options);
this.agent = new CustomAgent(options, wsdlSocket, xsdSocket);
}
}

util.inherits(MyHttpClient, httpClient);

MyHttpClient.prototype.request = function(rurl, data, callback, exheaders, exoptions) {
var self = this;
var options = self.buildRequest(rurl, data, exheaders, exoptions);
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"compileOnSave": true,
"compilerOptions": {
"target": "es3",
"target": "es2020",
"module": "commonjs",
"moduleResolution": "nodenext",
"outDir": "lib",
"sourceMap": true,
"declaration": true,
Expand Down

0 comments on commit cded0c3

Please sign in to comment.