Comparing version 0.3.2 to 0.4.0
@@ -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 @@ ================== |
@@ -0,1 +1,3 @@ | ||
"use strict"; | ||
module.exports = require('./lib/soap'); |
@@ -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; |
208
lib/soap.js
@@ -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; |
1785
lib/wsdl.js
/* | ||
* 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, '&') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>') | ||
.replace(/"/g, '"') | ||
.replace(/'/g, ''') | ||
} | ||
if (typeof (obj) === 'string') { | ||
return obj | ||
.replace(/&/g, '&') | ||
.replace(/</g, '<') | ||
.replace(/>/g, '>') | ||
.replace(/"/g, '"') | ||
.replace(/'/g, '''); | ||
} | ||
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, |
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
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
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
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
254866
56
2250
169
3
13
+ Addedsax@>=0.6
+ Addedsax@1.4.1(transitive)
- Removednode-expat@>=1.6.1
- Removedbindings@1.5.0(transitive)
- Removedfile-uri-to-path@1.0.0(transitive)
- Removednan@2.20.0(transitive)
- Removednode-expat@2.4.1(transitive)