express-fileupload
Advanced tools
Comparing version 0.0.7 to 0.1.0
215
lib/index.js
@@ -1,5 +0,13 @@ | ||
var busboy = require('connect-busboy'); | ||
var fs = require('fs-extra'); | ||
var streamifier = require('streamifier'); | ||
'use strict'; | ||
const Busboy = require('busboy'); | ||
const fs = require('fs-extra'); | ||
const streamifier = require('streamifier'); | ||
const ACCEPTABLE_MIME = /^(?:multipart\/.+)$/i; | ||
const UNACCEPTABLE_METHODS = [ | ||
'GET', | ||
'HEAD' | ||
]; | ||
module.exports = function(options) { | ||
@@ -9,80 +17,153 @@ options = options || {}; | ||
return function(req, res, next) { | ||
return busboy(options)(req, res, function() { | ||
// If no busboy req obj, then no uploads are taking place | ||
if (!req.busboy) | ||
if (!hasBody(req) || !hasAcceptableMethod(req) || !hasAcceptableMime(req)) | ||
return next(); | ||
req.files = null; | ||
processMultipart(options, req, res, next); | ||
}; | ||
}; | ||
req.busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mimetype) { | ||
req.body = req.body || {}; | ||
req.body[fieldname] = val; | ||
}); | ||
/** | ||
* Processes multipart request | ||
* Builds a req.body object for fields | ||
* Builds a req.files object for files | ||
* @param {Object} options expressFileupload and Busboy options | ||
* @param {Object} req Express request object | ||
* @param {Object} res Express response object | ||
* @param {Function} next Express next method | ||
* @return {void} | ||
*/ | ||
function processMultipart(options, req, res, next) { | ||
let busboyOptions = {}; | ||
let busboy; | ||
req.busboy.on('file', function(fieldname, file, filename, encoding, mimetype) { | ||
var buf = new Buffer(0); | ||
var safeFileNameRegex = /[^\w-]/g; | ||
req.files = null; | ||
file.on('data', function(data) { | ||
buf = Buffer.concat([buf, data]); | ||
// Build busboy config | ||
for (let k in options) { | ||
if (Object.prototype.hasOwnProperty.call(options, k)) { | ||
busboyOptions[k] = options[k]; | ||
} | ||
} | ||
if (options.debug) { | ||
return console.log('Uploading %s -> %s', fieldname, filename); | ||
} | ||
}); | ||
// Attach request headers to busboy config | ||
busboyOptions.headers = req.headers; | ||
file.on('end', function() { | ||
if (!req.files) | ||
req.files = {}; | ||
// see: https://github.com/richardgirges/express-fileupload/issues/14 | ||
// firefox uploads empty file in case of cache miss when f5ing page. | ||
// resulting in unexpected behavior. if there is no file data, the file is invalid. | ||
if(!buf.length) | ||
return; | ||
// Init busboy instance | ||
busboy = new Busboy(busboyOptions); | ||
if (options.safeFileNames) { | ||
if (typeof options.safeFileNames === 'object') | ||
safeFileNameRegex = options.safeFileNames; | ||
// Build multipart req.body fields | ||
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mime) { | ||
req.body = req.body || {}; | ||
filename = filename.replace(safeFileNameRegex, ''); | ||
let prev = req.body[fieldname]; | ||
console.log('filename yo', filename); | ||
} | ||
if (!prev) | ||
return req.body[fieldname] = val; | ||
var newFile = { | ||
name: filename, | ||
data: buf, | ||
encoding: encoding, | ||
mimetype: mimetype, | ||
mv: function(path, callback) { | ||
var fstream; | ||
fstream = fs.createWriteStream(path); | ||
streamifier.createReadStream(buf).pipe(fstream); | ||
fstream.on('error', function(error) { | ||
callback(error); | ||
}); | ||
fstream.on('close', function() { | ||
callback(null); | ||
}); | ||
} | ||
}; | ||
if (Array.isArray(prev)) | ||
return prev.push(val); | ||
if (!req.files.hasOwnProperty(fieldname)) { | ||
req.files[fieldname] = newFile; | ||
} else { | ||
if (req.files[fieldname] instanceof Array) | ||
req.files[fieldname].push(newFile); | ||
else | ||
req.files[fieldname] = [req.files[fieldname], newFile]; | ||
} | ||
}); | ||
}); | ||
req.body[fieldname] = [prev, val]; | ||
}); | ||
req.busboy.on('finish', next); | ||
// Build req.files fields | ||
busboy.on('file', function(fieldname, file, filename, encoding, mime) { | ||
let buf = new Buffer(0); | ||
let safeFileNameRegex = /[^\w-]/g; | ||
req.pipe(req.busboy); | ||
file.on('data', function(data) { | ||
buf = Buffer.concat([buf, data]); | ||
if (options.debug) | ||
return console.log('Uploading %s -> %s', fieldname, filename); | ||
}); | ||
}; | ||
}; | ||
file.on('end', function() { | ||
if (!req.files) | ||
req.files = {}; | ||
// see: https://github.com/richardgirges/express-fileupload/issues/14 | ||
// firefox uploads empty file in case of cache miss when f5ing page. | ||
// resulting in unexpected behavior. if there is no file data, the file is invalid. | ||
if(!buf.length) | ||
return; | ||
if (options.safeFileNames) { | ||
if (typeof options.safeFileNames === 'object') | ||
safeFileNameRegex = options.safeFileNames; | ||
filename = filename.replace(safeFileNameRegex, ''); | ||
} | ||
let newFile = { | ||
name: filename, | ||
data: buf, | ||
encoding: encoding, | ||
mimetype: mime, | ||
mv: function(path, callback) { | ||
let fstream = fs.createWriteStream(path); | ||
streamifier.createReadStream(buf).pipe(fstream); | ||
fstream.on('error', function(error) { | ||
if (callback) | ||
callback(error); | ||
}); | ||
fstream.on('close', function() { | ||
if (callback) | ||
callback(null); | ||
}); | ||
} | ||
}; | ||
// Non-array fields | ||
if (!req.files.hasOwnProperty(fieldname)) { | ||
req.files[fieldname] = newFile; | ||
} else { | ||
// Array fields | ||
if (req.files[fieldname] instanceof Array) | ||
req.files[fieldname].push(newFile); | ||
else | ||
req.files[fieldname] = [req.files[fieldname], newFile]; | ||
} | ||
}); | ||
}); | ||
busboy.on('finish', next); | ||
req.pipe(busboy); | ||
} | ||
// Methods below were copied from, or heavily inspired by the Connect and connect-busboy packages | ||
/** | ||
* Ensures the request is not using a non-compliant multipart method | ||
* such as GET or HEAD | ||
* @param {Object} req Express req object | ||
* @return {Boolean} | ||
*/ | ||
function hasAcceptableMethod(req) { | ||
return (UNACCEPTABLE_METHODS.indexOf(req.method) < 0); | ||
} | ||
/** | ||
* Ensures that only multipart requests are processed by express-fileupload | ||
* @param {Object} req Express req object | ||
* @return {Boolean} | ||
*/ | ||
function hasAcceptableMime(req) { | ||
let str = (req.headers['content-type'] || '').split(';')[0]; | ||
return ACCEPTABLE_MIME.test(str); | ||
} | ||
/** | ||
* Ensures the request contains a content body | ||
* @param {Object} req Express req object | ||
* @return {Boolean} | ||
*/ | ||
function hasBody(req) { | ||
return ('transfer-encoding' in req.headers) || | ||
('content-length' in req.headers && req.headers['content-length'] !== '0'); | ||
} |
{ | ||
"name": "express-fileupload", | ||
"version": "0.0.7", | ||
"version": "0.1.0", | ||
"author": "Richard Girges <richardgirges@gmail.com>", | ||
"description": "Simple express file upload middleware that wraps around connect-busboy", | ||
"description": "Simple express file upload middleware that wraps around Busboy", | ||
"main": "./lib/index", | ||
"scripts": { | ||
"test": "istanbul cover _mocha -- -R spec", | ||
"lint": "eslint ./", | ||
"coveralls": "cat ./coverage/lcov.info | coveralls" | ||
}, | ||
"dependencies": { | ||
"connect-busboy": "0.0.2", | ||
"busboy": "^0.2.14", | ||
"fs-extra": "^0.22.1", | ||
@@ -13,3 +18,3 @@ "streamifier": "^0.1.1" | ||
"engines": { | ||
"node": ">=0.8.0" | ||
"node": ">=4.0.0" | ||
}, | ||
@@ -23,15 +28,17 @@ "keywords": [ | ||
"files", | ||
"connect-busboy", | ||
"busboy", | ||
"middleware" | ||
], | ||
"licenses": [ | ||
{ | ||
"type": "MIT", | ||
"url": "https://github.com/richardgirges/express-fileupload/raw/master/LICENSE" | ||
} | ||
], | ||
"license": "MIT", | ||
"repository": "richardgirges/express-fileupload", | ||
"devDependencies": { | ||
"express": "^4.13.4" | ||
"body-parser": "^1.16.1", | ||
"coveralls": "^2.11.16", | ||
"eslint": "^3.15.0", | ||
"eslint-config-google": "^0.7.1", | ||
"express": "^4.13.4", | ||
"istanbul": "^0.4.5", | ||
"mocha": "^3.2.0", | ||
"supertest": "^3.0.0" | ||
} | ||
} |
@@ -1,4 +0,19 @@ | ||
# Description | ||
# express-fileupload | ||
Simple express middleware for uploading files. | ||
[![npm Package](https://img.shields.io/npm/v/express-fileupload.svg?style=flat-square)](https://www.npmjs.org/package/express-fileupload) | ||
[![Build Status](https://travis-ci.org/richardgirges/express-fileupload.svg?branch=master)](https://travis-ci.org/richardgirges/express-fileupload) | ||
[![downloads per month](http://img.shields.io/npm/dm/express-fileupload.svg)](https://www.npmjs.org/package/express-fileupload) | ||
[![Coverage Status](https://img.shields.io/coveralls/richardgirges/express-fileupload.svg)](https://coveralls.io/r/richardgirges/express-fileupload) | ||
# Version 0.1.0 Breaking Changes | ||
## BREAKING CHANGE: No more urlencoded support | ||
As of `v0.1.0`, there is NO MORE `application/x-www-form-urlencoded` SUPPORT! Moving forward, express-fileupload is considered a "multipart" solution only. | ||
If you want to parse `urlencoded` requests, [use body-parser](https://github.com/expressjs/body-parser#bodyparserurlencodedoptions). | ||
## BREAKING CHANGE: Official support for Node v4.x.x + | ||
Use with lower versions of Node at your own risk! | ||
# Install | ||
@@ -116,6 +131,2 @@ ```bash | ||
# Known Bugs | ||
##### If you're using bodyParser middleware | ||
Add `app.use(fileUpload())` *AFTER* `app.use(bodyParser.json)` and any other `bodyParser` middlewares! This limitation will be investigated in an upcoming release. | ||
# Help Wanted | ||
@@ -122,0 +133,0 @@ Pull Requests are welcomed! |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
776017
17
463
136
8
4
1
+ Addedbusboy@^0.2.14
+ Addedbusboy@0.2.14(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addeddicer@0.2.5(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedreadable-stream@1.1.14(transitive)
+ Addedstreamsearch@0.1.2(transitive)
+ Addedstring_decoder@0.10.31(transitive)
- Removedconnect-busboy@0.0.2
- Removedbusboy@1.6.0(transitive)
- Removedconnect-busboy@0.0.2(transitive)
- Removedstreamsearch@1.1.0(transitive)