From ca2d3b4df536086a81d3dcc2203f23c2b4c8f822 Mon Sep 17 00:00:00 2001 From: Johannes Zellner Date: Sat, 27 Jun 2015 15:39:28 +0200 Subject: initial commit --- src/files.js | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/multipart.js | 47 +++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 src/files.js create mode 100644 src/multipart.js (limited to 'src') 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 @@ +'use strict'; + +var fs = require('fs'), + path = require('path'), + ejs = require('ejs'), + rimraf = require('rimraf'), + HttpError = require('connect-lastmile').HttpError, + HttpSuccess = require('connect-lastmile').HttpSuccess; + +exports = module.exports = { + get: get, + put: put, + del: del +}; + +var FILE_BASE = path.resolve(__dirname, '../files'); + +// http://stackoverflow.com/questions/11293857/fastest-way-to-copy-file-in-node-js +function copyFile(source, target, cb) { + var cbCalled = false; + + var rd = fs.createReadStream(source); + rd.on("error", function(err) { + done(err); + }); + + var wr = fs.createWriteStream(target); + wr.on("error", function(err) { + done(err); + }); + + wr.on("close", function(ex) { + done(); + }); + + rd.pipe(wr); + + function done(err) { + if (!cbCalled) { + cb(err); + cbCalled = true; + } + } +} + +function render(view, options) { + return ejs.render(fs.readFileSync(view, 'utf8'), options); +} + +function getAbsolutePath(filePath) { + var absoluteFilePath = path.resolve(FILE_BASE, filePath); + + if (absoluteFilePath.indexOf(FILE_BASE) !== 0) return null; + return absoluteFilePath; +} + +function get(req, res, next) { + var filePath = req.params[0]; + var absoluteFilePath = getAbsolutePath(filePath); + if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed')); + + fs.stat(absoluteFilePath, function (error, result) { + if (error) return next(new HttpError(404, error)); + + console.log('get', absoluteFilePath, result); + + if (result.isFile()) return res.sendfile(absoluteFilePath); + if (result.isDirectory()) return res.status(200).send({ entries: fs.readdirSync(absoluteFilePath) }); + + return next(new HttpError(500, 'unsupported type')); + }); +} + +function put(req, res, next) { + var filePath = req.params[0]; + + if (!req.files.file) return next(new HttpError(400, 'missing file')); + + var absoluteFilePath = getAbsolutePath(filePath); + if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed')); + + fs.stat(absoluteFilePath, function (error, result) { + if (error && error.code !== 'ENOENT') return next(new HttpError(500, error)); + + console.log('put', absoluteFilePath, result, req.files.file); + + if (result && result.isDirectory()) return next(new HttpError(409, 'cannot put on directories')); + if (!result || result.isFile()) { + return copyFile(req.files.file.path, absoluteFilePath, function (error) { + if (error) return next(new HttpError(500, error)); + next(new HttpSuccess(201, {})); + }); + } + + return next(new HttpError(500, 'unsupported type')); + }); +} + +function del(req, res, next) { + var filePath = req.params[0]; + var absoluteFilePath = getAbsolutePath(filePath); + if (!absoluteFilePath) return next(new HttpError(403, 'Path not allowed')); + + fs.stat(absoluteFilePath, function (error, result) { + if (error) return next(new HttpError(404, error)); + + rimraf(absoluteFilePath, function (error) { + if (error) return next(new HttpError(500, 'Unable to remove')); + next(new HttpError(200, {})); + }); + }); +} 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 @@ +/* jshint node:true */ + +'use strict'; + +var multiparty = require('multiparty'), + timeout = require('connect-timeout'); + +function _mime(req) { + var str = req.headers['content-type'] || ''; + return str.split(';')[0]; +} + +module.exports = function multipart(options) { + return function (req, res, next) { + if (_mime(req) !== 'multipart/form-data') return res.status(400).send('Invalid content-type. Expecting multipart'); + + var form = new multiparty.Form({ + uploadDir: '/tmp', + keepExtensions: true, + maxFieldsSize: options.maxFieldsSize || (2 * 1024), // only field size, not files + limit: options.limit || '500mb', // file sizes + autoFiles: true + }); + + // increase timeout of file uploads by default to 3 mins + if (req.clearTimeout) req.clearTimeout(); // clear any previous installed timeout middleware + + timeout(options.timeout || (3 * 60 * 1000))(req, res, function () { + req.fields = { }; + req.files = { }; + + form.parse(req, function (err, fields, files) { + if (err) return res.status(400).send('Error parsing request'); + next(null); + }); + + form.on('file', function (name, file) { + req.files[name] = file; + }); + + form.on('field', function (name, value) { + req.fields[name] = value; // otherwise fields.name is an array + }); + }); + }; +}; + -- cgit v1.2.3