Skip to content

Instantly share code, notes, and snippets.

@dead-claudia
Last active March 13, 2017 08:31
Show Gist options
  • Save dead-claudia/4d0777348f8a34ab9fd0dad3b437ad71 to your computer and use it in GitHub Desktop.
Save dead-claudia/4d0777348f8a34ab9fd0dad3b437ad71 to your computer and use it in GitHub Desktop.
Sample server using stream function syntax (ported from my website's dev server)
import fs from "fs"
import path from "path"
import express from "express"
import stylus from "stylus"
import morgan from "morgan"
import autoprefixer from "autoprefixer-stylus"
import pugLocals from "./pug-locals.js"
import generateBlog from "./generate-blog-posts.js"
const app = express()
function nocache(res) {
res.setHeader("Pragma", "no-cache")
res.setHeader("Cache-Control", "no-cache,private,no-store," +
"must-revalidate,max-stale=0,post-check=0,pre-check=0")
res.setHeader("Expires", 0)
}
app.set("views", "src")
app.set("view engine", "pug")
app.set("strict routing", true)
app.use((req, res, next) => {
nocache(res)
next()
})
app.use(morgan("common"))
// Return a permission error on directory traversal
app.use((req, res, next) => {
if (path.posix.join("/", req.path) !== req.path) return res.sendStatus(403)
return next()
})
const website = new express.Router({
strict: app.get("strict routing"),
})
// /license.*, .mixin.{html,css}, .pug, .ignore.*
website.get(
/^\/license[\/\.]|\.(mixin\.(html|css)|pug|ignore(\.[^\.]+))$/,
(req, res, next) => next({code: "ENOENT"}))
website.get("*.html", (req, res) => {
const file = req.path.slice(1)
return res.render(file.replace(/\.html$/, ".pug"), pugLocals(file, false))
})
website.get("*.css", stylus.middleware({
src: path.resolve(__dirname, "../src"),
// This'll be cleared when doing a full compilation, anyways.
dest: path.resolve(__dirname, "../dist"),
force: true,
compile(str, path) {
return stylus(str)
.set("filename", path)
.use(autoprefixer())
},
}))
function getBlog(route, render) {
website.get(route, (req, res, next) =>
generateBlog().then(data => render(req, res, data)).catch(next))
}
getBlog("/blog.atom.xml", (req, res, data) =>
res.type("xml").send(data.feed.render("atom-1.0")))
getBlog("/blog.rss.xml", (req, res, data) =>
res.type("xml").send(data.feed.render("rss-2.0")))
getBlog("/blog.json", (req, res, data) => res.send({posts: data.posts}))
getBlog("/blog/*.md", (req, res, data) =>
// Slice off the initial `/blog/` in req.path
res.send(data.compiled[req.path.slice(6)]))
const base = path.resolve(__dirname, "../src")
const read = root => (req, res, next) => {
const file = path.resolve(root, req.path.slice(1))
return fs.stat(file, (err, stat) => {
if (err != null) return next(err)
if (!stat.isFile()) return res.redirect(`${req.baseUrl}${req.path}/`)
return fs.createReadStream(file)
.on("error", next)
.pipe(res.type(path.basename(file)).status(200))
})
}
website.get("*.css", read(path.resolve(__dirname, "../dist")))
website.get("*.*", read(base))
website.get("/", (req, res) =>
res.render("index.pug", pugLocals("index.html", false)))
website.get("*", (req, res, next) => {
const file = path.resolve(base, req.path.slice(1))
return fs.stat(file, (err, stat) => {
if (err != null) return next(err)
if (stat.isFile()) return next({code: "ENOENT"})
const file = `${req.baseUrl}${req.path}/index`
return res.render(`${file}.jade`, pugLocals(`${file}.html`, false))
})
})
app.use("/website", website)
app.use("*", (req, res) => res.sendStatus(404))
app.listen(8080, () =>
console.log("Server ready at http://localhost:8080/website"))
// Assumes a hypothetical stream framework
import fs from "fs-promise"
import path from "path"
import * as framework from "framework"
import * as router from "framework-router"
import * as stylus from "framework-stylus"
import * as pug from "framework-pug"
import * as morgan from "framework-morgan"
import autoprefixer from "autoprefixer-stylus"
import pugLocals from "./pug-locals.js"
import generateBlog from "./generate-blog-posts.js"
const app = framework.create()
const styl = stylus.create({
src: path.resolve(__dirname, "../src"),
// This'll be cleared when doing a full compilation, anyways.
dest: path.resolve(__dirname, "../dist"),
force: true,
compile(str, path) {
return stylus.stylus(str)
.set("filename", path)
.use(autoprefixer())
},
})
const pug = pug.create({src: path.resolve(__dirname, "../src")})
app.use(morgan.create("common"))
app.use((req, res, next) => {
const route = router.create(req, res, {strict: true})
// Prevent caching
res.setHeader("Pragma", "no-cache")
res.setHeader("Cache-Control", "no-cache,private,no-store," +
"must-revalidate,max-stale=0,post-check=0,pre-check=0")
res.setHeader("Expires", 0)
// Return a permission error on directory traversal
if (route.path.startsWith(".") || route.path.startsWith("..")) {
res.sendStatus(403)
} else {
await next(route)
}
})
app.use((req, res, route, next) => {
const resolved = route.descend("/website/**")
if (resolved == null) {
res.sendStatus(404)
} else {
await next(resolved)
}
})
// /license.*, .mixin.{html,css}, .pug, .ignore.*
const ignored = /^license[\/\.]|\.(mixin\.(html|css)|pug|ignore(\.[^\.]+))$/
app.use((req, res, resolved) => {
if (resolved.match(ignored)) {
throw {code: "ENOENT"}
} else if (resolved.match("*.html")) {
await pug.render(
req, res,
resolved.path.replace(/\.html$/, ".pug"),
pugLocals(resolved.path.slice(1), false))
} else if (resolved.match("*.css")) {
const file = path.resolve(__dirname, "../dist", req.path.slice(1))
await styl.render(req, res, resolved.path, file)
} else if (resolved.match("/blog.{atom,rss}.xml")) {
const {feed} = await generateBlog()
res.type("xml")
res.send(feed.render(
resolved.match("/blog.atom.xml") ? "atom-1.0" : "rss-2.0"
))
} else if (resolved.match("/blog.json")) {
const {posts} = await generateBlog()
res.type("json")
res.send(JSON.stringify({posts}))
} else if (resolved.match("/blog/*.md")) {
const {compiled} = await generateBlog()
res.type("md")
// Slice off the initial `/blog/` in req.path
res.send(compiled[resolved.path.slice(6)])
} else if (resolved.match("*.*")) {
const file = path.resolve(__dirname, "../src", req.path.slice(1))
try {
const stat = await fs.stat(file)
res.type(path.basename(file))
await new Promise((resolve, reject) => {
fs.createReadStream(file).on("error", reject)
.pipe(res).on("error", reject)
.on("close", resolve)
})
res.end()
} catch (e) {
if (e.code !== "EISDIR") throw e
return route.redirect(req, res, `${route.path}/`)
}
} else if (resolved.match("/")) {
await pug.render(req, res, "index.pug",
pugLocals("index.html", false))
} else {
const file = `${req.path}/index`
await pug.render(req, res, `${file}.jade`,
pugLocals(`${file}.html`, false))
}
})
app.listen(8080, () => console.log("Server ready at http://localhost:8080/website"))
// The `framework` module is surprisingly straightforward, particularly for
// what's used within my server alone.
import http from "http"
const resUtils = {
send(body) {
if (!this.getHeader("Content-Type")) this.type("html")
// populate Content-Length
// convert chunk to Buffer; saves later double conversions
let chunk = Buffer.from(body, "utf-8")
this.setHeader("Content-Length", chunk.length)
// freshness
if (this.req.fresh) this.statusCode = 304
// strip irrelevant headers
if (204 === this.statusCode || 304 === this.statusCode) {
this.removeHeader("Content-Type")
this.removeHeader("Content-Length")
this.removeHeader("Transfer-Encoding")
chunk = Buffer.alloc(0)
}
if (this.req.method === "HEAD") {
// skip body for HEAD
this.end()
} else {
// respond
this.end(chunk, "utf-8")
}
},
type(type) {
return this.setHeader("Content-Type",
type.indexOf("/") < 0 ? mime.lookup(type) : type)
},
sendStatus(status) {
var body = statusCodes[statusCode] || String(statusCode)
this.statusCode = statusCode
this.type("txt")
return this.send(body)
},
}
export function create(settings={}) {
if (typeof settings === "function") [settings, init] = [{}, settings]
const onError = settings.onError || console.error
const server = (settings.mod || http).createServer()
const funcs = []
async function run(i, req, res, ...args) {
if (i === funcs.length) return
return (0, funcs[i])(req, res, ...args, (...args) => {
return run(i + 1, req, res, ...args)
})
}
server.on("request", (req, res) => {
Object.assign(res, {settings}, resUtils)
return run(0, req, res).catch(onError)
})
server.use = funcs.push.bind(funcs)
return server
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment