Commit ca2d3b4d by Johannes Zellner

initial commit

0 parents
node_modules/
{
"node": true,
"browser": true,
"unused": true,
"globalstrict": true,
"predef": [ "angular", "$", "describe", "it", "before", "after" ]
}
#!/usr/bin/env node
'use strict';
var express = require('express'),
morgan = require('morgan'),
compression = require('compression'),
bodyParser = require('body-parser'),
lastMile = require('connect-lastmile'),
multipart = require('./src/multipart'),
files = require('./src/files.js');
var app = express();
var router = new express.Router();
var multipart = multipart({ maxFieldsSize: 2 * 1024, limit: '512mb', timeout: 3 * 60 * 1000 });
router.get('/api/files/*', files.get);
router.put('/api/files/*', multipart, files.put);
router.delete('/api/files/*', files.del);
app.use(morgan('dev'));
app.use(compression());
app.use(bodyParser.json());
app.use(router);
app.use(lastMile());
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Surfer listening at http://%s:%s', host, port);
});
\ No newline at end of file
{
"name": "surfer",
"version": "1.0.0",
"description": "Simple file server",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"file",
"server"
],
"author": "Johannes Zellner <johannes@nebulon.de>",
"license": "MIT",
"dependencies": {
"body-parser": "^1.13.1",
"compression": "^1.5.0",
"connect-lastmile": "0.0.10",
"connect-timeout": "^1.6.2",
"ejs": "^2.3.1",
"express": "^4.12.4",
"morgan": "^1.6.0",
"multiparty": "^4.1.2",
"rimraf": "^2.4.0"
}
}
{
"name": "surfer",
"version": "1.0.0",
"description": "Simple file server",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"file",
"server"
],
"author": "Johannes Zellner <johannes@nebulon.de>",
"license": "MIT",
"dependencies": {
"body-parser": "^1.13.1",
"compression": "^1.5.0",
"connect-lastmile": "0.0.10",
"connect-timeout": "^1.6.2",
"ejs": "^2.3.1",
"express": "^4.12.4",
"morgan": "^1.6.0",
"multiparty": "^4.1.2",
"rimraf": "^2.4.0"
}
}
'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, {}));
});
});
}
/* 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
});
});
};
};
<html>
<head>
<title> <%= dirPath %> </title>
</head>
<body>
Directory <%= dirPath %>:
<ul>
<% entries.forEach(function (entry) { %>
<li><a href="/api/files/<%= dirPath %>/<%= entry %>"><%= entry %></a></li>
<% }); %>
</ul>
</body>
</html>
\ No newline at end of file
<html>
<head>
<title> File </title>
</head>
<body>
File <%= filePath %>:
<pre>
<%= fileContent %>
</pre>
</body>
</html>
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!