UNPKG

webserv

Version:

a quick, flexible, fully typed development server

112 lines 5.1 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "fs", "path", "url", "../HttpError", "../log", "../util/file/getStat", "../util/file/sendFile", "./forwarder"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fs_1 = require("fs"); const path_1 = require("path"); const url_1 = require("url"); const HttpError_1 = require("../HttpError"); const log_1 = require("../log"); const getStat_1 = require("../util/file/getStat"); const sendFile_1 = require("../util/file/sendFile"); const forwarder_1 = require("./forwarder"); function getPath(target, extensions = []) { return __awaiter(this, void 0, void 0, function* () { if (yield checkAccess(target)) { return target; } for (let extension of extensions) { const path = target + extension; if (yield checkAccess(path)) { return path; } } }); } function checkAccess(target, mode = fs_1.constants.F_OK) { return new Promise((resolve) => { fs_1.access(target, mode, (err) => { err ? resolve() : resolve(target); }); }); } function isMissingTrailingSlash(url) { const pathname = url_1.parse(url).pathname; return pathname.length <= 1 || pathname.charAt(pathname.length - 1) === '/'; } function findDefaultFile(path, search) { return __awaiter(this, void 0, void 0, function* () { for (let searchFile of search) { const searchTarget = path_1.join(path, searchFile); if ((yield checkAccess(searchTarget)) && (yield getStat_1.getStat(searchTarget)).isFile()) { return searchTarget; } } }); } function listDirectoryContents(target) { return new Promise((resolve) => { fs_1.readdir(target, (err, files) => { if (err) { throw err; } resolve({ directory: target, files }); }); }); } exports.serve = ({ basePath = process.cwd(), trailingSlash, showDirectoryContents = true, searchDefaults = ['index.html'], extensions = ['', '.js'] }) => { const base = path_1.resolve(basePath); log_1.log.debug('serving path', base); return (request, response) => __awaiter(void 0, void 0, void 0, function* () { const target = path_1.join(base, decodeURI(url_1.parse(request.url).pathname)); const path = yield getPath(target, extensions); log_1.log.debug(`Request to serve ${target}`); if (!path) { throw new HttpError_1.HttpError(404 /* NotFound */); } if (path.indexOf(base) === -1) { log_1.log.debug(`Attempted to access ${path} from ${basePath} with ${request.url}`); throw new HttpError_1.HttpError(403 /* Forbidden */); } const stat = yield getStat_1.getStat(path); if (stat.isDirectory()) { if (trailingSlash && isMissingTrailingSlash(request.url)) { return forwarder_1.forwarder({ location: request.url + '/' })(request, response); } const search = yield findDefaultFile(path, searchDefaults); if (search) { return sendFile_1.sendFile(request, response, search); } else if (showDirectoryContents) { return listDirectoryContents(path); } else { throw new HttpError_1.HttpError(404 /* NotFound */); } } else { return sendFile_1.sendFile(request, response, path); } }); }; }); //# sourceMappingURL=serve.js.map