soap 0.20.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.editorconfig +23 -23
  2. package/.jshintrc +29 -29
  3. package/.travis.yml +22 -22
  4. package/CONTRIBUTING.md +52 -58
  5. package/History.md +52 -2
  6. package/LICENSE +7 -7
  7. package/PUBLISHING.md +28 -28
  8. package/Readme.md +1062 -931
  9. package/coverage/coverage.json +1 -0
  10. package/coverage/lcov-report/base.css +212 -0
  11. package/coverage/lcov-report/index.html +119 -0
  12. package/coverage/lcov-report/node-soap/index.html +93 -0
  13. package/coverage/lcov-report/node-soap/index.js.html +74 -0
  14. package/coverage/lcov-report/node-soap/lib/client.js.html +1001 -0
  15. package/coverage/lcov-report/node-soap/lib/http.js.html +416 -0
  16. package/coverage/lcov-report/node-soap/lib/index.html +171 -0
  17. package/coverage/lcov-report/node-soap/lib/nscontext.js.html +734 -0
  18. package/coverage/lcov-report/node-soap/lib/security/BasicAuthSecurity.js.html +137 -0
  19. package/coverage/lcov-report/node-soap/lib/security/BearerSecurity.js.html +134 -0
  20. package/coverage/lcov-report/node-soap/lib/security/ClientSSLSecurity.js.html +296 -0
  21. package/coverage/lcov-report/node-soap/lib/security/ClientSSLSecurityPFX.js.html +218 -0
  22. package/coverage/lcov-report/node-soap/lib/security/WSSecurity.js.html +278 -0
  23. package/coverage/lcov-report/node-soap/lib/security/index.html +158 -0
  24. package/coverage/lcov-report/node-soap/lib/security/index.js.html +92 -0
  25. package/coverage/lcov-report/node-soap/lib/server.js.html +1139 -0
  26. package/coverage/lcov-report/node-soap/lib/soap.js.html +314 -0
  27. package/coverage/lcov-report/node-soap/lib/utils.js.html +161 -0
  28. package/coverage/lcov-report/node-soap/lib/wsdl.js.html +6275 -0
  29. package/coverage/lcov-report/prettify.css +1 -0
  30. package/coverage/lcov-report/prettify.js +1 -0
  31. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  32. package/coverage/lcov-report/sorter.js +158 -0
  33. package/coverage/lcov.info +3325 -0
  34. package/index.js +3 -3
  35. package/lib/client.js +434 -425
  36. package/lib/http.js +129 -129
  37. package/lib/nscontext.js +223 -223
  38. package/lib/security/BasicAuthSecurity.js +24 -24
  39. package/lib/security/BearerSecurity.js +23 -23
  40. package/lib/security/ClientSSLSecurity.js +82 -65
  41. package/lib/security/ClientSSLSecurityPFX.js +51 -51
  42. package/lib/security/WSSecurity.js +90 -90
  43. package/lib/security/WSSecurityCert.js +78 -78
  44. package/lib/security/index.js +10 -10
  45. package/lib/security/templates/wsse-security-header.ejs +12 -12
  46. package/lib/security/templates/wsse-security-token.ejs +3 -3
  47. package/lib/server.js +474 -444
  48. package/lib/soap.d.ts +220 -0
  49. package/lib/soap.js +110 -110
  50. package/lib/utils.js +30 -30
  51. package/lib/wsdl.js +2272 -2234
  52. package/package.json +8 -8
  53. package/soap-stub.js +148 -148
  54. package/.npmignore +0 -2
package/lib/server.js CHANGED
@@ -1,444 +1,474 @@
1
- /*
2
- * Copyright (c) 2011 Vinay Pulim <vinay@milewise.com>
3
- * MIT Licensed
4
- */
5
-
6
- "use strict";
7
-
8
- function getDateString(d) {
9
- function pad(n) {
10
- return n < 10 ? '0' + n : n;
11
- }
12
- return d.getUTCFullYear() + '-'
13
- + pad(d.getUTCMonth() + 1) + '-'
14
- + pad(d.getUTCDate()) + 'T'
15
- + pad(d.getUTCHours()) + ':'
16
- + pad(d.getUTCMinutes()) + ':'
17
- + pad(d.getUTCSeconds()) + 'Z';
18
- }
19
-
20
- var url = require('url'),
21
- compress = null,
22
- events = require('events'),
23
- util = require('util'),
24
- findPrefix = require('./utils').findPrefix;
25
-
26
- try {
27
- compress = require("compress");
28
- } catch (error) {
29
- }
30
-
31
- var Server = function (server, path, services, wsdl, options) {
32
- var self = this;
33
-
34
- events.EventEmitter.call(this);
35
-
36
- options = options || {};
37
- this.path = path;
38
- this.services = services;
39
- this.wsdl = wsdl;
40
- this.suppressStack = options && options.suppressStack;
41
- this.returnFault = options && options.returnFault;
42
-
43
- if (path[path.length - 1] !== '/')
44
- path += '/';
45
- wsdl.onReady(function (err) {
46
- if (typeof server.route === 'function' && typeof server.use === 'function') {
47
- //handle only the required URL path for express server
48
- server.route(path).all(function (req, res, next) {
49
- if (typeof self.authorizeConnection === 'function') {
50
- if (!self.authorizeConnection(req)) {
51
- res.end();
52
- return;
53
- }
54
- }
55
- self._requestListener(req, res);
56
- });
57
- } else {
58
- var listeners = server.listeners('request').slice();
59
- server.removeAllListeners('request');
60
- server.addListener('request', function (req, res) {
61
- if (typeof self.authorizeConnection === 'function') {
62
- if (!self.authorizeConnection(req)) {
63
- res.end();
64
- return;
65
- }
66
- }
67
- var reqPath = url.parse(req.url).pathname;
68
- if (reqPath[reqPath.length - 1] !== '/') {
69
- reqPath += '/';
70
- }
71
- if (path === reqPath) {
72
- self._requestListener(req, res);
73
- } else {
74
- for (var i = 0, len = listeners.length; i < len; i++) {
75
- listeners[i].call(this, req, res);
76
- }
77
- }
78
- });
79
- }
80
- });
81
-
82
- this._initializeOptions(options);
83
- };
84
- util.inherits(Server, events.EventEmitter);
85
-
86
- Server.prototype.addSoapHeader = function (soapHeader, name, namespace, xmlns) {
87
- if (!this.soapHeaders) {
88
- this.soapHeaders = [];
89
- }
90
- if (typeof soapHeader === 'object') {
91
- soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true);
92
- }
93
- return this.soapHeaders.push(soapHeader) - 1;
94
- };
95
-
96
- Server.prototype.changeSoapHeader = function (index, soapHeader, name, namespace, xmlns) {
97
- if (!this.soapHeaders) {
98
- this.soapHeaders = [];
99
- }
100
- if (typeof soapHeader === 'object') {
101
- soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true);
102
- }
103
- this.soapHeaders[index] = soapHeader;
104
- };
105
-
106
- Server.prototype.getSoapHeaders = function () {
107
- return this.soapHeaders;
108
- };
109
-
110
- Server.prototype.clearSoapHeaders = function () {
111
- this.soapHeaders = null;
112
- };
113
-
114
- Server.prototype._initializeOptions = function (options) {
115
- this.wsdl.options.attributesKey = options.attributesKey || 'attributes';
116
- };
117
-
118
- Server.prototype._processRequestXml = function (req, res, xml) {
119
- var self = this;
120
- var result;
121
- var error;
122
- try {
123
- if (typeof self.log === 'function') {
124
- self.log("received", xml);
125
- }
126
- self._process(xml, req, function (result, statusCode) {
127
- if (statusCode) {
128
- res.statusCode = statusCode;
129
- }
130
- res.write(result);
131
- res.end();
132
- if (typeof self.log === 'function') {
133
- self.log("replied", result);
134
- }
135
- });
136
- } catch (err) {
137
- if (err.Fault !== undefined) {
138
- return self._sendError(err.Fault, function (result, statusCode) {
139
- res.statusCode = statusCode || 500;
140
- res.write(result);
141
- res.end();
142
- if (typeof self.log === 'function') {
143
- self.log("error", err);
144
- }
145
- }, new Date().toISOString());
146
- } else {
147
- error = err.stack ? (self.suppressStack === true ? err.message : err.stack) : err;
148
- res.statusCode = 500;
149
- res.write(error);
150
- res.end();
151
- if (typeof self.log === 'function') {
152
- self.log("error", error);
153
- }
154
- }
155
- }
156
- };
157
-
158
- Server.prototype._requestListener = function (req, res) {
159
- var self = this;
160
- var reqParse = url.parse(req.url);
161
- var reqPath = reqParse.pathname;
162
- var reqQuery = reqParse.search;
163
-
164
- if (typeof self.log === 'function') {
165
- self.log("info", "Handling " + req.method + " on " + req.url);
166
- }
167
-
168
- if (req.method === 'GET') {
169
- if (reqQuery && reqQuery.toLowerCase() === '?wsdl') {
170
- if (typeof self.log === 'function') {
171
- self.log("info", "Wants the WSDL");
172
- }
173
- res.setHeader("Content-Type", "application/xml");
174
- res.write(self.wsdl.toXML());
175
- }
176
- res.end();
177
- } else if (req.method === 'POST') {
178
- if (typeof req.headers['content-type'] !== "undefined") {
179
- res.setHeader('Content-Type', req.headers['content-type']);
180
- } else {
181
- res.setHeader('Content-Type', "application/xml");
182
- }
183
-
184
- //request body is already provided by an express middleware
185
- //in this case unzipping should also be done by the express middleware itself
186
- if (req.body) {
187
- return self._processRequestXml(req, res, req.body.toString());
188
- }
189
-
190
- var chunks = [], gunzip;
191
- if (compress && req.headers["content-encoding"] === "gzip") {
192
- gunzip = new compress.Gunzip();
193
- gunzip.init();
194
- }
195
- req.on('data', function (chunk) {
196
- if (gunzip)
197
- chunk = gunzip.inflate(chunk, "binary");
198
- chunks.push(chunk);
199
- });
200
- req.on('end', function () {
201
- var xml = chunks.join('');
202
- var result;
203
- var error;
204
- if (gunzip) {
205
- gunzip.end();
206
- gunzip = null;
207
- }
208
- self._processRequestXml(req, res, xml);
209
- });
210
- }
211
- else {
212
- res.end();
213
- }
214
- };
215
-
216
- Server.prototype._process = function (input, req, callback) {
217
- var self = this,
218
- pathname = url.parse(req.url).pathname.replace(/\/$/, ''),
219
- obj = this.wsdl.xmlToObject(input),
220
- body = obj.Body,
221
- headers = obj.Header,
222
- bindings = this.wsdl.definitions.bindings, binding,
223
- method, methodName,
224
- serviceName, portName,
225
- includeTimestamp = obj.Header && obj.Header.Security && obj.Header.Security.Timestamp;
226
-
227
- if (typeof self.authenticate === 'function') {
228
- if (!obj.Header || !obj.Header.Security) {
229
- throw new Error('No security header');
230
- }
231
- if (!self.authenticate(obj.Header.Security)) {
232
- throw new Error('Invalid username or password');
233
- }
234
- }
235
-
236
- if (typeof self.log === 'function') {
237
- self.log("info", "Attempting to bind to " + pathname);
238
- }
239
-
240
- //Avoid Cannot convert undefined or null to object due to Object.keys(body)
241
- //and throw more meaningful error
242
- if (!body) {
243
- throw new Error('Failed to parse the SOAP Message body');
244
- }
245
-
246
- // use port.location and current url to find the right binding
247
- binding = (function (self) {
248
- var services = self.wsdl.definitions.services;
249
- var firstPort;
250
- var name;
251
- for (name in services) {
252
- serviceName = name;
253
- var service = services[serviceName];
254
- var ports = service.ports;
255
- for (name in ports) {
256
- portName = name;
257
- var port = ports[portName];
258
- var portPathname = url.parse(port.location).pathname.replace(/\/$/, '');
259
-
260
- if (typeof self.log === 'function') {
261
- self.log("info", "Trying " + portName + " from path " + portPathname);
262
- }
263
-
264
- if (portPathname === pathname)
265
- return port.binding;
266
-
267
- // The port path is almost always wrong for generated WSDLs
268
- if (!firstPort) {
269
- firstPort = port;
270
- }
271
- }
272
- }
273
- return !firstPort ? void 0 : firstPort.binding;
274
- })(this);
275
-
276
- if (!binding) {
277
- throw new Error('Failed to bind to WSDL');
278
- }
279
-
280
- try {
281
- if (binding.style === 'rpc') {
282
- methodName = Object.keys(body)[0];
283
-
284
- self.emit('request', obj, methodName);
285
- if (headers)
286
- self.emit('headers', headers, methodName);
287
-
288
- self._executeMethod({
289
- serviceName: serviceName,
290
- portName: portName,
291
- methodName: methodName,
292
- outputName: methodName + 'Response',
293
- args: body[methodName],
294
- headers: headers,
295
- style: 'rpc'
296
- }, req, callback);
297
- } else {
298
- var messageElemName = (Object.keys(body)[0] === 'attributes' ? Object.keys(body)[1] : Object.keys(body)[0]);
299
- var pair = binding.topElements[messageElemName];
300
-
301
- self.emit('request', obj, pair.methodName);
302
- if (headers)
303
- self.emit('headers', headers, pair.methodName);
304
-
305
- self._executeMethod({
306
- serviceName: serviceName,
307
- portName: portName,
308
- methodName: pair.methodName,
309
- outputName: pair.outputName,
310
- args: body[messageElemName],
311
- headers: headers,
312
- style: 'document'
313
- }, req, callback, includeTimestamp);
314
- }
315
- }
316
- catch (error) {
317
- if (error.Fault !== undefined) {
318
- return self._sendError(error.Fault, callback, includeTimestamp);
319
- }
320
-
321
- throw error;
322
- }
323
- };
324
-
325
- Server.prototype._executeMethod = function (options, req, callback, includeTimestamp) {
326
- options = options || {};
327
- var self = this,
328
- method, body,
329
- serviceName = options.serviceName,
330
- portName = options.portName,
331
- methodName = options.methodName,
332
- outputName = options.outputName,
333
- args = options.args,
334
- style = options.style,
335
- handled = false;
336
-
337
- try {
338
- method = this.services[serviceName][portName][methodName];
339
- } catch (error) {
340
- return callback(this._envelope('', includeTimestamp));
341
- }
342
-
343
- function handleResult(error, result) {
344
- if (handled)
345
- return;
346
- handled = true;
347
-
348
- if (error && error.Fault !== undefined) {
349
- return self._sendError(error.Fault, callback, includeTimestamp);
350
- }
351
- else if (result === undefined) {
352
- // Backward compatibility to support one argument callback style
353
- result = error;
354
- }
355
-
356
- if (style === 'rpc') {
357
- body = self.wsdl.objectToRpcXML(outputName, result, '', self.wsdl.definitions.$targetNamespace);
358
- } else {
359
- var element = self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output;
360
- body = self.wsdl.objectToDocumentXML(outputName, result, element.targetNSAlias, element.targetNamespace);
361
- }
362
- callback(self._envelope(body, includeTimestamp));
363
- }
364
-
365
- if (!self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output) {
366
- // no output defined = one-way operation so return empty response
367
- handled = true;
368
- callback('');
369
- }
370
-
371
- var result = method(args, handleResult, options.headers, req);
372
- if (typeof result !== 'undefined') {
373
- handleResult(result);
374
- }
375
- };
376
-
377
- Server.prototype._envelope = function (body, includeTimestamp) {
378
- var defs = this.wsdl.definitions,
379
- ns = defs.$targetNamespace,
380
- encoding = '',
381
- alias = findPrefix(defs.xmlns, ns);
382
- var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
383
- "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
384
- encoding +
385
- this.wsdl.xmlnsInEnvelope + '>';
386
- var headers = '';
387
-
388
- if (includeTimestamp) {
389
- var now = new Date();
390
- var created = getDateString(now);
391
- var expires = getDateString(new Date(now.getTime() + (1000 * 600)));
392
-
393
- headers += "<o:Security soap:mustUnderstand=\"1\" " +
394
- "xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " +
395
- "xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
396
- " <u:Timestamp u:Id=\"_0\">" +
397
- " <u:Created>" + created + "</u:Created>" +
398
- " <u:Expires>" + expires + "</u:Expires>" +
399
- " </u:Timestamp>" +
400
- " </o:Security>\n";
401
- }
402
-
403
- if (this.soapHeaders) {
404
- headers += this.soapHeaders.join("\n");
405
- }
406
-
407
- if (headers !== '') {
408
- xml += "<soap:Header>" + headers + "</soap:Header>";
409
- }
410
-
411
- xml += "<soap:Body>" +
412
- body +
413
- "</soap:Body>" +
414
- "</soap:Envelope>";
415
- return xml;
416
- };
417
-
418
- Server.prototype._sendError = function (soapFault, callback, includeTimestamp) {
419
- var self = this,
420
- fault;
421
-
422
- var statusCode;
423
- if (soapFault.statusCode) {
424
- statusCode = soapFault.statusCode;
425
- soapFault.statusCode = undefined;
426
- }
427
-
428
- if (soapFault.faultcode) {
429
- // Soap 1.1 error style
430
- // Root element will be prependend with the soap NS
431
- // It must match the NS defined in the Envelope (set by the _envelope method)
432
- fault = self.wsdl.objectToDocumentXML("soap:Fault", soapFault, undefined);
433
- }
434
- else {
435
- // Soap 1.2 error style.
436
- // 3rd param is the NS prepended to all elements
437
- // It must match the NS defined in the Envelope (set by the _envelope method)
438
- fault = self.wsdl.objectToDocumentXML("Fault", soapFault, "soap");
439
- }
440
-
441
- return callback(self._envelope(fault, includeTimestamp), statusCode);
442
- };
443
-
444
- exports.Server = Server;
1
+ /*
2
+ * Copyright (c) 2011 Vinay Pulim <vinay@milewise.com>
3
+ * MIT Licensed
4
+ */
5
+
6
+ "use strict";
7
+
8
+ function getDateString(d) {
9
+ function pad(n) {
10
+ return n < 10 ? '0' + n : n;
11
+ }
12
+ return d.getUTCFullYear() + '-'
13
+ + pad(d.getUTCMonth() + 1) + '-'
14
+ + pad(d.getUTCDate()) + 'T'
15
+ + pad(d.getUTCHours()) + ':'
16
+ + pad(d.getUTCMinutes()) + ':'
17
+ + pad(d.getUTCSeconds()) + 'Z';
18
+ }
19
+
20
+ var url = require('url'),
21
+ zlib = null,
22
+ events = require('events'),
23
+ util = require('util'),
24
+ findPrefix = require('./utils').findPrefix;
25
+
26
+ try {
27
+ zlib = require("zlib");
28
+ } catch (error) {
29
+ }
30
+
31
+ var Server = function (server, path, services, wsdl, options) {
32
+ var self = this;
33
+
34
+ events.EventEmitter.call(this);
35
+
36
+ options = options || {};
37
+ this.path = path;
38
+ this.services = services;
39
+ this.wsdl = wsdl;
40
+ this.suppressStack = options && options.suppressStack;
41
+ this.returnFault = options && options.returnFault;
42
+ this.onewayOptions = options && options.oneWay || {};
43
+
44
+ if (path[path.length - 1] !== '/')
45
+ path += '/';
46
+ wsdl.onReady(function (err) {
47
+ if (typeof server.route === 'function' && typeof server.use === 'function') {
48
+ //handle only the required URL path for express server
49
+ server.route(path).all(function (req, res, next) {
50
+ if (typeof self.authorizeConnection === 'function') {
51
+ if (!self.authorizeConnection(req)) {
52
+ res.end();
53
+ return;
54
+ }
55
+ }
56
+ self._requestListener(req, res);
57
+ });
58
+ } else {
59
+ var listeners = server.listeners('request').slice();
60
+ server.removeAllListeners('request');
61
+ server.addListener('request', function (req, res) {
62
+ if (typeof self.authorizeConnection === 'function') {
63
+ if (!self.authorizeConnection(req)) {
64
+ res.end();
65
+ return;
66
+ }
67
+ }
68
+ var reqPath = url.parse(req.url).pathname;
69
+ if (reqPath[reqPath.length - 1] !== '/') {
70
+ reqPath += '/';
71
+ }
72
+ if (path === reqPath) {
73
+ self._requestListener(req, res);
74
+ } else {
75
+ for (var i = 0, len = listeners.length; i < len; i++) {
76
+ listeners[i].call(this, req, res);
77
+ }
78
+ }
79
+ });
80
+ }
81
+ });
82
+
83
+ this._initializeOptions(options);
84
+ };
85
+ util.inherits(Server, events.EventEmitter);
86
+
87
+ Server.prototype._processSoapHeader = function (soapHeader, name, namespace, xmlns) {
88
+ var self = this;
89
+
90
+ switch (typeof soapHeader) {
91
+ case 'object':
92
+ return this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true);
93
+ case 'function':
94
+ return function() {
95
+ var result = soapHeader.apply(null, arguments);
96
+
97
+ if (typeof result === 'object') {
98
+ return self.wsdl.objectToXML(result, name, namespace, xmlns, true);
99
+ } else {
100
+ return result;
101
+ }
102
+ };
103
+ default:
104
+ return soapHeader;
105
+ }
106
+ };
107
+
108
+ Server.prototype.addSoapHeader = function (soapHeader, name, namespace, xmlns) {
109
+ if (!this.soapHeaders) {
110
+ this.soapHeaders = [];
111
+ }
112
+ soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns);
113
+ return this.soapHeaders.push(soapHeader) - 1;
114
+ };
115
+
116
+ Server.prototype.changeSoapHeader = function (index, soapHeader, name, namespace, xmlns) {
117
+ if (!this.soapHeaders) {
118
+ this.soapHeaders = [];
119
+ }
120
+ soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns);
121
+ this.soapHeaders[index] = soapHeader;
122
+ };
123
+
124
+ Server.prototype.getSoapHeaders = function () {
125
+ return this.soapHeaders;
126
+ };
127
+
128
+ Server.prototype.clearSoapHeaders = function () {
129
+ this.soapHeaders = null;
130
+ };
131
+
132
+ Server.prototype._initializeOptions = function (options) {
133
+ this.wsdl.options.attributesKey = options.attributesKey || 'attributes';
134
+ this.onewayOptions.statusCode = this.onewayOptions.responseCode || 200;
135
+ this.onewayOptions.emptyBody = !!this.onewayOptions.emptyBody;
136
+ };
137
+
138
+ Server.prototype._processRequestXml = function (req, res, xml) {
139
+ var self = this;
140
+ var result;
141
+ var error;
142
+ try {
143
+ if (typeof self.log === 'function') {
144
+ self.log("received", xml);
145
+ }
146
+ self._process(xml, req, function (result, statusCode) {
147
+ if (statusCode) {
148
+ res.statusCode = statusCode;
149
+ }
150
+ res.write(result);
151
+ res.end();
152
+ if (typeof self.log === 'function') {
153
+ self.log("replied", result);
154
+ }
155
+ });
156
+ } catch (err) {
157
+ if (err.Fault !== undefined) {
158
+ return self._sendError(err.Fault, function (result, statusCode) {
159
+ res.statusCode = statusCode || 500;
160
+ res.write(result);
161
+ res.end();
162
+ if (typeof self.log === 'function') {
163
+ self.log("error", err);
164
+ }
165
+ }, new Date().toISOString());
166
+ } else {
167
+ error = err.stack ? (self.suppressStack === true ? err.message : err.stack) : err;
168
+ res.statusCode = 500;
169
+ res.write(error);
170
+ res.end();
171
+ if (typeof self.log === 'function') {
172
+ self.log("error", error);
173
+ }
174
+ }
175
+ }
176
+ };
177
+
178
+ Server.prototype._requestListener = function (req, res) {
179
+ var self = this;
180
+ var reqParse = url.parse(req.url);
181
+ var reqPath = reqParse.pathname;
182
+ var reqQuery = reqParse.search;
183
+
184
+ if (typeof self.log === 'function') {
185
+ self.log("info", "Handling " + req.method + " on " + req.url);
186
+ }
187
+
188
+ if (req.method === 'GET') {
189
+ if (reqQuery && reqQuery.toLowerCase() === '?wsdl') {
190
+ if (typeof self.log === 'function') {
191
+ self.log("info", "Wants the WSDL");
192
+ }
193
+ res.setHeader("Content-Type", "application/xml");
194
+ res.write(self.wsdl.toXML());
195
+ }
196
+ res.end();
197
+ } else if (req.method === 'POST') {
198
+ if (typeof req.headers['content-type'] !== "undefined") {
199
+ res.setHeader('Content-Type', req.headers['content-type']);
200
+ } else {
201
+ res.setHeader('Content-Type', "application/xml");
202
+ }
203
+
204
+ //request body is already provided by an express middleware
205
+ //in this case unzipping should also be done by the express middleware itself
206
+ if (req.body) {
207
+ return self._processRequestXml(req, res, req.body.toString());
208
+ }
209
+
210
+ var chunks = [], gunzip, source = req;
211
+ if (req.headers["content-encoding"] === "gzip") {
212
+ gunzip = zlib.createGunzip();
213
+ req.pipe(gunzip);
214
+ source = gunzip;
215
+ }
216
+ source.on('data', function (chunk) {
217
+ chunks.push(chunk);
218
+ });
219
+ source.on('end', function () {
220
+ var xml = chunks.join('');
221
+ var result;
222
+ var error;
223
+ self._processRequestXml(req, res, xml);
224
+ });
225
+ }
226
+ else {
227
+ res.end();
228
+ }
229
+ };
230
+
231
+ Server.prototype._process = function (input, req, callback) {
232
+ var self = this,
233
+ pathname = url.parse(req.url).pathname.replace(/\/$/, ''),
234
+ obj = this.wsdl.xmlToObject(input),
235
+ body = obj.Body,
236
+ headers = obj.Header,
237
+ bindings = this.wsdl.definitions.bindings, binding,
238
+ method, methodName,
239
+ serviceName, portName,
240
+ includeTimestamp = obj.Header && obj.Header.Security && obj.Header.Security.Timestamp;
241
+
242
+ if (typeof self.authenticate === 'function') {
243
+ if (!obj.Header || !obj.Header.Security) {
244
+ throw new Error('No security header');
245
+ }
246
+ if (!self.authenticate(obj.Header.Security)) {
247
+ throw new Error('Invalid username or password');
248
+ }
249
+ }
250
+
251
+ if (typeof self.log === 'function') {
252
+ self.log("info", "Attempting to bind to " + pathname);
253
+ }
254
+
255
+ //Avoid Cannot convert undefined or null to object due to Object.keys(body)
256
+ //and throw more meaningful error
257
+ if (!body) {
258
+ throw new Error('Failed to parse the SOAP Message body');
259
+ }
260
+
261
+ // use port.location and current url to find the right binding
262
+ binding = (function (self) {
263
+ var services = self.wsdl.definitions.services;
264
+ var firstPort;
265
+ var name;
266
+ for (name in services) {
267
+ serviceName = name;
268
+ var service = services[serviceName];
269
+ var ports = service.ports;
270
+ for (name in ports) {
271
+ portName = name;
272
+ var port = ports[portName];
273
+ var portPathname = url.parse(port.location).pathname.replace(/\/$/, '');
274
+
275
+ if (typeof self.log === 'function') {
276
+ self.log("info", "Trying " + portName + " from path " + portPathname);
277
+ }
278
+
279
+ if (portPathname === pathname)
280
+ return port.binding;
281
+
282
+ // The port path is almost always wrong for generated WSDLs
283
+ if (!firstPort) {
284
+ firstPort = port;
285
+ }
286
+ }
287
+ }
288
+ return !firstPort ? void 0 : firstPort.binding;
289
+ })(this);
290
+
291
+ if (!binding) {
292
+ throw new Error('Failed to bind to WSDL');
293
+ }
294
+
295
+ try {
296
+ if (binding.style === 'rpc') {
297
+ methodName = Object.keys(body)[0];
298
+
299
+ self.emit('request', obj, methodName);
300
+ if (headers)
301
+ self.emit('headers', headers, methodName);
302
+
303
+ self._executeMethod({
304
+ serviceName: serviceName,
305
+ portName: portName,
306
+ methodName: methodName,
307
+ outputName: methodName + 'Response',
308
+ args: body[methodName],
309
+ headers: headers,
310
+ style: 'rpc'
311
+ }, req, callback);
312
+ } else {
313
+ var messageElemName = (Object.keys(body)[0] === 'attributes' ? Object.keys(body)[1] : Object.keys(body)[0]);
314
+ var pair = binding.topElements[messageElemName];
315
+
316
+ self.emit('request', obj, pair.methodName);
317
+ if (headers)
318
+ self.emit('headers', headers, pair.methodName);
319
+
320
+ self._executeMethod({
321
+ serviceName: serviceName,
322
+ portName: portName,
323
+ methodName: pair.methodName,
324
+ outputName: pair.outputName,
325
+ args: body[messageElemName],
326
+ headers: headers,
327
+ style: 'document'
328
+ }, req, callback, includeTimestamp);
329
+ }
330
+ }
331
+ catch (error) {
332
+ if (error.Fault !== undefined) {
333
+ return self._sendError(error.Fault, callback, includeTimestamp);
334
+ }
335
+
336
+ throw error;
337
+ }
338
+ };
339
+
340
+ Server.prototype._executeMethod = function (options, req, callback, includeTimestamp) {
341
+ options = options || {};
342
+ var self = this,
343
+ method, body, headers,
344
+ serviceName = options.serviceName,
345
+ portName = options.portName,
346
+ methodName = options.methodName,
347
+ outputName = options.outputName,
348
+ args = options.args,
349
+ style = options.style,
350
+ handled = false;
351
+
352
+ if (this.soapHeaders) {
353
+ headers = this.soapHeaders.map(function(header) {
354
+ if (typeof header === 'function') {
355
+ return header(methodName, args, options.headers, req);
356
+ } else {
357
+ return header;
358
+ }
359
+ }).join("\n");
360
+ }
361
+
362
+ try {
363
+ method = this.services[serviceName][portName][methodName];
364
+ } catch (error) {
365
+ return callback(this._envelope('', headers, includeTimestamp));
366
+ }
367
+
368
+ function handleResult(error, result) {
369
+ if (handled)
370
+ return;
371
+ handled = true;
372
+
373
+ if (error && error.Fault !== undefined) {
374
+ return self._sendError(error.Fault, callback, includeTimestamp);
375
+ }
376
+ else if (result === undefined) {
377
+ // Backward compatibility to support one argument callback style
378
+ result = error;
379
+ }
380
+
381
+ if (style === 'rpc') {
382
+ body = self.wsdl.objectToRpcXML(outputName, result, '', self.wsdl.definitions.$targetNamespace);
383
+ } else {
384
+ var element = self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output;
385
+ body = self.wsdl.objectToDocumentXML(outputName, result, element.targetNSAlias, element.targetNamespace);
386
+ }
387
+ callback(self._envelope(body, headers, includeTimestamp));
388
+ }
389
+
390
+ if (!self.wsdl.definitions.services[serviceName].ports[portName].binding.methods[methodName].output) {
391
+ // no output defined = one-way operation so return empty response
392
+ handled = true;
393
+ body = '';
394
+ if (this.onewayOptions.emptyBody) {
395
+ body = self._envelope('', headers, includeTimestamp);
396
+ }
397
+ callback(body, this.onewayOptions.responseCode);
398
+ }
399
+
400
+ var result = method(args, handleResult, options.headers, req);
401
+ if (typeof result !== 'undefined') {
402
+ handleResult(result);
403
+ }
404
+ };
405
+
406
+ Server.prototype._envelope = function (body, headers, includeTimestamp) {
407
+ var defs = this.wsdl.definitions,
408
+ ns = defs.$targetNamespace,
409
+ encoding = '',
410
+ alias = findPrefix(defs.xmlns, ns);
411
+
412
+ var envelopeDefinition = this.wsdl.options.forceSoap12Headers
413
+ ? "http://www.w3.org/2003/05/soap-envelope"
414
+ : "http://schemas.xmlsoap.org/soap/envelope/"
415
+
416
+ var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
417
+ "<soap:Envelope xmlns:soap=\"" + envelopeDefinition + "\" " +
418
+ encoding +
419
+ this.wsdl.xmlnsInEnvelope + '>';
420
+
421
+ headers = headers || '';
422
+
423
+ if (includeTimestamp) {
424
+ var now = new Date();
425
+ var created = getDateString(now);
426
+ var expires = getDateString(new Date(now.getTime() + (1000 * 600)));
427
+
428
+ headers += "<o:Security soap:mustUnderstand=\"1\" " +
429
+ "xmlns:o=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " +
430
+ "xmlns:u=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" +
431
+ " <u:Timestamp u:Id=\"_0\">" +
432
+ " <u:Created>" + created + "</u:Created>" +
433
+ " <u:Expires>" + expires + "</u:Expires>" +
434
+ " </u:Timestamp>" +
435
+ " </o:Security>\n";
436
+ }
437
+
438
+ if (headers !== '') {
439
+ xml += "<soap:Header>" + headers + "</soap:Header>";
440
+ }
441
+
442
+ xml += body ? "<soap:Body>" + body + "</soap:Body>" : "<soap:Body/>";
443
+
444
+ xml += "</soap:Envelope>";
445
+ return xml;
446
+ };
447
+
448
+ Server.prototype._sendError = function (soapFault, callback, includeTimestamp) {
449
+ var self = this,
450
+ fault;
451
+
452
+ var statusCode;
453
+ if (soapFault.statusCode) {
454
+ statusCode = soapFault.statusCode;
455
+ soapFault.statusCode = undefined;
456
+ }
457
+
458
+ if (soapFault.faultcode) {
459
+ // Soap 1.1 error style
460
+ // Root element will be prependend with the soap NS
461
+ // It must match the NS defined in the Envelope (set by the _envelope method)
462
+ fault = self.wsdl.objectToDocumentXML("soap:Fault", soapFault, undefined);
463
+ }
464
+ else {
465
+ // Soap 1.2 error style.
466
+ // 3rd param is the NS prepended to all elements
467
+ // It must match the NS defined in the Envelope (set by the _envelope method)
468
+ fault = self.wsdl.objectToDocumentXML("Fault", soapFault, "soap");
469
+ }
470
+
471
+ return callback(self._envelope(fault, '', includeTimestamp), statusCode);
472
+ };
473
+
474
+ exports.Server = Server;