Comparing version 0.8.0 to 0.9.0
@@ -14,7 +14,12 @@ #Contribution Guidelines | ||
##Submitting a Pull Request | ||
* Pull Requests must be rebased to the latest version of master and squashed to a single commit i.e. `git checkout master;git pull upstream master;git checkout feature-branch;git rebase -i master` | ||
* Pull Requests must have accompanying tests (either Unit or Request/Response Sample tests are welcome). Your chances of getting the PR merged are very low if you don't provide any tests. | ||
* Pull Requests **must be rebased to the latest version of master and _squashed to a single commit_** i.e. `git checkout master;git pull upstream master;git checkout feature-branch;git rebase -i master` | ||
* Pull Requests **must have accompanying tests** (either Unit or Request/Response Sample tests are welcome). Your chances of getting the PR merged are very low if you don't provide any tests. | ||
* Pull Requests must have passing travis builds. | ||
* Pull Requests must be able to merge automatically from github. | ||
* Please do not close a pull request due to a request to rebase. Git is a powerful VCS and deserves your time in learning how to rebase properly. Pull Requests are updated automatically on github when you force push to your branch after rebasing. | ||
* Please **do not close a pull request due to a request to rebase**. Git is a powerful VCS and deserves your time in learning how to rebase properly. Pull Requests are updated automatically on github when you force push to your branch after rebasing. | ||
Very useful articles/help on this topic: | ||
- [GitHub Help - About Git rebase](https://help.github.com/articles/about-git-rebase/) | ||
- [GitHub Help - Using Git rebase](https://help.github.com/articles/using-git-rebase/) | ||
* Please use descriptive commit messages. Commit messages are used during the creation of history and release notes. You'll make the job of maintaners much easier by doing this. | ||
@@ -21,0 +26,0 @@ |
@@ -0,1 +1,20 @@ | ||
0.9.0 / 2015-05-18 | ||
================= | ||
* [FIX] Fix to allow request options and headers to persist for all includes. Fix to properly handle when an import/include starts with a schema element. (#608) | ||
* [FIX] Do not end request for keep-alive connections (#600) | ||
* [ENHANCEMENT] Added Client 'response' event (#610) | ||
* [FIX] If response is json, then error should not be thrown. Fix issue #580 (#581) | ||
* [FIX] Sub-namespace should be correct regardless of order of enumeration i.e. should not be overriden by other prop's namespace (#607) | ||
* [DOC] Added a section about Server Events to README.md (#596) | ||
* [ENHANCEMENT] Added Server 'request' event (#595) | ||
* [ENHANCEMENT] Add support for One-Way Operations (#590) | ||
* [FIX] `lib/wsdl.js` util function `extend()` doesn't throw an Error when handling elements that are not objects. (#589) | ||
* [ENHANCEMENT] ClientSSLSecurity now accepts a `ca`-certificate. (#588) | ||
* [ENHANCEMENT] ClientSSLSecurity should be able to take a Buffer as `key` and `cert` parameter. Additionally the certificates are checked whether they are correct or not (starting with `-----BEGIN`). (#586) | ||
* [ENHANCEMENT] Add support for sending NULL values (#578) | ||
* [ENHANCEMENT] Follow 302 redirects, don't mix quotes (#577) | ||
* [DOC] Update CONTRIBUTING.md | ||
* [FIX] Respond with security timestamp if request had one (#579) | ||
0.8.0 / 2015-02-17 | ||
@@ -2,0 +21,0 @@ ================= |
@@ -18,2 +18,3 @@ /* | ||
util = require('util'), | ||
debug = require('debug')('node-soap'), | ||
url = require('url'); | ||
@@ -221,2 +222,3 @@ | ||
self.lastResponseHeaders = response && response.headers; | ||
self.emit('response', body); | ||
@@ -229,2 +231,8 @@ if (err) { | ||
} catch (error) { | ||
//When the output element cannot be looked up in the wsdl, | ||
//Then instead of sending the error, We pass the body in the response. | ||
if(!output.$lookupTypes) { | ||
debug('Response element is not present. Unable to convert response xml to json.'); | ||
return callback(null,response,body); | ||
} | ||
error.response = response; | ||
@@ -236,2 +244,7 @@ error.body = body; | ||
if (!output){ | ||
// one-way, no output expected | ||
return callback(null, null, body, obj.Header); | ||
} | ||
result = obj.Body[output.$name]; | ||
@@ -238,0 +251,0 @@ // RPC/literal response body may contain elements with added suffixes I.E. |
@@ -6,3 +6,3 @@ /* | ||
"use strict"; | ||
'use strict'; | ||
@@ -14,3 +14,3 @@ var url = require('url'); | ||
exports.request = function(rurl, data, callback, exheaders, exoptions) { | ||
var httpRequest = function httpRequest(rurl, data, callback, exheaders, exoptions) { | ||
var curl = url.parse(rurl); | ||
@@ -21,10 +21,10 @@ var secure = curl.protocol === 'https:'; | ||
var path = [curl.pathname || '/', curl.search || '', curl.hash || ''].join(''); | ||
var method = data ? "POST" : "GET"; | ||
var method = data ? 'POST' : 'GET'; | ||
var headers = { | ||
"User-Agent": "node-soap/" + VERSION, | ||
"Accept" : "text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8", | ||
"Accept-Encoding": "none", | ||
"Accept-Charset": "utf-8", | ||
"Connection": "close", | ||
"Host": host + (isNaN(port) ? "" : ":" + port) | ||
'User-Agent': 'node-soap/' + VERSION, | ||
'Accept' : 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8', | ||
'Accept-Encoding': 'none', | ||
'Accept-Charset': 'utf-8', | ||
'Connection': 'close', | ||
'Host': host + (isNaN(port) ? '' : ':' + port) | ||
}; | ||
@@ -34,4 +34,4 @@ var attr; | ||
if (typeof data === 'string') { | ||
headers["Content-Length"] = Buffer.byteLength(data, 'utf8'); | ||
headers["Content-Type"] = "application/x-www-form-urlencoded"; | ||
headers['Content-Length'] = Buffer.byteLength(data, 'utf8'); | ||
headers['Content-Type'] = 'application/x-www-form-urlencoded'; | ||
} | ||
@@ -45,4 +45,9 @@ | ||
method: method, | ||
headers: headers | ||
headers: headers, | ||
followAllRedirects: true | ||
}; | ||
if (headers.Connection === 'keep-alive') { | ||
options.body = data; | ||
} | ||
@@ -56,3 +61,3 @@ exoptions = exoptions || {}; | ||
} else { | ||
if (typeof body === "string") { | ||
if (typeof body === 'string') { | ||
// Remove any extra characters that appear before or after the SOAP | ||
@@ -69,5 +74,10 @@ // envelope. | ||
}); | ||
request.end(data); | ||
if (headers.Connection !== 'keep-alive') { | ||
request.end(data); | ||
} | ||
return request; | ||
}; | ||
exports.request = httpRequest; |
@@ -7,5 +7,56 @@ 'use strict'; | ||
function ClientSSLSecurity(keyPath, certPath, defaults) { | ||
this.key = fs.readFileSync(keyPath); | ||
this.cert = fs.readFileSync(certPath); | ||
/** | ||
* activates SSL for an already existing client | ||
* | ||
* @module ClientSSLSecurity | ||
* @param {Buffer|String} key | ||
* @param {Buffer|String} cert | ||
* @param {Buffer|String} [ca] | ||
* @param {Object} [defaults] | ||
* @constructor | ||
*/ | ||
function ClientSSLSecurity(key, cert, ca, defaults) { | ||
if (key) { | ||
if(Buffer.isBuffer(key)) { | ||
this.key = key; | ||
} else if (typeof key === 'string') { | ||
this.key = fs.readFileSync(key); | ||
} else { | ||
throw new Error('key should be a buffer or a string!'); | ||
} | ||
if(this.key.toString().lastIndexOf('-----BEGIN RSA PRIVATE KEY-----', 0) !== 0) { | ||
throw new Error('key should start with -----BEGIN RSA PRIVATE KEY-----'); | ||
} | ||
} | ||
if (cert) { | ||
if(Buffer.isBuffer(cert)) { | ||
this.cert = cert; | ||
} else if (typeof cert === 'string') { | ||
this.cert = fs.readFileSync(cert); | ||
} else { | ||
throw new Error('cert should be a buffer or a string!'); | ||
} | ||
if(this.cert.toString().lastIndexOf('-----BEGIN CERTIFICATE-----', 0) !== 0) { | ||
throw new Error('cert should start with -----BEGIN CERTIFICATE-----'); | ||
} | ||
} | ||
if (ca) { | ||
if(Buffer.isBuffer(ca)) { | ||
this.ca = ca; | ||
} else if (typeof ca === 'string') { | ||
this.ca = fs.readFileSync(ca); | ||
} else { | ||
defaults = ca; | ||
this.ca = null; | ||
} | ||
if(this.ca && this.ca.toString().lastIndexOf('-----BEGIN CERTIFICATE-----', 0) !== 0) { | ||
throw new Error('ca should start with -----BEGIN CERTIFICATE-----'); | ||
} | ||
} | ||
this.defaults = {}; | ||
@@ -22,2 +73,3 @@ _.merge(this.defaults, defaults); | ||
options.cert = this.cert; | ||
options.ca = this.ca; | ||
_.merge(options, this.defaults); | ||
@@ -24,0 +76,0 @@ options.agent = new https.Agent(options); |
@@ -14,2 +14,14 @@ /* | ||
function getDateString(d) { | ||
function pad(n) { | ||
return n < 10 ? '0' + n : n; | ||
} | ||
return d.getUTCFullYear() + '-' | ||
+ pad(d.getUTCMonth() + 1) + '-' | ||
+ pad(d.getUTCDate()) + 'T' | ||
+ pad(d.getUTCHours()) + ':' | ||
+ pad(d.getUTCMinutes()) + ':' | ||
+ pad(d.getUTCSeconds()) + 'Z'; | ||
} | ||
var url = require('url'), | ||
@@ -143,3 +155,4 @@ compress = null, | ||
method, methodName, | ||
serviceName, portName; | ||
serviceName, portName, | ||
includeTimestamp = obj.Header && obj.Header.Security && obj.Header.Security.Timestamp; | ||
@@ -197,2 +210,3 @@ if (typeof self.authenticate === 'function') { | ||
self.emit('request', obj, methodName); | ||
if (headers) | ||
@@ -214,2 +228,3 @@ self.emit('headers', headers, methodName); | ||
self.emit('request', obj, pair.methodName); | ||
if (headers) | ||
@@ -226,3 +241,3 @@ self.emit('headers', headers, pair.methodName); | ||
style: 'document' | ||
}, callback); | ||
}, callback, includeTimestamp); | ||
} | ||
@@ -235,3 +250,3 @@ } | ||
var fault = self.wsdl.objectToDocumentXML("Fault", e.Fault, "soap"); | ||
callback(self._envelope(fault)); | ||
callback(self._envelope(fault, includeTimestamp)); | ||
} | ||
@@ -243,3 +258,3 @@ else | ||
Server.prototype._executeMethod = function(options, callback) { | ||
Server.prototype._executeMethod = function(options, callback, includeTimestamp) { | ||
options = options || {}; | ||
@@ -259,3 +274,3 @@ var self = this, | ||
} catch (e) { | ||
return callback(this._envelope('')); | ||
return callback(this._envelope('', includeTimestamp)); | ||
} | ||
@@ -274,5 +289,11 @@ | ||
} | ||
callback(self._envelope(body)); | ||
callback(self._envelope(body, includeTimestamp)); | ||
} | ||
if(!self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output){ | ||
// no output defined = one-way operation so return empty response | ||
handled = true; | ||
callback(''); | ||
} | ||
var result = method(args, handleResult, options.headers); | ||
@@ -284,3 +305,3 @@ if (typeof result !== 'undefined') { | ||
Server.prototype._envelope = function(body) { | ||
Server.prototype._envelope = function(body, includeTimestamp) { | ||
var defs = this.wsdl.definitions, | ||
@@ -293,4 +314,20 @@ ns = defs.$targetNamespace, | ||
encoding + | ||
this.wsdl.xmlnsInEnvelope + '>' + | ||
"<soap:Body>" + | ||
this.wsdl.xmlnsInEnvelope + '>'; | ||
if (includeTimestamp) { | ||
var now = new Date(); | ||
var created = getDateString(now); | ||
var expires = getDateString(new Date(now.getTime() + (1000 * 600))); | ||
xml += "<soap:Header>" + | ||
" <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>" + | ||
"</soap:Header>"; | ||
} | ||
xml += "<soap:Body>" + | ||
body + | ||
@@ -297,0 +334,0 @@ "</soap:Body>" + |
@@ -18,2 +18,3 @@ /* | ||
var stripBom = require('strip-bom'); | ||
var debug = require('debug')('node-soap'); | ||
var _ = require('lodash'); | ||
@@ -91,7 +92,8 @@ | ||
function extend(base, obj) { | ||
Object.keys(obj).forEach(function(key) { | ||
if(!base.hasOwnProperty(key)) | ||
base[key] = obj[key]; | ||
}); | ||
if(base !== null && typeof base === "object" && obj !== null && typeof obj === "object"){ | ||
Object.keys(obj).forEach(function(key) { | ||
if(!base.hasOwnProperty(key)) | ||
base[key] = obj[key]; | ||
}); | ||
} | ||
return base; | ||
@@ -487,3 +489,3 @@ } | ||
if(!this.element) { | ||
console.log(nsName.name + " is not present in wsdl and cannot be processed correctly."); | ||
debug(nsName.name + " is not present in wsdl and cannot be processed correctly."); | ||
return; | ||
@@ -1046,3 +1048,3 @@ } | ||
for (var methodName in methods) { | ||
if (methods[methodName].input && methods[methodName].output) { | ||
if (methods[methodName].input) { | ||
var inputName = methods[methodName].input.$name; | ||
@@ -1090,2 +1092,6 @@ var outputName=""; | ||
this.options.xmlKey = options.xmlKey || this.xmlKey; | ||
// Allow any request headers to keep passing through | ||
this.options.wsdl_headers = options.wsdl_headers; | ||
this.options.wsdl_options = options.wsdl_options; | ||
}; | ||
@@ -1112,3 +1118,3 @@ | ||
open_wsdl(includePath, function(err, wsdl) { | ||
open_wsdl(includePath, this.options, function(err, wsdl) { | ||
if (err) { | ||
@@ -1538,2 +1544,3 @@ return callback(err); | ||
var value = ''; | ||
var nonSubNameSpace = ''; | ||
if (first) { | ||
@@ -1590,3 +1597,3 @@ value = self.objectToXML(child, name, namespace, xmlns, false, null, parameterTypeObject, ancXmlns); | ||
ns = obj[self.options.attributesKey].xsi_type.namespace + ':'; | ||
nonSubNameSpace = obj[self.options.attributesKey].xsi_type.namespace + ':'; | ||
ancXmlns.push(obj[self.options.attributesKey].xsi_type.xmlns); | ||
@@ -1604,3 +1611,3 @@ value = self.objectToXML(child, name, obj[self.options.attributesKey].xsi_type.namespace, obj[self.options.attributesKey].xsi_type.xmlns, false, null, null, ancXmlns); | ||
if (!Array.isArray(child)) { | ||
parts.push(['<', ns, name, attr, xmlnsAttrib, '>'].join('')); | ||
parts.push(['<', nonSubNameSpace || ns, name, attr, xmlnsAttrib, (child === null ? ' xsi:nil="true"' : ''), '>'].join('')); | ||
} | ||
@@ -1610,3 +1617,3 @@ | ||
if (!Array.isArray(child)) { | ||
parts.push(['</', ns, name, '>'].join('')); | ||
parts.push(['</', nonSubNameSpace || ns, name, '>'].join('')); | ||
} | ||
@@ -1624,2 +1631,6 @@ } | ||
if(child === null) { | ||
child = []; | ||
} | ||
if (child[this.options.attributesKey] && child[this.options.attributesKey].xsi_type) { | ||
@@ -1730,2 +1741,4 @@ var xsiType = child[this.options.attributesKey].xsi_type; | ||
root = null, | ||
types = null, | ||
schema = null, | ||
options = self.options; | ||
@@ -1753,8 +1766,14 @@ | ||
root = new DefinitionsElement(nsName, attrs, options); | ||
stack.push(root); | ||
} else if (name === 'schema') { | ||
root = new SchemaElement(nsName, attrs, options); | ||
// Shim a structure in here to allow the proper objects to be created when merging back. | ||
root = new DefinitionsElement('definitions', {}, {}); | ||
types = new TypesElement('types', {}, {}); | ||
schema = new SchemaElement(nsName, attrs, options); | ||
types.addChild(schema); | ||
root.addChild(types); | ||
stack.push(schema); | ||
} else { | ||
throw new Error('Unexpected root element of WSDL or include'); | ||
} | ||
stack.push(root); | ||
} | ||
@@ -1824,5 +1843,2 @@ }; | ||
delete options.wsdl_headers; | ||
delete options.wsdl_options; | ||
var wsdl; | ||
@@ -1829,0 +1845,0 @@ if (!/^http/.test(uri)) { |
{ | ||
"name": "soap", | ||
"version": "0.8.0", | ||
"version": "0.9.0", | ||
"description": "A minimal node SOAP client", | ||
@@ -13,3 +13,4 @@ "engines": { | ||
"sax": ">=0.6", | ||
"strip-bom": "~0.3.1" | ||
"strip-bom": "~0.3.1", | ||
"debug": "~0.7.4" | ||
}, | ||
@@ -16,0 +17,0 @@ "repository": { |
@@ -90,2 +90,14 @@ # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] | ||
### Server Events | ||
Server instances emit the following events: | ||
* request - Emitted for every received messages. | ||
The signature of the callback is `function(request, methodName)`. | ||
* headers - Emitted when the SOAP Headers are not empty. | ||
The signature of the callback is `function(headers, methodName)`. | ||
The sequence order of the calls is `request`, `headers` and then the dedicated | ||
service method. | ||
### SOAP Fault | ||
@@ -275,2 +287,5 @@ | ||
Useful if you want to globally log errors. | ||
* response - Emitted after a response is received. The event handler receives | ||
the entire response body. This is emitted for all responses (both success and | ||
errors). | ||
@@ -277,0 +292,0 @@ |
Sorry, the diff of this file is not supported yet
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
135968
2434
448
5
+ Addeddebug@~0.7.4
+ Addeddebug@0.7.4(transitive)