Skip to content

Commit

Permalink
Massive overhauls. Adding Travis C.I. build. FINALLY have testing!!! …
Browse files Browse the repository at this point in the history
…Added linting rules to keep the project clean.
  • Loading branch information
richardgirges committed Feb 18, 2017
1 parent 92d7ad5 commit 266c10d
Show file tree
Hide file tree
Showing 16 changed files with 1,392 additions and 60 deletions.
17 changes: 17 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "google",
"env": {
"node": true,
"mocha": true
},
"parserOptions": {
"ecmaVersion": 6
},
"rules": {
"comma-dangle": [2, "never"],
"max-len": [2, {
"code": 100,
"tabWidth": 2
}]
}
}
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ npm-debug.log
node_modules
*.log
*.gz
test/uploadedfiles/*
!test/uploadedfiles/placeholder.txt

test/uploads
test/manual/uploads/*
!test/manual/uploads/placeholder.txt
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
sudo: false
language: node_js
node_js:
- "4"
- "5"
- "6"
- "7"
script:
- npm test
- npm run lint
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
# Description
Simple express middleware for uploading files.

# Version 0.1.0 Breaking Change
As of `v0.1.0`, there is NO MORE `application/x-www-form-urlencoded` SUPPORT!
# 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).

Moving forward, express-fileupload is considered a "multipart" solution only.
## BREAKING CHANGE: Official support for Node v4.x.x +
Use with lower versions of Node at your own risk!

# Install
```bash
Expand Down
47 changes: 23 additions & 24 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
var Busboy = require('busboy');
var fs = require('fs-extra');
var streamifier = require('streamifier');
'use strict';

var ACCEPTABLE_MIME = /^(?:multipart\/.+)$/i;
var UNACCEPTABLE_METHODS = [
const Busboy = require('busboy');
const fs = require('fs-extra');
const streamifier = require('streamifier');

const ACCEPTABLE_MIME = /^(?:multipart\/.+)$/i;
const UNACCEPTABLE_METHODS = [
'GET',
'HEAD'
];
Expand All @@ -19,7 +21,6 @@ module.exports = function(options) {
};
};


/**
* Processes multipart request
* Builds a req.body object for fields
Expand All @@ -31,14 +32,16 @@ module.exports = function(options) {
* @return {void}
*/
function processMultipart(options, req, res, next) {
var busboyOptions = {};
var busboy;
let busboyOptions = {};
let busboy;

req.files = null;

// Build busboy config
for (var k in options) {
busboyOptions[k] = options[k];
for (let k in options) {
if (Object.prototype.hasOwnProperty.call(options, k)) {
busboyOptions[k] = options[k];
}
}

// Attach request headers to busboy config
Expand All @@ -51,7 +54,7 @@ function processMultipart(options, req, res, next) {
busboy.on('field', function(fieldname, val, fieldnameTruncated, valTruncated, encoding, mime) {
req.body = req.body || {};

var prev = req.body[fieldname];
let prev = req.body[fieldname];

if (!prev)
return req.body[fieldname] = val;
Expand All @@ -64,8 +67,8 @@ function processMultipart(options, req, res, next) {

// Build req.files fields
busboy.on('file', function(fieldname, file, filename, encoding, mime) {
var buf = new Buffer(0);
var safeFileNameRegex = /[^\w-]/g;
let buf = new Buffer(0);
let safeFileNameRegex = /[^\w-]/g;

file.on('data', function(data) {
buf = Buffer.concat([buf, data]);
Expand All @@ -77,11 +80,11 @@ function processMultipart(options, req, res, next) {
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)
if(!buf.length)
return;

if (options.safeFileNames) {
Expand All @@ -91,13 +94,13 @@ function processMultipart(options, req, res, next) {
filename = filename.replace(safeFileNameRegex, '');
}

var newFile = {
let newFile = {
name: filename,
data: buf,
encoding: encoding,
mimetype: mime,
mv: function(path, callback) {
var fstream = fs.createWriteStream(path);
let fstream = fs.createWriteStream(path);

streamifier.createReadStream(buf).pipe(fstream);

Expand Down Expand Up @@ -131,11 +134,7 @@ function processMultipart(options, req, res, next) {
req.pipe(busboy);
}


/**************************************************************
* Methods below were copied from, or heavily inspired by
* the Connect and connect-busboy packages
**************************************************************/
// 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
Expand All @@ -153,7 +152,7 @@ function hasAcceptableMethod(req) {
* @return {Boolean}
*/
function hasAcceptableMime(req) {
var str = (req.headers['content-type'] || '').split(';')[0];
let str = (req.headers['content-type'] || '').split(';')[0];

return ACCEPTABLE_MIME.test(str);
}
Expand All @@ -166,4 +165,4 @@ function hasAcceptableMime(req) {
function hasBody(req) {
return ('transfer-encoding' in req.headers) ||
('content-length' in req.headers && req.headers['content-length'] !== '0');
}
}
22 changes: 13 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
{
"name": "express-fileupload",
"version": "0.1.0-beta",
"version": "0.1.0",
"author": "Richard Girges <richardgirges@gmail.com>",
"description": "Simple express file upload middleware that wraps around Busboy",
"main": "./lib/index",
"scripts": {
"test": "mocha \"test/**/*.spec.js\"",
"lint": "eslint ./"
},
"dependencies": {
"busboy": "^0.2.14",
"fs-extra": "^0.22.1",
"streamifier": "^0.1.1"
},
"engines": {
"node": ">=0.8.0"
"node": ">=4.0.0"
},
"keywords": [
"express",
Expand All @@ -22,14 +26,14 @@
"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",
"eslint": "^3.15.0",
"eslint-config-google": "^0.7.1",
"express": "^4.13.4",
"mocha": "^3.2.0",
"supertest": "^3.0.0"
}
}
Binary file added test/files/basketball.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/files/car.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/files/tree.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
25 changes: 12 additions & 13 deletions test/upload.test.js → test/manual/manualtest.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
var express = require('express'),
fileUpload = require('../lib/index.js'),
app = express();
const express = require('express');
const fileUpload = require('../../lib/index.js');
const app = express();

app.use('/form', express.static(__dirname + '/upload.test.html'));
app.use('/form', express.static(__dirname + '/index.html'));

// default options
app.use(fileUpload());
Expand All @@ -12,7 +12,8 @@ app.get('/ping', function(req, res) {
});

app.post('/upload', function(req, res) {
var sampleFile, uploadPath;
let sampleFile;
let uploadPath;

if (!req.files) {
res.status(400).send('No files were uploaded.');
Expand All @@ -23,18 +24,16 @@ app.post('/upload', function(req, res) {

sampleFile = req.files.sampleFile;

uploadPath = __dirname + '/uploadedfiles/' + sampleFile.name;
uploadPath = __dirname + '/uploads/' + sampleFile.name;

sampleFile.mv(uploadPath, function(err) {
if (err) {
res.status(500).send(err);
}
else {
res.send('File uploaded to ' + uploadPath);
}
if (err)
return res.status(500).send(err);

res.send('File uploaded to ' + uploadPath);
});
});

app.listen(8000, function() {
console.log('Express server listening on port 8000');
})
});
File renamed without changes.
86 changes: 86 additions & 0 deletions test/multipartFields.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use strict';

const request = require('supertest');

const {
app
} = require('./server');

let mockUser = {
firstName: 'Joe',
lastName: 'Schmo',
email: 'joe@mailinator.com'
};

let mockCars = [
'rsx',
'tsx',
'civic',
'integra'
];

describe('Test Multipart Form Single Field Submissions', function() {
it('submit multipart user data with POST', function(done) {
request(app)
.post('/fields/user')
.field('firstName', mockUser.firstName)
.field('lastName', mockUser.lastName)
.field('email', mockUser.email)
.expect('Content-Type', /json/)
.expect(200, {
firstName: mockUser.firstName,
lastName: mockUser.lastName,
email: mockUser.email
}, done);
});

it('submit multipart user data with PUT', function(done) {
request(app)
.post('/fields/user')
.field('firstName', mockUser.firstName)
.field('lastName', mockUser.lastName)
.field('email', mockUser.email)
.expect('Content-Type', /json/)
.expect(200, {
firstName: mockUser.firstName,
lastName: mockUser.lastName,
email: mockUser.email
}, done);
});

it('fail when user data submitted without multipart', function(done) {
request(app)
.post('/fields/user')
.send(mockUser)
.expect(400)
.end(done);
});

it('fail when user data not submitted', function(done) {
request(app)
.post('/fields/user')
.expect(400)
.end(done);
});
});

describe('Test Multipart Form Array Field Submissions', function() {
it('submit array of data with POST', function(done) {
let req = request(app).post('/fields/array');

for (let i = 0; i < mockCars.length; i++) {
req.field('testField', mockCars[i]);
}

req
.expect(200)
.end(function(err, res) {
if (err)
return done(err);

let responseMatchesRequest = res.body.join(',') === mockCars.join(',');

done(responseMatchesRequest ? null : 'Data was returned as expected.');
});
});
});
Loading

0 comments on commit 266c10d

Please sign in to comment.