Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

refactor tunnel middleware into two phases

By splitting the tunnel logic into a detection phase and a handling phase,
applications are free to override the handling logic.

In order to maintain backwards-compatibility, instead of refactoring the
existing tunnel middleware, a tunnel-demux middleware to detect the type of
tunnel request, and tunnel-(rpc|specs|type) middleware to handle each type of
request have been added. Mojito itself will now use these new middleware in
place of the single tunnel middleware, which will remain for those applications
that are specifying it in their configuration.
  • Loading branch information...
commit 9ed57ebc5512743d932301a5d89d4f5b25676320 1 parent e61c900
@ekashida ekashida authored
View
120 lib/app/middleware/mojito-handler-tunnel-demux.js
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2011-2013, Yahoo! Inc. All rights reserved.
+ * Copyrights licensed under the New BSD License.
+ * See the accompanying LICENSE file for terms.
+ */
+
+/*global require, module*/
+/*jslint sloppy:true, nomen:true*/
+
+
+var liburl = require('url'),
+ RE_REPEATING_SLASH = /\/{2,}/g;
+
+function trimSlash(str) {
+ if (str.charAt(0) === '/') {
+ str = str.substring(1, str.length);
+ }
+ if (str.charAt(str.length - 1) === '/') {
+ str = str.substring(0, str.length - 1);
+ }
+ return str;
+}
+
+
+/**
+ * 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 that = this,
+ appConfig = config.store.getAppConfig({}) || {},
+ staticPrefix,
+ tunnelPrefix;
+
+ staticPrefix = appConfig.staticHandling && appConfig.staticHandling.prefix;
+ tunnelPrefix = appConfig.tunnelPrefix;
+
+ if (staticPrefix) {
+ staticPrefix = '/' + trimSlash(staticPrefix);
+ }
+ if (tunnelPrefix) {
+ tunnelPrefix = '/' + trimSlash(tunnelPrefix);
+ }
+
+ this.staticPrefix = staticPrefix || '/static';
+ this.tunnelPrefix = tunnelPrefix || '/tunnel';
+
+ return function (req, res, next) {
+ var hasTunnelPrefix = req.url.indexOf(that.tunnelPrefix) === 0,
+ hasTunnelHeader = req.headers['x-mojito-header'] === 'tunnel',
+ name,
+ type,
+ url,
+ parts;
+
+ // If we are not tunneling get out of here fast!
+ if (!hasTunnelPrefix && !hasTunnelHeader) {
+ return next();
+ }
+
+ req._tunnel = {};
+
+ /**
+ Tunnel examples
+
+ RPC tunnel:
+ /tunnel (or it could just have the tunnel header)
+
+ Type tunnel:
+ /static/{type}/definition.json
+ /{tunnelPrefix}/{type}/definition.json // custom prefix
+ /tunnel/static/{type}/definition.json // according to a UT
+
+ Spec tunnel:
+ /static/{type}/specs/default.json
+ /{staticPrefix}/{type}/specs/default.json // custom prefix
+ /tunnel/static/{type}/specs/default.json // according to a UT
+ **/
+
+ url = req.url.split('?')[0];
+
+ // Normalization step to handle `/{tunnelPrefix}`, `/{staticPrefix}`,
+ // and `/{tunnelPrefix}/{staticPrefix}` URLs.
+ url = url.replace(that.staticPrefix, '')
+ .replace(that.tunnelPrefix, '')
+ .replace(RE_REPEATING_SLASH, '/');
+
+ parts = url.split('/');
+
+ if (parts.length) {
+ name = parts[parts.length - 1];
+ type = parts[1];
+
+ // Spec tunnel
+ if (parts[parts.length - 2] === 'specs') {
+ req._tunnel.specsReq = {
+ type: type,
+ name: name
+ };
+ return next();
+ }
+ // Type tunnel
+ if (name === 'definition.json') {
+ req._tunnel.typeReq = {
+ type: type
+ };
+ return next();
+ }
+ }
+
+ // RPC tunnel
+ if (req.url === that.tunnelPrefix && req.method === 'POST') {
+ req._tunnel.rpcReq = {};
+ return next();
+ }
+
+ return next();
+ };
+};
View
66 lib/app/middleware/mojito-handler-tunnel-rpc.js
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011-2013, Yahoo! Inc. All rights reserved.
+ * Copyrights licensed under the New BSD License.
+ * See the accompanying LICENSE file for terms.
+ */
+
+/*global exports, 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 RPC tunnel requests.
+ *
+ * @param {Object} config The configuration.
+ * @return {Function} The handler.
+ */
+module.exports = function (config) {
+ return function (req, res, next) {
+ var command = req.body,
+ instance = command.instance;
+
+ command.context = command.context || {};
+
+ if (!req._tunnel || !req._tunnel.rpcReq) {
+ return next();
+ }
+
+ // When switching from the client context to the server context, we
+ // have to override the runtime.
+ 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.
+ config.store.expandInstance(instance, command.context, function (err, instance) {
+ // Replace with the expanded instance.
+ command.instance = instance;
+ req.command = {
+ action: command.action,
+ instance: {
+ // Magic here to delegate to tunnelProxy.
+ base: 'tunnelProxy'
+ },
+ params: {
+ body: {
+ proxyCommand: command
+ }
+ },
+ context: command.context
+ };
+ return next();
+ });
+ };
+};
View
66 lib/app/middleware/mojito-handler-tunnel-specs.js
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011-2013, Yahoo! Inc. All rights reserved.
+ * Copyrights licensed under the New BSD License.
+ * See the accompanying LICENSE file for terms.
+ */
+
+/*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.
+ *
+ * @param {Object} config The configuration.
+ * @return {Function} The handler.
+ */
+module.exports = function (config) {
+ return function (req, res, next) {
+ var specsReq = req._tunnel && req._tunnel.specsReq,
+ instance = {},
+ type,
+ name;
+
+ if (!specsReq) {
+ return next();
+ }
+
+ type = specsReq.type;
+ name = specsReq.name;
+ name = name && name.split('.').slice(0, -1).join('.');
+
+ if (!type || !name) {
+ return sendError(res, 'Not found: ' + req.url, 500);
+ }
+
+ instance.base = type;
+
+ if (name !== 'default') {
+ instance.base += ':' + name;
+ }
+
+ config.store.expandInstanceForEnv('client', instance, req.context,
+ function (err, data) {
+ if (err) {
+ return sendError(
+ res,
+ 'Error opening: ' + req.url + '\n' + err,
+ 500
+ );
+ }
+ return sendData(res, data);
+ });
+ };
+};
View
56 lib/app/middleware/mojito-handler-tunnel-type.js
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011-2013, Yahoo! Inc. All rights reserved.
+ * Copyrights licensed under the New BSD License.
+ * See the accompanying LICENSE file for terms.
+ */
+
+/*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.
+ *
+ * @param {Object} config The configuration.
+ * @return {Function} The handler.
+ */
+module.exports = function (config) {
+ return function (req, res, next) {
+ var typeReq = req._tunnel && req._tunnel.typeReq,
+ instance = {};
+
+ if (!typeReq) {
+ return next();
+ }
+
+ if (!typeReq.type) {
+ return sendError(res, 'Not found: ' + req.url, 500);
+ }
+
+ instance.type = typeReq.type;
+
+ config.store.expandInstanceForEnv('client', instance, req.context,
+ function (err, data) {
+ if (err) {
+ return sendError(
+ res,
+ 'Error opening: ' + req.url + '\n' + err,
+ 500
+ );
+ }
+ return sendData(res, data);
+ });
+ };
+};
View
5 lib/mojito.js
@@ -90,7 +90,10 @@ MojitoServer.MOJITO_MIDDLEWARE = [
'mojito-parser-body',
'mojito-parser-cookies',
'mojito-contextualizer',
- 'mojito-handler-tunnel',
+ 'mojito-handler-tunnel-demux',
+ 'mojito-handler-tunnel-rpc',
+ 'mojito-handler-tunnel-specs',
+ 'mojito-handler-tunnel-type',
'mojito-router',
'mojito-handler-dispatcher'
];

0 comments on commit 9ed57eb

Please sign in to comment.
Something went wrong with that request. Please try again.