THRIFT-2398:Improve Node Server Library\nClient: Node\nPatch: Randy Abernethy\n\nGeneral server parameter harmonization and comments
diff --git a/lib/js/test/server_http.js b/lib/js/test/server_http.js
index 01174bc..ce09afc 100644
--- a/lib/js/test/server_http.js
+++ b/lib/js/test/server_http.js
@@ -35,12 +35,12 @@
var ThriftTestSvcOpt = {
transport: TBufferedTransport,
protocol: TJSONProtocol,
- cls: ThriftTestSvc,
+ processor: ThriftTestSvc,
handler: ThriftTestHandler
};
var ThriftWebServerOptions = {
- staticFilePath: ".",
+ files: ".",
services: {
"/service": ThriftTestSvcOpt
}
diff --git a/lib/js/test/server_https.js b/lib/js/test/server_https.js
index 28f0585..69d7e89 100644
--- a/lib/js/test/server_https.js
+++ b/lib/js/test/server_https.js
@@ -35,21 +35,21 @@
//Setup the I/O stack options for the ThriftTest service
var ThriftTestSvcOpt = {
- transport: TBufferedTransport,
- protocol: TJSONProtocol,
- cls: ThriftTestSvc,
- handler: ThriftTestHandler
+ transport: TBufferedTransport,
+ protocol: TJSONProtocol,
+ processor: ThriftTestSvc,
+ handler: ThriftTestHandler
};
var ThriftWebServerOptions = {
- staticFilePath: ".",
- tlsOptions: {
- key: fs.readFileSync("../../../test/keys/server.key"),
- cert: fs.readFileSync("../../../test/keys/server.crt")
- },
- services: {
- "/service": ThriftTestSvcOpt
- }
+ files: ".",
+ tls: {
+ key: fs.readFileSync("../../../test/keys/server.key"),
+ cert: fs.readFileSync("../../../test/keys/server.crt")
+ },
+ services: {
+ "/service": ThriftTestSvcOpt
+ }
};
var server = thrift.createWebServer(ThriftWebServerOptions);
@@ -57,6 +57,3 @@
server.listen(port);
console.log("Serving files from: " + __dirname);
console.log("Http/Thrift Server running on port: " + port);
-
-
-
diff --git a/lib/nodejs/lib/thrift/index.js b/lib/nodejs/lib/thrift/index.js
index 8487464..dd965d2 100644
--- a/lib/nodejs/lib/thrift/index.js
+++ b/lib/nodejs/lib/thrift/index.js
@@ -28,12 +28,7 @@
var server = require('./server');
exports.createServer = server.createServer;
-exports.createSSLServer = server.createSSLServer;
-exports.createHttpServer = server.createHttpServer;
-exports.createHttpsServer = server.createHttpsServer;
-exports.httpMiddleware = server.httpMiddleware;
exports.createMultiplexServer = server.createMultiplexServer;
-exports.createMultiplexSSLServer = server.createMultiplexSSLServer;
var web_server = require('./web_server');
exports.createWebServer = web_server.createWebServer;
diff --git a/lib/nodejs/lib/thrift/server.js b/lib/nodejs/lib/thrift/server.js
index 398d398..06ee90b 100644
--- a/lib/nodejs/lib/thrift/server.js
+++ b/lib/nodejs/lib/thrift/server.js
@@ -17,23 +17,24 @@
* under the License.
*/
var net = require('net');
-var http = require('http');
-var https = require('https');
var tls = require('tls');
-var url = require("url");
-var path = require("path");
-var fs = require("fs");
var ttransport = require('./transport'),
TBinaryProtocol = require('./protocol').TBinaryProtocol;
+/**
+ * Create a Thrift server which can serve one or multiple services.
+ * @param {object} processor - A normal or multiplexedProcessor (must
+ * be preconstructed with the desired handler).
+ * @param {ServerOptions} options - Optional additional server configuration.
+ * @returns {object} - The Apache Thrift Multipled Server.
+ */
exports.createMultiplexServer = function(processor, options) {
-
var transport = (options && options.transport) ? options.transport : ttransport.TBufferedTransport;
var protocol = (options && options.protocol) ? options.protocol : TBinaryProtocol;
- return net.createServer(function(stream) {
+ function serverImpl(stream) {
var self = this;
stream.on('data', transport.receiver(function(transportWithData) {
var input = new protocol(transportWithData);
@@ -51,8 +52,7 @@
processStatus = processor.process(input, output);
transportWithData.commitPosition();
} while (true);
- }
- catch (err) {
+ } catch (err) {
if (err instanceof ttransport.InputBufferUnderrunError) {
//The last data in the buffer was not a complete message, wait for the rest
transportWithData.rollbackPosition();
@@ -81,128 +81,24 @@
stream.on('end', function() {
stream.end();
});
- });
-};
-
-exports.createMultiplexSSLServer = function(processor, options) {
-
- var transport = (options && options.transport) ? options.transport : ttransport.TBufferedTransport;
- var protocol = (options && options.protocol) ? options.protocol : TBinaryProtocol;
-
- return tls.createServer(options, function(stream) {
- var self = this;
- stream.on('data', transport.receiver(function(transportWithData) {
- var input = new protocol(transportWithData);
- var output = new protocol(new transport(undefined, function(buf) {
- try {
- stream.write(buf);
- } catch (err) {
- self.emit('error', err);
- stream.end();
- }
- }));
-
- try {
- do {
- processStatus = processor.process(input, output);
- transportWithData.commitPosition();
- } while (true);
- }
- catch (err) {
- if (err instanceof ttransport.InputBufferUnderrunError) {
- //The last data in the buffer was not a complete message, wait for the rest
- transportWithData.rollbackPosition();
- }
- else if (err.message === "Invalid type: undefined") {
- //No more data in the buffer
- //This trap is a bit hackish
- //The next step to improve the node behavior here is to have
- // the compiler generated process method throw a more explicit
- // error when the network buffer is empty (regardles of the
- // protocol/transport stack in use) and replace this heuristic.
- // Also transports should probably not force upper layers to
- // manage their buffer positions (i.e. rollbackPosition() and
- // commitPosition() should be eliminated in lieu of a transport
- // encapsulated buffer management strategy.)
- transportWithData.rollbackPosition();
- }
- else {
- //Unexpected error
- self.emit('error', err);
- stream.end();
- }
- }
- }));
-
- stream.on('end', function() {
- stream.end();
- });
- });
-};
-
-
-function httpRequestHandler(cls, handler, options) {
- if (cls.Processor) {
- cls = cls.Processor;
- }
- var processor = new cls(handler);
- var transport = (options && options.transport) ? options.transport : ttransport.TBufferedTransport;
- var protocol = (options && options.protocol) ? options.protocol : TBinaryProtocol;
-
- return function(request, response) {
- request.on('data', transport.receiver(function(transportWithData) {
- var input = new protocol(transportWithData);
- var output = new protocol(new transport(undefined, function(buf) {
- try {
- response.write(buf);
- } catch (err) {
- response.writeHead(500);
- }
- response.end();
- }));
-
- try {
- processor.process(input, output);
- transportWithData.commitPosition();
- }
- catch (err) {
- if (err instanceof ttransport.InputBufferUnderrunError) {
- transportWithData.rollbackPosition();
- } else {
- response.writeHead(500);
- response.end();
- throw err;
- }
- }
- }));
};
-}
-
-exports.httpMiddleware = httpRequestHandler;
-
-exports.createHttpServer = function(cls, handler, options) {
- return http.createServer(options, httpRequestHandler(cls, handler, options));
-};
-
-exports.createHttpsServer = function(cls, handler, options) {
- return https.createServer(options, httpRequestHandler(cls, handler, options));
-};
-
-
-exports.createServer = function(cls, handler, options) {
- if (cls.Processor) {
- cls = cls.Processor;
+
+ if (options.tls) {
+ return tls.createServer(options.tls, serverImpl);
+ } else {
+ return net.createServer(serverImpl);
}
- var processor = new cls(handler);
-
- return exports.createMultiplexServer(processor,options);
};
-exports.createSSLServer = function(cls, handler, options) {
- if (cls.Processor) {
- cls = cls.Processor;
+/**
+ * Create a single service Apache Thrift server.
+ * @param {object} processor - A service class or processor function.
+ * @param {ServerOptions} options - Optional additional server configuration.
+ * @returns {object} - The Apache Thrift Multipled Server.
+ */
+exports.createServer = function(processor, handler, options) {
+ if (processor.Processor) {
+ processor = processor.Processor;
}
- var processor = new cls(handler);
-
- return exports.createMultiplexSSLServer(processor,options);
+ return exports.createMultiplexServer(new processor(handler), options);
};
diff --git a/lib/nodejs/lib/thrift/web_server.js b/lib/nodejs/lib/thrift/web_server.js
index a040380..fbe4f02 100644
--- a/lib/nodejs/lib/thrift/web_server.js
+++ b/lib/nodejs/lib/thrift/web_server.js
@@ -23,6 +23,7 @@
var fs = require("fs");
var crypto = require("crypto");
+var MultiplexedProcessor = require('./multiplexed_processor').MultiplexedProcessor;
var TTransport = require('./transport');
var TBufferedTransport = require('./transport').TBufferedTransport;
var TBinaryProtocol = require('./protocol').TBinaryProtocol;
@@ -39,7 +40,7 @@
* configured for a max of 4GB presently and needs to be adjusted
* if Node/Browsers become capabile of > 4GB frames.
*
- * - FIN is always 1, ATRPC messages are sent in a single frame
+ * - FIN is 1 if the message is complete
* - RSV1/2/3 are always 0
* - Opcode is 1(TEXT) for TJSONProtocol and 2(BIN) for TBinaryProtocol
* - Mask Present bit is 1 sending to-server and 0 sending to-client
@@ -122,11 +123,13 @@
* @property {Buffer} nextFrame - Multiple ATRPC messages may be sent in a
* single WebSocket frame, this Buffer contains
* any bytes remaining to be decoded
+ * @property {Boolean} FIN - True is the message is complete
*/
/** Decodes a WebSocket frame
*
- * @param {Buffer} frame - The raw inbound frame
+ * @param {Buffer} frame - The raw inbound frame, if this is a continuation
+ * frame it must have a mask property with the mask.
* @returns {WSDecodeResult} - The decoded payload
*
* @see {@link WSDecodeResult}
@@ -136,11 +139,13 @@
data: null,
mask: null,
binEncoding: false,
- nextFrame: null
+ nextFrame: null,
+ FIN: true
};
+
//Byte 0 - FIN & OPCODE
if (wsFrame.fin.FIN != (frame[0] & wsFrame.fin.FIN)) {
- console.log("WebSocket frame error: Received a frame without fin set.");
+ result.FIN = false;
}
result.binEncoding = (wsFrame.frameOpCodes.BIN == (frame[0] & wsFrame.frameOpCodes.BIN));
//Byte 1 or 1-3 or 1-9 - SIZE
@@ -159,17 +164,22 @@
result.mask = new Buffer(4);
frame.copy(result.mask, 0, dataOffset, dataOffset + 4);
dataOffset += 4;
- }
+ }
//Payload
result.data = new Buffer(len);
frame.copy(result.data, 0, dataOffset, dataOffset+len);
- wsFrame.applyMask(result.data, result.mask);
-
- //Residual Frames
+ if (result.mask) {
+ wsFrame.applyMask(result.data, result.mask);
+ }
+ //Next Frame
if (frame.length > dataOffset+len) {
result.nextFrame = new Buffer(frame.length - (dataOffset+len));
frame.copy(result.nextFrame, 0, dataOffset+len, frame.length);
}
+ //Don't forward control frames
+ if (frame[0] & wsFrame.frameOpCodes.FINCTRL) {
+ result.data = null;
+ }
return result;
},
@@ -206,7 +216,8 @@
frameOpCodes: {
CONT: 0x00,
TEXT: 0x01,
- BIN: 0x02
+ BIN: 0x02,
+ CTRL: 0x80
},
mask: {
@@ -226,44 +237,42 @@
/**
* @class
- * @name WebServerOptions
- * @property {string} staticFilePath - Path to serve static files from, if absent or ""
- * static file service is disabled
- * @property {object} tlsOptions - Node.js TLS options (see: nodejs.org/api/tls.html),
- * if not present or null regular http is used,
- * at least a key and a cert must be defined to use SSL/TLS
- * @property {object} services - An object hash mapping service URI strings
- * to ThriftServiceOptions objects
- * @property {object} headers - An object hash mapping header strings to header value,
+ * @name ServerOptions
+ * @property {array} cors - Array of CORS origin strings to permit requests from.
+ * @property {string} files - Path to serve static files from, if absent or ""
+ * static file service is disabled.
+ * @property {object} headers - An object hash mapping header strings to header value
* strings, these headers are transmitted in response to
* static file GET operations.
- * @see {@link ThriftServiceOptions}
+ * @property {object} services - An object hash mapping service URI strings
+ * to ServiceOptions objects
+ * @property {object} tls - Node.js TLS options (see: nodejs.org/api/tls.html),
+ * if not present or null regular http is used,
+ * at least a key and a cert must be defined to use SSL/TLS
+ * @see {@link ServiceOptions}
*/
/**
* @class
- * @name ThriftServiceOptions
+ * @name ServiceOptions
* @property {object} transport - The layered transport to use (defaults
* to TBufferedTransport).
- * @property {object} protocol - The Thrift Protocol to use (defaults to
+ * @property {object} protocol - The serialization Protocol to use (defaults to
* TBinaryProtocol).
- * @property {object} processor - The Thrift Service class generated by the IDL
- * Compiler for the service (the "cls" key can also
- * be used for this attribute).
+ * @property {object} processor - The Thrift Service class/processor generated
+ * by the IDL Compiler for the service (the "cls"
+ * key can also be used for this attribute).
* @property {object} handler - The handler methods for the Thrift Service.
- * @property {array} corsOrigins - Array of CORS origin strings to permit requests from.
*/
/**
- * Creates a Thrift server which can serve static files and/or one or
+ * Create a Thrift server which can serve static files and/or one or
* more Thrift Services.
- * @param {WebServerOptions} options - The server configuration.
- * @returns {object} - The Thrift server.
- *
- * @see {@link WebServerOptions}
+ * @param {ServerOptions} options - The server configuration.
+ * @returns {object} - The Apache Thrift Web Server.
*/
exports.createWebServer = function(options) {
- var baseDir = options.staticFilePath;
+ var baseDir = options.files;
var contentTypesByExtension = {
'.txt': 'text/plain',
'.html': 'text/html',
@@ -282,53 +291,62 @@
var services = options.services;
for (uri in services) {
var svcObj = services[uri];
- var processor = (svcObj.processor) ? (svcObj.processor.Processor || svcObj.processor) :
- (svcObj.cls.Processor || svcObj.cls);
- svcObj.processor = new processor(svcObj.handler);
+
+ //Setup the processor
+ if (svcObj.processor instanceof MultiplexedProcessor) {
+ //Multiplex processors have pre embeded processor/handler pairs, save as is
+ svcObj.processor = svcObj.processor;
+ } else {
+ //For historical reasons Node.js supports processors passed in directly or via the
+ // IDL Compiler generated class housing the processor. Also, the options property
+ // for a Processor has been called both cls and processor at different times. We
+ // support any of the four possibilities here.
+ var processor = (svcObj.processor) ? (svcObj.processor.Processor || svcObj.processor) :
+ (svcObj.cls.Processor || svcObj.cls);
+ //Processors can be supplied as constructed objects with handlers already embeded,
+ // if a handler is provided we construct a new processor, if not we use the processor
+ // object directly
+ if (svcObj.handler) {
+ svcObj.processor = new processor(svcObj.handler);
+ } else {
+ svcObj.processor = processor;
+ }
+ }
svcObj.transport = svcObj.transport ? svcObj.transport : TBufferedTransport;
svcObj.protocol = svcObj.protocol ? svcObj.protocol : TBinaryProtocol;
}
//Verify CORS requirements
- function VerifyCORSAndSetHeaders(request, response, svc) {
- if (request.headers.origin && svc.corsOrigins) {
- if (svcObj.corsOrigins["*"] || svcObj.corsOrigins[request.headers.origin]) {
- //Sucess, origin allowed
+ function VerifyCORSAndSetHeaders(request, response) {
+ if (request.headers.origin && options.cors) {
+ if (options.cors["*"] || options.cors[request.headers.origin]) {
+ //Allow, origin allowed
response.setHeader("access-control-allow-origin", request.headers.origin);
- response.setHeader("access-control-allow-methods", "POST, OPTIONS");
+ response.setHeader("access-control-allow-methods", "GET, POST, OPTIONS");
response.setHeader("access-control-allow-headers", "content-type, accept");
response.setHeader("access-control-max-age", "60");
return true;
} else {
- //Failure, origin denied
+ //Disallow, origin denied
return false;
}
}
- //Success, CORS is not in use
+ //Allow, CORS is not in use
return true;
}
- //Handle OPTIONS method (CORS support)
+ //Handle OPTIONS method (CORS)
///////////////////////////////////////////////////
function processOptions(request, response) {
- var uri = url.parse(request.url).pathname;
- var svc = services[uri];
- if (!svc) {
- //Unsupported service
- response.writeHead("403", "No Apache Thrift Service at " + uri, {});
- response.end();
- return;
- }
-
- //Verify CORS requirements
- if (VerifyCORSAndSetHeaders(request, response, svc)) {
+ if (VerifyCORSAndSetHeaders(request, response)) {
response.writeHead("204", "No Content", {"content-length": 0});
} else {
response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {});
}
response.end();
}
+
//Handle POST methods (TXHRTransport)
///////////////////////////////////////////////////
@@ -343,7 +361,7 @@
}
//Verify CORS requirements
- if (!VerifyCORSAndSetHeaders(request, response, svc)) {
+ if (!VerifyCORSAndSetHeaders(request, response)) {
response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {});
response.end();
return;
@@ -365,12 +383,10 @@
try {
svc.processor.process(input, output);
transportWithData.commitPosition();
- }
- catch (err) {
+ } catch (err) {
if (err instanceof TTransport.InputBufferUnderrunError) {
transportWithData.rollbackPosition();
- }
- else {
+ } else {
response.writeHead(500);
response.end();
}
@@ -378,6 +394,7 @@
}));
}
+
//Handle GET methods (Static Page Server)
///////////////////////////////////////////////////
function processGet(request, response) {
@@ -387,6 +404,14 @@
response.end();
return;
}
+
+ //Verify CORS requirements
+ if (!VerifyCORSAndSetHeaders(request, response)) {
+ response.writeHead("403", "Origin " + request.headers.origin + " not allowed", {});
+ response.end();
+ return;
+ }
+
//Locate the file requested and send it
var uri = url.parse(request.url).pathname;
var filename = path.join(baseDir, uri);
@@ -422,12 +447,10 @@
});
}
+
//Handle WebSocket calls (TWebSocketTransport)
///////////////////////////////////////////////////
- function processWS(data, socket) {
- var svc = services[Object.keys(services)[0]];
- //TODO: add multiservice support (maybe multiplexing is the answer for both XHR and WS?)
-
+ function processWS(data, socket, svc) {
svc.transport.receiver(function(transportWithData) {
var input = new svc.protocol(transportWithData);
var output = new svc.protocol(new svc.transport(undefined, function(buf) {
@@ -456,8 +479,8 @@
//Create the server (HTTP or HTTPS)
var server = null;
- if (options.tlsOptions) {
- server = https.createServer(options.tlsOptions);
+ if (options.tls) {
+ server = https.createServer(options.tls);
} else {
server = http.createServer();
}
@@ -478,19 +501,55 @@
response.end();
}
}).on('upgrade', function(request, socket, head) {
+ //Lookup service
+ var svc;
+ try {
+ svc = services[Object.keys(services)[0]];
+ } catch(e) {
+ if (!route) {
+ socket.write("HTTP/1.1 403 No Apache Thrift Service availible\r\n\r\n");
+ return;
+ }
+ }
+ //Perform upgrade
var hash = crypto.createHash("sha1")
hash.update(request.headers['sec-websocket-key'] + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
socket.write("HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
"Connection: Upgrade\r\n" +
"Sec-WebSocket-Accept: " + hash.digest("base64") + "\r\n" +
- "\r\n");
+ "\r\n");
+ //Handle WebSocket traffic
+ var data = null;
socket.on('data', function(frame) {
- do {
- var result = wsFrame.decode(frame);
- processWS(result.data, socket);
- frame = result.nextFrame;
- } while (frame);
+ try {
+ while (frame) {
+ result = wsFrame.decode(frame);
+ //Prepend any existing decoded data
+ if (data) {
+ if (result.data) {
+ var newData = new Buffer(data.length + result.data.length);
+ data.copy(newData);
+ result.data.copy(newData, data.length);
+ result.data = newData;
+ } else {
+ result.data = data;
+ }
+ data = null;
+ }
+ //If this completes a message process it
+ if (result.FIN) {
+ processWS(result.data, socket, svc);
+ } else {
+ data = result.data;
+ }
+ //Prepare next frame for decoding (if any)
+ frame = result.nextFrame;
+ };
+ } catch(e) {
+ console.log("TWebSocketTransport Exception: " + e);
+ socket.destroy();
+ }
});
});
diff --git a/lib/nodejs/test/client.js b/lib/nodejs/test/client.js
index 2aa2295..a6fabfc 100644
--- a/lib/nodejs/test/client.js
+++ b/lib/nodejs/test/client.js
@@ -24,8 +24,6 @@
var fs = require('fs');
var assert = require('assert');
var thrift = require('thrift');
-var ThriftTransports = require('thrift/transport');
-var ThriftProtocols = require('thrift/protocol');
var ThriftTest = require('./gen-nodejs/ThriftTest');
var ThriftTestDriver = require('./thrift_test_driver').ThriftTestDriver;
var ThriftTestDriverPromise = require('./thrift_test_driver_promise').ThriftTestDriver;
@@ -39,32 +37,15 @@
.option('--promise', 'test with promise style functions')
.parse(process.argv);
-var protocol = undefined;
-var transport = undefined;
-var testDriver = undefined;
-if (program.protocol === "binary") {
- protocol = ThriftProtocols.TBinaryProtocol;
-} else if (program.protocol === "json") {
- protocol = ThriftProtocols.TJSONProtocol;
-} else {
- //default
- protocol = ThriftProtocols.TBinaryProtocol;
-}
+var protocol = thrift.TBinaryProtocol;
+if (program.protocol === "json") {
+ protocol = thrift.TJSONProtocol;
+}
+var transport = thrift.TBufferedTransport;
if (program.transport === "framed") {
- transport = ThriftTransports.TFramedTransport;
-} else if (program.transport === "buffered") {
- transport = ThriftTransports.TBufferedTransport;
-} else {
- //default
- transport = ThriftTransports.TBufferedTransport;
-}
-
-if (program.promise) {
- testDriver = ThriftTestDriverPromise;
-} else {
- testDriver = ThriftTestDriver;
+ transport = thrift.TFramedTransport;
}
var options = {
@@ -87,6 +68,10 @@
assert(false, err);
});
+var testDriver = ThriftTestDriver;
+if (program.promise) {
+ testDriver = ThriftTestDriverPromise;
+}
testDriver(client, function (status) {
console.log(status);
connection.end();
diff --git a/lib/nodejs/test/multiplex_client.js b/lib/nodejs/test/multiplex_client.js
index 9ef716b..6580cb5 100644
--- a/lib/nodejs/test/multiplex_client.js
+++ b/lib/nodejs/test/multiplex_client.js
@@ -17,13 +17,12 @@
* under the License.
*/
var thrift = require('thrift');
-var ThriftTransports = require('thrift/transport');
-var ThriftProtocols = require('thrift/protocol');
var assert = require('assert');
var ThriftTest = require('./gen-nodejs/ThriftTest'),
SecondService = require('./gen-nodejs/SecondService'),
ttypes = require('./gen-nodejs/ThriftTest_types');
+var ThriftTestDriver = require('./thrift_test_driver').ThriftTestDriver;
var program = require('commander');
@@ -33,27 +32,16 @@
.option('--ssl', 'use ssl transport')
.parse(process.argv);
-var protocol = undefined;
-var transport = undefined;
-
-if (program.protocol === "binary") {
- protocol = ThriftProtocols.TBinaryProtocol;
-} else if (program.protocol === "json") {
- protocol = ThriftProtocols.TJSONProtocol;
-} else {
- //default
- protocol = ThriftProtocols.TBinaryProtocol;
-}
-
+var transport = thrift.TBufferedTransport;
if (program.transport === "framed") {
- transport = ThriftTransports.TFramedTransport;
-} else if (program.transport === "buffered") {
- transport = ThriftTransports.TBufferedTransport;
-} else {
- //default
- transport = ThriftTransports.TBufferedTransport;
+ transport = thrift.TFramedTransport;
}
+var protocol = thrift.TBinaryProtocol;
+if (program.protocol === "json") {
+ protocol = thrift.TJSONProtocol;
+}
+
var options = {
transport: transport,
protocol: protocol
@@ -76,290 +64,17 @@
assert(false, err);
});
-// deepEqual doesn't work with fields using node-int64
-
-function checkRecursively(map1, map2) {
- if (typeof map1 !== 'function' && typeof map2 !== 'function') {
- if (!map1 || typeof map1 !== 'object') {
- assert.equal(map1, map2);
- } else {
- for (var key in map1) {
- checkRecursively(map1[key], map2[key]);
- }
- }
- }
-}
-
-client.testString("Test", function(err, response) {
+connection.on('connect', function() {
+ secondclient.secondtestString("Test", function(err, response) {
assert(!err);
assert.equal("Test", response);
-});
-secondclient.secondtestString("Test", function(err, response) {
- assert(!err);
- assert.equal("Test", response);
-});
+ });
-
-client.testVoid(function(err, response) {
- assert(!err);
- assert.equal(undefined, response); //void
-});
-
-
-secondclient.secondtestString("Test", function(err, response) {
- assert(!err);
- assert.equal("Test", response);
-});
-
-client.testString("", function(err, response) {
- assert(!err);
- assert.equal("", response);
-});
-
-// all Languages in UTF-8
-var stringTest = "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, " +
- "Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, " +
- "Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, " +
- "Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, " +
- "Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, " +
- "ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, " +
- "Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, " +
- "Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, " +
- "ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, " +
- "Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, " +
- "Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, " +
- "Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, " +
- "Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, " +
- "Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, " +
- "Македонски, മലയാളം, मराठी, Bahasa Melayu, مازِرونی, Nnapulitano, " +
- "Nedersaksisch, नेपाल भाषा, Nederlands, Norsk (nynorsk), Norsk (" +
- "bokmål), Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, " +
- "Deitsch, Norfuk / Pitkern, Polski, پنجابی, پښتو, Português, Runa " +
- "Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, " +
- "Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, " +
- "Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், " +
- "తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, " +
- "Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, " +
- "ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語";
-
-client.testString(stringTest, function(err, response) {
- assert(!err);
- assert.equal(stringTest, response);
-});
-
-var specialCharacters = 'quote: \" backslash:' +
- ' forwardslash-escaped: \/ ' +
- ' backspace: \b formfeed: \f newline: \n return: \r tab: ' +
- ' now-all-of-them-together: "\\\/\b\n\r\t' +
- ' now-a-bunch-of-junk: !@#$%&()(&%$#{}{}<><><';
-client.testString(specialCharacters, function(err, response) {
- assert(!err);
- assert.equal(specialCharacters, response);
-});
-
-
-client.testByte(1, function(err, response) {
- assert(!err);
- assert.equal(1, response);
-});
-client.testByte(0, function(err, response) {
- assert(!err);
- assert.equal(0, response);
-});
-client.testByte(-1, function(err, response) {
- assert(!err);
- assert.equal(-1, response);
-});
-client.testByte(-127, function(err, response) {
- assert(!err);
- assert.equal(-127, response);
-});
-
-client.testI32(-1, function(err, response) {
- assert(!err);
- assert.equal(-1, response);
-});
-
-client.testI64(5, function(err, response) {
- assert(!err);
- assert.equal(5, response);
-});
-client.testI64(-5, function(err, response) {
- assert(!err);
- assert.equal(-5, response);
-});
-client.testI64(-34359738368, function(err, response) {
- assert(!err);
- assert.equal(-34359738368, response);
-});
-
-client.testDouble(-5.2098523, function(err, response) {
- assert(!err);
- assert.equal(-5.2098523, response);
-});
-client.testDouble(7.012052175215044, function(err, response) {
- assert(!err);
- assert.equal(7.012052175215044, response);
-});
-
-
-var out = new ttypes.Xtruct({
- string_thing: 'Zero',
- byte_thing: 1,
- i32_thing: -3,
- i64_thing: 1000000
-});
-client.testStruct(out, function(err, response) {
- assert(!err);
- checkRecursively(out, response);
-});
-
-
-var out2 = new ttypes.Xtruct2();
-out2.byte_thing = 1;
-out2.struct_thing = out;
-out2.i32_thing = 5;
-client.testNest(out2, function(err, response) {
- assert(!err);
- checkRecursively(out2, response);
-});
-
-
-var mapout = {};
-for (var i = 0; i < 5; ++i) {
- mapout[i] = i - 10;
-}
-client.testMap(mapout, function(err, response) {
- assert(!err);
- assert.deepEqual(mapout, response);
-});
-
-
-var mapTestInput = {
- "a": "123",
- "a b": "with spaces ",
- "same": "same",
- "0": "numeric key",
- "longValue": stringTest,
- stringTest: "long key"
-};
-client.testStringMap(mapTestInput, function(err, response) {
- assert(!err);
- assert.deepEqual(mapTestInput, response);
-});
-
-
-var setTestInput = [1, 2, 3];
-client.testSet(setTestInput, function(err, response) {
- assert(!err);
- assert.deepEqual(setTestInput, response);
-});
-client.testList(setTestInput, function(err, response) {
- assert(!err);
- assert.deepEqual(setTestInput, response);
-});
-
-client.testEnum(ttypes.Numberz.ONE, function(err, response) {
- assert(!err);
- assert.equal(ttypes.Numberz.ONE, response);
-});
-
-client.testTypedef(69, function(err, response) {
- assert(!err);
- assert.equal(69, response);
-});
-
-
-var mapMapTest = {
- "4": {
- "1": 1,
- "2": 2,
- "3": 3,
- "4": 4
- },
- "-4": {
- "-4": -4,
- "-3": -3,
- "-2": -2,
- "-1": -1
- }
-};
-client.testMapMap(mapMapTest, function(err, response) {
- assert(!err);
- assert.deepEqual(mapMapTest, response);
-});
-
-var crazy = new ttypes.Insanity({
- "userMap": {
- "5": 5,
- "8": 8
- },
- "xtructs": [new ttypes.Xtruct({
- "string_thing": "Goodbye4",
- "byte_thing": 4,
- "i32_thing": 4,
- "i64_thing": 4
- }), new ttypes.Xtruct({
- "string_thing": "Hello2",
- "byte_thing": 2,
- "i32_thing": 2,
- "i64_thing": 2
- })]
-});
-var insanity = {
- "1": {
- "2": crazy,
- "3": crazy
- },
- "2": {
- "6": {
- "userMap": null,
- "xtructs": null
- }
- }
-};
-client.testInsanity(crazy, function(err, response) {
- assert(!err);
- checkRecursively(insanity, response);
-});
-
-
-client.testException('TException', function(err, response) {
- //assert(err); //BUG?
- assert(!response);
-});
-client.testException('Xception', function(err, response) {
- assert(!response);
- assert.equal(err.errorCode, 1001);
- assert.equal('Xception', err.message);
-});
-client.testException('no Exception', function(err, response) {
- assert(!err);
- assert.equal(undefined, response); //void
-});
-
-
-client.testOneway(1, function(err, response) {
- assert(!response); //should not answer
-});
-
-/**
- * redo a simple test after the oneway to make sure we aren't "off by one" --
- * if the server treated oneway void like normal void, this next test will
- * fail since it will get the void confirmation rather than the correct
- * result. In this circumstance, the client will throw the exception:
- *
- * TApplicationException: Wrong method namea
- */
-client.testI32(-1, function(err, response) {
- assert(!err);
- assert.equal(-1, response);
-});
-
-setTimeout(function() {
- console.log("Server successfully tested!");
+ ThriftTestDriver(client, function (status) {
+ console.log(status);
connection.end();
-}, 1500);
+ });
+});
// to make it also run on expresso
exports.expressoTest = function() {};
diff --git a/lib/nodejs/test/multiplex_server.js b/lib/nodejs/test/multiplex_server.js
index a2ea535..6331f6f 100644
--- a/lib/nodejs/test/multiplex_server.js
+++ b/lib/nodejs/test/multiplex_server.js
@@ -17,9 +17,6 @@
* under the License.
*/
var thrift = require('thrift');
-var Thrift = thrift.Thrift;
-var ThriftTransports = require('thrift/transport');
-var ThriftProtocols = require('thrift/protocol');
var ThriftTest = require('./gen-nodejs/ThriftTest'),
SecondService = require('./gen-nodejs/SecondService'),
@@ -36,25 +33,14 @@
.option('--ssl', 'use ssl transport')
.parse(process.argv);
-var protocol = undefined;
-var transport = undefined;
-
-if (program.protocol === "binary") {
- protocol = ThriftProtocols.TBinaryProtocol;
-} else if (program.protocol === "json") {
- protocol = ThriftProtocols.TJSONProtocol;
-} else {
- //default
- protocol = ThriftProtocols.TBinaryProtocol;
+var protocol = thrift.TBinaryProtocol;
+if (program.protocol === "json") {
+ protocol = thrift.TJSONProtocol;
}
+var transport = thrift.TBufferedTransport;
if (program.transport === "framed") {
- transport = ThriftTransports.TFramedTransport;
-} else if (program.transport === "buffered") {
- transport = ThriftTransports.TBufferedTransport;
-} else {
- //default
- transport = ThriftTransports.TBufferedTransport;
+ transport = thrift.TFramedTransport;
}
var ThriftTestHandler = require("./test_handler").ThriftTestHandler;
@@ -81,14 +67,12 @@
protocol: protocol
};
-var server = undefined;
if (program.ssl) {
//ssl options
- options.key = fs.readFileSync(path.resolve(__dirname, 'server.key'));
- options.cert = fs.readFileSync(path.resolve(__dirname, 'server.crt'));
- server = thrift.createMultiplexSSLServer(processor, options);
-} else {
- server = thrift.createMultiplexServer(processor, options);
+ options.tls = {
+ key: fs.readFileSync(path.resolve(__dirname, 'server.key')),
+ cert: fs.readFileSync(path.resolve(__dirname, 'server.crt'))
+ }
}
-server.listen(9090);
+thrift.createMultiplexServer(processor, options).listen(9090);
diff --git a/lib/nodejs/test/server.js b/lib/nodejs/test/server.js
index acc0398..6f5abe6 100644
--- a/lib/nodejs/test/server.js
+++ b/lib/nodejs/test/server.js
@@ -25,13 +25,10 @@
var fs = require('fs');
var path = require('path');
var thrift = require('thrift');
-var ThriftTransports = require('thrift/transport');
-var ThriftProtocols = require('thrift/protocol');
var ThriftTest = require('./gen-nodejs/ThriftTest');
var ThriftTestHandler = require('./test_handler').ThriftTestHandler;
var ThriftTestHandlerPromise = require('./test_handler_promise').ThriftTestHandler;
-
var program = require('commander');
program
@@ -41,46 +38,30 @@
.option('--promise', 'test with promise style functions')
.parse(process.argv);
-var protocol = undefined;
-var transport = undefined;
-var handler = undefined;
-
-if (program.protocol === "binary") {
- protocol = ThriftProtocols.TBinaryProtocol;
-} else if (program.protocol === "json") {
- protocol = ThriftProtocols.TJSONProtocol;
-} else {
- //default
- protocol = ThriftProtocols.TBinaryProtocol;
-}
-
+var transport = thrift.TBufferedTransport;
if (program.transport === "framed") {
- transport = ThriftTransports.TFramedTransport;
-} else if (program.transport === "buffered") {
- transport = ThriftTransports.TBufferedTransport;
-} else {
- //default
- transport = ThriftTransports.TBufferedTransport;
-}
+ transport = thrift.TFramedTransport;
+}
+var protocol = thrift.TBinaryProtocol;
+if (program.protocol === "json") {
+ protocol = thrift.TJSONProtocol;
+}
+
+var handler = ThriftTestHandler;
if (program.promise) {
handler = ThriftTestHandlerPromise;
-} else {
- handler = ThriftTestHandler;
-}
+}
var options = {
protocol: protocol,
transport: transport
};
-
if (program.ssl) {
- //ssl options
- options.key = fs.readFileSync(path.resolve(__dirname, 'server.key'));
- options.cert = fs.readFileSync(path.resolve(__dirname, 'server.crt'));
- thrift.createSSLServer(ThriftTest, handler, options).listen(9090);
-
-} else {
- //default
- thrift.createServer(ThriftTest, handler, options).listen(9090);
+ options.tls = {
+ key: fs.readFileSync(path.resolve(__dirname, 'server.key')),
+ cert: fs.readFileSync(path.resolve(__dirname, 'server.crt'))
+ }
}
+thrift.createServer(ThriftTest, handler, options).listen(9090);
+
diff --git a/lib/nodejs/test/test_handler.js b/lib/nodejs/test/test_handler.js
index 33c8941..ea1dc1d 100644
--- a/lib/nodejs/test/test_handler.js
+++ b/lib/nodejs/test/test_handler.js
@@ -21,7 +21,7 @@
// Apache Thrift test service.
var ttypes = require('./gen-nodejs/ThriftTest_types');
-var TException = require('thrift/thrift').TException;
+var TException = require('thrift').Thrift.TException;
var ThriftTestHandler = exports.ThriftTestHandler = {
testVoid: function(result) {
diff --git a/lib/nodejs/test/test_handler_promise.js b/lib/nodejs/test/test_handler_promise.js
index fc698eb..c1561bc 100644
--- a/lib/nodejs/test/test_handler_promise.js
+++ b/lib/nodejs/test/test_handler_promise.js
@@ -21,7 +21,7 @@
// Apache Thrift test service.
var ttypes = require('./gen-nodejs/ThriftTest_types');
-var TException = require('thrift/thrift').TException;
+var TException = require('thrift').Thrift.TException;
var ThriftTestHandler = exports.ThriftTestHandler = {
testVoid: function() {