UNPKG

2.17 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 redirect: ({ request, mapping, redirect, response }) => {
46 if (request.method !== 'GET') {
47 return Promise.resolve(405)
48 }
49 let filePath = /([^?#]+)/.exec(unescape(redirect))[1] // filter URL parameters & hash
50 if (!path.isAbsolute(filePath)) {
51 filePath = path.join(mapping.cwd, filePath)
52 }
53 const directoryAccess = !!filePath.match(/(\\|\/)$/) // Test known path separators
54 if (directoryAccess) {
55 filePath = filePath.substring(0, filePath.length - 1)
56 }
57 return statAsync(filePath)
58 .then(async stat => {
59 if (mapping['case-sensitive']) {
60 await checkCaseSensitivePath(filePath)
61 }
62 const isDirectory = stat.isDirectory()
63 if (isDirectory ^ directoryAccess) {
64 return 404
65 }
66 if (isDirectory) {
67 return sendIndex(response, filePath)
68 }
69 return sendFile(response, filePath, stat)
70 })
71 .catch(() => 404)
72 }
73}