Comparing version 0.6.1 to 0.7.0
@@ -0,1 +1,19 @@ | ||
0.7.0 / 2015-02-10 | ||
================= | ||
* [ENHANCEMENT] (Server) Server emits a `headers` event to globally handle SOAP Headers. (#564 ) | ||
* [ENHANCEMENT] (Server) A service method can send back a SOAP Fault response to a client by throwing an object that contains a `Fault` property. (#563) | ||
* [FIX] Don't throw an Error if an `element` is not defined. (#562) | ||
* [ENHANCEMENT] Added more primitive types (`['positiveInteger', 'nonPositiveInteger', 'negativeInteger', 'nonNegativeInteger']`). (#560) | ||
* [FIX] (Client) Respect empty SOAP actions in operations. (#554) | ||
* [ENHANCEMENT] (Client) The client now emits `message`, `request` and `soapError` events. (#547, #559) | ||
* [ENHANCEMENT] (Server) The server is now aware of the SOAP header(s) from incoming request. (#551) | ||
* [ENHANCEMENT] (Client) Until now, only the SOAP Body was returned from the invoked client method. With this PR also the SOAP Header(s) will be returned. (#539) | ||
0.6.1 / 2014-12-20 | ||
@@ -2,0 +20,0 @@ ================== |
@@ -16,5 +16,9 @@ /* | ||
assert = require('assert'), | ||
events = require('events'), | ||
util = require('util'), | ||
url = require('url'); | ||
var Client = function(wsdl, endpoint, options) { | ||
events.EventEmitter.call(this); | ||
options = options || {}; | ||
@@ -25,2 +29,3 @@ this.wsdl = wsdl; | ||
}; | ||
util.inherits(Client, events.EventEmitter); | ||
@@ -103,4 +108,4 @@ Client.prototype.addSoapHeader = function(soapHeader, name, namespace, xmlns) { | ||
} | ||
self._invoke(method, args, location, function(error, result, raw) { | ||
callback(error, result, raw); | ||
self._invoke(method, args, location, function(error, result, raw, soapHeader) { | ||
callback(error, result, raw, soapHeader); | ||
}, options, extraHeaders); | ||
@@ -122,9 +127,18 @@ }; | ||
req = null, | ||
soapAction = this.SOAPAction ? this.SOAPAction(ns, name) : (method.soapAction || (((ns.lastIndexOf("/") !== ns.length - 1) ? ns + "/" : ns) + name)), | ||
soapAction, | ||
alias = findKey(defs.xmlns, ns), | ||
headers = { | ||
SOAPAction: '"' + soapAction + '"', | ||
'Content-Type': "text/xml; charset=utf-8" | ||
}, | ||
alias = findKey(defs.xmlns, ns); | ||
}; | ||
if (this.SOAPAction) { | ||
soapAction = this.SOAPAction; | ||
} else if (method.soapAction !== undefined && method.soapAction !== null) { | ||
soapAction = method.soapAction; | ||
} else { | ||
soapAction = ((ns.lastIndexOf("/") !== ns.length - 1) ? ns + "/" : ns) + name; | ||
} | ||
headers.SOAPAction = '"' + soapAction + '"'; | ||
options = options || {}; | ||
@@ -177,2 +191,5 @@ | ||
self.emit('message', message); | ||
self.emit('request', xml); | ||
req = http.request(location, xml, function(err, response, body) { | ||
@@ -192,2 +209,3 @@ var result; | ||
error.body = body; | ||
self.emit('soapError', error); | ||
return callback(error, response, body); | ||
@@ -211,3 +229,3 @@ } | ||
callback(null, result, body); | ||
callback(null, result, body, obj.Header); | ||
} | ||
@@ -214,0 +232,0 @@ }, headers, options); |
@@ -15,3 +15,5 @@ /* | ||
var url = require('url'), | ||
compress = null; | ||
compress = null, | ||
events = require('events'), | ||
util = require('util'); | ||
@@ -26,2 +28,4 @@ try { | ||
events.EventEmitter.call(this); | ||
options = options || {}; | ||
@@ -60,2 +64,3 @@ this.path = path; | ||
}; | ||
util.inherits(Server, events.EventEmitter); | ||
@@ -137,4 +142,5 @@ Server.prototype._initializeOptions = function(options) { | ||
body = obj.Body, | ||
headers = obj.Header, | ||
bindings = this.wsdl.definitions.bindings, binding, | ||
methods, method, methodName, | ||
method, methodName, | ||
serviceName, portName; | ||
@@ -189,26 +195,46 @@ | ||
methods = binding.methods; | ||
try { | ||
if (binding.style === 'rpc') { | ||
methodName = Object.keys(body)[0]; | ||
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); | ||
if (headers) | ||
self.emit('headers', headers, methodName); | ||
self._executeMethod({ | ||
serviceName: serviceName, | ||
portName: portName, | ||
methodName: methodName, | ||
outputName: methodName + 'Response', | ||
args: body[methodName], | ||
headers: headers, | ||
style: 'rpc' | ||
}, callback); | ||
} else { | ||
var messageElemName = Object.keys(body)[0]; | ||
var pair = binding.topElements[messageElemName]; | ||
if (headers) | ||
self.emit('headers', headers, pair.methodName); | ||
self._executeMethod({ | ||
serviceName: serviceName, | ||
portName: portName, | ||
methodName: pair.methodName, | ||
outputName: pair.outputName, | ||
args: body[messageElemName], | ||
headers: headers, | ||
style: 'document' | ||
}, callback); | ||
} | ||
} | ||
catch (e) { | ||
if (e.Fault !== undefined) { | ||
// 3rd param is the NS prepended to all elements | ||
// It must match the NS defined in the Envelope (set by the _envelope method) | ||
var fault = self.wsdl.objectToDocumentXML("Fault", e.Fault, "soap"); | ||
callback(self._envelope(fault)); | ||
} | ||
else | ||
throw e; | ||
} | ||
}; | ||
@@ -248,3 +274,3 @@ | ||
var result = method(args, handleResult); | ||
var result = method(args, handleResult, options.headers); | ||
if (typeof result !== 'undefined') { | ||
@@ -251,0 +277,0 @@ handleResult(result); |
@@ -31,2 +31,6 @@ /* | ||
short: 1, | ||
negativeInteger: 1, | ||
nonNegativeInteger: 1, | ||
positiveInteger: 1, | ||
nonPositiveInteger:1, | ||
unsignedByte: 1, | ||
@@ -481,2 +485,6 @@ unsignedInt: 1, | ||
this.element = schema.elements[nsName.name]; | ||
if(!this.element) { | ||
console.log(nsName.name + " is not present in wsdl and cannot be processed correctly."); | ||
return; | ||
} | ||
this.element.targetNSAlias = ns; | ||
@@ -1311,2 +1319,20 @@ this.element.targetNamespace = definitions.xmlns[ns]; | ||
}; | ||
p.oncdata = function (text) { | ||
text = trim(text); | ||
if (!text.length) | ||
return; | ||
if (/<\?xml[\s\S]+\?>/.test(text)) { | ||
var top = stack[stack.length - 1]; | ||
var value = self.xmlToObject(text); | ||
if (top.object[self.options.attributesKey]) { | ||
top.object[self.options.valueKey] = value; | ||
} else { | ||
top.object = value; | ||
} | ||
} else { | ||
p.ontext(text); | ||
} | ||
}; | ||
@@ -1360,12 +1386,14 @@ p.ontext = function(text) { | ||
} | ||
} | ||
var body = root.Envelope.Body; | ||
if (body.Fault) { | ||
var error = new Error(body.Fault.faultcode + ': ' + body.Fault.faultstring + (body.Fault.detail ? ': ' + body.Fault.detail : '')); | ||
error.root = root; | ||
throw error; | ||
if (root.Envelope) { | ||
var body = root.Envelope.Body; | ||
if (body.Fault) { | ||
var error = new Error(body.Fault.faultcode + ': ' + body.Fault.faultstring + (body.Fault.detail ? ': ' + body.Fault.detail : '')); | ||
error.root = root; | ||
throw error; | ||
} | ||
return root.Envelope; | ||
} | ||
return root.Envelope; | ||
return root; | ||
}; | ||
@@ -1372,0 +1400,0 @@ |
{ | ||
"name": "soap", | ||
"version": "0.6.1", | ||
"version": "0.7.0", | ||
"description": "A minimal node SOAP client", | ||
@@ -5,0 +5,0 @@ "engines": { |
@@ -49,3 +49,3 @@ # Soap [![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] | ||
}; | ||
} | ||
}, | ||
@@ -58,2 +58,9 @@ // This is how to define an asynchronous function. | ||
}) | ||
}, | ||
// This is how to receive incoming headers | ||
HeadersAwareFunction: function(args, cb, headers) { | ||
return { | ||
name: headers.Token | ||
}; | ||
} | ||
@@ -85,2 +92,50 @@ } | ||
### SOAP Fault | ||
A service method can reply with a SOAP Fault to a client by `throw`ing an | ||
object with a `Fault` property. | ||
``` javascript | ||
throw { | ||
Fault: { | ||
Code: { | ||
Value: "soap:Sender", | ||
Subcode: { value: "rpc:BadArguments" } | ||
}, | ||
Reason: { Text: "Processing Error" } | ||
} | ||
}; | ||
``` | ||
### SOAP Headers | ||
A service method can look at the SOAP headers by providing a 3rd arguments. | ||
``` javascript | ||
{ | ||
HeadersAwareFunction: function(args, cb, headers) { | ||
return { | ||
name: headers.Token | ||
}; | ||
} | ||
} | ||
``` | ||
It is also possible to subscribe to the 'headers' event. | ||
The event is triggered before the service method is called, and only when the | ||
SOAP Headers are not empty. | ||
``` javascript | ||
server = soap.listen(...) | ||
server.on('headers', function(headers, methodName) { | ||
// It is possible to change the value of the headers | ||
// before they are handed to the service method. | ||
// It is also possible to throw a SOAP Fault | ||
}); | ||
``` | ||
First parameter is the Headers object; | ||
second parameter is the name of the SOAP method that will called | ||
(in case you need to handle the headers differently based on the method). | ||
### server security example using PasswordDigest | ||
@@ -179,4 +234,6 @@ | ||
``` javascript | ||
client.MyFunction({name: 'value'}, function(err, result) { | ||
client.MyFunction({name: 'value'}, function(err, result, raw, soapHeader) { | ||
// result is a javascript object | ||
// raw is the raw response | ||
// soapHeader is the response soap header as a javascript object | ||
}) | ||
@@ -212,2 +269,13 @@ ``` | ||
### Client Events | ||
Client instances emit the following events: | ||
* request - Emitted before a request is sent. The event handler receives the | ||
entire Soap request (Envelope) including headers. | ||
* message - Emitted before a request is sent. The event handler receives the | ||
Soap body contents. Useful if you don't want to log /store Soap headers. | ||
* soapError - Emitted when an erroneous response is received. | ||
Useful if you want to globally log errors. | ||
## WSSecurity | ||
@@ -214,0 +282,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
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
119282
2293
433
1