Comparing version 1.2.0 to 2.0.0-alpha.1
88
index.js
@@ -1,71 +0,33 @@ | ||
var makeError = require('./lib/make-error') | ||
var makeMiddleware = require('./lib/make-middleware') | ||
var createFileFilter = require('./lib/file-filter') | ||
var createMiddleware = require('./lib/middleware') | ||
var diskStorage = require('./storage/disk') | ||
var memoryStorage = require('./storage/memory') | ||
function allowAll (req, file, cb) { | ||
cb(null, true) | ||
function _middleware (limits, fields, fileStrategy) { | ||
return createMiddleware(function setup () { | ||
return { | ||
fields: fields, | ||
limits: limits, | ||
fileFilter: createFileFilter(fields), | ||
fileStrategy: fileStrategy | ||
} | ||
}) | ||
} | ||
function Multer (options) { | ||
if (options.storage) { | ||
this.storage = options.storage | ||
} else if (options.dest) { | ||
this.storage = diskStorage({ destination: options.dest }) | ||
} else { | ||
this.storage = memoryStorage() | ||
} | ||
this.limits = options.limits | ||
this.fileFilter = options.fileFilter || allowAll | ||
} | ||
Multer.prototype._makeMiddleware = function (fields, fileStrategy) { | ||
function setup () { | ||
var fileFilter = this.fileFilter | ||
var filesLeft = Object.create(null) | ||
fields.forEach(function (field) { | ||
if (typeof field.maxCount === 'number') { | ||
filesLeft[field.name] = field.maxCount | ||
} else { | ||
filesLeft[field.name] = Infinity | ||
} | ||
}) | ||
function wrappedFileFilter (req, file, cb) { | ||
if ((filesLeft[file.fieldname] || 0) <= 0) { | ||
return cb(makeError('LIMIT_UNEXPECTED_FILE', file.fieldname)) | ||
} | ||
filesLeft[file.fieldname] -= 1 | ||
fileFilter(req, file, cb) | ||
} | ||
return { | ||
limits: this.limits, | ||
storage: this.storage, | ||
fileFilter: wrappedFileFilter, | ||
fileStrategy: fileStrategy | ||
} | ||
} | ||
return makeMiddleware(setup.bind(this)) | ||
} | ||
Multer.prototype.single = function (name) { | ||
return this._makeMiddleware([{ name: name, maxCount: 1 }], 'VALUE') | ||
return _middleware(this.limits, [{ name: name, maxCount: 1 }], 'VALUE') | ||
} | ||
Multer.prototype.array = function (name, maxCount) { | ||
return this._makeMiddleware([{ name: name, maxCount: maxCount }], 'ARRAY') | ||
return _middleware(this.limits, [{ name: name, maxCount: maxCount }], 'ARRAY') | ||
} | ||
Multer.prototype.fields = function (fields) { | ||
return this._makeMiddleware(fields, 'OBJECT') | ||
return _middleware(this.limits, fields, 'OBJECT') | ||
} | ||
Multer.prototype.none = function () { | ||
return this._makeMiddleware([], 'NONE') | ||
return _middleware(this.limits, [], 'NONE') | ||
} | ||
@@ -76,5 +38,5 @@ | ||
return { | ||
fields: [], | ||
limits: this.limits, | ||
storage: this.storage, | ||
fileFilter: this.fileFilter, | ||
fileFilter: function () {}, | ||
fileStrategy: 'ARRAY' | ||
@@ -84,19 +46,17 @@ } | ||
return makeMiddleware(setup.bind(this)) | ||
return createMiddleware(setup.bind(this)) | ||
} | ||
function multer (options) { | ||
if (options === undefined) { | ||
return new Multer({}) | ||
} | ||
if (options === undefined) options = {} | ||
if (options === null) throw new TypeError('Expected object for arugment "options", got null') | ||
if (typeof options !== 'object') throw new TypeError('Expected object for arugment "options", got ' + (typeof options)) | ||
if (typeof options === 'object' && options !== null) { | ||
return new Multer(options) | ||
if (options.dest || options.storage || options.fileFilter) { | ||
throw new Error('The "dest", "storage" and "fileFilter" options where removed in Multer 2.0. Please refer to the latest documentation for new usage.') | ||
} | ||
throw new TypeError('Expected object for argument options') | ||
return new Multer(options) | ||
} | ||
module.exports = multer | ||
module.exports.diskStorage = diskStorage | ||
module.exports.memoryStorage = memoryStorage |
@@ -1,15 +0,5 @@ | ||
var objectAssign = require('object-assign') | ||
function arrayRemove (arr, item) { | ||
var idx = arr.indexOf(item) | ||
if (~idx) arr.splice(idx, 1) | ||
} | ||
function FileAppender (strategy, req) { | ||
this.strategy = strategy | ||
this.req = req | ||
function createFileAppender (strategy, req, fields) { | ||
switch (strategy) { | ||
case 'NONE': break | ||
case 'VALUE': break | ||
case 'VALUE': req.file = null; break | ||
case 'ARRAY': req.files = []; break | ||
@@ -19,50 +9,19 @@ case 'OBJECT': req.files = Object.create(null); break | ||
} | ||
} | ||
FileAppender.prototype.insertPlaceholder = function (file) { | ||
var placeholder = { | ||
fieldname: file.fieldname | ||
if (strategy === 'OBJECT') { | ||
fields.forEach(function (field) { | ||
req.files[field.name] = [] | ||
}) | ||
} | ||
switch (this.strategy) { | ||
case 'NONE': break | ||
case 'VALUE': break | ||
case 'ARRAY': this.req.files.push(placeholder); break | ||
case 'OBJECT': | ||
if (this.req.files[file.fieldname]) { | ||
this.req.files[file.fieldname].push(placeholder) | ||
} else { | ||
this.req.files[file.fieldname] = [placeholder] | ||
} | ||
break | ||
return function append (file) { | ||
switch (strategy) { | ||
case 'NONE': break | ||
case 'VALUE': req.file = file; break | ||
case 'ARRAY': req.files.push(file); break | ||
case 'OBJECT': req.files[file.fieldName].push(file); break | ||
} | ||
} | ||
return placeholder | ||
} | ||
FileAppender.prototype.removePlaceholder = function (placeholder) { | ||
switch (this.strategy) { | ||
case 'NONE': break | ||
case 'VALUE': break | ||
case 'ARRAY': arrayRemove(this.req.files, placeholder); break | ||
case 'OBJECT': | ||
if (this.req.files[placeholder.fieldname].length === 1) { | ||
delete this.req.files[placeholder.fieldname] | ||
} else { | ||
arrayRemove(this.req.files[placeholder.fieldname], placeholder) | ||
} | ||
break | ||
} | ||
} | ||
FileAppender.prototype.replacePlaceholder = function (placeholder, file) { | ||
if (this.strategy === 'VALUE') { | ||
this.req.file = file | ||
return | ||
} | ||
delete placeholder.fieldname | ||
objectAssign(placeholder, file) | ||
} | ||
module.exports = FileAppender | ||
module.exports = createFileAppender |
{ | ||
"name": "multer", | ||
"description": "Middleware for handling `multipart/form-data`.", | ||
"version": "1.2.0", | ||
"version": "2.0.0-alpha.1", | ||
"contributors": [ | ||
@@ -22,22 +22,22 @@ "Hage Yaapa <captain@hacksparrow.com> (http://www.hacksparrow.com)", | ||
"dependencies": { | ||
"append-field": "^0.1.0", | ||
"busboy": "^0.2.11", | ||
"concat-stream": "^1.5.0", | ||
"mkdirp": "^0.5.1", | ||
"object-assign": "^3.0.0", | ||
"append-field": "^1.0.0", | ||
"busboy": "^0.2.13", | ||
"fs-temp": "^1.1.1", | ||
"on-finished": "^2.3.0", | ||
"type-is": "^1.6.4", | ||
"xtend": "^4.0.0" | ||
"pify": "^2.3.0", | ||
"pump": "^1.0.1", | ||
"type-is": "^1.6.13" | ||
}, | ||
"devDependencies": { | ||
"express": "^4.13.1", | ||
"form-data": "^1.0.0-rc1", | ||
"fs-temp": "^0.1.2", | ||
"mocha": "^2.2.5", | ||
"rimraf": "^2.4.1", | ||
"standard": "^4.5.4", | ||
"assert-rejects": "^0.1.0", | ||
"express": "^4.14.0", | ||
"form-data": "^2.1.0", | ||
"get-stream": "^2.3.1", | ||
"hasha": "^2.2.0", | ||
"mocha": "^3.1.0", | ||
"standard": "^8.3.0", | ||
"testdata-w3c-json-form": "^0.2.0" | ||
}, | ||
"engines": { | ||
"node": ">= 0.10.0" | ||
"node": ">= 0.12.0" | ||
}, | ||
@@ -47,3 +47,2 @@ "files": [ | ||
"index.js", | ||
"storage/", | ||
"lib/" | ||
@@ -50,0 +49,0 @@ ], |
150
README.md
@@ -11,3 +11,3 @@ # Multer [![Build Status](https://travis-ci.org/expressjs/multer.svg?branch=master)](https://travis-ci.org/expressjs/multer) [![NPM version](https://badge.fury.io/js/multer.svg)](https://badge.fury.io/js/multer) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard) | ||
```sh | ||
$ npm install --save multer | ||
npm install --save multer | ||
``` | ||
@@ -22,7 +22,7 @@ | ||
```javascript | ||
var multer = require('multer') | ||
var express = require('express') | ||
var multer = require('multer') | ||
var upload = multer({ dest: 'uploads/' }) | ||
var app = express() | ||
var upload = multer() | ||
@@ -51,11 +51,12 @@ app.post('/profile', upload.single('avatar'), function (req, res, next) { | ||
In case you need to handle a text-only multipart form, you can use any of the multer methods (`.single()`, `.array()`, `fields()`). Here is an example using `.array()`: | ||
In case you need to handle a text-only multipart form, you can use the `.none()` method, example: | ||
```javascript | ||
var multer = require('multer') | ||
var express = require('express') | ||
var app = express() | ||
var multer = require('multer') | ||
var upload = multer() | ||
app.post('/profile', upload.array(), function (req, res, next) { | ||
app.post('/profile', upload.none(), function (req, res, next) { | ||
// req.body contains the text fields | ||
@@ -71,41 +72,17 @@ }) | ||
Key | Description | Note | ||
--- | --- | --- | ||
`fieldname` | Field name specified in the form | | ||
`originalname` | Name of the file on the user's computer | | ||
`encoding` | Encoding type of the file | | ||
`mimetype` | Mime type of the file | | ||
`size` | Size of the file in bytes | | ||
`destination` | The folder to which the file has been saved | `DiskStorage` | ||
`filename` | The name of the file within the `destination` | `DiskStorage` | ||
`path` | The full path to the uploaded file | `DiskStorage` | ||
`buffer` | A `Buffer` of the entire file | `MemoryStorage` | ||
### `multer(opts)` | ||
Multer accepts an options object, the most basic of which is the `dest` | ||
property, which tells Multer where to upload the files. In case you omit the | ||
options object, the files will be kept in memory and never written to disk. | ||
By default, Multer will rename the files so as to avoid naming conflicts. The | ||
renaming function can be customized according to your needs. | ||
The following are the options that can be passed to Multer. | ||
Key | Description | ||
--- | --- | ||
`dest` or `storage` | Where to store the files | ||
`fileFilter` | Function to control which files are accepted | ||
`limits` | Limits of the uploaded data | ||
`fieldName` | Field name specified in the form | ||
`originalName` | Name of the file on the user's computer | ||
`size` | Size of the file in bytes | ||
`stream` | Stream of file | ||
In an average web app, only `dest` might be required, and configured as shown in | ||
the following example. | ||
### `multer(opts)` | ||
```javascript | ||
var upload = multer({ dest: 'uploads/' }) | ||
``` | ||
Multer accepts an options object, the following are the options that can be | ||
passed to Multer. | ||
If you want more control over your uploads, you'll want to use the `storage` | ||
option instead of `dest`. Multer ships with storage engines `DiskStorage` | ||
and `MemoryStorage`; More engines are available from third parties. | ||
Key | Description | ||
-------- | ----------- | ||
`limits` | Limits of the uploaded data [(full description)](#limits) | ||
@@ -153,63 +130,2 @@ #### `.single(fieldname)` | ||
### `storage` | ||
#### `DiskStorage` | ||
The disk storage engine gives you full control on storing files to disk. | ||
```javascript | ||
var storage = multer.diskStorage({ | ||
destination: function (req, file, cb) { | ||
cb(null, '/tmp/my-uploads') | ||
}, | ||
filename: function (req, file, cb) { | ||
cb(null, file.fieldname + '-' + Date.now()) | ||
} | ||
}) | ||
var upload = multer({ storage: storage }) | ||
``` | ||
There are two options available, `destination` and `filename`. They are both | ||
functions that determine where the file should be stored. | ||
`destination` is used to determine within which folder the uploaded files should | ||
be stored. This can also be given as a `string` (e.g. `'/tmp/uploads'`). If no | ||
`destination` is given, the operating system's default directory for temporary | ||
files is used. | ||
**Note:** You are responsible for creating the directory when providing | ||
`destination` as a function. When passing a string, multer will make sure that | ||
the directory is created for you. | ||
`filename` is used to determine what the file should be named inside the folder. | ||
If no `filename` is given, each file will be given a random name that doesn't | ||
include any file extension. | ||
**Note:** Multer will not append any file extension for you, your function | ||
should return a filename complete with an file extension. | ||
Each function gets passed both the request (`req`) and some information about | ||
the file (`file`) to aid with the decision. | ||
Note that `req.body` might not have been fully populated yet. It depends on the | ||
order that the client transmits fields and files to the server. | ||
#### `MemoryStorage` | ||
The memory storage engine stores the files in memory as `Buffer` objects. It | ||
doesn't have any options. | ||
```javascript | ||
var storage = multer.memoryStorage() | ||
var upload = multer({ storage: storage }) | ||
``` | ||
When using memory storage, the file info will contain a field called | ||
`buffer` that contains the entire file. | ||
**WARNING**: Uploading very large files, or relatively small files in large | ||
numbers very quickly, can cause your application to run out of memory when | ||
memory storage is used. | ||
### `limits` | ||
@@ -233,25 +149,2 @@ | ||
### `fileFilter` | ||
Set this to a function to control which files should be uploaded and which | ||
should be skipped. The function should look like this: | ||
```javascript | ||
function fileFilter (req, file, cb) { | ||
// The function should call `cb` with a boolean | ||
// to indicate if the file should be accepted | ||
// To reject this file pass `false`, like so: | ||
cb(null, false) | ||
// To accept the file pass `true`, like so: | ||
cb(null, true) | ||
// You can always pass an error if something goes wrong: | ||
cb(new Error('I don\'t have a clue!')) | ||
} | ||
``` | ||
## Error handling | ||
@@ -279,10 +172,1 @@ | ||
``` | ||
## Custom storage engine | ||
See [the documentation here](/StorageEngine.md) if you want to build your own | ||
storage engine. | ||
## License | ||
[MIT](LICENSE) |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
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
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
7
0
17089
8
10
251
2
166
3
1
+ Addedfs-temp@^1.1.1
+ Addedpify@^2.3.0
+ Addedpump@^1.0.1
+ Addedappend-field@1.0.0(transitive)
+ Addedbase32-encode@1.2.0(transitive)
+ Addedencode-utf8@1.0.3(transitive)
+ Addedend-of-stream@1.4.4(transitive)
+ Addedfmix@0.1.0(transitive)
+ Addedfs-temp@1.2.1(transitive)
+ Addedimul@1.0.1(transitive)
+ Addedmurmur-32@0.2.0(transitive)
+ Addedonce@1.4.0(transitive)
+ Addedpify@2.3.0(transitive)
+ Addedpump@1.0.3(transitive)
+ Addedrandom-path@0.1.2(transitive)
+ Addedto-data-view@1.1.0(transitive)
+ Addedwrappy@1.0.2(transitive)
- Removedconcat-stream@^1.5.0
- Removedmkdirp@^0.5.1
- Removedobject-assign@^3.0.0
- Removedxtend@^4.0.0
- Removedappend-field@0.1.0(transitive)
- Removedbuffer-from@1.1.2(transitive)
- Removedconcat-stream@1.6.2(transitive)
- Removedisarray@1.0.0(transitive)
- Removedminimist@1.2.8(transitive)
- Removedmkdirp@0.5.6(transitive)
- Removedobject-assign@3.0.0(transitive)
- Removedprocess-nextick-args@2.0.1(transitive)
- Removedreadable-stream@2.3.8(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedstring_decoder@1.1.1(transitive)
- Removedtypedarray@0.0.6(transitive)
- Removedutil-deprecate@1.0.2(transitive)
- Removedxtend@4.0.2(transitive)
Updatedappend-field@^1.0.0
Updatedbusboy@^0.2.13
Updatedtype-is@^1.6.13