diff options
author | Johannes Zellner <johannes@nebulon.de> | 2015-06-27 15:39:28 +0200 |
---|---|---|
committer | Johannes Zellner <johannes@nebulon.de> | 2015-06-27 15:39:28 +0200 |
commit | ca2d3b4df536086a81d3dcc2203f23c2b4c8f822 (patch) | |
tree | 95b7d8cfbdbaa065f09c4756d8a72b92b974c885 /src | |
download | Surfer-ca2d3b4df536086a81d3dcc2203f23c2b4c8f822.tar.gz Surfer-ca2d3b4df536086a81d3dcc2203f23c2b4c8f822.tar.zst Surfer-ca2d3b4df536086a81d3dcc2203f23c2b4c8f822.zip |
initial commit
Diffstat (limited to 'src')
-rw-r--r-- | src/files.js | 112 | ||||
-rw-r--r-- | src/multipart.js | 47 |
2 files changed, 159 insertions, 0 deletions
diff --git a/src/files.js b/src/files.js new file mode 100644 index 0000000..fd9c8fd --- /dev/null +++ b/src/files.js | |||
@@ -0,0 +1,112 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var fs = require('fs'), | ||
4 | path = require('path'), | ||
5 | ejs = require('ejs'), | ||
6 | rimraf = require('rimraf'), | ||
7 | HttpError = require('connect-lastmile').HttpError, | ||
8 | HttpSuccess = require('connect-lastmile').HttpSuccess; | ||
9 | |||
10 | exports = module.exports = { | ||
11 | get: get, | ||
12 | put: put, | ||
13 | del: del | ||
14 | }; | ||
15 | |||
16 | var FILE_BASE = path.resolve(__dirname, '../files'); | ||
17 | |||
18 | // http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js | ||
19 | function copyFile(source, target, cb) { | ||
20 | var cbCalled = false; | ||
21 | |||
22 | var rd = fs.createReadStream(source); | ||
23 | rd.on("error", function(err) { | ||
24 | done(err); | ||
25 | }); | ||
26 | |||
27 | var wr = fs.createWriteStream(target); | ||
28 | wr.on("error", function(err) { | ||
29 | done(err); | ||
30 | }); | ||
31 | |||
32 | wr.on("close", function(ex) { | ||
33 | done(); | ||
34 | }); | ||
35 | |||
36 | rd.pipe(wr); | ||
37 | |||
38 | function done(err) { | ||
39 | if (!cbCalled) { | ||
40 | cb(err); | ||
41 | cbCalled = true; | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | |||
46 | function render(view, options) { | ||
47 | return ejs.render(fs.readFileSync(view, 'utf8'), options); | ||
48 | } | ||
49 | |||
50 | function getAbsolutePath(filePath) { | ||
51 | var absoluteFilePath = path.resolve(FILE_BASE, filePath); | ||
52 | |||
53 | if (absoluteFilePath.indexOf(FILE_BASE) !== 0) return null; | ||
54 | return absoluteFilePath; | ||
55 | } | ||
56 | |||
57 | function get(req, res, next) { | ||
58 | var filePath = req.params[0]; | ||
59 | var absoluteFilePath = getAbsolutePath(filePath); | ||
60 | if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed')); | ||
61 | |||
62 | fs.stat(absoluteFilePath, function (error, result) { | ||
63 | if (error) return next(new HttpError(404, error)); | ||
64 | |||
65 | console.log('get', absoluteFilePath, result); | ||
66 | |||
67 | if (result.isFile()) return res.sendfile(absoluteFilePath); | ||
68 | if (result.isDirectory()) return res.status(200).send({ entries: fs.readdirSync(absoluteFilePath) }); | ||
69 | |||
70 | return next(new HttpError(500, 'unsupported type')); | ||
71 | }); | ||
72 | } | ||
73 | |||
74 | function put(req, res, next) { | ||
75 | var filePath = req.params[0]; | ||
76 | |||
77 | if (!req.files.file) return next(new HttpError(400, 'missing file')); | ||
78 | |||
79 | var absoluteFilePath = getAbsolutePath(filePath); | ||
80 | if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed')); | ||
81 | |||
82 | fs.stat(absoluteFilePath, function (error, result) { | ||
83 | if (error && error.code !== 'ENOENT') return next(new HttpError(500, error)); | ||
84 | |||
85 | console.log('put', absoluteFilePath, result, req.files.file); | ||
86 | |||
87 | if (result && result.isDirectory()) return next(new HttpError(409, 'cannot put on directories')); | ||
88 | if (!result || result.isFile()) { | ||
89 | return copyFile(req.files.file.path, absoluteFilePath, function (error) { | ||
90 | if (error) return next(new HttpError(500, error)); | ||
91 | next(new HttpSuccess(201, {})); | ||
92 | }); | ||
93 | } | ||
94 | |||
95 | return next(new HttpError(500, 'unsupported type')); | ||
96 | }); | ||
97 | } | ||
98 | |||
99 | function del(req, res, next) { | ||
100 | var filePath = req.params[0]; | ||
101 | var absoluteFilePath = getAbsolutePath(filePath); | ||
102 | if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed')); | ||
103 | |||
104 | fs.stat(absoluteFilePath, function (error, result) { | ||
105 | if (error) return next(new HttpError(404, error)); | ||
106 | |||
107 | rimraf(absoluteFilePath, function (error) { | ||
108 | if (error) return next(new HttpError(500, 'Unable to remove')); | ||
109 | next(new HttpError(200, {})); | ||
110 | }); | ||
111 | }); | ||
112 | } | ||
diff --git a/src/multipart.js b/src/multipart.js new file mode 100644 index 0000000..7b994cc --- /dev/null +++ b/src/multipart.js | |||
@@ -0,0 +1,47 @@ | |||
1 | /* jshint node:true */ | ||
2 | |||
3 | 'use strict'; | ||
4 | |||
5 | var multiparty = require('multiparty'), | ||
6 | timeout = require('connect-timeout'); | ||
7 | |||
8 | function _mime(req) { | ||
9 | var str = req.headers['content-type'] || ''; | ||
10 | return str.split(';')[0]; | ||
11 | } | ||
12 | |||
13 | module.exports = function multipart(options) { | ||
14 | return function (req, res, next) { | ||
15 | if (_mime(req) !== 'multipart/form-data') return res.status(400).send('Invalid content-type. Expecting multipart'); | ||
16 | |||
17 | var form = new multiparty.Form({ | ||
18 | uploadDir: '/tmp', | ||
19 | keepExtensions: true, | ||
20 | maxFieldsSize: options.maxFieldsSize || (2 * 1024), // only field size, not files | ||
21 | limit: options.limit || '500mb', // file sizes | ||
22 | autoFiles: true | ||
23 | }); | ||
24 | |||
25 | // increase timeout of file uploads by default to 3 mins | ||
26 | if (req.clearTimeout) req.clearTimeout(); // clear any previous installed timeout middleware | ||
27 | |||
28 | timeout(options.timeout || (3 * 60 * 1000))(req, res, function () { | ||
29 | req.fields = { }; | ||
30 | req.files = { }; | ||
31 | |||
32 | form.parse(req, function (err, fields, files) { | ||
33 | if (err) return res.status(400).send('Error parsing request'); | ||
34 | next(null); | ||
35 | }); | ||
36 | |||
37 | form.on('file', function (name, file) { | ||
38 | req.files[name] = file; | ||
39 | }); | ||
40 | |||
41 | form.on('field', function (name, value) { | ||
42 | req.fields[name] = value; // otherwise fields.name is an array | ||
43 | }); | ||
44 | }); | ||
45 | }; | ||
46 | }; | ||
47 | |||