1 | const fs = require('fs');
|
2 | const path = require('path');
|
3 | const mime = require('../mime');
|
4 | const EventEmitter = require('events');
|
5 | const ResponseStream = require('./ResponseStream');
|
6 |
|
7 | const methods = {
|
8 | GET: (filename, req) => {
|
9 | req.end = () => {
|
10 | const stream = should404(filename) ?
|
11 | new ResponseStream().error(404, `ENOENT: no such file or directory, open '${filename}'`) :
|
12 | fs.createReadStream(filename);
|
13 | req.res = stream;
|
14 | stream.headers = {
|
15 | 'content-length': 0,
|
16 | 'content-type': mime.lookup(path.extname(filename)),
|
17 | };
|
18 | stream.on('open', () => {
|
19 | req.emit('response', stream);
|
20 | });
|
21 | if (stream instanceof ResponseStream) return;
|
22 | stream.statusCode = 200;
|
23 | stream.on('end', () => {
|
24 | stream.headers['content-length'] = stream.bytesRead;
|
25 | });
|
26 | stream.on('error', (err) => {
|
27 | stream.statusCode = 400;
|
28 | stream.status = err.message;
|
29 | });
|
30 | };
|
31 | },
|
32 | POST: (filename, req) => {
|
33 | const chunks = [];
|
34 | req.write = (data) => {
|
35 | chunks.push(data);
|
36 | };
|
37 | req.end = (data) => {
|
38 | chunks.push(data);
|
39 | const stream = fs.createWriteStream(filename);
|
40 | const standin = new ResponseStream();
|
41 | req.res = standin;
|
42 | standin.headers = {
|
43 | 'content-length': 0,
|
44 | 'content-type': mime.lookup(path.extname(filename)),
|
45 | };
|
46 | stream.on('finish', () => {
|
47 | req.emit('response', standin);
|
48 | });
|
49 | stream.on('open', () => {
|
50 | (function write() {
|
51 | const chunk = chunks.shift();
|
52 | if (!chunk) return;
|
53 | if (!stream.write(chunk)) {
|
54 | stream.once('drain', write);
|
55 | } else {
|
56 | write();
|
57 | }
|
58 | }());
|
59 | stream.end();
|
60 | });
|
61 | };
|
62 | },
|
63 | DELETE: (filename, req) => {
|
64 | req.end = () => {
|
65 | const stream = new ResponseStream();
|
66 | req.res = stream;
|
67 | stream.headers = {
|
68 | 'content-length': 0,
|
69 | 'content-type': mime.lookup(path.extname(filename)),
|
70 | };
|
71 | fs.unlink(filename, (err) => {
|
72 | req.emit('response', err ? stream.error(400, err.message) : stream);
|
73 | });
|
74 | };
|
75 | },
|
76 | };
|
77 |
|
78 | class Req extends EventEmitter {
|
79 | constructor() {
|
80 | super();
|
81 | this._headers = {};
|
82 | }
|
83 |
|
84 | setHeader() {}
|
85 | getHeader() {}
|
86 | }
|
87 |
|
88 | function request(options) {
|
89 | const method = methods[options.method];
|
90 | if (!method) throw new Error(`Invalid request method "${method}"`);
|
91 | const filename = options.href.replace('file://', '');
|
92 |
|
93 | const req = new Req();
|
94 | method(filename, req, options);
|
95 | return req;
|
96 | }
|
97 |
|
98 | function should404(p) {
|
99 | try {
|
100 | return fs.lstatSync(p).isDirectory();
|
101 | } catch (err) {
|
102 | return true;
|
103 | }
|
104 | }
|
105 |
|
106 | module.exports = {
|
107 | request,
|
108 | };
|