const http = require("http"); const express = require("express"); const morgan = require("morgan"); const staticAssets = require("./middleware/staticAssets"); const createRouter = require("./createRouter"); morgan.token("fwd", req => { return req.get("x-forwarded-for").replace(/\s/g, ""); }); function errorHandler(err, req, res, next) { console.error(err.stack); res .status(500) .type("text") .send("Internal Server Error"); next(err); } function createServer(publicDir, statsFile) { const app = express(); app.disable("x-powered-by"); if (process.env.NODE_ENV !== "test") { app.use( morgan( // Modified version of the Heroku router's log format // https://devcenter.heroku.com/articles/http-routing#heroku-router-log-format 'method=:method path=":url" host=:req[host] request_id=:req[x-request-id] cf_ray=:req[cf-ray] fwd=:fwd status=:status bytes=:res[content-length]' ) ); } app.use(errorHandler); app.use(express.static(publicDir, { maxAge: "365d" })); app.use(staticAssets(statsFile)); app.use(createRouter()); const server = http.createServer(app); // Heroku dynos automatically timeout after 30s. Set our // own timeout here to force sockets to close before that. // https://devcenter.heroku.com/articles/request-timeout server.setTimeout(25000, socket => { const message = `Timeout of 25 seconds exceeded`; socket.end( [ "HTTP/1.1 503 Service Unavailable", "Date: " + new Date().toGMTString(), "Content-Length: " + Buffer.byteLength(message), "Content-Type: text/plain", "Connection: close", "", message ].join("\r\n") ); }); return server; } module.exports = createServer;