Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

replace tunnel middleware with refactored version

- Remove trailing slashes from tunnel/static prefixes.
- Add flag and flag check to determine when to stop processing the request.
  • Loading branch information...
commit 31295f4cda6cae19a3187a00f6a9f7c452fe6c2c 1 parent 9112208
Eugene Kashida ekashida authored
36 lib/app/middleware/mojito-handler-tunnel-demux.js → lib/app/middleware/mojito-handler-tunnel-parser.js
View
@@ -5,21 +5,19 @@
*/
/*global require, module*/
-/*jslint sloppy:true, nomen:true*/
-
-
-var liburl = require('url'),
- libpath = require('path');
-
+/*jslint sloppy:true, nomen:true, white:true*/
+var RE_TRAILING_SLASHES = /\/+$/;
/**
- * Export a function which can create the handler.
- * @param {Object} config Data to configure the handler.
- * @return {Object} The newly constructed handler.
+ * Export a function which can parse tunnel requests.
+ * @param {Object} config The configuration.
+ * @return {Object} The parser.
*/
module.exports = function (config) {
- var appConfig = config.store.getAppConfig({}) || {},
+ var liburl = require('url'),
+ libpath = require('path'),
+ appConfig = config.store.getAppConfig({}) || {},
staticPrefix,
tunnelPrefix;
@@ -27,9 +25,11 @@ module.exports = function (config) {
tunnelPrefix = appConfig.tunnelPrefix;
if (staticPrefix) {
+ staticPrefix = staticPrefix.replace(RE_TRAILING_SLASHES, '');
staticPrefix = '/' + staticPrefix;
}
if (tunnelPrefix) {
+ tunnelPrefix = tunnelPrefix.replace(RE_TRAILING_SLASHES, '');
tunnelPrefix = '/' + tunnelPrefix;
}
@@ -50,8 +50,6 @@ module.exports = function (config) {
return next();
}
- req._tunnel = {};
-
/**
Tunnel examples
@@ -86,27 +84,23 @@ module.exports = function (config) {
// Get the mojit type.
type = parts[1];
- // Spec tunnel
+ // "Spec" tunnel request
if (parts[parts.length - 2] === 'specs') {
req._tunnel.specsReq = {
type: type,
name: name
};
- return next();
}
- // Type tunnel
- if (name === 'definition') {
+ // "Type" tunnel request
+ else if (name === 'definition') {
req._tunnel.typeReq = {
type: type
};
- return next();
}
}
-
- // RPC tunnel
- if (req.url === tunnelPrefix && req.method === 'POST') {
+ // "RPC" tunnel request
+ else if (req.url === tunnelPrefix && req.method === 'POST') {
req._tunnel.rpcReq = {};
- return next();
}
return next();
3  lib/app/middleware/mojito-handler-tunnel-rpc.js
View
@@ -37,7 +37,6 @@ module.exports = function (config) {
}
command = req.body;
- instance = command.instance;
command.context = command.context || {};
// When switching from the client context to the server context, we
@@ -48,7 +47,7 @@ module.exports = function (config) {
// and attach it within a "tunnelCommand", which will be handled by
// Mojito instead of looking up a route for it.
config.store.expandInstance(
- instance,
+ command.instance,
command.context,
function (err, instance) {
// Replace with the expanded instance.
49 lib/app/middleware/mojito-handler-tunnel-specs.js
View
@@ -7,19 +7,6 @@
/*global module*/
/*jslint sloppy:true, nomen:true*/
-
-function sendData(res, data, code) {
- res.writeHead((code || 200), {
- 'content-type': 'application/json; charset="utf-8"'
- });
- res.end(JSON.stringify(data, null, 4));
-}
-
-function sendError(res, msg, code) {
- sendData(res, {error: msg}, (code || 500));
-}
-
-
/**
* Exports a middleware factory that can handle spec tunnel requests.
*
@@ -29,6 +16,7 @@ function sendError(res, msg, code) {
module.exports = function (config) {
return function (req, res, next) {
var specsReq = req._tunnel && req._tunnel.specsReq,
+ instance,
type,
name;
@@ -40,20 +28,31 @@ module.exports = function (config) {
name = specsReq.name;
if (!type || !name) {
- return sendError(res, 'Not found: ' + req.url, 404);
+ return req._tunnel.sendError(res, 'Not found: ' + req.url, 404);
+ }
+
+ instance = {
+ base: type
+ };
+
+ if (name !== 'default') {
+ instance.base += ':' + name;
}
- config.store.expandInstanceForEnv('client', {
- base: (name === 'default') ? type : type + ':' + name
- }, req.context, function (err, data) {
- if (err) {
- return sendError(
- res,
- 'Error opening: ' + req.url + '\n' + err,
- 500
- );
+ config.store.expandInstanceForEnv(
+ 'client',
+ instance,
+ req.context,
+ function (err, data) {
+ if (err) {
+ return req._tunnel.sendError(
+ res,
+ 'Error opening: ' + req.url + '\n' + err,
+ 500
+ );
+ }
+ return req._tunnel.sendData(res, data);
}
- return sendData(res, data);
- });
+ );
};
};
45 lib/app/middleware/mojito-handler-tunnel-type.js
View
@@ -7,19 +7,6 @@
/*global module*/
/*jslint sloppy:true, nomen:true*/
-
-function sendData(res, data, code) {
- res.writeHead((code || 200), {
- 'content-type': 'application/json; charset="utf-8"'
- });
- res.end(JSON.stringify(data, null, 4));
-}
-
-function sendError(res, msg, code) {
- sendData(res, {error: msg}, (code || 500));
-}
-
-
/**
* Exports a middleware factory that can handle type tunnel requests.
*
@@ -28,27 +15,35 @@ function sendError(res, msg, code) {
*/
module.exports = function (config) {
return function (req, res, next) {
- var typeReq = req._tunnel && req._tunnel.typeReq;
+ var typeReq = req._tunnel && req._tunnel.typeReq,
+ instance;
if (!typeReq) {
return next();
}
if (!typeReq.type) {
- return sendError(res, 'Not found: ' + req.url, 404);
+ return req._tunnel.sendError(res, 'Not found: ' + req.url, 404);
}
- config.store.expandInstanceForEnv('client', {
+ instance = {
type: typeReq.type
- }, req.context, function (err, data) {
- if (err) {
- return sendError(
- res,
- 'Error opening: ' + req.url + '\n' + err,
- 500
- );
+ };
+
+ config.store.expandInstanceForEnv(
+ 'client',
+ instance,
+ req.context,
+ function (err, data) {
+ if (err) {
+ return req._tunnel.sendError(
+ res,
+ 'Error opening: ' + req.url + '\n' + err,
+ 500
+ );
+ }
+ return req._tunnel.sendData(res, data);
}
- return sendData(res, data);
- });
+ );
};
};
235 lib/app/middleware/mojito-handler-tunnel.js
View
@@ -4,202 +4,59 @@
* See the accompanying LICENSE file for terms.
*/
+/*global require, module*/
+/*jslint sloppy:true, nomen:true*/
-/*jslint anon:true, sloppy:true, nomen:true*/
-
-
-var liburl = require('url'),
- logger,
- RX_MULTI_SLASH_ALL = /\/+/g;
-
-
-function trimSlash(str) {
- if ('/' === str.charAt(str.length - 1)) {
- return str.substring(0, str.length - 1);
- }
- return str;
-}
-
-
-function TunnelServer() {}
-
-/*
-* store.client.js expandInstance() makes an RPC call to the TunnelServer.
-* The header 'x-mojito-header' (read here and set in
-* store.client.js) tells the server not to try to route the URL, it gets handled
-* by this critter. The targeted URL _might actually exist_ but we need to make
-* sure that it _does not_ if the mojito header is set to 'tunnel'.
-*/
-TunnelServer.prototype = {
-
- handle: function(store, globalLogger) {
- var self = this,
- config;
- logger = globalLogger;
- //console.log('creating handle');
- this._store = store;
- config = store.getAppConfig({});
- this.tunnelPrefix = (config && config.tunnelPrefix) ?
- config.tunnelPrefix :
- '/tunnel';
- this.staticPrefix = '/static';
- if (config && config.staticHandling &&
- config.staticHandling.hasOwnProperty('prefix')) {
- this.staticPrefix = (config.staticHandling.prefix ?
- '/' + config.staticHandling.prefix :
- '');
- }
- this.tunnelPrefix = trimSlash(this.tunnelPrefix);
- this.staticPrefix = trimSlash(this.staticPrefix);
- if (!this.tunnelPrefix) {
- // this makes the logic below a bit simpler
- this.tunnelPrefix = '/';
- }
-
- return function(req, res, next) {
- var url, parts;
-
- // If we are not in a tunnel get out of here fast
- if (req.url.indexOf(self.tunnelPrefix) !== 0 &&
- req.headers['x-mojito-header'] !== 'tunnel') {
- return next();
+/**
+ * Export a middleware aggregate.
+ * @param {Object} The configuration.
+ * @return {Object} The handler.
+ */
+module.exports = function (config) {
+ var tunnelSubstack = [
+ require('./mojito-handler-tunnel-parser')(config),
+ require('./mojito-handler-tunnel-rpc')(config),
+ require('./mojito-handler-tunnel-specs')(config),
+ require('./mojito-handler-tunnel-type')(config)
+ ];
+
+ return function (req, res, next) {
+ var len,
+ i;
+
+ // Connects the tunnel middleware substack.
+ function connect(err) {
+ // Exit the substack on error.
+ if (err) {
+ next(err);
}
+ }
- url = req.url.replace(self.tunnelPrefix, '').replace(
- self.staticPrefix,
- ''
- );
- url = url.replace(RX_MULTI_SLASH_ALL, '/');
- url = url.split('?')[0];
- parts = url.split('/');
-
- if (parts.length === 4 && parts[2] === 'specs') {
- return self._handleSpec(req, res, next, parts[1], parts[3]);
+ req._tunnel = {
+ sendData: function (res, data, code) {
+ res.writeHead((code || 200), {
+ 'content-type': 'application/json; charset="utf-8"'
+ });
+ res.end(JSON.stringify(data, null, 4));
+
+ // Flag the end of this request.
+ req._tunnel.done = true;
+ },
+ sendError: function (res, msg, code) {
+ this.sendData(res, {error: msg}, (code || 500));
}
- if (parts.length === 3 && parts[2] === 'definition.json') {
- return self._handleType(req, res, next, parts[1]);
- }
- if (req.url === self.tunnelPrefix && 'POST' === req.method) {
- return self._handleRpc(req, res, next);
- }
- next();
};
- },
-
-
- _handleSpec: function(req, res, next, type, basename) {
- var name,
- instance = {},
- my = this;
-
- name = basename.split('.').slice(0, -1).join('.') || null;
- if (!type || !name) {
- my._sendError(res, 'Not found: ' + req.url, 500);
- return;
- }
-
- instance.base = type;
-
- if (name !== 'default') {
- instance.base += ':' + name;
- }
-
- this._store.expandInstanceForEnv('client', instance, req.context,
- function(err, data) {
- if (err) {
- my._sendError(res, 'Error opening: ' + req.url + '\n' +
- err,
- 500
- );
- return;
- }
- my._sendData(res, data);
- });
- },
-
-
- _handleType: function(req, res, next, type) {
- var instance = {},
- my = this;
-
- if (!type) {
- my._sendError(res, 'Not found: ' + req.url, 500);
- return;
- }
-
- instance.type = type;
-
- this._store.expandInstanceForEnv('client', instance, req.context,
- function(err, data) {
- if (err) {
- my._sendError(res, 'Error opening: ' + req.url + '\n' +
- err,
- 'debug',
- 'Tunnel:specs'
- );
- return;
- }
- my._sendData(res, data);
- });
- },
+ // Iterate over the tunnel middleware substack.
+ for (i = 0, len = tunnelSubstack.length; i < len; i += 1) {
+ tunnelSubstack[i](req, res, connect);
-
- _handleRpc: function(req, res, next) {
- var data = req.body,
- command = data;
-
-
- // when taking in the client context on the server side, we have to
- // override the runtime, because the runtime switches from client to server
- if (!command.context) {
- command.context = {};
+ // End this request if we've provided an end-point in the stack.
+ if (req._tunnel.done) {
+ return;
+ }
}
- command.context.runtime = 'server';
-
- // all we need to do is expand the instance given within the RPC call
- // and attach it within a "tunnelCommand", which will be handled by
- // Mojito instead of looking up a route for it.
- this._store.expandInstance(command.instance, command.context,
- function(err, inst) {
- // replace with the expanded instance
- command.instance = inst;
- req.command = {
- action: command.action,
- instance: {
- // Magic here to delegate to tunnelProxy.
- base: 'tunnelProxy'
- },
- params: {
- body: {
- proxyCommand: command
- }
- },
- context: data.context
- };
- next();
- });
- },
-
- _sendError: function(res, msg, code) {
- this._sendData(res, {error: msg}, (code || 500));
- },
- _sendData: function(res, data, code) {
- res.writeHead((code || 200), {
- 'content-type': 'application/json; charset="utf-8"'
- });
- res.end(JSON.stringify(data, null, 4));
- }
-};
-
-
-/**
- * Export a function which can create the handler.
- * @param {Object} config Data to configure the handler.
- * @return {Object} The newly constructed handler.
- */
-module.exports = function(config) {
- var tunnel = new TunnelServer();
- return tunnel.handle(config.store, config.logger);
+ next();
+ };
};
5 lib/mojito.js
View
@@ -90,10 +90,7 @@ MojitoServer.MOJITO_MIDDLEWARE = [
'mojito-parser-body',
'mojito-parser-cookies',
'mojito-contextualizer',
- 'mojito-handler-tunnel-demux',
- 'mojito-handler-tunnel-rpc',
- 'mojito-handler-tunnel-specs',
- 'mojito-handler-tunnel-type',
+ 'mojito-handler-tunnel',
'mojito-router',
'mojito-handler-dispatcher'
];
Please sign in to comment.
Something went wrong with that request. Please try again.