UNPKG

2.39 kBJavaScriptView Raw
1'use strict'
2
3const fs = require('fs')
4const mime = require('../detect/mime')
5const path = require('path')
6const util = require('util')
7
8const defaultMimeType = mime.getType('bin')
9const statAsync = util.promisify(fs.stat)
10const readdirAsync = util.promisify(fs.readdir)
11
12function sendFile (response, filePath, stat) {
13 return new Promise((resolve, reject) => {
14 response.writeHead(200, {
15 'Content-Type': mime.getType(path.extname(filePath)) || defaultMimeType,
16 'Content-Length': stat.size
17 })
18 fs.createReadStream(filePath)
19 .on('error', reject)
20 .on('end', resolve)
21 .pipe(response)
22 })
23}
24
25function sendIndex (response, folderPath) {
26 const indexPath = path.join(folderPath, 'index.html')
27 return statAsync(indexPath)
28 .then(stat => sendFile(response, indexPath, stat))
29}
30
31async function checkCaseSensitivePath (filePath) {
32 const folderPath = path.dirname(filePath)
33 if (folderPath && folderPath !== filePath) {
34 const name = path.basename(filePath)
35 const names = await readdirAsync(folderPath)
36 if (!names.includes(name)) {
37 throw new Error('Not found')
38 }
39 return checkCaseSensitivePath(folderPath)
40 }
41}
42
43module.exports = {
44 schema: {
45 'case-sensitive': {
46 type: 'boolean',
47 defaultValue: false
48 },
49 'ignore-if-not-found': {
50 type: 'boolean',
51 defaultValue: false
52 }
53 },
54 method: 'GET',
55 redirect: ({ request, mapping, redirect, response }) => {
56 let filePath = /([^?#]+)/.exec(unescape(redirect))[1] // filter URL parameters & hash
57 if (!path.isAbsolute(filePath)) {
58 filePath = path.join(mapping.cwd, filePath)
59 }
60 const directoryAccess = !!filePath.match(/(\\|\/)$/) // Test known path separators
61 if (directoryAccess) {
62 filePath = filePath.substring(0, filePath.length - 1)
63 }
64 return statAsync(filePath)
65 .then(async stat => {
66 if (mapping['case-sensitive']) {
67 await checkCaseSensitivePath(filePath)
68 }
69 const isDirectory = stat.isDirectory()
70 if (isDirectory ^ directoryAccess) {
71 return 404 // Can't ignore if not found
72 }
73 if (isDirectory) {
74 return sendIndex(response, filePath)
75 }
76 return sendFile(response, filePath, stat)
77 })
78 .catch(() => {
79 if (!mapping['ignore-if-not-found']) {
80 return 404
81 }
82 })
83 }
84}