From d0db2571e4a7f372bfb04a4a321d9155256a3cc9 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Tue, 16 Jan 2018 16:30:13 -0500 Subject: [PATCH] Guarantee all WebApp handler functions run in a Fiber. https://github.com/VeliovGroup/Meteor-Files/issues/538 --- packages/webapp/connect.js | 40 ++++++++++++++++++++++++++++++++ packages/webapp/webapp_server.js | 15 +++++------- 2 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 packages/webapp/connect.js diff --git a/packages/webapp/connect.js b/packages/webapp/connect.js new file mode 100644 index 0000000000..124ab1edda --- /dev/null +++ b/packages/webapp/connect.js @@ -0,0 +1,40 @@ +import npmConnect from "connect"; + +export function connect(...connectArgs) { + const handlers = npmConnect.apply(this, connectArgs); + const originalUse = handlers.use; + + // Wrap the handlers.use method so that any provided handler functions + // alway run in a Fiber. + handlers.use = function use(...useArgs) { + const { stack } = this; + const originalLength = stack.length; + const result = originalUse.apply(this, useArgs); + + // If we just added anything to the stack, wrap each new entry.handle + // with a function that calls Promise.asyncApply to ensure the + // original handler runs in a Fiber. + for (let i = originalLength; i < stack.length; ++i) { + const entry = stack[i]; + const originalHandle = entry.handle; + + if (originalHandle.length >= 4) { + // If the original handle had four (or more) parameters, the + // wrapper must also have four parameters, since connect uses + // handle.length to dermine whether to pass the error as the first + // argument to the handle function. + entry.handle = function handle(err, req, res, next) { + return Promise.asyncApply(originalHandle, this, arguments); + }; + } else { + entry.handle = function handle(req, res, next) { + return Promise.asyncApply(originalHandle, this, arguments); + }; + } + } + + return result; + }; + + return handlers; +} diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index 6622807b37..7a1d3b3d5f 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -7,7 +7,7 @@ import { } from "path"; import { parse as parseUrl } from "url"; import { createHash } from "crypto"; -import connect from "connect"; +import { connect } from "./connect.js"; import compress from "compression"; import cookieParser from "cookie-parser"; import query from "qs-middleware"; @@ -687,9 +687,7 @@ function runWebAppServer() { // Serve static files from the manifest. // This is inspired by the 'static' middleware. app.use(function (req, res, next) { - Promise.resolve().then(() => { - WebAppInternals.staticFilesMiddleware(staticFiles, req, res, next); - }); + WebAppInternals.staticFilesMiddleware(staticFiles, req, res, next); }); // Core Meteor packages like dynamic-import can add handlers before @@ -715,11 +713,10 @@ function runWebAppServer() { }); app.use(function (req, res, next) { - Promise.resolve().then(() => { - if (! appUrl(req.url)) { - return next(); - } + if (! appUrl(req.url)) { + return next(); + } else { var headers = { 'Content-Type': 'text/html; charset=utf-8' }; @@ -803,7 +800,7 @@ function runWebAppServer() { res.writeHead(500, headers); res.end(); }); - }); + } }); // Return 404 by default, if no other handlers serve this URL.