Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mhzed committed Oct 10, 2014
0 parents commit 52c62a3
Show file tree
Hide file tree
Showing 13 changed files with 2,010 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
4 changes: 4 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.map
*.coffee
test/
node_modules/
110 changes: 110 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
This module lets you connect to web services using SOAP, in pure javascript, using node or browser.

This module is branched from node module "[email protected]". Specific changes are:

* soap server removed
* use [email protected] as xml parser, because its pure javascript
* use jQuery $.ajax for http request, to support browser
* removed all other dependencies on nodejs modules

Features (copied from [email protected] Readme.md):

* Very simple API
* Handles both RPC and Document schema types
* Supports multiRef SOAP messages (thanks to [@kaven276](https://github.com/kaven276))
* Support for both synchronous and asynchronous method handlers
* WS-Security (currently only UsernameToken and PasswordText encoding is supported)

## Install

Install with [npm](http://github.com/isaacs/npm):

```
npm install tinysoap
```

## Browser

Embed jquery script first, for example:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

Then embed the file "./tinysoap-browser-min.js"

<script src="tinysoap-browser-min.js"></script>
Then you write code such as:

// in global scope:
this.tinysoap.createClient("/ACMEWebService?WSDL", function(err, client) {
if (!err)
console.log(client); // all methods are stored in client
});

JSONP is not currently supported, but should be very simple to add...

## Module

### soap.createClient(url, callback) - create a new SOAP client from a WSDL url

``` javascript
var soap = require('soap');
var url = 'http://example.com/wsdl?wsdl';
var args = {name: 'value'};
soap.createClient(url, function(err, client) {
client.MyFunction(args, function(err, result) {
console.log(result);
});
});
```

## Client

An instance of Client is passed to the soap.createClient callback. It is used to execute methods on the soap service.

### Client.describe() - description of services, ports and methods as a JavaScript object

``` javascript
client.describe() // returns
{
MyService: {
MyPort: {
MyFunction: {
input: {
name: 'string'
}
}
}
}
}
```

### Client.setSecurity(security) - use the specified security protocol (see WSSecurity below)

``` javascript
client.setSecurity(new WSSecurity('username', 'password'))
```

### Client.*method*(args, callback) - call *method* on the SOAP service.

``` javascript
client.MyFunction({name: 'value'}, function(err, result) {
// result is a javascript object
})
```
### Client.*service*.*port*.*method*(args, callback) - call a *method* using a specific *service* and *port*

``` javascript
client.MyService.MyPort.MyFunction({name: 'value'}, function(err, result) {
// result is a javascript object
})
```

## WSSecurity

WSSecurity implements WS-Security. UsernameToken and PasswordText/PasswordDigest is supported. An instance of WSSecurity is passed to Client.setSecurity.

``` javascript
new WSSecurity(username, password, passwordType)
//'PasswordDigest' or 'PasswordText' default is PasswordText
```
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./lib/soap');
7 changes: 7 additions & 0 deletions lib/assert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

module.exports = function(expr, msg) {
if (!(true == !!expr)) {
console.log(msg);
throw new Error(msg);
}
}
149 changes: 149 additions & 0 deletions lib/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2011 Vinay Pulim <[email protected]>
* MIT Licensed
*/

function findKey(obj, val) {
for (var n in obj) if (obj[n] === val) return n;
}

var http = require('./http'),
assert = require('./assert'),
url = require('./url');

var Client = function(wsdl, endpoint) {
this.wsdl = wsdl;
this._initializeServices(endpoint);
}

Client.prototype.setEndpoint = function(endpoint) {
this.endpoint = endpoint;
this._initializeServices(endpoint);
}

Client.prototype.describe = function() {
var types = this.wsdl.definitions.types;
return this.wsdl.describeServices();
}

Client.prototype.setSecurity = function(security) {
this.security = security;
}

Client.prototype.setSOAPAction = function(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);
}
}

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;
}

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);
if (!this[name]) this[name] = def[name];
}
return def;
}

Client.prototype._defineMethod = function(method, location) {
var self = this;
return function(args, callback) {
if (typeof args === 'function') {
callback = args;
args = {};
}
self._invoke(method, args, location, function(error, result, raw) {
callback(error, result, raw);
})
}
}

Client.prototype._invoke = function(method, arguments, location, callback) {
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,
headers = {
SOAPAction: this.SOAPAction ? this.SOAPAction(ns, name) : (((ns.lastIndexOf("/") != ns.length - 1) ? ns + "/" : ns) + name),
'Content-Type': "text/xml; charset=utf-8"
},
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(!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/" ');
}
else if (typeof(arguments) === 'string') {
message = arguments;
}
else {
assert(!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.security ? self.security.toXML() : "") +
"</soap:Header>" +
"<soap:Body>" +
message +
"</soap:Body>" +
"</soap:Envelope>";

http.request(location, xml, function(err, response, body) {
if (err) {
callback(err, body?self.wsdl.xmlToObject(body):null, body);
}
else {
try {
var obj = self.wsdl.xmlToObject(body);
}
catch (error) {
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);
}

exports.Client = Client;
95 changes: 95 additions & 0 deletions lib/http.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright (c) 2011 Vinay Pulim <[email protected]>
* MIT Licensed
*/

var url = require('./url');

var VERSION = "0.2.0";

exports.request = function(rurl, data, callback, exheaders, exoptions) {

if (typeof window !== 'undefined') {

headers = {
"User-Agent": "node-soap/" + VERSION,
"Accept": "text/html,application/xhtml+xml,application/xml",
"Accept-Encoding": "none",
"Accept-Charset": "utf-8",
"Content-Type" : "application/x-www-form-urlencoded",
"Connection": "close",
"Host": host
};
exheaders = exheaders || {};
for (var attr in exheaders) {
headers[attr] = exheaders[attr];
}
$.ajax(rurl, {
headers : headers,
type : data ? "POST" : "GET",
data : data,
dataType: 'text',
success : function(data, status, xhr) {
resp = {statusCode : 200}
callback(null, resp, data);
},
error : function(xhr, status, err) {
resp = {statusCode : xhr.status}
callback(err, resp, xhr.responseText);
}
})

} else { // nodejs

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",
"Accept-Encoding": "none",
"Accept-Charset": "utf-8",
"Connection": "close",
"Host": host
};

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];
}

var options = curl;
options.method = method;
options.headers = headers;

exoptions = exoptions || {};
for (var attr in exoptions) {
options[attr] = exoptions[attr];
}

var p;
if (secure) p = require('https')
else p = require("http")

var request = p.request(options, function (res, body) {
var body = "";
res.on('data', function (chunk) {
body += chunk;
})
res.on("end", function () {
callback(null, res, body);
})
});
request.on('error', callback);
request.end(data);
}
}
Loading

0 comments on commit 52c62a3

Please sign in to comment.