Comparing version 0.17.0 to 0.18.0
@@ -0,1 +1,17 @@ | ||
0.18.0 / 2016-11-25 | ||
================= | ||
* [DOC] Added documentation for adding custom http header (#890) | ||
* [DOC] Update soap stub example (#883) | ||
* [ENHANCEMENT] Add body parameter to soap responding stub. (#897) | ||
* [ENHANCEMENT] Added Stream support. (#837) | ||
* [ENHANCEMENT] Avoid matching <x:Envelope> tags inside comments (#877) | ||
* [FIX] Ensure that supplied request-object is passed through. (#894) | ||
* [FIX] Fix exception 'Parameter 'url' must be a string, not object' (#870) | ||
* [FIX] Handle empty SOAP Body properly. (#891) | ||
* [FIX] Set lodash dependency version to ^3.10.1 (#895) | ||
* [MAINTENANCE] Fix test case description (#886) | ||
* [MAINTENANCE] Fixed request-response-samples-test so that tests with only request.xml and request.json actually get run (#878) | ||
* [MAINTENANCE] Fixing minor jshint issues. (#884) | ||
0.17.0 / 2016-06-23 | ||
@@ -2,0 +18,0 @@ ================= |
@@ -15,3 +15,4 @@ /* | ||
findPrefix = require('./utils').findPrefix, | ||
_ = require('lodash'); | ||
_ = require('lodash'), | ||
concatStream = require('concat-stream'); | ||
@@ -122,2 +123,3 @@ var Client = function(wsdl, endpoint, options) { | ||
Client.prototype._initializeOptions = function(options) { | ||
this.streamAllowed = options.stream; | ||
this.wsdl.options.attributesKey = options.attributesKey || 'attributes'; | ||
@@ -286,5 +288,54 @@ this.wsdl.options.envelopeKey = options.envelopeKey || 'soap'; | ||
if (this.streamAllowed && typeof self.httpClient.requestStream === 'function') { | ||
callback = _.once(callback); | ||
var startTime = Date.now(); | ||
req = self.httpClient.requestStream(location, xml, headers, options, self); | ||
self.lastRequestHeaders = req.headers; | ||
var onError = function onError(err) { | ||
self.lastResponse = null; | ||
self.lastResponseHeaders = null; | ||
self.lastElapsedTime = null; | ||
self.emit('response', null, null); | ||
callback(err); | ||
}; | ||
req.on('error', onError); | ||
req.on('response', function (response) { | ||
response.on('error', onError); | ||
// When the output element cannot be looked up in the wsdl, play it safe and | ||
// don't stream | ||
if(response.statusCode !== 200 || !output || !output.$lookupTypes) { | ||
response.pipe(concatStream({encoding: 'string'}, function (body) { | ||
self.lastResponse = body; | ||
self.lastResponseHeaders = response && response.headers; | ||
self.lastElapsedTime = Date.now() - startTime; | ||
self.emit('response', body, response); | ||
return parseSync(body, response); | ||
})); | ||
return; | ||
} | ||
self.wsdl.xmlToObject(response, function (error, obj) { | ||
self.lastResponse = response; | ||
self.lastResponseHeaders = response && response.headers; | ||
self.lastElapsedTime = Date.now() - startTime; | ||
self.emit('response', '<stream>', response); | ||
if (error) { | ||
error.response = response; | ||
error.body = '<stream>'; | ||
self.emit('soapError', error); | ||
return callback(error, response); | ||
} | ||
return finish(obj, '<stream>', response); | ||
}); | ||
}); | ||
return; | ||
} | ||
req = self.httpClient.request(location, xml, function(err, response, body) { | ||
var result; | ||
var obj; | ||
self.lastResponse = body; | ||
@@ -298,53 +349,67 @@ self.lastResponseHeaders = response && response.headers; | ||
} else { | ||
return parseSync(body, response); | ||
} | ||
}, headers, options, self); | ||
try { | ||
obj = self.wsdl.xmlToObject(body); | ||
} catch (error) { | ||
// When the output element cannot be looked up in the wsdl and the body is JSON | ||
// instead of sending the error, we pass the body in the response. | ||
if(!output || !output.$lookupTypes) { | ||
debug('Response element is not present. Unable to convert response xml to json.'); | ||
// If the response is JSON then return it as-is. | ||
var json = _.isObject(body) ? body : tryJSONparse(body); | ||
if (json) { | ||
return callback(null, response, json); | ||
} | ||
function parseSync(body, response) { | ||
var obj; | ||
try { | ||
obj = self.wsdl.xmlToObject(body); | ||
} catch (error) { | ||
// When the output element cannot be looked up in the wsdl and the body is JSON | ||
// instead of sending the error, we pass the body in the response. | ||
if(!output || !output.$lookupTypes) { | ||
debug('Response element is not present. Unable to convert response xml to json.'); | ||
// If the response is JSON then return it as-is. | ||
var json = _.isObject(body) ? body : tryJSONparse(body); | ||
if (json) { | ||
return callback(null, response, json); | ||
} | ||
error.response = response; | ||
error.body = body; | ||
self.emit('soapError', error); | ||
return callback(error, response, body); | ||
} | ||
error.response = response; | ||
error.body = body; | ||
self.emit('soapError', error); | ||
return callback(error, response, body); | ||
} | ||
return finish(obj, body, response); | ||
} | ||
if (!output){ | ||
// one-way, no output expected | ||
return callback(null, null, body, obj.Header); | ||
} | ||
function finish(obj, body, response) { | ||
var result; | ||
if( typeof obj.Body !== 'object' ) { | ||
var error = new Error('Cannot parse response'); | ||
error.response = response; | ||
error.body = body; | ||
return callback(error, obj, body); | ||
} | ||
if (!output){ | ||
// one-way, no output expected | ||
return callback(null, null, body, obj.Header); | ||
} | ||
result = obj.Body[output.$name]; | ||
// RPC/literal response body may contain elements with added suffixes I.E. | ||
// 'Response', or 'Output', or 'Out' | ||
// This doesn't necessarily equal the ouput message name. See WSDL 1.1 Section 2.4.5 | ||
if(!result){ | ||
result = obj.Body[output.$name.replace(/(?:Out(?:put)?|Response)$/, '')]; | ||
} | ||
if (!result) { | ||
['Response', 'Out', 'Output'].forEach(function (term) { | ||
if (obj.Body.hasOwnProperty(name + term)) { | ||
return result = obj.Body[name + term]; | ||
} | ||
}); | ||
} | ||
if( typeof obj.Body !== 'object' ) { | ||
var error = new Error('Cannot parse response'); | ||
error.response = response; | ||
error.body = body; | ||
return callback(error, obj, body); | ||
} | ||
callback(null, result, body, obj.Header); | ||
// if Soap Body is empty | ||
if (!obj.Body) { | ||
return callback(null, obj, body, obj.Header); | ||
} | ||
}, headers, options, self); | ||
result = obj.Body[output.$name]; | ||
// RPC/literal response body may contain elements with added suffixes I.E. | ||
// 'Response', or 'Output', or 'Out' | ||
// This doesn't necessarily equal the ouput message name. See WSDL 1.1 Section 2.4.5 | ||
if(!result){ | ||
result = obj.Body[output.$name.replace(/(?:Out(?:put)?|Response)$/, '')]; | ||
} | ||
if (!result) { | ||
['Response', 'Out', 'Output'].forEach(function (term) { | ||
if (obj.Body.hasOwnProperty(name + term)) { | ||
return result = obj.Body[name + term]; | ||
} | ||
}); | ||
} | ||
callback(null, result, body, obj.Header); | ||
} | ||
// Added mostly for testability, but possibly useful for debugging | ||
@@ -351,0 +416,0 @@ if(req && req.headers) //fixes an issue when req or req.headers is indefined |
@@ -70,6 +70,6 @@ /* | ||
options.body = data; | ||
exoptions = exoptions || {}; | ||
@@ -101,3 +101,4 @@ for (attr in exoptions) { | ||
// envelope. | ||
var match = body.match(/(?:<\?[^?]*\?>[\s]*)?<([^:]*):Envelope([\S\s]*)<\/\1:Envelope>/i); | ||
var match = | ||
body.replace(/<!--[\s\S]*?-->/, "").match(/(?:<\?[^?]*\?>[\s]*)?<([^:]*):Envelope([\S\s]*)<\/\1:Envelope>/i); | ||
if (match) { | ||
@@ -121,6 +122,12 @@ body = match[0]; | ||
}); | ||
return req; | ||
}; | ||
HttpClient.prototype.requestStream = function(rurl, data, exheaders, exoptions) { | ||
var self = this; | ||
var options = self.buildRequest(rurl, data, exheaders, exoptions); | ||
return self._request(options); | ||
}; | ||
module.exports = HttpClient; |
@@ -31,3 +31,3 @@ /* | ||
var Server = function(server, path, services, wsdl, options) { | ||
var Server = function (server, path, services, wsdl, options) { | ||
var self = this; | ||
@@ -44,6 +44,6 @@ | ||
path += '/'; | ||
wsdl.onReady(function(err) { | ||
if(typeof server.route === 'function' && typeof server.use === 'function'){ | ||
wsdl.onReady(function (err) { | ||
if (typeof server.route === 'function' && typeof server.use === 'function') { | ||
//handle only the required URL path for express server | ||
server.route(path).all(function(req, res, next){ | ||
server.route(path).all(function (req, res, next) { | ||
if (typeof self.authorizeConnection === 'function') { | ||
@@ -60,3 +60,3 @@ if (!self.authorizeConnection(req)) { | ||
server.removeAllListeners('request'); | ||
server.addListener('request', function(req, res) { | ||
server.addListener('request', function (req, res) { | ||
if (typeof self.authorizeConnection === 'function') { | ||
@@ -69,3 +69,3 @@ if (!self.authorizeConnection(req)) { | ||
var reqPath = url.parse(req.url).pathname; | ||
if (reqPath[reqPath.length - 1] !== '/'){ | ||
if (reqPath[reqPath.length - 1] !== '/') { | ||
reqPath += '/'; | ||
@@ -88,3 +88,3 @@ } | ||
Server.prototype.addSoapHeader = function(soapHeader, name, namespace, xmlns) { | ||
Server.prototype.addSoapHeader = function (soapHeader, name, namespace, xmlns) { | ||
if (!this.soapHeaders) { | ||
@@ -99,3 +99,3 @@ this.soapHeaders = []; | ||
Server.prototype.changeSoapHeader = function(index, soapHeader, name, namespace, xmlns) { | ||
Server.prototype.changeSoapHeader = function (index, soapHeader, name, namespace, xmlns) { | ||
if (!this.soapHeaders) { | ||
@@ -110,15 +110,15 @@ this.soapHeaders = []; | ||
Server.prototype.getSoapHeaders = function() { | ||
Server.prototype.getSoapHeaders = function () { | ||
return this.soapHeaders; | ||
}; | ||
Server.prototype.clearSoapHeaders = function() { | ||
Server.prototype.clearSoapHeaders = function () { | ||
this.soapHeaders = null; | ||
}; | ||
Server.prototype._initializeOptions = function(options) { | ||
Server.prototype._initializeOptions = function (options) { | ||
this.wsdl.options.attributesKey = options.attributesKey || 'attributes'; | ||
}; | ||
Server.prototype._processRequestXml = function(req, res, xml){ | ||
Server.prototype._processRequestXml = function (req, res, xml) { | ||
var self = this; | ||
@@ -131,4 +131,4 @@ var result; | ||
} | ||
self._process(xml, req, function(result, statusCode) { | ||
if(statusCode) { | ||
self._process(xml, req, function (result, statusCode) { | ||
if (statusCode) { | ||
res.statusCode = statusCode; | ||
@@ -144,3 +144,3 @@ } | ||
if (err.Fault !== undefined) { | ||
return self._sendError(err.Fault, function(result, statusCode) { | ||
return self._sendError(err.Fault, function (result, statusCode) { | ||
res.statusCode = statusCode || 500; | ||
@@ -165,3 +165,3 @@ res.write(result); | ||
Server.prototype._requestListener = function(req, res) { | ||
Server.prototype._requestListener = function (req, res) { | ||
var self = this; | ||
@@ -186,11 +186,11 @@ var reqParse = url.parse(req.url); | ||
} else if (req.method === 'POST') { | ||
if (typeof req.headers['content-type'] !== "undefined") { | ||
res.setHeader('Content-Type', req.headers['content-type']); | ||
} else { | ||
res.setHeader('Content-Type', "application/xml"); | ||
} | ||
if (typeof req.headers['content-type'] !== "undefined") { | ||
res.setHeader('Content-Type', req.headers['content-type']); | ||
} else { | ||
res.setHeader('Content-Type', "application/xml"); | ||
} | ||
//request body is already provided by an express middleware | ||
//in this case unzipping should also be done by the express middleware itself | ||
if(req.body){ | ||
if (req.body) { | ||
return self._processRequestXml(req, res, req.body.toString()); | ||
@@ -204,3 +204,3 @@ } | ||
} | ||
req.on('data', function(chunk) { | ||
req.on('data', function (chunk) { | ||
if (gunzip) | ||
@@ -210,3 +210,3 @@ chunk = gunzip.inflate(chunk, "binary"); | ||
}); | ||
req.on('end', function() { | ||
req.on('end', function () { | ||
var xml = chunks.join(''); | ||
@@ -227,3 +227,3 @@ var result; | ||
Server.prototype._process = function(input, req, callback) { | ||
Server.prototype._process = function (input, req, callback) { | ||
var self = this, | ||
@@ -254,3 +254,3 @@ pathname = url.parse(req.url).pathname.replace(/\/$/, ''), | ||
//and throw more meaningful error | ||
if(!body){ | ||
if (!body) { | ||
throw new Error('Failed to parse the SOAP Message body'); | ||
@@ -260,3 +260,3 @@ } | ||
// use port.location and current url to find the right binding | ||
binding = (function(self) { | ||
binding = (function (self) { | ||
var services = self.wsdl.definitions.services; | ||
@@ -339,3 +339,3 @@ var firstPort; | ||
Server.prototype._executeMethod = function(options, req, callback, includeTimestamp) { | ||
Server.prototype._executeMethod = function (options, req, callback, includeTimestamp) { | ||
options = options || {}; | ||
@@ -380,3 +380,3 @@ var self = this, | ||
if(!self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output){ | ||
if (!self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output) { | ||
// no output defined = one-way operation so return empty response | ||
@@ -393,3 +393,3 @@ handled = true; | ||
Server.prototype._envelope = function(body, includeTimestamp) { | ||
Server.prototype._envelope = function (body, includeTimestamp) { | ||
var defs = this.wsdl.definitions, | ||
@@ -411,16 +411,16 @@ ns = defs.$targetNamespace, | ||
headers += "<o:Security soap:mustUnderstand=\"1\" " + | ||
"xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " + | ||
"xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + | ||
" <u:Timestamp u:Id=\"_0\">" + | ||
" <u:Created>" + created + "</u:Created>" + | ||
" <u:Expires>" + expires + "</u:Expires>" + | ||
" </u:Timestamp>" + | ||
" </o:Security>\n"; | ||
"xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " + | ||
"xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + | ||
" <u:Timestamp u:Id=\"_0\">" + | ||
" <u:Created>" + created + "</u:Created>" + | ||
" <u:Expires>" + expires + "</u:Expires>" + | ||
" </u:Timestamp>" + | ||
" </o:Security>\n"; | ||
} | ||
if(this.soapHeaders) { | ||
if (this.soapHeaders) { | ||
headers += this.soapHeaders.join("\n"); | ||
} | ||
if(headers !== '') { | ||
if (headers !== '') { | ||
xml += "<soap:Header>" + headers + "</soap:Header>"; | ||
@@ -436,3 +436,3 @@ } | ||
Server.prototype._sendError = function(soapFault, callback, includeTimestamp) { | ||
Server.prototype._sendError = function (soapFault, callback, includeTimestamp) { | ||
var self = this, | ||
@@ -442,3 +442,3 @@ fault; | ||
var statusCode; | ||
if(soapFault.statusCode) { | ||
if (soapFault.statusCode) { | ||
statusCode = soapFault.statusCode; | ||
@@ -445,0 +445,0 @@ soapFault.statusCode = undefined; |
@@ -26,3 +26,3 @@ /* | ||
callback(null, result); | ||
}) | ||
}); | ||
} else { | ||
@@ -29,0 +29,0 @@ process.nextTick(function () { |
{ | ||
"name": "soap", | ||
"version": "0.17.0", | ||
"version": "0.18.0", | ||
"description": "A minimal node SOAP client", | ||
@@ -11,5 +11,7 @@ "engines": { | ||
"compress": "^0.99.0", | ||
"concat-stream": "^1.5.1", | ||
"debug": "~0.7.4", | ||
"ejs": "~2.3.4", | ||
"lodash": "3.x.x", | ||
"finalhandler": "^0.5.0", | ||
"lodash": "^3.10.1", | ||
"node-uuid": "~1.4.3", | ||
@@ -20,2 +22,3 @@ "optional": "^0.1.3", | ||
"selectn": "^0.9.6", | ||
"serve-static": "^1.11.1", | ||
"strip-bom": "~0.3.1", | ||
@@ -22,0 +25,0 @@ "xml-crypto": "~0.8.0" |
@@ -395,2 +395,7 @@ # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coveralls Status][coveralls-image]][coveralls-url] [![Gitter chat][gitter-image]][gitter-url] | ||
- Add custom User-Agent: | ||
```javascript | ||
client.addHttpHeader('User-Agent', `CustomUserAgent`); | ||
``` | ||
#### Alternative method call using callback-last pattern | ||
@@ -710,3 +715,3 @@ | ||
clientStub.SomeOperation.respondWithError = soapStub.createRespondingStub({..error json...}); | ||
clientStub.SomeOperation.respondWithError = soapStub.createErroringStub({..error json...}); | ||
clientStub.SomeOperation.respondWithSuccess = soapStub.createRespondingStub({..success json...}); | ||
@@ -713,0 +718,0 @@ |
@@ -101,3 +101,3 @@ var _ = require('lodash'); | ||
*/ | ||
function createRespondingStub(object) { | ||
function createRespondingStub(object, body) { | ||
return function() { | ||
@@ -107,3 +107,3 @@ this.args.forEach(function(argSet) { | ||
}); | ||
this.yields(null, object); | ||
this.yields(null, object, body); | ||
}; | ||
@@ -110,0 +110,0 @@ } |
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
175118
3519
767
15
+ Addedconcat-stream@^1.5.1
+ Addedfinalhandler@^0.5.0
+ Addedserve-static@^1.11.1
+ Addedbuffer-from@1.1.2(transitive)
+ Addedconcat-stream@1.6.2(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addeddebug@2.2.02.6.9(transitive)
+ Addeddepd@2.0.0(transitive)
+ Addeddestroy@1.2.0(transitive)
+ Addedee-first@1.1.1(transitive)
+ Addedencodeurl@1.0.22.0.0(transitive)
+ Addedescape-html@1.0.3(transitive)
+ Addedetag@1.8.1(transitive)
+ Addedfinalhandler@0.5.1(transitive)
+ Addedfresh@0.5.2(transitive)
+ Addedhttp-errors@2.0.0(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedmime@1.6.0(transitive)
+ Addedms@0.7.12.0.02.1.3(transitive)
+ Addedon-finished@2.3.02.4.1(transitive)
+ Addedparseurl@1.3.3(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedrange-parser@1.2.1(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsend@0.19.0(transitive)
+ Addedserve-static@1.16.2(transitive)
+ Addedsetprototypeof@1.2.0(transitive)
+ Addedstatuses@1.3.12.0.1(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedtoidentifier@1.0.1(transitive)
+ Addedtypedarray@0.0.6(transitive)
+ Addedunpipe@1.0.0(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
- Removedsafe-buffer@5.2.1(transitive)
Updatedlodash@^3.10.1