Skip to content

Commit

Permalink
feat: merge upstream node-soap (#2)
Browse files Browse the repository at this point in the history
* Fixed some issues with xsd elements (vpulim#1057)

* Fixed some issues with xsd elements

* Made the fix more specific to the particular usecase

* Added a test for aliased namespaces

* Release v0.27.0

* Move @types/request to dependencies (vpulim#1059)

soap's d.ts files depend on request. Unfortunately, since request
doesn't ship its own types, that means consumers of soap also need
@types/request. Currently @types/request is just a dev dependency, which
doesn't get installed by `npm install`. The fix is to move
`@types/request` to the dependencies list.

The error looks like this:

```
node_modules/soap/lib/client.d.ts(4,26): error TS7016: Could not find a declaration file for module 'request'. '../../../tests/cases/user/soap/node_modules/request/index.js' implicitly has an 'any' type.
```

Note that this only shows up when consumers compile with --strict, which is
fairly common.  Typescript's user-code tests include soap and detected
it after 0.27 shipped.

* Release v0.27.1

* Updated read me to reflect changes in soap.listen (vpulim#1060)

* Updated Read.me to reflect changes in soap.listen

* Updated Readme.md

* Updated Readme.md

* Updated Readme.md

* types: move forceSoap12Headers to IWsdlBaseOptions (vpulim#1063)

"forceSoap12Headers" works on server since bcc41e6. So, this option
should be available to server as well.

* client.addSoapHeader() dynamic SOAP header (vpulim#1062)

* Added support for parsing of doubles and floats. (vpulim#1065)

* Added support for parsing of doubles and floats.
package-lock updated due to out-of-date version.

* Reverting changed package-lock file.
  • Loading branch information
nfantone authored and lfantone committed May 20, 2019
1 parent 1230b07 commit 4960668
Show file tree
Hide file tree
Showing 15 changed files with 215 additions and 27 deletions.
23 changes: 23 additions & 0 deletions History.md
@@ -1,3 +1,26 @@
0.27.1 / 2019-04-19
===================

* [FIX] Move @types/request to dependencies (#1059)

0.27.0 / 2019-04-18
===================

* [ENHANCEMENT] Added MTOM support for binary data (#1054)
* [ENHANCEMENT] Added callback for soap.listen (#1055)
* [ENHANCEMENT] add rsa-sha256 support for WSSecurityCert (#1052)
* [ENHANCEMENT] adding promise support for server method handlers.
* [FIX] Fixed PasswordDigest Generation (#1039)
* [FIX] Fixed some issues with xsd elements (#1057)
* [FIX] Handle response with error status code and without response body (#1053)
* [FIX] Stringify wsdl-related error messages to avoid non-descriptive [object Object] output. (#1037)
* [FIX] fix(compliance): updated the npm packages
* [FIX] fix(wsdl): array namespace override with colon(:) (#1045)
* [MAINTENANCE] adding source-map-support for ts mapping in stack trace; enabling tslint rules; added linting to travis; removing unnecessary self variables (#1047)
* [MAINTENANCE] converting the project to TypeScript (#1044)
* [MAINTENANCE] npm upgrade; removing ejs and external template files (#1046)
* [MAINTENANCE] npmignore cleanup; adding some types to Client (#1049)

0.26.0 / 2019-02-11
===================

Expand Down
13 changes: 9 additions & 4 deletions Readme.md
Expand Up @@ -16,7 +16,7 @@ This module lets you connect to web services using SOAP. It also provides a ser
- [Module](#module)
- [soap.createClient(url[, options], callback) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclienturl-options-callback---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path)
- [soap.createClientAsync(url[, options]) - create a new SOAP client from a WSDL url. Also supports a local filesystem path.](#soapcreateclientasyncurl-options---create-a-new-soap-client-from-a-wsdl-url-also-supports-a-local-filesystem-path)
- [soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.](#soaplistenserver-path-services-wsdl---create-a-new-soap-server-that-listens-on-path-and-provides-services)
- [soap.listen(*server*, *path*, *services*, *wsdl*, *callback*) - create a new SOAP server that listens on *path* and provides *services*.](#soaplistenserver-path-services-wsdl-callback---create-a-new-soap-server-that-listens-on-path-and-provides-services)
- [Options](#options)
- [Server Logging](#server-logging)
- [Server Events](#server-events)
Expand Down Expand Up @@ -145,9 +145,10 @@ The `options` argument allows you to customize the client with the following pro

Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-alive'}` in SOAP headers to avoid truncation of longer chunked responses.

### soap.listen(*server*, *path*, *services*, *wsdl*) - create a new SOAP server that listens on *path* and provides *services*.
### soap.listen(*server*, *path*, *services*, *wsdl*, *callback*) - create a new SOAP server that listens on *path* and provides *services*.
*server* can be a [http](https://nodejs.org/api/http.html) Server or [express](http://expressjs.com/) framework based server
*wsdl* is an xml string that defines the service.
*callback* a function to run after the server has been initialized.

``` javascript
var myService = {
Expand Down Expand Up @@ -203,7 +204,9 @@ Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-
});

server.listen(8000);
soap.listen(server, '/wsdl', myService, xml);
soap.listen(server, '/wsdl', myService, xml, function(){
console.log('server initialized');
});

//express server example
var app = express();
Expand All @@ -212,7 +215,9 @@ Note: for versions of node >0.10.X, you may need to specify `{connection: 'keep-
app.listen(8001, function(){
//Note: /wsdl route will be handled by soap module
//and all other routes & middleware will continue to work
soap.listen(app, '/wsdl', myService, xml);
soap.listen(app, '/wsdl', myService, xml, function(){
console.log('server initialized');
});
});

```
Expand Down
4 changes: 2 additions & 2 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "@flybondi/soap",
"version": "0.26.0",
"version": "0.27.1",
"description": "A minimal node SOAP client",
"engines": {
"node": ">=4.0.0"
Expand All @@ -16,6 +16,7 @@
"sax": ">=0.6",
"serve-static": "^1.11.1",
"strip-bom": "^3.0.0",
"@types/request": "^2.48.1",
"uuid": "^3.1.0",
"xml-crypto": "^1.2.0"
},
Expand Down Expand Up @@ -52,7 +53,6 @@
"@types/express": "^4.16.1",
"@types/lodash": "^4.14.122",
"@types/node": "^11.11.0",
"@types/request": "^2.48.1",
"@types/sax": "^1.0.1",
"@types/uuid": "^3.4.4",
"body-parser": "^1.15.2",
Expand Down
51 changes: 41 additions & 10 deletions src/client.ts
Expand Up @@ -58,7 +58,7 @@ export class Client extends EventEmitter {

private wsdl: WSDL;
private httpClient: HttpClient;
private soapHeaders: string[];
private soapHeaders: any[];
private httpHeaders: IHeaders;
private bodyAttributes: string[];
private endpoint: string;
Expand All @@ -82,13 +82,11 @@ export class Client extends EventEmitter {
}

/** add soapHeader to soap:Header node */
public addSoapHeader(soapHeader: any, name?: string, namespace?: string, xmlns?: string): number {
public addSoapHeader(soapHeader: any, name?: string, namespace?: any, xmlns?: string): number {
if (!this.soapHeaders) {
this.soapHeaders = [];
}
if (typeof soapHeader === 'object') {
soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true);
}
soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns);
return this.soapHeaders.push(soapHeader) - 1;
}

Expand All @@ -102,9 +100,7 @@ export class Client extends EventEmitter {
if (!this.soapHeaders) {
this.soapHeaders = [];
}
if (typeof soapHeader === 'object') {
soapHeader = this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true);
}
soapHeader = this._processSoapHeader(soapHeader, name, namespace, xmlns);
this.soapHeaders[index] = soapHeader;
}

Expand Down Expand Up @@ -266,6 +262,28 @@ export class Client extends EventEmitter {
};
}

private _processSoapHeader(soapHeader, name, namespace, xmlns) {
switch (typeof soapHeader) {
case 'object':
return this.wsdl.objectToXML(soapHeader, name, namespace, xmlns, true);
case 'function':
const _this = this;
// arrow function does not support arguments variable
// tslint:disable-next-line
return function() {
const result = soapHeader.apply(null, arguments);

if (typeof result === 'object') {
return _this.wsdl.objectToXML(result, name, namespace, xmlns, true);
} else {
return result;
}
};
default:
return soapHeader;
}
}

private _invoke(
method: OperationElement,
args,
Expand Down Expand Up @@ -411,6 +429,19 @@ export class Client extends EventEmitter {
input.$type || input.$lookupType
);
}

let decodedHeaders;
if (this.soapHeaders) {
decodedHeaders = this.soapHeaders
.map(header => {
if (typeof header === 'function') {
return header(method, location, soapAction, args);
} else {
return header;
}
})
.join('\n');
}
xml =
'<?xml version="1.0" encoding="utf-8"?>' +
'<' +
Expand All @@ -422,11 +453,11 @@ export class Client extends EventEmitter {
encoding +
this.wsdl.xmlnsInEnvelope +
'>' +
(this.soapHeaders || this.security
(decodedHeaders || this.security
? '<' +
envelopeKey +
':Header>' +
(this.soapHeaders ? this.soapHeaders.join('\n') : '') +
(decodedHeaders ? decodedHeaders : '') +
(this.security && !this.security.postProcess ? this.security.toXML() : '') +
'</' +
envelopeKey +
Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Expand Up @@ -96,6 +96,8 @@ export interface IWsdlBaseOptions {
wsdl_headers?: { [key: string]: any };
/** custom options for the request module on WSDL requests. */
wsdl_options?: { [key: string]: any };
/** set proper headers for SOAP v1.2. */
forceSoap12Headers?: boolean;
}

/** @deprecated use IOptions */
Expand All @@ -113,8 +115,6 @@ export interface IOptions extends IWsdlBaseOptions {
request?: req.RequestAPI<req.Request, req.CoreOptions, req.RequiredUriUrl>;
stream?: boolean;
// wsdl options that only work for client
/** set proper headers for SOAP v1.2. */
forceSoap12Headers?: boolean;
customDeserializer?: any;
/** if your wsdl operations contains names with Async suffix, you will need to override the default promise suffix to a custom one, default: Async. */
overridePromiseSuffix?: string;
Expand Down
6 changes: 4 additions & 2 deletions src/wsdl/elements.ts
Expand Up @@ -218,7 +218,9 @@ export class ElementElement extends Element {
const typeName: string = type.name;
const ns: string =
(xmlns && xmlns[type.prefix]) ||
(definitions.xmlns[type.prefix] !== undefined && this.schemaXmlns[type.prefix]) ||
((definitions.xmlns[type.prefix] !== undefined ||
definitions.xmlns[this.targetNSAlias] !== undefined) &&
this.schemaXmlns[type.prefix]) ||
definitions.xmlns[type.prefix];
const schema = definitions.schemas[ns];
const typeElement =
Expand Down Expand Up @@ -415,7 +417,7 @@ export class ExtensionElement extends Element {

if (typeElement) {
const base = typeElement.description(definitions, schema.xmlns);
desc = _.defaultsDeep(base, desc);
desc = typeof base === 'string' ? base : _.defaultsDeep(base, desc);
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/wsdl/index.ts
Expand Up @@ -450,6 +450,8 @@ export class WSDL {
} else {
if (name === 'int' || name === 'integer') {
value = parseInt(text, 10);
} else if (name === 'double' || name === 'float') {
value = Number(text);
} else if (name === 'bool' || name === 'boolean') {
value = text.toLowerCase() === 'true' || text === '1';
} else if (name === 'dateTime' || name === 'date') {
Expand Down
25 changes: 25 additions & 0 deletions test/client-test.js
Expand Up @@ -521,6 +521,31 @@ var fs = require('fs'),
});
});

it('should add dynamic soap headers', function (done) {
soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) {
assert.ok(client);
assert.ok(!client.getSoapHeaders());
let random;
function dynamicHeader(method, location, soapAction, args) {
random = Math.floor(Math.random() * 65536);
return {
TeSt_location: location,
TeSt_action: soapAction,
TeSt_random: random
};
}

client.addSoapHeader(dynamicHeader);
assert.ok(typeof client.getSoapHeaders()[0] === 'function');
client.MyOperation({}, function (err, result) {
assert.notEqual(client.lastRequest.indexOf('<TeSt_location>http://www.example.com/v1</TeSt_location>'), -1);
assert.notEqual(client.lastRequest.indexOf('<TeSt_action>MyOperation</TeSt_action>'), -1);
assert.notEqual(client.lastRequest.indexOf(`<TeSt_random>${random}</TeSt_random>`), -1);
done();
});
});
});

it('should add soap headers with a namespace', function (done) {
soap.createClient(__dirname + '/wsdl/default_namespace.wsdl', meta.options, function (err, client) {
assert.ok(client);
Expand Down
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:tns="http://www.Dummy.com/Common/Types" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.Dummy.com/Common/Types" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:complexType name="DummyResult">
<xs:sequence>
<xs:element name="DummyList" type="tns:DummyList" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="code" type="xs:string" use="optional"/>
</xs:complexType>
<xs:complexType name="Dummy">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="language" type="xs:language" use="optional"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="DummyList">
<xs:sequence>
<xs:element name="DummyElement" type="tns:Dummy" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="DummyFilter">
<xs:sequence>
<xs:element name="DummyIntFilter" type="xs:string" minOccurs="0"/>
<xs:element name="DummyStringFilter" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:c="http://www.Dummy.com/Common/Types" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:me="http://www.Dummy.com/Name/Types" targetNamespace="http://www.Dummy.com/Name/Types" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:import namespace="common.xsd" schemaLocation="common.xsd"/>
<xs:element name="DummyRequest" type="me:requestType"/>
<xs:element name="DummyResponse" type="me:responseType"/>
<xs:element name="requestType">
<xs:complexType>
<xs:sequence>
<xs:element name="DummyField1" type="xs:string" minOccurs="0"/>
<xs:element name="DummyFilter" type="c:DummyFilter" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="responseType">
<xs:complexType>
<xs:sequence>
<xs:element name="DummyResult" type="c:DummyResult"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
@@ -0,0 +1,6 @@
{
"DummyField1": "Humpty",
"DummyFilter": {
"DummyStringFilter": "Dumpty"
}
}
@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.Dummy.com" xmlns:n="http://www.Dummy.com/Name/Types"><soap:Body><n:DummyRequest xmlns:n="http://www.Dummy.com/Name/Types" xmlns="http://www.Dummy.com/Name/Types"><n:DummyField1>Humpty</n:DummyField1><n:DummyFilter><c:DummyStringFilter xmlns:c="http://www.Dummy.com/Common/Types">Dumpty</c:DummyStringFilter></n:DummyFilter></n:DummyRequest></soap:Body></soap:Envelope>
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.Dummy.com" xmlns:n="http://www.Dummy.com/Name/Types" xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://www.Dummy.com">
<wsdl:types>
<xs:schema>
<xs:import namespace="http://www.Dummy.com/Common/Types" schemaLocation="common.xsd"/>
<xs:import namespace="http://www.Dummy.com/Name/Types" schemaLocation="name.xsd"/>
</xs:schema>
</wsdl:types>
<wsdl:message name="DummyRequest">
<wsdl:part name="DummyRequest" element="n:DummyRequest"/>
</wsdl:message>
<wsdl:message name="DummyResponse">
<wsdl:part name="DummyResponse" element="n:DummyResponse"/>
</wsdl:message>
<wsdl:portType name="DummyPortType">
<wsdl:operation name="Dummy">
<wsdl:input message="tns:DummyRequest"/>
<wsdl:output message="tns:DummyResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DummyBinding" type="tns:DummyPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="Dummy">
<soap:operation soapAction="http://www.Dummy.com#Dummy" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="DummyService">
<wsdl:port name="DummyPortType" binding="tns:DummyBinding">
<soap:address location="http://www.Dummy.com/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

0 comments on commit 4960668

Please sign in to comment.