forked from fshost/xrpc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
xmlrpc.js
146 lines (124 loc) · 4.29 KB
/
xmlrpc.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
Express-XmlRpc - XML-RPC middleware for Express
based on rsscloud-node's xmlrpc module: https://github.com/lmorchard/rsscloud-node
specs: http://www.xmlrpc.com/spec
usage:
// assuming app is an express server, use just prior to router in config, e.g.
var express = require('express'),
xrpc = require('express-xmlrpc'),
app = express();
app.configure(function () {
app.use(express.methodOverride());
app.use(xrpc.xmlrpc);
app.use(server.router)
});
app.listen(3000);
*/
var XmlRpcParser = require('./lib/xmlrpc-parser');
exports.xmlRpc = function xmlRpc(req, res, next) {
// Only attempt to parse text/xml Content-Type
var ct = req.headers['content-type'] || '';
var mime = ct.split(';')[0];
if ('text/xml' != mime) { return next(); }
var raw = [];
var parser = new XmlRpcParser({
onDone: function (data) {
req.body_XMLRPC = data;
next();
},
onError: function (msg) {
req.body_XMLRPC = false;
next();
}
});
// If there's raw body data, try parsing that instead of hooking up events.
if (req.rawBody) {
return parser.parseString(req.rawBody).finish();
}
req.setEncoding('utf8');
req.on('data', function (chunk) {
raw.push(chunk);
parser.parseString(chunk);
});
req.on('end', function () {
req.rawBody = raw.join('');
parser.finish();
});
};
var XmlRpcResponse = require('./lib/xmlrpc-response');
var XmlRpcFault = require('./lib/xmlrpc-fault');
// returns a route handler for an express server which dispatches XML-RPC
// requests to handlers. The return value from a handler is transformed from
// javascript into an XML-RPC response and sent. Methods invoked consist
// of parameters and an additional argument of 'callback' which has a signature
// of callback(err, val) where val is data to respond to request with, or
// err is an error which will be responded as an xmlrpc fault
// (err.code can be set to a specific fault code if desired)
// note that optionally an object can be passed with a property of xmlRpcMethods
// containing methods.
// Also note that nested properties will be referenced as nested, e.g.
// xmlrpc call for 'blogger.getUsersBlogs' will reference to function A below
// { blogger: { getUsersBlogs: function A(...) { ... } } }
//
// app.post('/RPC2', xrpc.route({
// echo: function (param, callback) {
// callback(null, 'Echo: ' + param);
// // or if error, callback(err);
// }
// }));
exports.route = function route(handlers) {
if (handlers.xmlRpcMethods === undefined) {
context = this;
methods = handlers;
}
else {
context = handlers;
methods = handlers.xmlRpcMethods;
}
return function (req, res, next) {
res.type('text/xml');
var cb = function (err, rv) {
if (!err) {
res.send(new XmlRpcResponse([rv]).xml());
}
else {
res.send(new XmlRpcFault(err.code || 0, err.message || err).xml());
}
};
if (!req.body_XMLRPC) {
res.send(new XmlRpcFault(-32700, 'parse error. not well formed').xml());
}
var params = req.body_XMLRPC.params,
method = getRef(methods, req.body_XMLRPC.method);
if (method !== undefined) {
try {
params.push(cb);
method.apply(context, params);
}
catch (e) {
res.send(new XmlRpcFault(-32500, 'Unexpected exception ' + e).xml());
next(e);
}
}
else {
res.send(new XmlRpcFault(-32601, 'requested method ' + method + ' not found').xml());
}
};
};
function getRef(o, s) {
if (!s) {
return;
}
s = s.replace(/\[(\w+)\]/g, '.$1');
s = s.replace(/^\./, '');
var a = s.split('.');
while (a.length) {
var n = a.shift();
if (n in o) {
o = o[n];
} else {
return;
}
}
return o;
}