Socket
Socket
Sign inDemoInstall

soap

Package Overview
Dependencies
Maintainers
2
Versions
95
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

soap - npm Package Compare versions

Comparing version 0.3.2 to 0.4.0

.jshintrc

13

History.md

@@ -0,2 +1,15 @@

0.4.0 / 2014-02-15
==================
* package; increased minor version to 0.4 (xml parser change, tests)
* remove execute privileges on files #216
* add travis #219
* add jshint for index.js #220
* remove execute permissions on .gitignore #227
* fixed; fix requests if SOAP service is not on port 80, do not crash on errors #228
* fixed; undefined value for json in client method when message names end with Out or Output. #243
* add non xmlns attributes to elements during response parsing #241
* package; replace expat dependency with sax #246
* fixed; "Uncaught TypeError: Cannot read property '0' of undefined" #248
0.3.2 / 2014-01-21

@@ -3,0 +16,0 @@ ==================

2

index.js

@@ -0,1 +1,3 @@

"use strict";
module.exports = require('./lib/soap');

274

lib/client.js

@@ -5,164 +5,170 @@ /*

*/
"use strict";
function findKey(obj, val) {
for (var n in obj) if (obj[n] === val) return n;
for (var n in obj)
if (obj[n] === val)
return n;
}
var http = require('./http'),
assert = require('assert'),
url = require('url');
assert = require('assert'),
url = require('url');
var Client = function(wsdl, endpoint) {
this.wsdl = wsdl;
this._initializeServices(endpoint);
}
this.wsdl = wsdl;
this._initializeServices(endpoint);
};
Client.prototype.addSoapHeader = function(soapHeader, name, namespace, xmlns) {
if(!this.soapHeaders){
this.soapHeaders = [];
}
if(typeof soapHeader == 'object'){
soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns);
}
this.soapHeaders.push(soapHeader);
}
if (!this.soapHeaders) {
this.soapHeaders = [];
}
if (typeof soapHeader === 'object') {
soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns);
}
this.soapHeaders.push(soapHeader);
};
Client.prototype.setEndpoint = function(endpoint) {
this.endpoint = endpoint;
this._initializeServices(endpoint);
}
this.endpoint = endpoint;
this._initializeServices(endpoint);
};
Client.prototype.describe = function() {
var types = this.wsdl.definitions.types;
return this.wsdl.describeServices();
}
var types = this.wsdl.definitions.types;
return this.wsdl.describeServices();
};
Client.prototype.setSecurity = function(security) {
this.security = security;
}
this.security = security;
};
Client.prototype.setSOAPAction = function(SOAPAction) {
this.SOAPAction = SOAPAction;
}
this.SOAPAction = SOAPAction;
};
Client.prototype._initializeServices = function(endpoint) {
var definitions = this.wsdl.definitions,
services = definitions.services;
for (var name in services) {
this[name] = this._defineService(services[name], endpoint);
}
}
var definitions = this.wsdl.definitions,
services = definitions.services;
for (var name in services) {
this[name] = this._defineService(services[name], endpoint);
}
};
Client.prototype._defineService = function(service, endpoint) {
var ports = service.ports,
def = {};
for (var name in ports) {
def[name] = this._definePort(ports[name], endpoint ? endpoint : ports[name].location);
}
return def;
}
var ports = service.ports,
def = {};
for (var name in ports) {
def[name] = this._definePort(ports[name], endpoint ? endpoint : ports[name].location);
}
return def;
};
Client.prototype._definePort = function(port, endpoint) {
var location = endpoint,
binding = port.binding,
methods = binding.methods,
def = {};
for (var name in methods) {
def[name] = this._defineMethod(methods[name], location);
this[name] = def[name];
}
return def;
}
var location = endpoint,
binding = port.binding,
methods = binding.methods,
def = {};
for (var name in methods) {
def[name] = this._defineMethod(methods[name], location);
this[name] = def[name];
}
return def;
};
Client.prototype._defineMethod = function(method, location) {
var self = this;
return function(args, callback, options) {
if (typeof args === 'function') {
callback = args;
args = {};
}
self._invoke(method, args, location, function(error, result, raw) {
callback(error, result, raw);
}, options)
var self = this;
return function(args, callback, options) {
if (typeof args === 'function') {
callback = args;
args = {};
}
}
self._invoke(method, args, location, function(error, result, raw) {
callback(error, result, raw);
}, options);
};
};
Client.prototype._invoke = function(method, arguments, location, callback, options) {
var self = this,
name = method.$name,
input = method.input,
output = method.output,
style = method.style,
defs = this.wsdl.definitions,
ns = defs.$targetNamespace,
encoding = '',
message = '',
xml = null,
soapAction = this.SOAPAction ? this.SOAPAction(ns, name) : (method.soapAction || (((ns.lastIndexOf("/") != ns.length - 1) ? ns + "/" : ns) + name)),
headers = {
SOAPAction: '"' + soapAction + '"',
'Content-Type': "text/xml; charset=utf-8"
},
options = options || {},
alias = findKey(defs.xmlns, ns);
// Allow the security object to add headers
if (self.security && self.security.addHeaders)
self.security.addHeaders(headers);
if (self.security && self.security.addOptions)
self.security.addOptions(options);
if (input.parts) {
assert.ok(!style || style == 'rpc', 'invalid message definition for document style binding');
message = self.wsdl.objectToRpcXML(name, arguments, alias, ns);
(method.inputSoap === 'encoded') && (encoding = 'soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" ');
Client.prototype._invoke = function(method, args, location, callback, options) {
var self = this,
name = method.$name,
input = method.input,
output = method.output,
style = method.style,
defs = this.wsdl.definitions,
ns = defs.$targetNamespace,
encoding = '',
message = '',
xml = null,
soapAction = this.SOAPAction ? this.SOAPAction(ns, name) : (method.soapAction || (((ns.lastIndexOf("/") !== ns.length - 1) ? ns + "/" : ns) + name)),
headers = {
SOAPAction: '"' + soapAction + '"',
'Content-Type': "text/xml; charset=utf-8"
},
alias = findKey(defs.xmlns, ns);
options = options || {};
// Allow the security object to add headers
if (self.security && self.security.addHeaders)
self.security.addHeaders(headers);
if (self.security && self.security.addOptions)
self.security.addOptions(options);
if (input.parts) {
assert.ok(!style || style === 'rpc', 'invalid message definition for document style binding');
message = self.wsdl.objectToRpcXML(name, args, alias, ns);
(method.inputSoap === 'encoded') && (encoding = 'soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" ');
} else if (typeof (args) === 'string') {
message = args;
} else {
assert.ok(!style || style === 'document', 'invalid message definition for rpc style binding');
message = self.wsdl.objectToDocumentXML(input.$name, args, input.targetNSAlias, input.targetNamespace);
}
xml = "<soap:Envelope " +
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
encoding +
this.wsdl.xmlnsInEnvelope + '>' +
"<soap:Header>" +
(self.soapHeaders ? self.soapHeaders.join("\n") : "") +
(self.security ? self.security.toXML() : "") +
"</soap:Header>" +
"<soap:Body>" +
message +
"</soap:Body>" +
"</soap:Envelope>";
self.lastRequest = xml;
http.request(location, xml, function(err, response, body) {
var result;
var obj;
self.lastResponse = body;
self.lastResponseHeaders = response && response.headers;
if (err) {
callback(err);
} else {
try {
obj = self.wsdl.xmlToObject(body);
} catch (error) {
error.response = response;
error.body = body;
return callback(error, response, body);
}
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)$/, '')];
}
callback(null, result, body);
}
else if (typeof(arguments) === 'string') {
message = arguments;
}
else {
assert.ok(!style || style == 'document', 'invalid message definition for rpc style binding');
message = self.wsdl.objectToDocumentXML(input.$name, arguments, input.targetNSAlias, input.targetNamespace);
}
xml = "<soap:Envelope " +
"xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
encoding +
this.wsdl.xmlnsInEnvelope + '>' +
"<soap:Header>" +
(self.soapHeaders ? self.soapHeaders.join("\n") : "") +
(self.security ? self.security.toXML() : "") +
"</soap:Header>" +
"<soap:Body>" +
message +
"</soap:Body>" +
"</soap:Envelope>";
self.lastRequest = xml;
http.request(location, xml, function(err, response, body) {
self.lastResponse = body;
self.lastResponseHeaders = response.headers;
if (err) {
callback(err);
}
else {
try {
var obj = self.wsdl.xmlToObject(body);
}
catch (error) {
error.response = response;
error.body = body;
return callback(error, response, body);
}
var result = obj.Body[output.$name];
// RPC/literal response body may contain element named after the method + 'Response'
// This doesn't necessarily equal the ouput message name. See WSDL 1.1 Section 2.4.5
if(!result) {
result = obj.Body[name + 'Response'];
}
callback(null, result, body);
}
}, headers, options);
}
}, headers, options);
};
exports.Client = Client;

@@ -6,49 +6,52 @@ /*

var url = require('url'),
req = require('request');
"use strict";
var url = require('url');
var req = require('request');
var VERSION = "0.2.0";
exports.request = function(rurl, data, callback, exheaders, exoptions) {
var curl = url.parse(rurl);
var secure = curl.protocol == 'https:';
var host = curl.hostname;
var port = parseInt(curl.port || (secure ? 443 : 80));
var path = [curl.pathname || '/', curl.search || '', curl.hash || ''].join('');
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
};
var curl = url.parse(rurl);
var secure = curl.protocol === 'https:';
var host = curl.hostname;
var port = parseInt(curl.port || (secure ? 443 : 80));
var path = [curl.pathname || '/', curl.search || '', curl.hash || ''].join('');
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 + (port ? ":"+port : "")
};
var attr;
if (typeof data == 'string') {
headers["Content-Length"] = Buffer.byteLength(data, 'utf8');;
headers["Content-Type"] = "application/x-www-form-urlencoded";
}
if (typeof data === 'string') {
headers["Content-Length"] = Buffer.byteLength(data, 'utf8');
headers["Content-Type"] = "application/x-www-form-urlencoded";
}
exheaders = exheaders || {};
for (var attr in exheaders) { headers[attr] = exheaders[attr]; }
exheaders = exheaders || {};
for (attr in exheaders) { headers[attr] = exheaders[attr]; }
var options = {
uri: curl,
method: method,
headers: headers
};
var options = {
uri: curl,
method: method,
headers: headers
};
exoptions = exoptions || {};
for (var attr in exoptions) { options[attr] = exoptions[attr]; }
exoptions = exoptions || {};
for (attr in exoptions) { options[attr] = exoptions[attr]; }
var request = req(options, function (error, res, body) {
if (error) {
callback(error);
} else {
request.on('error', callback);
callback(null, res, body);
}
});
request.end(data);
}
var request = req(options, function (error, res, body) {
if (error) {
callback(error);
} else {
request.on('error', callback);
callback(null, res, body);
}
});
request.end(data);
};

@@ -6,238 +6,252 @@ /*

"use strict";
function findKey(obj, val) {
for (var n in obj) if (obj[n] === val) return n;
for (var n in obj)
if (obj[n] === val)
return n;
}
var url = require('url'),
compress = null;
compress = null;
try { compress = require("compress"); } catch(e) {}
try {
compress = require("compress");
} catch (e) {
}
var Server = function(server, path, services, wsdl) {
var self = this;
var self = this;
this.path = path;
this.services = services;
this.wsdl = wsdl;
this.path = path;
this.services = services;
this.wsdl = wsdl;
if (path[path.length-1] != '/') path += '/';
wsdl.onReady(function(err) {
var listeners = server.listeners('request').slice();
if (path[path.length - 1] !== '/')
path += '/';
wsdl.onReady(function(err) {
var listeners = server.listeners('request').slice();
server.removeAllListeners('request');
server.addListener('request', function(req, res) {
if (typeof self.authorizeConnection === 'function') {
if (!self.authorizeConnection(req.connection.remoteAddress)) {
res.end();
return;
}
}
var reqPath = url.parse(req.url).pathname;
if (reqPath[reqPath.length-1] != '/') reqPath += '/';
if (path === reqPath) {
self._requestListener(req, res);
}
else {
for (var i = 0, len = listeners.length; i < len; i++){
listeners[i].call(this, req, res);
}
}
});
})
}
server.removeAllListeners('request');
server.addListener('request', function(req, res) {
if (typeof self.authorizeConnection === 'function') {
if (!self.authorizeConnection(req.connection.remoteAddress)) {
res.end();
return;
}
}
var reqPath = url.parse(req.url).pathname;
if (reqPath[reqPath.length - 1] !== '/')
reqPath += '/';
if (path === reqPath) {
self._requestListener(req, res);
} else {
for (var i = 0, len = listeners.length; i < len; i++) {
listeners[i].call(this, req, res);
}
}
});
});
};
Server.prototype._requestListener = function(req, res) {
var self = this;
var reqParse = url.parse(req.url);
var reqPath = reqParse.pathname;
var reqQuery = reqParse.search;
var self = this;
var reqParse = url.parse(req.url);
var reqPath = reqParse.pathname;
var reqQuery = reqParse.search;
if (typeof self.log === 'function') {
self.log("info", "Handling "+req.method+" on "+req.url);
}
if (typeof self.log === 'function') {
self.log("info", "Handling " + req.method + " on " + req.url);
}
if (req.method === 'GET') {
if (reqQuery && reqQuery.toLowerCase() === '?wsdl') {
if (typeof self.log === 'function') {
self.log("info", "Wants the WSDL");
}
res.setHeader("Content-Type", "application/xml");
res.write(self.wsdl.toXML());
}
res.end();
if (req.method === 'GET') {
if (reqQuery && reqQuery.toLowerCase() === '?wsdl') {
if (typeof self.log === 'function') {
self.log("info", "Wants the WSDL");
}
res.setHeader("Content-Type", "application/xml");
res.write(self.wsdl.toXML());
}
else if (req.method === 'POST') {
res.setHeader('Content-Type', req.headers['content-type']);
var chunks = [], gunzip;
if (compress && req.headers["content-encoding"] == "gzip") {
gunzip = new compress.Gunzip;
gunzip.init();
}
req.on('data', function(chunk) {
if (gunzip) chunk = gunzip.inflate(chunk, "binary");
chunks.push(chunk);
})
req.on('end', function() {
var xml = chunks.join(''), result;
if (gunzip) {
gunzip.end();
gunzip = null
}
try {
self._process(xml, req.url, function(result) {
res.write(result);
res.end();
if (typeof self.log === 'function') {
self.log("received", xml);
self.log("replied", result);
}
});
}
catch(err) {
err = err.stack || err;
res.write(err);
res.end();
if (typeof self.log === 'function') {
self.log("error", err);
}
}
res.end();
} else if (req.method === 'POST') {
res.setHeader('Content-Type', req.headers['content-type']);
var chunks = [], gunzip;
if (compress && req.headers["content-encoding"] === "gzip") {
gunzip = new compress.Gunzip();
gunzip.init();
}
req.on('data', function(chunk) {
if (gunzip)
chunk = gunzip.inflate(chunk, "binary");
chunks.push(chunk);
});
req.on('end', function() {
var xml = chunks.join('');
var result;
var error;
if (gunzip) {
gunzip.end();
gunzip = null;
}
try {
self._process(xml, req.url, function(result) {
res.write(result);
res.end();
if (typeof self.log === 'function') {
self.log("received", xml);
self.log("replied", result);
}
});
}
else {
}
catch (err) {
error = err.stack || err;
res.write(error);
res.end();
}
}
if (typeof self.log === 'function') {
self.log("error", error);
}
}
});
}
else {
res.end();
}
};
Server.prototype._process = function(input, URL, callback) {
var self = this,
pathname = url.parse(URL).pathname.replace(/\/$/,''),
obj = this.wsdl.xmlToObject(input),
body = obj.Body,
bindings = this.wsdl.definitions.bindings, binding,
methods, method, methodName,
serviceName, portName;
if (typeof self.authenticate === 'function') {
if (obj.Header == null || obj.Header.Security == null) {
throw new Error('No security header');
}
if (!self.authenticate(obj.Header.Security)) {
throw new Error('Invalid username or password');
}
var self = this,
pathname = url.parse(URL).pathname.replace(/\/$/, ''),
obj = this.wsdl.xmlToObject(input),
body = obj.Body,
bindings = this.wsdl.definitions.bindings, binding,
methods, method, methodName,
serviceName, portName;
if (typeof self.authenticate === 'function') {
if (!obj.Header || !obj.Header.Security) {
throw new Error('No security header');
}
if (typeof self.log === 'function') {
self.log("info", "Attempting to bind to "+pathname);
if (!self.authenticate(obj.Header.Security)) {
throw new Error('Invalid username or password');
}
}
// use port.location and current url to find the right binding
binding = (function(self){
var services = self.wsdl.definitions.services;
var firstPort = undefined;
for(serviceName in services ) {
var service = services[serviceName];
var ports = service.ports;
for(portName in ports) {
var port = ports[portName];
var portPathname = url.parse(port.location).pathname.replace(/\/$/,'');
if (typeof self.log === 'function') {
self.log("info", "Attempting to bind to " + pathname);
}
if (typeof self.log === 'function') {
self.log("info", "Trying "+portName+" from path "+portPathname);
}
// use port.location and current url to find the right binding
binding = (function(self) {
var services = self.wsdl.definitions.services;
var firstPort;
var name;
for (name in services) {
serviceName = name;
var service = services[serviceName];
var ports = service.ports;
for (name in ports) {
portName = name;
var port = ports[portName];
var portPathname = url.parse(port.location).pathname.replace(/\/$/, '');
if(portPathname===pathname)
return port.binding;
// The port path is almost always wrong for genrated WSDLs
if(firstPort == undefined) {
firstPort = port;
}
}
if (typeof self.log === 'function') {
self.log("info", "Trying " + portName + " from path " + portPathname);
}
return firstPort == undefined ? undefined : firstPort.binding;
})(this);
if (!binding) {
throw new Error('Failed to bind to WSDL');
if (portPathname === pathname)
return port.binding;
// The port path is almost always wrong for genrated WSDLs
if (!firstPort) {
firstPort = port;
}
}
}
return !firstPort ? void 0 : firstPort.binding;
})(this);
methods = binding.methods;
if (!binding) {
throw new Error('Failed to bind to WSDL');
}
if(binding.style === 'rpc') {
methodName = Object.keys(body)[0];
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: methodName,
outputName: methodName + 'Response',
args: body[methodName],
style: 'rpc'
}, callback);
} else {
var messageElemName = Object.keys(body)[0];
var pair = binding.topElements[messageElemName];
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: pair.methodName,
outputName: pair.outputName,
args: body[messageElemName],
style: 'document'
}, callback);
}
}
methods = binding.methods;
if (binding.style === 'rpc') {
methodName = Object.keys(body)[0];
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: methodName,
outputName: methodName + 'Response',
args: body[methodName],
style: 'rpc'
}, callback);
} else {
var messageElemName = Object.keys(body)[0];
var pair = binding.topElements[messageElemName];
self._executeMethod({
serviceName: serviceName,
portName: portName,
methodName: pair.methodName,
outputName: pair.outputName,
args: body[messageElemName],
style: 'document'
}, callback);
}
};
Server.prototype._executeMethod = function(options, callback) {
options = options || {};
var self = this,
method, body,
serviceName = options.serviceName,
portName = options.portName,
methodName = options.methodName,
outputName = options.outputName,
args = options.args,
style = options.style,
handled = false;
options = options || {};
var self = this,
method, body,
serviceName = options.serviceName,
portName = options.portName,
methodName = options.methodName,
outputName = options.outputName,
args = options.args,
style = options.style,
handled = false;
try {
method = this.services[serviceName][portName][methodName];
} catch(e) {
return callback(this._envelope(''));
}
try {
method = this.services[serviceName][portName][methodName];
} catch (e) {
return callback(this._envelope(''));
}
function handleResult(result) {
if (handled) return;
handled = true;
function handleResult(result) {
if (handled)
return;
handled = true;
if(style==='rpc') {
body = self.wsdl.objectToRpcXML(outputName, result, '', self.wsdl.definitions.$targetNamespace);
} else {
var element = self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output;
body = self.wsdl.objectToDocumentXML(outputName, result, element.targetNSAlias, element.targetNamespace);
}
callback(self._envelope(body));
if (style === 'rpc') {
body = self.wsdl.objectToRpcXML(outputName, result, '', self.wsdl.definitions.$targetNamespace);
} else {
var element = self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output;
body = self.wsdl.objectToDocumentXML(outputName, result, element.targetNSAlias, element.targetNamespace);
}
callback(self._envelope(body));
}
var result = method(args, handleResult);
if (typeof result !== 'undefined') {
handleResult(result);
}
}
var result = method(args, handleResult);
if (typeof result !== 'undefined') {
handleResult(result);
}
};
Server.prototype._envelope = function(body) {
var defs = this.wsdl.definitions,
ns = defs.$targetNamespace,
encoding = '',
alias = findKey(defs.xmlns, ns);
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
encoding +
this.wsdl.xmlnsInEnvelope + '>' +
"<soap:Body>" +
body +
"</soap:Body>" +
"</soap:Envelope>";
return xml;
}
var defs = this.wsdl.definitions,
ns = defs.$targetNamespace,
encoding = '',
alias = findKey(defs.xmlns, ns);
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
encoding +
this.wsdl.xmlnsInEnvelope + '>' +
"<soap:Body>" +
body +
"</soap:Body>" +
"</soap:Envelope>";
return xml;
};
exports.Server = Server;

@@ -6,9 +6,11 @@ /*

"use strict";
var Client = require('./client').Client,
Server = require('./server').Server,
open_wsdl = require('./wsdl').open_wsdl,
crypto = require('crypto'),
WSDL = require('./wsdl').WSDL,
https = require('https'),
fs = require('fs');
Server = require('./server').Server,
open_wsdl = require('./wsdl').open_wsdl,
crypto = require('crypto'),
WSDL = require('./wsdl').WSDL,
https = require('https'),
fs = require('fs');

@@ -19,129 +21,131 @@ var WSDL = require('./wsdl').WSDL;

function _requestWSDL(url, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
if (typeof options === 'function') {
callback = options;
options = {};
}
var wsdl = _wsdlCache[url];
if (wsdl) {
callback(null, wsdl);
}
else {
open_wsdl(url, options, function(err, wsdl) {
if (err)
return callback(err);
else
_wsdlCache[url] = wsdl;
callback(null, wsdl);
})
}
var wsdl = _wsdlCache[url];
if (wsdl) {
callback(null, wsdl);
}
else {
open_wsdl(url, options, function(err, wsdl) {
if (err)
return callback(err);
else
_wsdlCache[url] = wsdl;
callback(null, wsdl);
});
}
}
function createClient(url, options, callback, endpoint) {
if (typeof options === 'function') {
endpoint = callback;
callback = options;
options = {};
}
endpoint = options.endpoint || endpoint;
_requestWSDL(url, options, function(err, wsdl) {
callback(err, wsdl && new Client(wsdl, endpoint));
})
if (typeof options === 'function') {
endpoint = callback;
callback = options;
options = {};
}
endpoint = options.endpoint || endpoint;
_requestWSDL(url, options, function(err, wsdl) {
callback(err, wsdl && new Client(wsdl, endpoint));
});
}
function listen(server, pathOrOptions, services, xml) {
var options = {},
path = pathOrOptions;
var options = {},
path = pathOrOptions;
if (typeof pathOrOptions === 'object') {
options = pathOrOptions;
path = options.path;
services = options.services;
xml = options.xml;
}
if (typeof pathOrOptions === 'object') {
options = pathOrOptions;
path = options.path;
services = options.services;
xml = options.xml;
}
var wsdl = new WSDL(xml || services, null, options);
return new Server(server, path, services, wsdl);
var wsdl = new WSDL(xml || services, null, options);
return new Server(server, path, services, wsdl);
}
function BasicAuthSecurity(username, password) {
this._username = username;
this._password = password;
this._username = username;
this._password = password;
}
BasicAuthSecurity.prototype.addHeaders = function (headers) {
headers['Authorization'] = "Basic " + new Buffer((this._username + ':' + this._password) || '').toString('base64');
}
BasicAuthSecurity.prototype.addHeaders = function(headers) {
headers.Authorization = "Basic " + new Buffer((this._username + ':' + this._password) || '').toString('base64');
};
BasicAuthSecurity.prototype.toXML = function() {
return "";
}
return "";
};
function ClientSSLSecurity(keyPath, certPath) {
this.key = fs.readFileSync(keyPath);
this.cert = fs.readFileSync(certPath);
this.key = fs.readFileSync(keyPath);
this.cert = fs.readFileSync(certPath);
}
ClientSSLSecurity.prototype.toXML = function (headers) {
return "";
}
ClientSSLSecurity.prototype.toXML = function(headers) {
return "";
};
ClientSSLSecurity.prototype.addOptions = function (options) {
options.key = this.key;
options.cert = this.cert;
options.agent = new https.Agent(options);
}
ClientSSLSecurity.prototype.addOptions = function(options) {
options.key = this.key;
options.cert = this.cert;
options.agent = new https.Agent(options);
};
function WSSecurity(username, password, passwordType) {
this._username = username;
this._password = password;
this._passwordType = passwordType || 'PasswordText';
this._username = username;
this._password = password;
this._passwordType = passwordType || 'PasswordText';
}
var passwordDigest = function(nonce, created, password) {
// digest = base64 ( sha1 ( nonce + created + password ) )
var pwHash = crypto.createHash('sha1');
var rawNonce = new Buffer(nonce || '', 'base64').toString('binary');
pwHash.update(rawNonce + created + password);
var passwordDigest = pwHash.digest('base64');
return passwordDigest;
}
// digest = base64 ( sha1 ( nonce + created + password ) )
var pwHash = crypto.createHash('sha1');
var rawNonce = new Buffer(nonce || '', 'base64').toString('binary');
pwHash.update(rawNonce + created + password);
var passwordDigest = pwHash.digest('base64');
return passwordDigest;
};
WSSecurity.prototype.toXML = function() {
// avoid dependency on date formatting libraries
function getDate(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';
// avoid dependency on date formatting libraries
function getDate(d) {
function pad(n) {
return n < 10 ? '0' + n : n;
}
var now = new Date();
var created = getDate( now );
var expires = getDate( new Date(now.getTime() + (1000 * 600)) );
return d.getUTCFullYear() + '-'
+ pad(d.getUTCMonth() + 1) + '-'
+ pad(d.getUTCDate()) + 'T'
+ pad(d.getUTCHours()) + ':'
+ pad(d.getUTCMinutes()) + ':'
+ pad(d.getUTCSeconds()) + 'Z';
}
var now = new Date();
var created = getDate(now);
var expires = getDate(new Date(now.getTime() + (1000 * 600)));
// nonce = base64 ( sha1 ( created + random ) )
var nHash = crypto.createHash('sha1');
nHash.update(created + Math.random());
var nonce = nHash.digest('base64');
// nonce = base64 ( sha1 ( created + random ) )
var nHash = crypto.createHash('sha1');
nHash.update(created + Math.random());
var nonce = nHash.digest('base64');
return "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
"<wsu:Timestamp wsu:Id=\"Timestamp-"+created+"\">" +
"<wsu:Created>"+created+"</wsu:Created>" +
"<wsu:Expires>"+expires+"</wsu:Expires>" +
"</wsu:Timestamp>" +
"<wsse:UsernameToken xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=\"SecurityToken-"+created+"\">" +
"<wsse:Username>"+this._username+"</wsse:Username>" +
(this._passwordType === 'PasswordText' ?
"<wsse:Password>"+this._password+"</wsse:Password>"
:
"<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">"+passwordDigest(nonce, created, this._password)+"</wsse:Password>"
) +
"<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">"+nonce+"</wsse:Nonce>" +
"<wsu:Created>"+created+"</wsu:Created>" +
"</wsse:UsernameToken>" +
"</wsse:Security>"
}
return "<wsse:Security xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
"<wsu:Timestamp wsu:Id=\"Timestamp-" + created + "\">" +
"<wsu:Created>" + created + "</wsu:Created>" +
"<wsu:Expires>" + expires + "</wsu:Expires>" +
"</wsu:Timestamp>" +
"<wsse:UsernameToken xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=\"SecurityToken-" + created + "\">" +
"<wsse:Username>" + this._username + "</wsse:Username>" +
(this._passwordType === 'PasswordText' ?
"<wsse:Password>" + this._password + "</wsse:Password>"
:
"<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + passwordDigest(nonce, created, this._password) + "</wsse:Password>"
) +
"<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + nonce + "</wsse:Nonce>" +
"<wsu:Created>" + created + "</wsu:Created>" +
"</wsse:UsernameToken>" +
"</wsse:Security>";
};

@@ -148,0 +152,0 @@ exports.BasicAuthSecurity = BasicAuthSecurity;

/*
* Copyright (c) 2011 Vinay Pulim <vinay@milewise.com>
* MIT Licensed
*
*/
/*jshint proto:true*/
var expat = require('node-expat'),
inherits = require('util').inherits,
http = require('./http'),
fs = require('fs'),
url = require('url'),
path = require('path'),
assert = require('assert').ok;
"use strict";
var sax = require('sax');
var inherits = require('util').inherits;
var http = require('./http');
var fs = require('fs');
var url = require('url');
var path = require('path');
var assert = require('assert').ok;
var Primitives = {
string: 1, boolean: 1, decimal: 1, float: 1, double: 1,
anyType: 1, byte: 1, int: 1, long: 1, short: 1,
unsignedByte: 1, unsignedInt: 1, unsignedLong: 1, unsignedShort: 1,
duration: 0, dateTime: 0, time: 0, date: 0,
gYearMonth: 0, gYear: 0, gMonthDay: 0, gDay: 0, gMonth: 0,
hexBinary: 0, base64Binary: 0, anyURI: 0, QName: 0, NOTATION: 0
string: 1,
boolean: 1,
decimal: 1,
float: 1,
double: 1,
anyType: 1,
byte: 1,
int: 1,
long: 1,
short: 1,
unsignedByte: 1,
unsignedInt: 1,
unsignedLong: 1,
unsignedShort: 1,
duration: 0,
dateTime: 0,
time: 0,
date: 0,
gYearMonth: 0,
gYear: 0,
gMonthDay: 0,
gDay: 0,
gMonth: 0,
hexBinary: 0,
base64Binary: 0,
anyURI: 0,
QName: 0,
NOTATION: 0
};
function splitNSName(nsName) {
var i = (nsName != null) ? nsName.indexOf(':') : -1;
return i < 0 ? {namespace:null,name:nsName} : {namespace:nsName.substring(0, i), name:nsName.substring(i+1)};
var i = typeof nsName === 'string' ? nsName.indexOf(':') : -1;
return i < 0 ? {namespace: null, name: nsName} : {namespace: nsName.substring(0, i), name: nsName.substring(i + 1)};
}
function xmlEscape(obj) {
if (typeof(obj) === 'string') {
return obj
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
}
if (typeof (obj) === 'string') {
return obj
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
return obj;
return obj;
}

@@ -45,89 +71,105 @@

function trim(text) {
return text.replace(trimLeft, '').replace(trimRight, '');
return text.replace(trimLeft, '').replace(trimRight, '');
}
function extend(base, obj) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
base[key] = obj[key];
}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
base[key] = obj[key];
}
return base;
}
return base;
}
function findKey(obj, val) {
for (var n in obj) if (obj[n] === val) return n;
for (var n in obj)
if (obj[n] === val)
return n;
}
var Element = function(nsName, attrs) {
var parts = splitNSName(nsName);
var parts = splitNSName(nsName);
this.nsName = nsName;
this.namespace = parts.namespace;
this.name = parts.name;
this.children = [];
this.xmlns = {};
for (var key in attrs) {
var match = /^xmlns:?(.*)$/.exec(key);
if (match) {
this.xmlns[match[1]] = attrs[key];
}
else {
this['$'+key] = attrs[key];
}
this.nsName = nsName;
this.namespace = parts.namespace;
this.name = parts.name;
this.children = [];
this.xmlns = {};
for (var key in attrs) {
var match = /^xmlns:?(.*)$/.exec(key);
if (match) {
this.xmlns[match[1]] = attrs[key];
}
}
else {
this['$' + key] = attrs[key];
}
}
};
Element.prototype.deleteFixedAttrs = function() {
this.children && this.children.length === 0 && delete this.children;
this.xmlns && Object.keys(this.xmlns).length === 0 && delete this.xmlns;
delete this.nsName;
delete this.namespace;
delete this.name;
}
this.children && this.children.length === 0 && delete this.children;
this.xmlns && Object.keys(this.xmlns).length === 0 && delete this.xmlns;
delete this.nsName;
delete this.namespace;
delete this.name;
};
Element.prototype.allowedChildren = [];
Element.prototype.startElement= function(stack, nsName, attrs) {
if (!this.allowedChildren) return;
var childClass = this.allowedChildren[splitNSName(nsName).name],
element = null;
Element.prototype.startElement = function(stack, nsName, attrs) {
if (!this.allowedChildren)
return;
if (childClass) {
stack.push(new childClass(nsName, attrs));
var ChildClass = this.allowedChildren[splitNSName(nsName).name],
element = null;
if (ChildClass) {
stack.push(new ChildClass(nsName, attrs));
}
else {
this.unexpected(nsName);
}
};
Element.prototype.endElement = function(stack, nsName) {
if (this.nsName === nsName) {
if (stack.length < 2)
return;
var parent = stack[stack.length - 2];
if (this !== stack[0]) {
extend(stack[0].xmlns, this.xmlns);
// delete this.xmlns;
parent.children.push(this);
parent.addChild(this);
}
else {
this.unexpected(nsName);
}
stack.pop();
}
};
}
Element.prototype.endElement = function(stack, nsName) {
if (this.nsName === nsName) {
if(stack.length < 2 ) return;
var parent = stack[stack.length - 2];
if (this !== stack[0]) {
extend(stack[0].xmlns, this.xmlns);
// delete this.xmlns;
parent.children.push(this);
parent.addChild(this);
}
stack.pop();
}
}
Element.prototype.addChild = function(child) { return; }
Element.prototype.addChild = function(child) {
return;
};
Element.prototype.unexpected = function(name) {
throw new Error('Found unexpected element (' + name + ') inside ' + this.nsName);
}
throw new Error('Found unexpected element (' + name + ') inside ' + this.nsName);
};
Element.prototype.description = function(definitions) {
return this.$name || this.name;
}
Element.prototype.init = function() {};
return this.$name || this.name;
};
Element.prototype.init = function() {
};
Element.createSubClass = function() {
var root = this;
var subElement = function() {
root.apply(this, arguments);
this.init();
};
// inherits(subElement, root);
subElement.prototype.__proto__ = root.prototype;
return subElement;
}
var root = this;
var subElement = function() {
root.apply(this, arguments);
this.init();
};
// inherits(subElement, root);
subElement.prototype.__proto__ = root.prototype;
return subElement;
};

@@ -157,865 +199,944 @@

var ElementTypeMap = {
types: [TypesElement, 'schema documentation'],
schema: [SchemaElement, 'element complexType simpleType include import'],
element: [ElementElement, 'annotation complexType'],
simpleType: [SimpleTypeElement, 'restriction'],
restriction: [RestrictionElement, 'enumeration'],
enumeration: [EnumerationElement, ''],
complexType: [ComplexTypeElement, 'annotation sequence all'],
sequence: [SequenceElement, 'element'],
all: [AllElement, 'element'],
service: [ServiceElement, 'port documentation'],
port: [PortElement, 'address documentation'],
binding: [BindingElement, '_binding SecuritySpec operation documentation'],
portType: [PortTypeElement, 'operation documentation'],
message: [MessageElement, 'part documentation'],
operation: [OperationElement, 'documentation input output fault _operation'],
input : [InputElement, 'body SecuritySpecRef documentation header'],
output : [OutputElement, 'body SecuritySpecRef documentation header'],
fault : [Element, '_fault documentation'],
definitions: [DefinitionsElement, 'types message portType binding service documentation'],
documentation: [DocumentationElement, '']
types: [TypesElement, 'schema documentation'],
schema: [SchemaElement, 'element complexType simpleType include import'],
element: [ElementElement, 'annotation complexType'],
simpleType: [SimpleTypeElement, 'restriction'],
restriction: [RestrictionElement, 'enumeration'],
enumeration: [EnumerationElement, ''],
complexType: [ComplexTypeElement, 'annotation sequence all'],
sequence: [SequenceElement, 'element'],
all: [AllElement, 'element'],
service: [ServiceElement, 'port documentation'],
port: [PortElement, 'address documentation'],
binding: [BindingElement, '_binding SecuritySpec operation documentation'],
portType: [PortTypeElement, 'operation documentation'],
message: [MessageElement, 'part documentation'],
operation: [OperationElement, 'documentation input output fault _operation'],
input: [InputElement, 'body SecuritySpecRef documentation header'],
output: [OutputElement, 'body SecuritySpecRef documentation header'],
fault: [Element, '_fault documentation'],
definitions: [DefinitionsElement, 'types message portType binding service documentation'],
documentation: [DocumentationElement, '']
};
function mapElementTypes(types) {
var types = types.split(' ');
var rtn = {}
types.forEach(function(type){
rtn[type.replace(/^_/,'')] = (ElementTypeMap[type] || [Element]) [0];
});
return rtn;
var rtn = {};
types = types.split(' ');
types.forEach(function(type) {
rtn[type.replace(/^_/, '')] = (ElementTypeMap[type] || [Element]) [0];
});
return rtn;
}
for(var n in ElementTypeMap) {
var v = ElementTypeMap[n];
v[0].prototype.allowedChildren = mapElementTypes(v[1]);
for (var n in ElementTypeMap) {
var v = ElementTypeMap[n];
v[0].prototype.allowedChildren = mapElementTypes(v[1]);
}
MessageElement.prototype.init = function() {
this.element = null;
this.parts = null;
}
SchemaElement.prototype.init = function() {
this.complexTypes = {};
this.types = {};
this.elements = {};
this.includes = [];
}
TypesElement.prototype.init = function() {
this.schemas = {};
}
OperationElement.prototype.init = function() {
this.input = null;
this.output = null;
this.inputSoap = null;
this.outputSoap = null;
this.style = '';
this.soapAction = '';
}
PortTypeElement.prototype.init = function() {
this.methods = {};
}
BindingElement.prototype.init = function() {
this.transport = '';
this.style = '';
this.methods = {};
}
PortElement.prototype.init = function() {
this.location = null;
}
ServiceElement.prototype.init = function() {
this.ports = {};
}
this.element = null;
this.parts = null;
};
SchemaElement.prototype.init = function() {
this.complexTypes = {};
this.types = {};
this.elements = {};
this.includes = [];
};
TypesElement.prototype.init = function() {
this.schemas = {};
};
OperationElement.prototype.init = function() {
this.input = null;
this.output = null;
this.inputSoap = null;
this.outputSoap = null;
this.style = '';
this.soapAction = '';
};
PortTypeElement.prototype.init = function() {
this.methods = {};
};
BindingElement.prototype.init = function() {
this.transport = '';
this.style = '';
this.methods = {};
};
PortElement.prototype.init = function() {
this.location = null;
};
ServiceElement.prototype.init = function() {
this.ports = {};
};
DefinitionsElement.prototype.init = function() {
if (this.name !== 'definitions') this.unexpected(nsName);
this.messages = {};
this.portTypes = {};
this.bindings = {};
this.services = {};
this.schemas = {};
}
DocumentationElement.prototype.init = function(){}
if (this.name !== 'definitions')this.unexpected(this.nsName);
this.messages = {};
this.portTypes = {};
this.bindings = {};
this.services = {};
this.schemas = {};
};
DocumentationElement.prototype.init = function() {
};
SchemaElement.prototype.addChild = function(child) {
if (child.$name in Primitives) return;
if (child.name === 'include' || child.name === 'import') {
var location = child.$schemaLocation || child.$location;
if (location) {
this.includes.push({
namespace: child.$namespace || child.$targetNamespace || this.$targetNamespace,
location: location
});
}
if (child.$name in Primitives)
return;
if (child.name === 'include' || child.name === 'import') {
var location = child.$schemaLocation || child.$location;
if (location) {
this.includes.push({
namespace: child.$namespace || child.$targetNamespace || this.$targetNamespace,
location: location
});
}
else if (child.name === 'complexType') {
this.complexTypes[child.$name] = child;
}
else if (child.name === 'complexType') {
this.complexTypes[child.$name] = child;
}
else if (child.name === 'element') {
this.elements[child.$name] = child;
}
else if (child.$name) {
this.types[child.$name] = child;
}
this.children.pop();
// child.deleteFixedAttrs();
};
TypesElement.prototype.addChild = function(child) {
assert(child instanceof SchemaElement);
this.schemas[child.$targetNamespace] = child;
};
InputElement.prototype.addChild = function(child) {
if (child.name === 'body') {
this.use = child.$use;
if (this.use === 'encoded') {
this.encodingStyle = child.$encodingStyle;
}
else if (child.name === 'element') {
this.elements[child.$name] = child;
this.children.pop();
}
};
OutputElement.prototype.addChild = function(child) {
if (child.name === 'body') {
this.use = child.$use;
if (this.use === 'encoded') {
this.encodingStyle = child.$encodingStyle;
}
else if (child.$name) {
this.types[child.$name] = child;
}
this.children.pop();
// child.deleteFixedAttrs();
}
TypesElement.prototype.addChild = function(child) {
assert(child instanceof SchemaElement);
this.schemas[child.$targetNamespace] = child;
}
InputElement.prototype.addChild = function(child) {
if (child.name === 'body') {
this.use = child.$use;
if (this.use === 'encoded') {
this.encodingStyle = child.$encodingStyle;
}
this.children.pop();
}
}
OutputElement.prototype.addChild = function(child) {
if (child.name === 'body') {
this.use = child.$use;
if (this.use === 'encoded') {
this.encodingStyle = child.$encodingStyle;
}
this.children.pop();
}
}
}
};
OperationElement.prototype.addChild = function(child) {
if (child.name === 'operation') {
this.soapAction = child.$soapAction || '';
this.style = child.$style || '';
this.children.pop();
}
}
if (child.name === 'operation') {
this.soapAction = child.$soapAction || '';
this.style = child.$style || '';
this.children.pop();
}
};
BindingElement.prototype.addChild = function(child) {
if (child.name === 'binding') {
this.transport = child.$transport;
this.style = child.$style;
this.children.pop();
}
}
if (child.name === 'binding') {
this.transport = child.$transport;
this.style = child.$style;
this.children.pop();
}
};
PortElement.prototype.addChild = function(child) {
if (child.name === 'address' && typeof(child.$location) !== 'undefined') {
this.location = child.$location;
}
}
if (child.name === 'address' && typeof (child.$location) !== 'undefined') {
this.location = child.$location;
}
};
DefinitionsElement.prototype.addChild = function(child) {
var self = this;
if (child instanceof TypesElement) {
self.schemas = child.schemas;
}
else if (child instanceof MessageElement) {
self.messages[child.$name] = child;
}
else if (child instanceof PortTypeElement) {
self.portTypes[child.$name] = child;
}
else if (child instanceof BindingElement) {
if (child.transport === 'http://schemas.xmlsoap.org/soap/http' ||
child.transport === 'http://www.w3.org/2003/05/soap/bindings/HTTP/')
self.bindings[child.$name] = child;
}
else if (child instanceof ServiceElement) {
self.services[child.$name] = child;
}
else if (child instanceof DocumentationElement) {
}
else {
assert(false, "Invalid child type");
}
this.children.pop();
}
var self = this;
if (child instanceof TypesElement) {
self.schemas = child.schemas;
}
else if (child instanceof MessageElement) {
self.messages[child.$name] = child;
}
else if (child instanceof PortTypeElement) {
self.portTypes[child.$name] = child;
}
else if (child instanceof BindingElement) {
if (child.transport === 'http://schemas.xmlsoap.org/soap/http' ||
child.transport === 'http://www.w3.org/2003/05/soap/bindings/HTTP/')
self.bindings[child.$name] = child;
}
else if (child instanceof ServiceElement) {
self.services[child.$name] = child;
}
else if (child instanceof DocumentationElement) {
}
else {
assert(false, "Invalid child type");
}
this.children.pop();
};
MessageElement.prototype.postProcess = function(definitions) {
var part = null, child,
children = this.children || [];
var part = null;
var child;
var children = this.children || [];
var ns;
var nsName;
var i;
for (var i in children) {
if ((child = children[i]).name === 'part') {
part = child;
break;
}
for (i in children) {
if ((child = children[i]).name === 'part') {
part = child;
break;
}
if (!part) return;
if (part.$element) {
delete this.parts;
var nsName = splitNSName(part.$element);
var ns = nsName.namespace;
this.element = definitions.schemas[definitions.xmlns[ns]].elements[nsName.name];
this.element.targetNSAlias = ns;
this.element.targetNamespace = definitions.xmlns[ns];
this.children.splice(0,1);
}
if (!part)
return;
if (part.$element) {
delete this.parts;
nsName = splitNSName(part.$element);
ns = nsName.namespace;
this.element = definitions.schemas[definitions.xmlns[ns]].elements[nsName.name];
this.element.targetNSAlias = ns;
this.element.targetNamespace = definitions.xmlns[ns];
this.children.splice(0, 1);
} else {
// rpc encoding
this.parts = {};
delete this.element;
for (i = 0; part = this.children[i]; i++) {
assert(part.name === 'part', 'Expected part element');
nsName = splitNSName(part.$type);
ns = definitions.xmlns[nsName.namespace];
var type = nsName.name;
var schemaDefinition = definitions.schemas[ns];
if (typeof schemaDefinition !== 'undefined') {
this.parts[part.$name] = definitions.schemas[ns].types[type] || definitions.schemas[ns].complexTypes[type];
} else {
this.parts[part.$name] = part.$type;
}
this.parts[part.$name].namespace = nsName.namespace;
this.parts[part.$name].xmlns = ns;
this.children.splice(i--, 1);
}
else {
// rpc encoding
this.parts = {};
delete this.element;
for (var i=0, part; part = this.children[i]; i++) {
assert(part.name === 'part', 'Expected part element');
var nsName = splitNSName(part.$type);
var ns = definitions.xmlns[nsName.namespace];
var type = nsName.name;
var schemaDefinition = definitions.schemas[ns];
if (typeof schemaDefinition !== 'undefined') {
this.parts[part.$name] = definitions.schemas[ns].types[type] || definitions.schemas[ns].complexTypes[type];
} else {
this.parts[part.$name] = part.$type;
}
this.parts[part.$name].namespace = nsName.namespace;
this.parts[part.$name].xmlns = ns;
this.children.splice(i--,1);
}
}
this.deleteFixedAttrs();
}
}
this.deleteFixedAttrs();
};
OperationElement.prototype.postProcess = function(definitions, tag) {
var children = this.children;
for (var i=0, child; child=children[i]; i++) {
if (child.name !== 'input' && child.name !== 'output') continue;
if(tag === 'binding') {
this[child.name] = child;
children.splice(i--,1);
continue;
}
var messageName = splitNSName(child.$message).name;
var message = definitions.messages[messageName]
message.postProcess(definitions);
if (message.element) {
definitions.messages[message.element.$name] = message
this[child.name] = message.element;
}
else {
this[child.name] = message;
}
children.splice(i--,1);
var children = this.children;
for (var i = 0, child; child = children[i]; i++) {
if (child.name !== 'input' && child.name !== 'output')
continue;
if (tag === 'binding') {
this[child.name] = child;
children.splice(i--, 1);
continue;
}
this.deleteFixedAttrs();
}
PortTypeElement.prototype.postProcess = function(definitions) {
var children = this.children;
if (typeof children === 'undefined') return;
for (var i=0, child; child=children[i]; i++) {
if (child.name != 'operation') continue;
child.postProcess(definitions, 'portType');
this.methods[child.$name] = child;
children.splice(i--,1);
var messageName = splitNSName(child.$message).name;
var message = definitions.messages[messageName];
message.postProcess(definitions);
if (message.element) {
definitions.messages[message.element.$name] = message;
this[child.name] = message.element;
}
delete this.$name;
this.deleteFixedAttrs();
}
BindingElement.prototype.postProcess = function(definitions) {
var type = splitNSName(this.$type).name,
portType = definitions.portTypes[type],
style = this.style,
children = this.children;
portType.postProcess(definitions);
this.methods = portType.methods;
// delete portType.methods; both binding and portType should keep the same set of operations
for (var i=0, child; child=children[i]; i++) {
if (child.name != 'operation') continue;
child.postProcess(definitions, 'binding');
children.splice(i--,1);
child.style || (child.style = style);
var method = this.methods[child.$name];
method.style = child.style;
method.soapAction = child.soapAction;
method.inputSoap = child.input || null;
method.outputSoap = child.output || null;
method.inputSoap && method.inputSoap.deleteFixedAttrs();
method.outputSoap && method.outputSoap.deleteFixedAttrs();
// delete method.$name; client will use it to make right request for top element name in body
// method.deleteFixedAttrs(); why ???
else {
this[child.name] = message;
}
children.splice(i--, 1);
}
this.deleteFixedAttrs();
};
delete this.$name;
delete this.$type;
this.deleteFixedAttrs();
}
PortTypeElement.prototype.postProcess = function(definitions) {
var children = this.children;
if (typeof children === 'undefined')
return;
for (var i = 0, child; child = children[i]; i++) {
if (child.name !== 'operation')
continue;
child.postProcess(definitions, 'portType');
this.methods[child.$name] = child;
children.splice(i--, 1);
}
delete this.$name;
this.deleteFixedAttrs();
};
BindingElement.prototype.postProcess = function(definitions) {
var type = splitNSName(this.$type).name,
portType = definitions.portTypes[type],
style = this.style,
children = this.children;
portType.postProcess(definitions);
this.methods = portType.methods;
// delete portType.methods; both binding and portType should keep the same set of operations
for (var i = 0, child; child = children[i]; i++) {
if (child.name !== 'operation')
continue;
child.postProcess(definitions, 'binding');
children.splice(i--, 1);
child.style || (child.style = style);
var method = this.methods[child.$name];
method.style = child.style;
method.soapAction = child.soapAction;
method.inputSoap = child.input || null;
method.outputSoap = child.output || null;
method.inputSoap && method.inputSoap.deleteFixedAttrs();
method.outputSoap && method.outputSoap.deleteFixedAttrs();
// delete method.$name; client will use it to make right request for top element name in body
// method.deleteFixedAttrs(); why ???
}
delete this.$name;
delete this.$type;
this.deleteFixedAttrs();
};
ServiceElement.prototype.postProcess = function(definitions) {
var children = this.children,
bindings = definitions.bindings;
for (var i=0, child; child=children[i]; i++) {
if (child.name != 'port') continue;
var bindingName = splitNSName(child.$binding).name;
var binding = bindings[bindingName];
if (binding) {
binding.postProcess(definitions);
this.ports[child.$name] = {
location: child.location,
binding: binding
}
children.splice(i--,1);
}
var children = this.children,
bindings = definitions.bindings;
for (var i = 0, child; child = children[i]; i++) {
if (child.name !== 'port')
continue;
var bindingName = splitNSName(child.$binding).name;
var binding = bindings[bindingName];
if (binding) {
binding.postProcess(definitions);
this.ports[child.$name] = {
location: child.location,
binding: binding
};
children.splice(i--, 1);
}
delete this.$name;
this.deleteFixedAttrs();
}
}
delete this.$name;
this.deleteFixedAttrs();
};
SimpleTypeElement.prototype.description = function(definitions) {
var children = this.children;
for (var i=0, child; child=children[i]; i++) {
if (child instanceof RestrictionElement)
return this.$name+"|"+child.description();
}
return {};
}
var children = this.children;
for (var i = 0, child; child = children[i]; i++) {
if (child instanceof RestrictionElement)
return this.$name + "|" + child.description();
}
return {};
};
RestrictionElement.prototype.description = function() {
var base = this.$base ? this.$base+"|" : "";
return base + this.children.map( function(child) {
return child.description();
} ).join(",");
}
var base = this.$base ? this.$base + "|" : "";
return base + this.children.map(function(child) {
return child.description();
}).join(",");
};
EnumerationElement.prototype.description = function() {
return this.$value;
}
return this.$value;
};
ComplexTypeElement.prototype.description = function(definitions) {
var children = this.children;
for (var i=0, child; child=children[i]; i++) {
if (child instanceof SequenceElement ||
child instanceof AllElement) {
return child.description(definitions);
}
var children = this.children;
if (!children) {
return {};
}
for (var i = 0, child; child = children[i]; i++) {
if (child instanceof SequenceElement ||
child instanceof AllElement) {
return child.description(definitions);
}
return {};
}
}
return {};
};
ElementElement.prototype.description = function(definitions) {
var element = {},
name = this.$name,
schema;
var maxOccurs = this.$maxOccurs || 1;
if ((isNaN(maxOccurs) && maxOccurs == 'unbounded') || maxOccurs > 1) {
name += '[]';
var element = {};
var name = this.$name;
var maxOccurs = this.$maxOccurs || 1;
var schema;
var typeName;
var ns;
var typeElement;
if ((isNaN(maxOccurs) && maxOccurs === 'unbounded') || maxOccurs > 1) {
name += '[]';
}
if (this.$type) {
typeName = splitNSName(this.$type).name;
ns = definitions.xmlns[splitNSName(this.$type).namespace];
schema = definitions.schemas[ns];
typeElement = schema && (schema.complexTypes[typeName] || schema.types[typeName]);
if (typeElement && !(typeName in Primitives)) {
element[name] = typeElement.description(definitions);
}
if (this.$type) {
var typeName = splitNSName(this.$type).name,
ns = definitions.xmlns[splitNSName(this.$type).namespace],
schema = definitions.schemas[ns],
typeElement = schema && ( schema.complexTypes[typeName] || schema.types[typeName] );
if (typeElement && !(typeName in Primitives)) {
element[name] = typeElement.description(definitions);
}
else
element[name] = this.$type;
else
element[name] = this.$type;
}
else {
var children = this.children;
element[name] = {};
for (var i = 0, child; child = children[i]; i++) {
if (child instanceof ComplexTypeElement)
element[name] = child.description(definitions);
}
else {
var children = this.children;
element[name] = {};
for (var i=0, child; child=children[i]; i++) {
if (child instanceof ComplexTypeElement)
element[name] = child.description(definitions);
}
}
return element;
}
AllElement.prototype.description =
SequenceElement.prototype.description = function(definitions) {
}
return element;
};
AllElement.prototype.description
= SequenceElement.prototype.description = function(definitions) {
var children = this.children;
var sequence = {};
for (var i=0, child; child=children[i]; i++) {
var description = child.description(definitions);
for (var key in description) {
sequence[key] = description[key];
}
for (var i = 0, child; child = children[i]; i++) {
var description = child.description(definitions);
for (var key in description) {
sequence[key] = description[key];
}
}
return sequence;
}
};
MessageElement.prototype.description = function(definitions) {
if (this.element) {
return this.element && this.element.description(definitions);
}
var desc = {};
desc[this.$name] = this.parts;
return desc;
}
if (this.element) {
return this.element && this.element.description(definitions);
}
var desc = {};
desc[this.$name] = this.parts;
return desc;
};
PortTypeElement.prototype.description = function(definitions) {
var methods = {};
for (var name in this.methods) {
var method = this.methods[name];
methods[name] = method.description(definitions);
}
return methods;
}
var methods = {};
for (var name in this.methods) {
var method = this.methods[name];
methods[name] = method.description(definitions);
}
return methods;
};
OperationElement.prototype.description = function(definitions) {
var inputDesc = this.input.description(definitions);
var outputDesc = this.output.description(definitions);
return {
input: inputDesc && inputDesc[Object.keys(inputDesc)[0]],
output: outputDesc && outputDesc[Object.keys(outputDesc)[0]]
}
}
var inputDesc = this.input.description(definitions);
var outputDesc = this.output.description(definitions);
return {
input: inputDesc && inputDesc[Object.keys(inputDesc)[0]],
output: outputDesc && outputDesc[Object.keys(outputDesc)[0]]
};
};
BindingElement.prototype.description = function(definitions) {
var methods = {};
for (var name in this.methods) {
var method = this.methods[name];
methods[name] = method.description(definitions);
}
return methods;
}
var methods = {};
for (var name in this.methods) {
var method = this.methods[name];
methods[name] = method.description(definitions);
}
return methods;
};
ServiceElement.prototype.description = function(definitions) {
var ports = {};
for (var name in this.ports) {
var port = this.ports[name];
ports[name] = port.binding.description(definitions);
}
return ports;
}
var ports = {};
for (var name in this.ports) {
var port = this.ports[name];
ports[name] = port.binding.description(definitions);
}
return ports;
};
var WSDL = function(definition, uri, options) {
var self = this,
fromFunc;
var self = this,
fromFunc;
this.uri = uri;
this.callback = function() {};
this.options = options || {};
this.uri = uri;
this.callback = function() {
};
this.options = options || {};
if (typeof definition === 'string') {
fromFunc = this._fromXML;
}
else if (typeof definition === 'object') {
fromFunc = this._fromServices;
}
else {
throw new Error('WSDL constructor takes either an XML string or service definition');
}
if (typeof definition === 'string') {
fromFunc = this._fromXML;
}
else if (typeof definition === 'object') {
fromFunc = this._fromServices;
}
else {
throw new Error('WSDL constructor takes either an XML string or service definition');
}
process.nextTick(function() {
fromFunc.call(self, definition);
process.nextTick(function() {
fromFunc.call(self, definition);
self.processIncludes(function(err) {
if (err) {
return self.callback(err);
}
self.processIncludes(function(err) {
var name;
if (err) {
return self.callback(err);
}
self.definitions.deleteFixedAttrs();
var services = self.services = self.definitions.services ;
if (services) {
for (var name in services) {
services[name].postProcess(self.definitions);
}
}
var complexTypes = self.definitions.complexTypes;
if (complexTypes) {
for (var name in complexTypes) {
complexTypes[name].deleteFixedAttrs();
}
}
self.definitions.deleteFixedAttrs();
var services = self.services = self.definitions.services;
if (services) {
for (name in services) {
services[name].postProcess(self.definitions);
}
}
var complexTypes = self.definitions.complexTypes;
if (complexTypes) {
for (name in complexTypes) {
complexTypes[name].deleteFixedAttrs();
}
}
// for document style, for every binding, prepare input message element name to (methodName, output message element name) mapping
var bindings = self.definitions.bindings;
for(var bindingName in bindings) {
var binding = bindings[bindingName];
if(binding.style !== 'document') continue;
var methods = binding.methods;
var topEls = binding.topElements = {};
for(var methodName in methods) {
var inputName = methods[methodName].input.$name;
var outputName = methods[methodName].output.$name;
topEls[inputName] = {"methodName": methodName, "outputName": outputName};
}
}
// for document style, for every binding, prepare input message element name to (methodName, output message element name) mapping
var bindings = self.definitions.bindings;
for (var bindingName in bindings) {
var binding = bindings[bindingName];
if (binding.style !== 'document')
continue;
var methods = binding.methods;
var topEls = binding.topElements = {};
for (var methodName in methods) {
var inputName = methods[methodName].input.$name;
var outputName = methods[methodName].output.$name;
topEls[inputName] = {"methodName": methodName, "outputName": outputName};
}
}
// prepare soap envelope xmlns definition string
self.xmlnsInEnvelope = self._xmlnsMap();
self.callback(err, self);
});
})
}
// prepare soap envelope xmlns definition string
self.xmlnsInEnvelope = self._xmlnsMap();
self.callback(err, self);
});
});
};
WSDL.prototype.onReady = function(callback) {
if (callback) this.callback = callback;
}
if (callback)
this.callback = callback;
};
WSDL.prototype._processNextInclude = function(includes, callback) {
var self = this,
include = includes.shift();
var self = this,
include = includes.shift();
if (!include) return callback()
if (!include)
return callback();
var includePath;
if (!/^http/.test(self.uri) && !/^http/.test(include.location)) {
includePath = path.resolve(path.dirname(self.uri), include.location);
} else {
includePath = url.resolve(self.uri, include.location);
var includePath;
if (!/^http/.test(self.uri) && !/^http/.test(include.location)) {
includePath = path.resolve(path.dirname(self.uri), include.location);
} else {
includePath = url.resolve(self.uri, include.location);
}
open_wsdl(includePath, function(err, wsdl) {
if (err) {
return callback(err);
}
open_wsdl(includePath, function(err, wsdl) {
if (err) {
return callback(err);
}
self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace] = wsdl.definitions;
self._processNextInclude(includes, function(err) {
callback(err);
})
self.definitions.schemas[include.namespace || wsdl.definitions.$targetNamespace] = wsdl.definitions;
self._processNextInclude(includes, function(err) {
callback(err);
});
}
});
};
WSDL.prototype.processIncludes = function(callback) {
var schemas = this.definitions.schemas,
includes = [];
var schemas = this.definitions.schemas,
includes = [];
for (var ns in schemas) {
var schema = schemas[ns];
includes = includes.concat(schema.includes || [])
}
for (var ns in schemas) {
var schema = schemas[ns];
includes = includes.concat(schema.includes || []);
}
this._processNextInclude(includes, callback);
}
this._processNextInclude(includes, callback);
};
WSDL.prototype.describeServices = function() {
var services = {};
for (var name in this.services) {
var service = this.services[name];
services[name] = service.description(this.definitions);
}
return services;
}
var services = {};
for (var name in this.services) {
var service = this.services[name];
services[name] = service.description(this.definitions);
}
return services;
};
WSDL.prototype.toXML = function() {
return this.xml || '';
}
return this.xml || '';
};
WSDL.prototype.xmlToObject = function(xml) {
var self = this,
p = new expat.Parser('UTF-8'),
objectName = null,
root = {},
schema = {
Envelope: {
Header: {
Security: {
UsernameToken: {
Username: 'string',
Password: 'string' }}},
Body: {
Fault: { faultcode: 'string', faultstring: 'string', detail: 'string' }}}},
stack = [{name: null, object: root, schema: schema}];
var refs = {}, id; // {id:{hrefs:[],obj:}, ...}
var self = this;
var p = sax.parser(true);
var objectName = null;
var root = {};
var schema = {
Envelope: {
Header: {
Security: {
UsernameToken: {
Username: 'string',
Password: 'string'
}
}
},
Body: {
Fault: {
faultcode: 'string',
faultstring: 'string',
detail: 'string'
}
}
}
};
var stack = [{name: null, object: root, schema: schema}];
p.on('startElement', function(nsName, attrs) {
var name = splitNSName(nsName).name,
top = stack[stack.length-1],
topSchema = top.schema,
obj = {};
var originalName = name;
var refs = {}, id; // {id:{hrefs:[],obj:}, ...}
if (!objectName && top.name === 'Body' && name !== 'Fault') {
var message = self.definitions.messages[name];
// Support RPC/literal messages where response body contains one element named
// after the operation + 'Response'. See http://www.w3.org/TR/wsdl#_names
if (!message) {
// Determine if this is request or response
var isInput = false;
var isOutput = false;
if ((/Response$/).test(name)) {
isOutput = true;
name = name.replace(/Response$/, '');
} else if ((/Request$/).test(name)) {
isInput = true;
name = name.replace(/Request$/, '');
} else if ((/Solicit$/).test(name)) {
isInput = true;
name = name.replace(/Solicit$/, '');
}
// Look up the appropriate message as given in the portType's operations
var portTypes = self.definitions.portTypes;
var portTypeNames = Object.keys(portTypes);
// Currently this supports only one portType definition.
var portType = portTypes[portTypeNames[0]];
if (isInput) name = portType.methods[name].input.$name;
else name = portType.methods[name].output.$name;
message = self.definitions.messages[name];
// 'cache' this alias to speed future lookups
self.definitions.messages[originalName] = self.definitions.messages[name];
}
p.onopentag = function(node) {
var nsName = node.name;
var attrs = node.attributes;
topSchema = message.description(self.definitions);
objectName = originalName;
}
if(attrs.href) {
id = attrs.href.substr(1);
if(!refs[id]) refs[id] = {hrefs:[],obj:null};
refs[id].hrefs.push({par:top.object,key:name,obj:obj});
}
if(id=attrs.id) {
if(!refs[id]) refs[id] = {hrefs:[],obj:null};
}
var name = splitNSName(nsName).name,
attributeName,
top = stack[stack.length - 1],
topSchema = top.schema,
elementAttributes = {},
hasNonXmlnsAttribute = false,
obj = {};
var originalName = name;
if (topSchema && topSchema[name+'[]']) name = name + '[]';
stack.push({name: originalName, object: obj, schema: topSchema && topSchema[name], id:attrs.id});
})
p.on('endElement', function(nsName) {
var cur = stack.pop(),
obj = cur.object,
top = stack[stack.length-1],
topObject = top.object,
topSchema = top.schema,
name = splitNSName(nsName).name;
if (topSchema && topSchema[name+'[]']) {
if (!topObject[name]) topObject[name] = [];
topObject[name].push(obj);
if (!objectName && top.name === 'Body' && name !== 'Fault') {
var message = self.definitions.messages[name];
// Support RPC/literal messages where response body contains one element named
// after the operation + 'Response'. See http://www.w3.org/TR/wsdl#_names
if (!message) {
// Determine if this is request or response
var isInput = false;
var isOutput = false;
if ((/Response$/).test(name)) {
isOutput = true;
name = name.replace(/Response$/, '');
} else if ((/Request$/).test(name)) {
isInput = true;
name = name.replace(/Request$/, '');
} else if ((/Solicit$/).test(name)) {
isInput = true;
name = name.replace(/Solicit$/, '');
}
else if (name in topObject) {
if (!Array.isArray(topObject[name])) {
topObject[name] = [topObject[name]];
}
topObject[name].push(obj);
}
else {
topObject[name] = obj;
}
if(cur.id) {
refs[cur.id].obj = obj;
}
})
p.on('text', function(text) {
text = trim(text);
if (!text.length) return;
// Look up the appropriate message as given in the portType's operations
var portTypes = self.definitions.portTypes;
var portTypeNames = Object.keys(portTypes);
// Currently this supports only one portType definition.
var portType = portTypes[portTypeNames[0]];
if (isInput)
name = portType.methods[name].input.$name;
else
name = portType.methods[name].output.$name;
message = self.definitions.messages[name];
// 'cache' this alias to speed future lookups
self.definitions.messages[originalName] = self.definitions.messages[name];
}
var top = stack[stack.length-1];
var name = splitNSName(top.schema).name,
value;
if (name === 'int' || name === 'integer') {
value = parseInt(text, 10);
} else if (name === 'bool' || name === 'boolean') {
value = text.toLowerCase() === 'true' || text === '1';
} else if (name === 'dateTime') {
value = new Date(text);
} else {
// handle string or other types
if (typeof top.object !== 'string') {
value = text;
} else {
value = top.object + text;
}
}
top.object = value;
});
if (!p.parse(xml, false)) {
throw new Error(p.getError());
topSchema = message.description(self.definitions);
objectName = originalName;
}
// merge obj with href
var merge = function(href, obj) {
for (var j in obj) {
if (obj.hasOwnProperty(j)) {
href.obj[j] = obj[j];
}
if (attrs.href) {
id = attrs.href.substr(1);
if (!refs[id])
refs[id] = {hrefs: [], obj: null};
refs[id].hrefs.push({par: top.object, key: name, obj: obj});
}
if (id = attrs.id) {
if (!refs[id])
refs[id] = {hrefs: [], obj: null};
}
//Handle element attributes
for(attributeName in attrs){
if(/^xmlns:?/.test(attributeName))continue;
hasNonXmlnsAttribute = true;
elementAttributes[attributeName] = attrs[attributeName];
}
if(hasNonXmlnsAttribute)obj.attributes = elementAttributes;
if (topSchema && topSchema[name + '[]'])
name = name + '[]';
stack.push({name: originalName, object: obj, schema: topSchema && topSchema[name], id: attrs.id});
};
p.onclosetag = function(nsName) {
var cur = stack.pop(),
obj = cur.object,
top = stack[stack.length - 1],
topObject = top.object,
topSchema = top.schema,
name = splitNSName(nsName).name;
if (topSchema && topSchema[name + '[]']) {
if (!topObject[name])
topObject[name] = [];
topObject[name].push(obj);
}
else if (name in topObject) {
if (!Array.isArray(topObject[name])) {
topObject[name] = [topObject[name]];
}
};
topObject[name].push(obj);
}
else {
topObject[name] = obj;
}
// MultiRef support: merge objects instead of replacing
for(var n in refs) {
var ref = refs[n];
for (var i = 0; i < ref.hrefs.length; i++) {
merge(ref.hrefs[i], ref.obj);
if (cur.id) {
refs[cur.id].obj = obj;
}
};
p.ontext = function(text) {
text = trim(text);
if (!text.length)
return;
var top = stack[stack.length - 1];
var name = splitNSName(top.schema).name,
value;
if (name === 'int' || name === 'integer') {
value = parseInt(text, 10);
} else if (name === 'bool' || name === 'boolean') {
value = text.toLowerCase() === 'true' || text === '1';
} else if (name === 'dateTime') {
value = new Date(text);
} else {
// handle string or other types
if (typeof top.object !== 'string') {
value = text;
} else {
value = top.object + text;
}
}
top.object = value;
};
var body = root.Envelope.Body;
if (body.Fault) {
throw new Error(body.Fault.faultcode+': '+body.Fault.faultstring+(body.Fault.detail ? ': ' + body.Fault.detail : ''));
p.write(xml).close();
// merge obj with href
var merge = function(href, obj) {
for (var j in obj) {
if (obj.hasOwnProperty(j)) {
href.obj[j] = obj[j];
}
}
return root.Envelope;
}
};
// MultiRef support: merge objects instead of replacing
for (var n in refs) {
var ref = refs[n];
for (var i = 0; i < ref.hrefs.length; i++) {
merge(ref.hrefs[i], ref.obj);
}
}
var body = root.Envelope.Body;
if (body.Fault) {
throw new Error(body.Fault.faultcode + ': ' + body.Fault.faultstring + (body.Fault.detail ? ': ' + body.Fault.detail : ''));
}
return root.Envelope;
};
WSDL.prototype.objectToDocumentXML = function(name, params, ns, xmlns) {
var args = {};
args[name] = params;
return this.objectToXML(args, null, ns, xmlns, true);
}
var args = {};
args[name] = params;
return this.objectToXML(args, null, ns, xmlns, true);
};
WSDL.prototype.objectToRpcXML = function(name, params, namespace, xmlns) {
var self = this,
parts = [],
defs = this.definitions,
namespace = namespace || findKey(defs.xmlns, xmlns),
xmlns = xmlns || defs.xmlns[namespace],
nsAttrName = '_xmlns';
parts.push(['<',namespace,':',name,'>'].join(''));
for (var key in params) {
if (key != nsAttrName) {
var value = params[key];
parts.push(['<',key,'>'].join(''));
parts.push((typeof value==='object')?this.objectToXML(value):xmlEscape(value));
parts.push(['</',key,'>'].join(''));
}
var self = this;
var parts = [];
var defs = this.definitions;
var nsAttrName = '_xmlns';
namespace = namespace || findKey(defs.xmlns, xmlns);
xmlns = xmlns || defs.xmlns[namespace];
parts.push(['<', namespace, ':', name, '>'].join(''));
for (var key in params) {
if (key !== nsAttrName) {
var value = params[key];
parts.push(['<', key, '>'].join(''));
parts.push((typeof value === 'object') ? this.objectToXML(value) : xmlEscape(value));
parts.push(['</', key, '>'].join(''));
}
parts.push(['</',namespace,':',name,'>'].join(''));
}
parts.push(['</', namespace, ':', name, '>'].join(''));
return parts.join('');
}
return parts.join('');
};
WSDL.prototype.objectToXML = function(obj, name, namespace, xmlns, first) {
var self = this,
parts = [],
xmlnsAttrib = first ? ' xmlns:'+namespace+'="'+xmlns+'"'+' xmlns="'+xmlns+'"' : '',
ns = namespace ? namespace + ':' : '';
if (Array.isArray(obj)) {
for (var i=0, item; item=obj[i]; i++) {
if (i > 0) {
parts.push(['</',ns,name,'>'].join(''));
parts.push(['<',ns,name,xmlnsAttrib,'>'].join(''));
}
parts.push(self.objectToXML(item, name, namespace, xmlns));
}
var self = this;
var parts = [];
var xmlnsAttrib = first
? ' xmlns:' + namespace + '="' + xmlns + '"' + ' xmlns="' + xmlns + '"'
: '';
var ns = namespace ? namespace + ':' : '';
if (Array.isArray(obj)) {
for (var i = 0, item; item = obj[i]; i++) {
if (i > 0) {
parts.push(['</', ns, name, '>'].join(''));
parts.push(['<', ns, name, xmlnsAttrib, '>'].join(''));
}
parts.push(self.objectToXML(item, name, namespace, xmlns));
}
else if (typeof obj === 'object') {
for (var name in obj) {
var child = obj[name];
parts.push(['<',ns,name,xmlnsAttrib,'>'].join(''));
parts.push(self.objectToXML(child, name, namespace, xmlns));
parts.push(['</',ns,name,'>'].join(''));
}
} else if (typeof obj === 'object') {
for (name in obj) {
var child = obj[name];
parts.push(['<', ns, name, xmlnsAttrib, '>'].join(''));
parts.push(self.objectToXML(child, name, namespace, xmlns));
parts.push(['</', ns, name, '>'].join(''));
}
else if (obj !== undefined) {
parts.push(xmlEscape(obj));
}
return parts.join('');
}
} else if (obj !== undefined) {
parts.push(xmlEscape(obj));
}
return parts.join('');
};
WSDL.prototype._parse = function(xml)
{
var self = this,
p = new expat.Parser('UTF-8'),
stack = [],
root = null;
p.on('startElement', function(nsName, attrs) {
var top = stack[stack.length - 1];
if (top) {
try {
top.startElement(stack, nsName, attrs);
}
catch(e) {
if (self.options.strict) {
throw e;
}
else {
stack.push(new Element(nsName, attrs));
}
}
WSDL.prototype._parse = function(xml) {
var self = this,
p = sax.parser(true),
stack = [],
root = null;
p.onopentag = function(node) {
var nsName = node.name;
var attrs = node.attributes;
var top = stack[stack.length - 1];
var name;
if (top) {
try {
top.startElement(stack, nsName, attrs);
} catch (e) {
if (self.options.strict) {
throw e;
} else {
stack.push(new Element(nsName, attrs));
}
else {
var name = splitNSName(nsName).name;
if (name === 'definitions') {
root = new DefinitionsElement(nsName, attrs);
}
else if (name === 'schema') {
root = new SchemaElement(nsName, attrs);
}
else {
throw new Error('Unexpected root element of WSDL or include');
}
stack.push(root);
}
})
p.on('endElement', function(name) {
var top = stack[stack.length - 1];
assert(top, 'Unmatched close tag: ' + name);
top.endElement(stack, name);
})
if (!p.parse(xml, false)) {
throw new Error(p.getError());
}
} else {
name = splitNSName(nsName).name;
if (name === 'definitions') {
root = new DefinitionsElement(nsName, attrs);
} else if (name === 'schema') {
root = new SchemaElement(nsName, attrs);
} else {
throw new Error('Unexpected root element of WSDL or include');
}
stack.push(root);
}
return root;
}
};
p.onclosetag = function(name) {
var top = stack[stack.length - 1];
assert(top, 'Unmatched close tag: ' + name);
top.endElement(stack, name);
};
p.write(xml).close();
return root;
};
WSDL.prototype._fromXML = function(xml) {
this.definitions = this._parse(xml);
this.xml = xml;
}
this.definitions = this._parse(xml);
this.xml = xml;
};
WSDL.prototype._fromServices = function(services) {
}
};
WSDL.prototype._xmlnsMap = function() {
var xmlns = this.definitions.xmlns;
var str = '';
for (var alias in xmlns) {
if (alias === '') continue;
var ns = xmlns[alias];
switch(ns) {
case "http://xml.apache.org/xml-soap" : // apachesoap
case "http://schemas.xmlsoap.org/wsdl/" : // wsdl
case "http://schemas.xmlsoap.org/wsdl/soap/" : // wsdlsoap
case "http://schemas.xmlsoap.org/soap/encoding/" : // soapenc
case "http://www.w3.org/2001/XMLSchema" : // xsd
continue;
}
if (~ns.indexOf('http://schemas.xmlsoap.org/')) continue;
if (~ns.indexOf('http://www.w3.org/')) continue;
if (~ns.indexOf('http://xml.apache.org/')) continue;
str += ' xmlns:' + alias + '="' + ns + '"';
var xmlns = this.definitions.xmlns;
var str = '';
for (var alias in xmlns) {
if (alias === '')
continue;
var ns = xmlns[alias];
switch (ns) {
case "http://xml.apache.org/xml-soap" : // apachesoap
case "http://schemas.xmlsoap.org/wsdl/" : // wsdl
case "http://schemas.xmlsoap.org/wsdl/soap/" : // wsdlsoap
case "http://schemas.xmlsoap.org/soap/encoding/" : // soapenc
case "http://www.w3.org/2001/XMLSchema" : // xsd
continue;
}
return str;
}
if (~ns.indexOf('http://schemas.xmlsoap.org/'))
continue;
if (~ns.indexOf('http://www.w3.org/'))
continue;
if (~ns.indexOf('http://xml.apache.org/'))
continue;
str += ' xmlns:' + alias + '="' + ns + '"';
}
return str;
};
function open_wsdl(uri, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
if (typeof options === 'function') {
callback = options;
options = {};
}
request_headers = options.wsdl_headers;
delete options.wsdl_headers;
request_options = options.wsdl_options;
delete options.wsdl_options;
var request_headers = options.wsdl_headers;
var request_options = options.wsdl_options;
var wsdl;
if (!/^http/.test(uri)) {
fs.readFile(uri, 'utf8', function (err, definition) {
if (err) {
callback(err)
}
else {
wsdl = new WSDL(definition, uri, options);
wsdl.onReady(callback);
}
})
}
else {
http.request(uri, null /* options */, function (err, response, definition) {
if (err) {
callback(err);
}
else if (response && response.statusCode == 200) {
wsdl = new WSDL(definition, uri, options);
wsdl.onReady(callback);
}
else {
callback(new Error('Invalid WSDL URL: '+uri + "\n\n\r Code: "+ response.statusCode + "\n\n\r Response Body: " + response.body));
}
}, request_headers, request_options);
}
delete options.wsdl_headers;
delete options.wsdl_options;
return wsdl;
var wsdl;
if (!/^http/.test(uri)) {
fs.readFile(uri, 'utf8', function(err, definition) {
if (err) {
callback(err);
}
else {
wsdl = new WSDL(definition, uri, options);
wsdl.onReady(callback);
}
});
}
else {
http.request(uri, null /* options */, function(err, response, definition) {
if (err) {
callback(err);
} else if (response && response.statusCode === 200) {
wsdl = new WSDL(definition, uri, options);
wsdl.onReady(callback);
} else {
callback(new Error('Invalid WSDL URL: ' + uri + "\n\n\r Code: " + response.statusCode + "\n\n\r Response Body: " + response.body));
}
}, request_headers, request_options);
}
return wsdl;
}

@@ -1022,0 +1143,0 @@

{
"name": "soap",
"version": "0.3.2",
"version": "0.4.0",
"description": "A minimal node SOAP client",

@@ -10,3 +10,3 @@ "engines": {

"dependencies": {
"node-expat": ">=1.6.1",
"sax": ">=0.6",
"request": ">=2.9.0"

@@ -23,3 +23,5 @@ },

"scripts": {
"test": "mocha -R spec -u exports test/*-test.js"
"mocha": "mocha -R spec -u exports test/*-test.js",
"jshint": "jshint index.js lib/http.js lib/client.js lib/soap.js lib/server.js lib/wsdl.js",
"test": "npm run-script jshint && npm run-script mocha"
},

@@ -36,4 +38,6 @@ "keywords": [

"devDependencies": {
"mocha": "~1.17.0"
"mocha": "~1.17.0",
"jshint": "~2.4.2",
"glob": "~3.2.8"
}
}
This module lets you connect to web services using SOAP. It also provides a server that allows you to run your own SOAP services.
[![Build Status](https://travis-ci.org/milewise/node-soap.png?branch=master)](https://travis-ci.org/milewise/node-soap)
Features:

@@ -4,0 +6,0 @@

@@ -26,5 +26,6 @@ var fs = require('fs'),

if (!/.wsdl$/.exec(file)) return;
wsdlStrictTests['should parse '+file] = function(done) {
wsdlStrictTests['should parse and describe '+file] = function(done) {
soap.createClient(__dirname+'/wsdl/strict/'+file, {strict: true}, function(err, client) {
assert.ok(!err);
client.describe();
done();

@@ -47,3 +48,3 @@ });

soap.createClient(__dirname+'/wsdl/connection/econnrefused.wsdl', function(err, client) {
assert.ok(/EADDRNOTAVAIL/.test(err));
assert.ok(/EADDRNOTAVAIL|ECONNREFUSED/.test(err), err);
done();

@@ -53,13 +54,25 @@ });

var server = null;
module.exports = {
beforeEach: function() {
var wsdl = fs.readFileSync(__dirname+'/wsdl/strict/stockquote.wsdl', 'utf8');
server = http.createServer(function(req, res) {
res.statusCode = 404;
res.end();
});
server.listen(15099);
soap.listen(server, '/stockquote', service, wsdl);
},
afterEach: function(done) {
if (!server) return done()
server.close(function() {
server = null;
done();
});
},
'SOAP Server': {
'should start': function(done) {
var wsdl = fs.readFileSync(__dirname+'/wsdl/strict/stockquote.wsdl', 'utf8'),
server = http.createServer(function(req, res) {
res.statusCode = 404;
res.end();
});
server.listen(15099);
soap.listen(server, '/stockquote', service, wsdl);
'should be running': function(done) {
request('http://localhost:15099', function(err, res, body) {

@@ -88,2 +101,15 @@ assert.ok(!err);

'should return a valid error if the server stops responding': function(done) {
soap.createClient('http://localhost:15099/stockquote?wsdl', function(err, client) {
assert.ok(!err);
server.close(function() {
server = null;
client.GetLastTradePrice({ tickerSymbol: 'trigger error' }, function(err, response, body) {
assert.ok(err);
done();
});
});
});
},
'should return complete client description': function(done) {

@@ -120,3 +146,3 @@ soap.createClient('http://localhost:15099/stockquote?wsdl', function(err, client) {

});
}
},
},

@@ -123,0 +149,0 @@ 'WSDL Parser (strict)': wsdlStrictTests,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc