123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- var fs = require("fs");
- var pathlib = require("path");
-
- var mimes = {
- txt: "text/plain",
- css: "text/css",
- html: "text/html",
-
- js: "application/javascript",
- json: "application/json",
- xml: "application/xml",
- zip: "application/zip",
- pdf: "application/pdf",
-
- gif: "image/gif",
- png: "image/png",
- jpeg: "image/jpeg",
- jpg: "image/jpeg",
- svg: "image/svg+xml",
- bmp: "image/bmp",
- webp: "image/webp",
-
- midi: "audio/midi",
- mp3: "audio/mpeg",
- ogg: "audio/ogg",
-
- webm: "video/webm",
- mkv: "video/mkv",
- ogv: "video/ogg",
- }
-
- function mimetype(path) {
- var unknown = "application/octet-stream";
-
- var ext = pathlib.extname(path);
- if (ext)
- return mimes[ext.substr(1)] || unknown;
- else
- return unknown;
- }
-
- function sendfile(path, app, pathname, req, res) {
- fs.open(path, "r", (err, fd) => {
- if (err) {
- app.notice(err);
- res.writeHead(404);
- res.end(app.template(app.res404,
- { method: req.method, pathname: pathname }));
- return;
- }
-
- res.writeHead(200, {
- "Content-Type": mimetype(path)
- });
-
- var rs = fs.createReadStream(null, { fd: fd });
- rs.on("error", err => {
- app.warning(err);
- });
- rs.on("data", d => res.write(d));
- rs.on("end", () => res.end());
- });
- }
-
- var transformCache = {};
- function handleTransform(path, req, res, app) {
- var ext = pathlib.extname(req.url).substring(1);
- if (ext === "")
- return false;
-
- var transform = app._transforms[ext];
- if (!transform)
- return false;
-
- if (transformCache[path]) {
- var c = transformCache[path];
- res.writeHead(c.status, c.headers);
- res.end(c.content);
- return true;
- }
-
- var data = { content: "", headers: null, status: null };
-
- var writeStream = {
- headersSent: false,
- status: 200,
- headers: {
- "content-type": transform.mime
- },
-
- write: function(d) {
- if (!writeStream.headersSent) {
- res.writeHead(writeStream.status, writeStream.headers);
- writeStream.headersSent = true;
- }
- if (d != null) {
- data.content += d;
- res.write(d);
- }
- },
-
- end: function(d, nocache) {
- writeStream.write(d);
-
- res.end();
-
- if (!nocache) {
- data.status = writeStream.status;
- data.headers = writeStream.headers;
- transformCache[path] = data;
- }
- },
-
- error: function(err) {
- if (writeStream.status === 200)
- writeStream.status = 500;
-
- app.warning("Transform for "+path+": "+err.toString());
- writeStream.end(null, true);
- }
- }
-
- transform.func(path, writeStream);
- return true;
- }
-
- module.exports = function(root, before) {
- return function(req, res, app) {
- // `req.urlobj.pathname` is too long.
- var pn = req.urlobj.pathname;
-
- // Join the web root with the request's path name
- var path = pathlib.join(root, pn.replace(before, ""));
-
- // If there's a transform, let that handle it
- if (handleTransform(path, req, res, app))
- return;
-
- // Send a file
- function send(path) {
- sendfile(path, app, pn, req, res);
- }
-
- // Prevent leaking information
- if (pn.indexOf("../") !== -1 || pn.indexOf("/..") !== -1 || pn === "..") {
- res.writeHead(403);
- res.end(app.template(app.res403,
- { method: req.method, pathname: pn }));
- return;
- }
-
- fs.stat(path, (err, stat) => {
-
- // If there's an error stat'ing, just error
- if (err) {
- app.notice(err);
- res.writeHead(404);
- res.end(app.template(app.res404,
- { method: req.method, pathname: pn }));
- return;
- }
-
- // If it's a directory, we want the index.html file,
- // or redirect to <pathname>/
- if (stat.isDirectory()) {
- if (pn[pn.length - 1] !== "/") {
- res.writeHead(302, { location: pn + "/" });
- res.end();
- return;
- }
-
- path = pathlib.join(path, "index.html");
- }
-
- // Send the file
- send(path);
- });
- }
- }
|