|
| 1 | +import { createServer } from 'http'; |
| 2 | +import { parse } from 'url'; |
| 3 | +import { resolve, sep } from 'path'; |
| 4 | +import { createReadStream, createWriteStream } from 'fs'; |
| 5 | +import { stat, readdir, rmdir, unlink } from 'fs/promises'; |
| 6 | +import mime from 'mime'; |
| 7 | + |
| 8 | +import mkcolHandler from './directory-creation.js'; |
| 9 | + |
| 10 | +const methods = Object.create(null); |
| 11 | + |
| 12 | +createServer((request, response) => { |
| 13 | + let handler = methods[request.method] || notAllowed; |
| 14 | + handler(request) |
| 15 | + .catch((error) => { |
| 16 | + if (error.status != null) return error; |
| 17 | + return { body: String(error), status: 500 }; |
| 18 | + }) |
| 19 | + .then(({ body, status = 200, type = 'text/plain' }) => { |
| 20 | + response.writeHead(status, { 'Content-Type': type }); |
| 21 | + if (body && body.pipe) body.pipe(response); |
| 22 | + else response.end(body); |
| 23 | + }); |
| 24 | +}).listen(8000); |
| 25 | + |
| 26 | +async function notAllowed(request) { |
| 27 | + return { |
| 28 | + status: 405, |
| 29 | + body: `Method ${request.method} not allowed.`, |
| 30 | + }; |
| 31 | +} |
| 32 | + |
| 33 | +var baseDirectory = process.cwd() + sep + 'test-files'; |
| 34 | + |
| 35 | +export function urlPath(url) { |
| 36 | + let { pathname } = parse(url); |
| 37 | + let path = resolve('test-files' + sep + decodeURIComponent(pathname).slice(1)); |
| 38 | + if (path != baseDirectory && !path.startsWith(baseDirectory + sep)) { |
| 39 | + throw { status: 403, body: 'Forbidden' }; |
| 40 | + } |
| 41 | + return path; |
| 42 | +} |
| 43 | + |
| 44 | +methods.GET = async function (request) { |
| 45 | + let path = urlPath(request.url); |
| 46 | + let stats; |
| 47 | + try { |
| 48 | + stats = await stat(path); |
| 49 | + } catch (error) { |
| 50 | + if (error.code != 'ENOENT') throw error; |
| 51 | + else return { status: 404, body: 'File not found' }; |
| 52 | + } |
| 53 | + if (stats.isDirectory()) { |
| 54 | + return { body: (await readdir(path)).join('\n') }; |
| 55 | + } else { |
| 56 | + return { body: createReadStream(path), type: mime.getType(path) }; |
| 57 | + } |
| 58 | +}; |
| 59 | + |
| 60 | +methods.DELETE = async function (request) { |
| 61 | + let path = urlPath(request.url); |
| 62 | + let stats; |
| 63 | + try { |
| 64 | + stats = await stat(path); |
| 65 | + } catch (error) { |
| 66 | + if (error.code != 'ENOENT') throw error; |
| 67 | + else return { status: 204 }; |
| 68 | + } |
| 69 | + if (stats.isDirectory()) await rmdir(path); |
| 70 | + else await unlink(path); |
| 71 | + return { status: 204 }; |
| 72 | +}; |
| 73 | + |
| 74 | +function pipeStream(from, to) { |
| 75 | + return new Promise((resolve, reject) => { |
| 76 | + from.on('error', reject); |
| 77 | + to.on('error', reject); |
| 78 | + to.on('finish', resolve); |
| 79 | + from.pipe(to); |
| 80 | + }); |
| 81 | +} |
| 82 | + |
| 83 | +methods.PUT = async function (request) { |
| 84 | + let path = urlPath(request.url); |
| 85 | + await pipeStream(request, createWriteStream(path)); |
| 86 | + return { status: 204 }; |
| 87 | +}; |
| 88 | + |
| 89 | +methods.MKCOL = mkcolHandler; |
0 commit comments