diff options
author | Minteck <freeziv.ytb@gmail.com> | 2021-03-07 18:29:17 +0100 |
---|---|---|
committer | Minteck <freeziv.ytb@gmail.com> | 2021-03-07 18:29:17 +0100 |
commit | 0f79e708bf07721b73ea41e5d341be08e8ea4dce (patch) | |
tree | f3c63cd6a9f4ef0b26f95eec6a031600232e80c8 /node_modules/formidable | |
download | electrode-0f79e708bf07721b73ea41e5d341be08e8ea4dce.tar.gz electrode-0f79e708bf07721b73ea41e5d341be08e8ea4dce.tar.bz2 electrode-0f79e708bf07721b73ea41e5d341be08e8ea4dce.zip |
Initial commit
Diffstat (limited to 'node_modules/formidable')
-rw-r--r-- | node_modules/formidable/LICENSE | 22 | ||||
-rw-r--r-- | node_modules/formidable/README.md | 735 | ||||
-rw-r--r-- | node_modules/formidable/benchmark-2020-01-29_xeon-x3440.png | bin | 0 -> 25658 bytes | |||
-rw-r--r-- | node_modules/formidable/lib/file.js | 81 | ||||
-rw-r--r-- | node_modules/formidable/lib/incoming_form.js | 558 | ||||
-rw-r--r-- | node_modules/formidable/lib/index.js | 3 | ||||
-rw-r--r-- | node_modules/formidable/lib/json_parser.js | 30 | ||||
-rw-r--r-- | node_modules/formidable/lib/multipart_parser.js | 332 | ||||
-rw-r--r-- | node_modules/formidable/lib/octet_parser.js | 20 | ||||
-rw-r--r-- | node_modules/formidable/lib/querystring_parser.js | 27 | ||||
-rw-r--r-- | node_modules/formidable/package.json | 60 |
11 files changed, 1868 insertions, 0 deletions
diff --git a/node_modules/formidable/LICENSE b/node_modules/formidable/LICENSE new file mode 100644 index 0000000..7c66bea --- /dev/null +++ b/node_modules/formidable/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2011-present Felix Geisendörfer, and contributors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/node_modules/formidable/README.md b/node_modules/formidable/README.md new file mode 100644 index 0000000..e6c5075 --- /dev/null +++ b/node_modules/formidable/README.md @@ -0,0 +1,735 @@ +<p align="center"> + <img alt="npm formidable package logo" src="https://raw.githubusercontent.com/node-formidable/formidable/master/logo.png" /> +</p> + +# formidable [![npm version][npmv-img]][npmv-url] [![MIT license][license-img]][license-url] [![Libera Manifesto][libera-manifesto-img]][libera-manifesto-url] [![Twitter][twitter-img]][twitter-url] + +> A Node.js module for parsing form data, especially file uploads. + +### Important Notes + +- This README is for the upcoming (end of February) v2 release! +- Every version prior and including `v1.2.2` is deprecated, please upgrade! +- Install with `formidable@canary` until v2 land officially in `latest` +- see more about the changes in the [CHANGELOG.md](https://github.com/node-formidable/formidable/blob/master/CHANGELOG.md) + +[![Code style][codestyle-img]][codestyle-url] +[![codecoverage][codecov-img]][codecov-url] +[![linux build status][linux-build-img]][build-url] +[![windows build status][windows-build-img]][build-url] +[![macos build status][macos-build-img]][build-url] + +If you have any _how-to_ kind of questions, please read the [Contributing +Guide][contributing-url] and [Code of Conduct][code_of_conduct-url] +documents.<br /> For bugs reports and feature requests, [please create an +issue][open-issue-url] or ping [@tunnckoCore](https://twitter.com/tunnckoCore) +at Twitter. + +[![Conventional Commits][ccommits-img]][ccommits-url] +[![Minimum Required Nodejs][nodejs-img]][npmv-url] +[![Tidelift Subcsription][tidelift-img]][tidelift-url] +[![Buy me a Kofi][kofi-img]][kofi-url] +[![Renovate App Status][renovateapp-img]][renovateapp-url] +[![Make A Pull Request][prs-welcome-img]][prs-welcome-url] + +This project is [semantically versioned](https://semver.org) and available as +part of the [Tidelift Subscription][tidelift-url] for professional grade +assurances, enhanced support and security. +[Learn more.](https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise) + +_The maintainers of `formidable` and thousands of other packages are working +with Tidelift to deliver commercial support and maintenance for the Open Source +dependencies you use to build your applications. Save time, reduce risk, and +improve code health, while paying the maintainers of the exact dependencies you +use._ + +[![][npm-weekly-img]][npmv-url] [![][npm-monthly-img]][npmv-url] +[![][npm-yearly-img]][npmv-url] [![][npm-alltime-img]][npmv-url] + +## Status: Maintained [![npm version][npmv-canary-img]][npmv-url] + +This module was initially developed by +[**@felixge**](https://github.com/felixge) for +[Transloadit](http://transloadit.com/), a service focused on uploading and +encoding images and videos. It has been battle-tested against hundreds of GBs of +file uploads from a large variety of clients and is considered production-ready +and is used in production for years. + +Currently, we are few maintainers trying to deal with it. :) More contributors +are always welcome! :heart: Jump on +[issue #412](https://github.com/felixge/node-formidable/issues/412) which is +closed, but if you are interested we can discuss it and add you after strict rules, like +enabling Two-Factor Auth in your npm and GitHub accounts. + +_**Note:** The github `master` branch is a "canary" branch - try it with `npm i formidable@canary`. +Do not expect (for now) things from it to be inside the`latest` "dist-tag" in the +Npm. The`formidable@latest`is the`v1.2.1` version and probably it will be the +last`v1` release!_ + +_**Note: v2 is coming soon!**_ + +## Highlights + +- [Fast (~900-2500 mb/sec)](#benchmarks) & streaming multipart parser +- Automatically writing file uploads to disk (soon optionally) +- [Plugins API](#useplugin-plugin) - allowing custom parsers and plugins +- Low memory footprint +- Graceful error handling +- Very high test coverage + +## Install + +This project requires `Node.js >= 10.13`. Install it using +[yarn](https://yarnpkg.com) or [npm](https://npmjs.com).<br /> _We highly +recommend to use Yarn when you think to contribute to this project._ + +```sh +npm install formidable +# or the canary version +npm install formidable@canary +``` + +or with Yarn v1/v2 + +```sh +yarn add formidable +# or the canary version +yarn add formidable@canary +``` + +This is a low-level package, and if you're using a high-level framework it _may_ +already be included. Check the examples below and the `examples/` folder. + +## Examples + +For more examples look at the `examples/` directory. + +### with Node.js http module + +Parse an incoming file upload, with the +[Node.js's built-in `http` module](https://nodejs.org/api/http.html). + +```js +const http = require('http'); +const formidable = require('formidable'); + +const server = http.createServer((req, res) => { + if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') { + // parse a file upload + const form = formidable({ multiples: true }); + + form.parse(req, (err, fields, files) => { + res.writeHead(200, { 'content-type': 'application/json' }); + res.end(JSON.stringify({ fields, files }, null, 2)); + }); + + return; + } + + // show a file upload form + res.writeHead(200, { 'content-type': 'text/html' }); + res.end(` + <h2>With Node.js <code>"http"</code> module</h2> + <form action="/api/upload" enctype="multipart/form-data" method="post"> + <div>Text field title: <input type="text" name="title" /></div> + <div>File: <input type="file" name="multipleFiles" multiple="multiple" /></div> + <input type="submit" value="Upload" /> + </form> + `); +}); + +server.listen(8080, () => { + console.log('Server listening on http://localhost:8080/ ...'); +}); +``` + +### with Express.js + +There are multiple variants to do this, but Formidable just need Node.js Request +stream, so something like the following example should work just fine, without +any third-party [Express.js](https://ghub.now.sh/express) middleware. + +Or try the +[examples/with-express.js](https://github.com/node-formidable/node-formidable/blob/master/examples/with-express.js) + +```js +const express = require('express'); +const formidable = require('formidable'); + +const app = express(); + +app.get('/', (req, res) => { + res.send(` + <h2>With <code>"express"</code> npm package</h2> + <form action="/api/upload" enctype="multipart/form-data" method="post"> + <div>Text field title: <input type="text" name="title" /></div> + <div>File: <input type="file" name="someExpressFiles" multiple="multiple" /></div> + <input type="submit" value="Upload" /> + </form> + `); +}); + +app.post('/api/upload', (req, res, next) => { + const form = formidable({ multiples: true }); + + form.parse(req, (err, fields, files) => { + if (err) { + next(err); + return; + } + res.json({ fields, files }); + }); +}); + +app.listen(3000, () => { + console.log('Server listening on http://localhost:3000 ...'); +}); +``` + +### with Koa and Formidable + +Of course, with [Koa v1, v2 or future v3](https://ghub.now.sh/koa) the things +are very similar. You can use `formidable` manually as shown below or through +the [koa-better-body](https://ghub.now.sh/koa-better-body) package which is +using `formidable` under the hood and support more features and different +request bodies, check its documentation for more info. + +_Note: this example is assuming Koa v2. Be aware that you should pass `ctx.req` +which is Node.js's Request, and **NOT** the `ctx.request` which is Koa's Request +object - there is a difference._ + +```js +const Koa = require('koa'); +const formidable = require('formidable'); + +const app = new Koa(); + +app.on('error', (err) => { + console.error('server error', err); +}); + +app.use(async (ctx, next) => { + if (ctx.url === '/api/upload' && ctx.method.toLowerCase() === 'post') { + const form = formidable({ multiples: true }); + + // not very elegant, but that's for now if you don't want touse `koa-better-body` + // or other middlewares. + await new Promise((resolve, reject) => { + form.parse(ctx.req, (err, fields, files) => { + if (err) { + reject(err); + return; + } + + ctx.set('Content-Type', 'application/json'); + ctx.status = 200; + ctx.state = { fields, files }; + ctx.body = JSON.stringify(ctx.state, null, 2); + resolve(); + }); + }); + await next(); + return; + } + + // show a file upload form + ctx.set('Content-Type', 'text/html'); + ctx.status = 200; + ctx.body = ` + <h2>With <code>"koa"</code> npm package</h2> + <form action="/api/upload" enctype="multipart/form-data" method="post"> + <div>Text field title: <input type="text" name="title" /></div> + <div>File: <input type="file" name="koaFiles" multiple="multiple" /></div> + <input type="submit" value="Upload" /> + </form> + `; +}); + +app.use((ctx) => { + console.log('The next middleware is called'); + console.log('Results:', ctx.state); +}); + +app.listen(3000, () => { + console.log('Server listening on http://localhost:3000 ...'); +}); +``` + +## Benchmarks (for v2) + +The benchmark is quite old, from the old codebase. But maybe quite true though. +Previously the numbers was around ~500 mb/sec. Currently with moving to the new +Node.js Streams API it's faster. You can clearly see the differences between the +Node versions. + +_Note: a lot better benchmarking could and should be done in future._ + +Benchmarked on 8GB RAM, Xeon X3440 (2.53 GHz, 4 cores, 8 threads) + +``` +~/github/node-formidable master +❯ nve --parallel 8 10 12 13 node benchmark/bench-multipart-parser.js + + ⬢ Node 8 + +1261.08 mb/sec + + ⬢ Node 10 + +1113.04 mb/sec + + ⬢ Node 12 + +2107.00 mb/sec + + ⬢ Node 13 + +2566.42 mb/sec +``` + +![benchmark January 29th, 2020](./benchmark-2020-01-29_xeon-x3440.png) + +## API + +### Formidable / IncomingForm + +All shown are equivalent. + +_Please pass [`options`](#options) to the function/constructor, not by assigning +them to the instance `form`_ + +```js +const formidable = require('formidable'); +const form = formidable(options); + +// or +const { formidable } = require('formidable'); +const form = formidable(options); + +// or +const { IncomingForm } = require('formidable'); +const form = new IncomingForm(options); + +// or +const { Formidable } = require('formidable'); +const form = new Formidable(options); +``` + +### Options + +See it's defaults in [src/Formidable.js](./src/Formidable.js#L14-L22) (the +`DEFAULT_OPTIONS` constant). + +- `options.encoding` **{string}** - default `'utf-8'`; sets encoding for + incoming form fields, +- `options.uploadDir` **{string}** - default `os.tmpdir()`; the directory for + placing file uploads in. You can move them later by using `fs.rename()` +- `options.keepExtensions` **{boolean}** - default `false`; to include the + extensions of the original files or not +- `options.maxFileSize` **{number}** - default `200 * 1024 * 1024` (200mb); + limit the size of uploaded file. +- `options.maxFields` **{number}** - default `1000`; limit the number of fields + that the Querystring parser will decode, set 0 for unlimited +- `options.maxFieldsSize` **{number}** - default `20 * 1024 * 1024` (20mb); + limit the amount of memory all fields together (except files) can allocate in + bytes. +- `options.hash` **{boolean}** - default `false`; include checksums calculated + for incoming files, set this to some hash algorithm, see + [crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options) + for available algorithms +- `options.multiples` **{boolean}** - default `false`; when you call the + `.parse` method, the `files` argument (of the callback) will contain arrays of + files for inputs which submit multiple files using the HTML5 `multiple` + attribute. Also, the `fields` argument will contain arrays of values for + fields that have names ending with '[]'. + +_**Note:** If this size of combined fields, or size of some file is exceeded, an +`'error'` event is fired._ + +```js +// The amount of bytes received for this form so far. +form.bytesReceived; +``` + +```js +// The expected number of bytes in this form. +form.bytesExpected; +``` + +### .parse(request, callback) + +Parses an incoming Node.js `request` containing form data. If `callback` is +provided, all fields and files are collected and passed to the callback. + +```js +const formidable = require('formidable'); + +const form = formidable({ multiples: true, uploadDir: __dirname }); + +form.parse(req, (err, fields, files) => { + console.log('fields:', fields); + console.log('files:', files); +}); +``` + +You may overwrite this method if you are interested in directly accessing the +multipart stream. Doing so will disable any `'field'` / `'file'` events +processing which would occur otherwise, making you fully responsible for +handling the processing. + +In the example below, we listen on couple of events and direct them to the +`data` listener, so you can do whatever you choose there, based on whether its +before the file been emitted, the header value, the header name, on field, on +file and etc. + +Or the other way could be to just override the `form.onPart` as it's shown a bit +later. + +```js +form.once('error', console.error); + +form.on('fileBegin', (filename, file) => { + form.emit('data', { name: 'fileBegin', filename, value: file }); +}); + +form.on('file', (filename, file) => { + form.emit('data', { name: 'file', key: filename, value: file }); +}); + +form.on('field', (fieldName, fieldValue) => { + form.emit('data', { name: 'field', key: fieldName, value: fieldValue }); +}); + +form.once('end', () => { + console.log('Done!'); +}); + +// If you want to customize whatever you want... +form.on('data', ({ name, key, value, buffer, start, end, ...more }) => { + if (name === 'partBegin') { + } + if (name === 'partData') { + } + if (name === 'headerField') { + } + if (name === 'headerValue') { + } + if (name === 'headerEnd') { + } + if (name === 'headersEnd') { + } + if (name === 'field') { + console.log('field name:', key); + console.log('field value:', value); + } + if (name === 'file') { + console.log('file:', key, value); + } + if (name === 'fileBegin') { + console.log('fileBegin:', key, value); + } +}); +``` + +### .use(plugin: Plugin) + +A method that allows you to extend the Formidable library. By default we include +4 plugins, which esentially are adapters to plug the different built-in parsers. + +**The plugins added by this method are always enabled.** + +_See [src/plugins/](./src/plugins/) for more detailed look on default plugins._ + +The `plugin` param has such signature: + +```typescript +function(formidable: Formidable, options: Options): void; +``` + +The architecture is simple. The `plugin` is a function that is passed with the +Formidable instance (the `form` across the README examples) and the options. + +**Note:** the plugin function's `this` context is also the same instance. + +```js +const formidable = require('formidable'); + +const form = formidable({ keepExtensions: true }); + +form.use((self, options) => { + // self === this === form + console.log('woohoo, custom plugin'); + // do your stuff; check `src/plugins` for inspiration +}); + +form.parse(req, (error, fields, files) => { + console.log('done!'); +}); +``` + +**Important to note**, is that inside plugin `this.options`, `self.options` and +`options` MAY or MAY NOT be the same. General best practice is to always use the +`this`, so you can later test your plugin independently and more easily. + +If you want to disable some parsing capabilities of Formidable, you can disable +the plugin which corresponds to the parser. For example, if you want to disable +multipart parsing (so the [src/parsers/Multipart.js](./src/parsers/Multipart.js) +which is used in [src/plugins/multipart.js](./src/plugins/multipart.js)), then +you can remove it from the `options.enabledPlugins`, like so + +```js +const { Formidable } = require('formidable'); + +const form = new Formidable({ + hash: 'sha1', + enabledPlugins: ['octetstream', 'querystring', 'json'], +}); +``` + +**Be aware** that the order _MAY_ be important too. The names corresponds 1:1 to +files in [src/plugins/](./src/plugins) folder. + +Pull requests for new built-in plugins MAY be accepted - for example, more +advanced querystring parser. Add your plugin as a new file in `src/plugins/` +folder (lowercased) and follow how the other plugins are made. + +### form.onPart + +If you want to use Formidable to only handle certain parts for you, you can do +something similar. Or see +[#387](https://github.com/node-formidable/node-formidable/issues/387) for +inspiration, you can for example validate the mime-type. + +```js +const form = formidable(); + +form.onPart = (part) => { + part.on('data', (buffer) { + // do whatever you want here + }); +}; +``` + +For example, force Formidable to be used only on non-file "parts" (i.e., html +fields) + +```js +const form = formidable(); + +form.onPart = function(part) { + // let formidable handle only non-file parts + if (part.filename === '' || !part.mime) { + // used internally, please do not override! + form.handlePart(part); + } +}; +``` + +### File + +```ts +export interface File { + // The size of the uploaded file in bytes. + // If the file is still being uploaded (see `'fileBegin'` event), + // this property says how many bytes of the file have been written to disk yet. + file.size: number; + + // The path this file is being written to. You can modify this in the `'fileBegin'` event in + // case you are unhappy with the way formidable generates a temporary path for your files. + file.path: string; + + // The name this file had according to the uploading client. + file.name: string | null; + + // The mime type of this file, according to the uploading client. + file.type: string | null; + + // A Date object (or `null`) containing the time this file was last written to. + // Mostly here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/). + file.lastModifiedDate: Date | null; + + // If `options.hash` calculation was set, you can read the hex digest out of this var. + file.hash: string | 'sha1' | 'md5' | 'sha256' | null; +} +``` + +#### file.toJSON() + +This method returns a JSON-representation of the file, allowing you to +`JSON.stringify()` the file which is useful for logging and responding to +requests. + +### Events + +#### `'progress'` + +Emitted after each incoming chunk of data that has been parsed. Can be used to +roll your own progress bar. + +```js +form.on('progress', (bytesReceived, bytesExpected) => {}); +``` + +#### `'field'` + +Emitted whenever a field / value pair has been received. + +```js +form.on('field', (name, value) => {}); +``` + +#### `'fileBegin'` + +Emitted whenever a new file is detected in the upload stream. Use this event if +you want to stream the file to somewhere else while buffering the upload on the +file system. + +```js +form.on('fileBegin', (name, file) => {}); +``` + +#### `'file'` + +Emitted whenever a field / file pair has been received. `file` is an instance of +`File`. + +```js +form.on('file', (name, file) => {}); +``` + +#### `'error'` + +Emitted when there is an error processing the incoming form. A request that +experiences an error is automatically paused, you will have to manually call +`request.resume()` if you want the request to continue firing `'data'` events. + +```js +form.on('error', (err) => {}); +``` + +#### `'aborted'` + +Emitted when the request was aborted by the user. Right now this can be due to a +'timeout' or 'close' event on the socket. After this event is emitted, an +`error` event will follow. In the future there will be a separate 'timeout' +event (needs a change in the node core). + +```js +form.on('aborted', () => {}); +``` + +#### `'end'` + +Emitted when the entire request has been received, and all contained files have +finished flushing to disk. This is a great place for you to send your response. + +```js +form.on('end', () => {}); +``` + +## Ports & Credits + +- [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ + parser based on formidable +- [Ryan Dahl](http://twitter.com/ryah) for his work on + [http-parser](http://github.com/ry/http-parser) which heavily inspired the + initial `multipart_parser.js`. + +## Contributing + +If the documentation is unclear or has a typo, please click on the page's `Edit` +button (pencil icon) and suggest a correction. If you would like to help us fix +a bug or add a new feature, please check our +[Contributing Guide](./CONTRIBUTING.md). Pull requests are welcome! + +Thanks goes to these wonderful people +([emoji key](https://allcontributors.org/docs/en/emoji-key)): + +<!-- ALL-CONTRIBUTORS-LIST:START --> +<!-- prettier-ignore-start --> +<!-- markdownlint-disable --> +<table> + <tr> + <td align="center"><a href="https://twitter.com/felixge"><img src="https://avatars3.githubusercontent.com/u/15000?s=460&v=4" width="100px;" alt=""/><br /><sub><b>Felix Geisendörfer</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=felixge" title="Code">💻</a> <a href="#design-felixge" title="Design">🎨</a> <a href="#ideas-felixge" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=felixge" title="Documentation">📖</a></td> + <td align="center"><a href="https://tunnckoCore.com"><img src="https://avatars3.githubusercontent.com/u/5038030?v=4" width="100px;" alt=""/><br /><sub><b>Charlike Mike Reagent</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AtunnckoCore" title="Bug reports">🐛</a> <a href="#infra-tunnckoCore" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#design-tunnckoCore" title="Design">🎨</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore" title="Code">💻</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore" title="Documentation">📖</a> <a href="#example-tunnckoCore" title="Examples">💡</a> <a href="#ideas-tunnckoCore" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-tunnckoCore" title="Maintenance">🚧</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=tunnckoCore" title="Tests">⚠️</a></td> + <td align="center"><a href="https://github.com/kedarv"><img src="https://avatars1.githubusercontent.com/u/1365665?v=4" width="100px;" alt=""/><br /><sub><b>Kedar</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=kedarv" title="Code">💻</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=kedarv" title="Tests">⚠️</a> <a href="#question-kedarv" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Akedarv" title="Bug reports">🐛</a></td> + <td align="center"><a href="https://github.com/GrosSacASac"><img src="https://avatars0.githubusercontent.com/u/5721194?v=4" width="100px;" alt=""/><br /><sub><b>Walle Cyril</b></sub></a><br /><a href="#question-GrosSacASac" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AGrosSacASac" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=GrosSacASac" title="Code">💻</a> <a href="#financial-GrosSacASac" title="Financial">💵</a> <a href="#ideas-GrosSacASac" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-GrosSacASac" title="Maintenance">🚧</a></td> + <td align="center"><a href="https://github.com/xarguments"><img src="https://avatars2.githubusercontent.com/u/40522463?v=4" width="100px;" alt=""/><br /><sub><b>Xargs</b></sub></a><br /><a href="#question-xarguments" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Axarguments" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=xarguments" title="Code">💻</a> <a href="#maintenance-xarguments" title="Maintenance">🚧</a></td> + <td align="center"><a href="https://github.com/Amit-A"><img src="https://avatars1.githubusercontent.com/u/7987238?v=4" width="100px;" alt=""/><br /><sub><b>Amit-A</b></sub></a><br /><a href="#question-Amit-A" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AAmit-A" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=Amit-A" title="Code">💻</a></td> + </tr> + <tr> + <td align="center"><a href="https://charmander.me/"><img src="https://avatars1.githubusercontent.com/u/1889843?v=4" width="100px;" alt=""/><br /><sub><b>Charmander</b></sub></a><br /><a href="#question-charmander" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Acharmander" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=charmander" title="Code">💻</a> <a href="#ideas-charmander" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-charmander" title="Maintenance">🚧</a></td> + <td align="center"><a href="https://twitter.com/dylan_piercey"><img src="https://avatars2.githubusercontent.com/u/4985201?v=4" width="100px;" alt=""/><br /><sub><b>Dylan Piercey</b></sub></a><br /><a href="#ideas-DylanPiercey" title="Ideas, Planning, & Feedback">🤔</a></td> + <td align="center"><a href="http://ochrona.jawne.info.pl"><img src="https://avatars1.githubusercontent.com/u/3618479?v=4" width="100px;" alt=""/><br /><sub><b>Adam Dobrawy</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Aad-m" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=ad-m" title="Documentation">📖</a></td> + <td align="center"><a href="https://github.com/amitrohatgi"><img src="https://avatars3.githubusercontent.com/u/12177021?v=4" width="100px;" alt=""/><br /><sub><b>amitrohatgi</b></sub></a><br /><a href="#ideas-amitrohatgi" title="Ideas, Planning, & Feedback">🤔</a></td> + <td align="center"><a href="https://github.com/fengxinming"><img src="https://avatars2.githubusercontent.com/u/6262382?v=4" width="100px;" alt=""/><br /><sub><b>Jesse Feng</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Afengxinming" title="Bug reports">🐛</a></td> + <td align="center"><a href="https://qtmsheep.com"><img src="https://avatars1.githubusercontent.com/u/7271496?v=4" width="100px;" alt=""/><br /><sub><b>Nathanael Demacon</b></sub></a><br /><a href="#question-quantumsheep" title="Answering Questions">💬</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=quantumsheep" title="Code">💻</a> <a href="https://github.com/node-formidable/node-formidable/pulls?q=is%3Apr+reviewed-by%3Aquantumsheep" title="Reviewed Pull Requests">👀</a></td> + </tr> + <tr> + <td align="center"><a href="https://github.com/MunMunMiao"><img src="https://avatars1.githubusercontent.com/u/18216142?v=4" width="100px;" alt=""/><br /><sub><b>MunMunMiao</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3AMunMunMiao" title="Bug reports">🐛</a></td> + <td align="center"><a href="https://github.com/gabipetrovay"><img src="https://avatars0.githubusercontent.com/u/1170398?v=4" width="100px;" alt=""/><br /><sub><b>Gabriel Petrovay</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/issues?q=author%3Agabipetrovay" title="Bug reports">🐛</a> <a href="https://github.com/node-formidable/node-formidable/commits?author=gabipetrovay" title="Code">💻</a></td> + <td align="center"><a href="https://github.com/Elzair"><img src="https://avatars0.githubusercontent.com/u/2352818?v=4" width="100px;" alt=""/><br /><sub><b>Philip Woods</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=Elzair" title="Code">💻</a> <a href="#ideas-Elzair" title="Ideas, Planning, & Feedback">🤔</a></td> + <td align="center"><a href="https://github.com/dmolim"><img src="https://avatars2.githubusercontent.com/u/7090374?v=4" width="100px;" alt=""/><br /><sub><b>Dmitry Ivonin</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=dmolim" title="Documentation">📖</a></td> + <td align="center"><a href="https://audiobox.fm"><img src="https://avatars1.githubusercontent.com/u/12844?v=4" width="100px;" alt=""/><br /><sub><b>Claudio Poli</b></sub></a><br /><a href="https://github.com/node-formidable/node-formidable/commits?author=masterkain" title="Code">💻</a></td> + </tr> +</table> + +<!-- markdownlint-enable --> +<!-- prettier-ignore-end --> + +<!-- ALL-CONTRIBUTORS-LIST:END --> + +## License + +Formidable is licensed under the [MIT License][license-url]. + +<!-- badges --> +<!-- prettier-ignore-start --> + +[codestyle-url]: https://github.com/airbnb/javascript +[codestyle-img]: https://badgen.net/badge/code%20style/airbnb%20%2B%20prettier/ff5a5f?icon=airbnb&cache=300 +[codecov-url]: https://codecov.io/gh/node-formidable/node-formidable +[codecov-img]: https://badgen.net/codecov/c/github/node-formidable/node-formidable/master?icon=codecov +[npmv-canary-img]: https://badgen.net/npm/v/formidable/canary?icon=npm +[npmv-dev-img]: https://badgen.net/npm/v/formidable/dev?icon=npm +[npmv-img]: https://badgen.net/npm/v/formidable?icon=npm +[npmv-url]: https://npmjs.com/package/formidable +[license-img]: https://badgen.net/npm/license/formidable +[license-url]: https://github.com/node-formidable/node-formidable/blob/master/LICENSE +[chat-img]: https://badgen.net/badge/chat/on%20gitter/46BC99?icon=gitter +[chat-url]: https://gitter.im/node-formidable/Lobby +[libera-manifesto-url]: https://liberamanifesto.com +[libera-manifesto-img]: https://badgen.net/badge/libera/manifesto/grey +[renovateapp-url]: https://renovatebot.com +[renovateapp-img]: https://badgen.net/badge/renovate/enabled/green?cache=300 +[prs-welcome-img]: https://badgen.net/badge/PRs/welcome/green?cache=300 +[prs-welcome-url]: http://makeapullrequest.com +[twitter-url]: https://twitter.com/tunnckoCore +[twitter-img]: https://badgen.net/twitter/follow/tunnckoCore?icon=twitter&color=1da1f2&cache=300 + +[npm-weekly-img]: https://badgen.net/npm/dw/formidable?icon=npm&cache=300 +[npm-monthly-img]: https://badgen.net/npm/dm/formidable?icon=npm&cache=300 +[npm-yearly-img]: https://badgen.net/npm/dy/formidable?icon=npm&cache=300 +[npm-alltime-img]: https://badgen.net/npm/dt/formidable?icon=npm&cache=300&label=total%20downloads + +[nodejs-img]: https://badgen.net/badge/node/>=%2010.13/green?cache=300 + +[ccommits-url]: https://conventionalcommits.org/ +[ccommits-img]: https://badgen.net/badge/conventional%20commits/v1.0.0/green?cache=300 + +[contributing-url]: https://github.com/node-formidable/node-formidable/blob/master/CONTRIBUTING.md +[code_of_conduct-url]: https://github.com/node-formidable/node-formidable/blob/master/CODE_OF_CONDUCT.md + +[open-issue-url]: https://github.com/node-formidable/node-formidable/issues/new + +[tidelift-url]: https://tidelift.com/subscription/pkg/npm-formidable?utm_source=npm-formidable&utm_medium=referral&utm_campaign=enterprise +[tidelift-img]: https://badgen.net/badge/tidelift/subscription/4B5168?labelColor=F6914D + +[kofi-url]: https://ko-fi.com/tunnckoCore/commissions +[kofi-img]: https://badgen.net/badge/ko-fi/support/29abe0c2?cache=300&icon=https://rawcdn.githack.com/tunnckoCore/badgen-icons/f8264c6414e0bec449dd86f2241d50a9b89a1203/icons/kofi.svg + +[linux-build-img]: https://badgen-net.charlike.now.sh/github/checks/node-formidable/node-formidable?label=linux%20build&icon=github +[macos-build-img]: https://badgen-net.charlike.now.sh/github/checks/node-formidable/node-formidable?label=macos%20build&icon=github +[windows-build-img]: https://badgen-net.charlike.now.sh/github/checks/node-formidable/node-formidable?label=windows%20build&icon=github +[build-url]: https://github.com/node-formidable/node-formidable/actions?query=workflow%3Anodejs +<!-- prettier-ignore-end --> diff --git a/node_modules/formidable/benchmark-2020-01-29_xeon-x3440.png b/node_modules/formidable/benchmark-2020-01-29_xeon-x3440.png Binary files differnew file mode 100644 index 0000000..ef6f0fb --- /dev/null +++ b/node_modules/formidable/benchmark-2020-01-29_xeon-x3440.png diff --git a/node_modules/formidable/lib/file.js b/node_modules/formidable/lib/file.js new file mode 100644 index 0000000..50d34c0 --- /dev/null +++ b/node_modules/formidable/lib/file.js @@ -0,0 +1,81 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +var util = require('util'), + fs = require('fs'), + EventEmitter = require('events').EventEmitter, + crypto = require('crypto'); + +function File(properties) { + EventEmitter.call(this); + + this.size = 0; + this.path = null; + this.name = null; + this.type = null; + this.hash = null; + this.lastModifiedDate = null; + + this._writeStream = null; + + for (var key in properties) { + this[key] = properties[key]; + } + + if(typeof this.hash === 'string') { + this.hash = crypto.createHash(properties.hash); + } else { + this.hash = null; + } +} +module.exports = File; +util.inherits(File, EventEmitter); + +File.prototype.open = function() { + this._writeStream = new fs.WriteStream(this.path); +}; + +File.prototype.toJSON = function() { + var json = { + size: this.size, + path: this.path, + name: this.name, + type: this.type, + mtime: this.lastModifiedDate, + length: this.length, + filename: this.filename, + mime: this.mime + }; + if (this.hash && this.hash != "") { + json.hash = this.hash; + } + return json; +}; + +File.prototype.write = function(buffer, cb) { + var self = this; + if (self.hash) { + self.hash.update(buffer); + } + + if (this._writeStream.closed) { + return cb(); + } + + this._writeStream.write(buffer, function() { + self.lastModifiedDate = new Date(); + self.size += buffer.length; + self.emit('progress', self.size); + cb(); + }); +}; + +File.prototype.end = function(cb) { + var self = this; + if (self.hash) { + self.hash = self.hash.digest('hex'); + } + this._writeStream.end(function() { + self.emit('end'); + cb(); + }); +}; diff --git a/node_modules/formidable/lib/incoming_form.js b/node_modules/formidable/lib/incoming_form.js new file mode 100644 index 0000000..dbd920b --- /dev/null +++ b/node_modules/formidable/lib/incoming_form.js @@ -0,0 +1,558 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +var crypto = require('crypto'); +var fs = require('fs'); +var util = require('util'), + path = require('path'), + File = require('./file'), + MultipartParser = require('./multipart_parser').MultipartParser, + QuerystringParser = require('./querystring_parser').QuerystringParser, + OctetParser = require('./octet_parser').OctetParser, + JSONParser = require('./json_parser').JSONParser, + StringDecoder = require('string_decoder').StringDecoder, + EventEmitter = require('events').EventEmitter, + Stream = require('stream').Stream, + os = require('os'); + +function IncomingForm(opts) { + if (!(this instanceof IncomingForm)) return new IncomingForm(opts); + EventEmitter.call(this); + + opts=opts||{}; + + this.error = null; + this.ended = false; + + this.maxFields = opts.maxFields || 1000; + this.maxFieldsSize = opts.maxFieldsSize || 20 * 1024 * 1024; + this.maxFileSize = opts.maxFileSize || 200 * 1024 * 1024; + this.keepExtensions = opts.keepExtensions || false; + this.uploadDir = opts.uploadDir || (os.tmpdir && os.tmpdir()) || os.tmpDir(); + this.encoding = opts.encoding || 'utf-8'; + this.headers = null; + this.type = null; + this.hash = opts.hash || false; + this.multiples = opts.multiples || false; + + this.bytesReceived = null; + this.bytesExpected = null; + + this._parser = null; + this._flushing = 0; + this._fieldsSize = 0; + this._fileSize = 0; + this.openedFiles = []; + + return this; +} +util.inherits(IncomingForm, EventEmitter); +exports.IncomingForm = IncomingForm; + +IncomingForm.prototype.parse = function(req, cb) { + this.pause = function() { + try { + req.pause(); + } catch (err) { + // the stream was destroyed + if (!this.ended) { + // before it was completed, crash & burn + this._error(err); + } + return false; + } + return true; + }; + + this.resume = function() { + try { + req.resume(); + } catch (err) { + // the stream was destroyed + if (!this.ended) { + // before it was completed, crash & burn + this._error(err); + } + return false; + } + + return true; + }; + + // Setup callback first, so we don't miss anything from data events emitted + // immediately. + if (cb) { + var fields = {}, files = {}; + this + .on('field', function(name, value) { + fields[name] = value; + }) + .on('file', function(name, file) { + if (this.multiples) { + if (files[name]) { + if (!Array.isArray(files[name])) { + files[name] = [files[name]]; + } + files[name].push(file); + } else { + files[name] = file; + } + } else { + files[name] = file; + } + }) + .on('error', function(err) { + cb(err, fields, files); + }) + .on('end', function() { + cb(null, fields, files); + }); + } + + // Parse headers and setup the parser, ready to start listening for data. + this.writeHeaders(req.headers); + + // Start listening for data. + var self = this; + req + .on('error', function(err) { + self._error(err); + }) + .on('aborted', function() { + self.emit('aborted'); + self._error(new Error('Request aborted')); + }) + .on('data', function(buffer) { + self.write(buffer); + }) + .on('end', function() { + if (self.error) { + return; + } + + var err = self._parser.end(); + if (err) { + self._error(err); + } + }); + + return this; +}; + +IncomingForm.prototype.writeHeaders = function(headers) { + this.headers = headers; + this._parseContentLength(); + this._parseContentType(); +}; + +IncomingForm.prototype.write = function(buffer) { + if (this.error) { + return; + } + if (!this._parser) { + this._error(new Error('uninitialized parser')); + return; + } + + this.bytesReceived += buffer.length; + this.emit('progress', this.bytesReceived, this.bytesExpected); + + var bytesParsed = this._parser.write(buffer); + if (bytesParsed !== buffer.length) { + this._error(new Error('parser error, '+bytesParsed+' of '+buffer.length+' bytes parsed')); + } + + return bytesParsed; +}; + +IncomingForm.prototype.pause = function() { + // this does nothing, unless overwritten in IncomingForm.parse + return false; +}; + +IncomingForm.prototype.resume = function() { + // this does nothing, unless overwritten in IncomingForm.parse + return false; +}; + +IncomingForm.prototype.onPart = function(part) { + // this method can be overwritten by the user + this.handlePart(part); +}; + +IncomingForm.prototype.handlePart = function(part) { + var self = this; + + // This MUST check exactly for undefined. You can not change it to !part.filename. + if (part.filename === undefined) { + var value = '' + , decoder = new StringDecoder(this.encoding); + + part.on('data', function(buffer) { + self._fieldsSize += buffer.length; + if (self._fieldsSize > self.maxFieldsSize) { + self._error(new Error('maxFieldsSize exceeded, received '+self._fieldsSize+' bytes of field data')); + return; + } + value += decoder.write(buffer); + }); + + part.on('end', function() { + self.emit('field', part.name, value); + }); + return; + } + + this._flushing++; + + var file = new File({ + path: this._uploadPath(part.filename), + name: part.filename, + type: part.mime, + hash: self.hash + }); + + this.emit('fileBegin', part.name, file); + + file.open(); + this.openedFiles.push(file); + + part.on('data', function(buffer) { + self._fileSize += buffer.length; + if (self._fileSize > self.maxFileSize) { + self._error(new Error('maxFileSize exceeded, received '+self._fileSize+' bytes of file data')); + return; + } + if (buffer.length == 0) { + return; + } + self.pause(); + file.write(buffer, function() { + self.resume(); + }); + }); + + part.on('end', function() { + file.end(function() { + self._flushing--; + self.emit('file', part.name, file); + self._maybeEnd(); + }); + }); +}; + +function dummyParser(self) { + return { + end: function () { + self.ended = true; + self._maybeEnd(); + return null; + } + }; +} + +IncomingForm.prototype._parseContentType = function() { + if (this.bytesExpected === 0) { + this._parser = dummyParser(this); + return; + } + + if (!this.headers['content-type']) { + this._error(new Error('bad content-type header, no content-type')); + return; + } + + if (this.headers['content-type'].match(/octet-stream/i)) { + this._initOctetStream(); + return; + } + + if (this.headers['content-type'].match(/urlencoded/i)) { + this._initUrlencoded(); + return; + } + + if (this.headers['content-type'].match(/multipart/i)) { + var m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i); + if (m) { + this._initMultipart(m[1] || m[2]); + } else { + this._error(new Error('bad content-type header, no multipart boundary')); + } + return; + } + + if (this.headers['content-type'].match(/json/i)) { + this._initJSONencoded(); + return; + } + + this._error(new Error('bad content-type header, unknown content-type: '+this.headers['content-type'])); +}; + +IncomingForm.prototype._error = function(err) { + if (this.error || this.ended) { + return; + } + + this.error = err; + this.emit('error', err); + + if (Array.isArray(this.openedFiles)) { + this.openedFiles.forEach(function(file) { + file._writeStream.destroy(); + setTimeout(fs.unlink, 0, file.path, function(error) { }); + }); + } +}; + +IncomingForm.prototype._parseContentLength = function() { + this.bytesReceived = 0; + if (this.headers['content-length']) { + this.bytesExpected = parseInt(this.headers['content-length'], 10); + } else if (this.headers['transfer-encoding'] === undefined) { + this.bytesExpected = 0; + } + + if (this.bytesExpected !== null) { + this.emit('progress', this.bytesReceived, this.bytesExpected); + } +}; + +IncomingForm.prototype._newParser = function() { + return new MultipartParser(); +}; + +IncomingForm.prototype._initMultipart = function(boundary) { + this.type = 'multipart'; + + var parser = new MultipartParser(), + self = this, + headerField, + headerValue, + part; + + parser.initWithBoundary(boundary); + + parser.onPartBegin = function() { + part = new Stream(); + part.readable = true; + part.headers = {}; + part.name = null; + part.filename = null; + part.mime = null; + + part.transferEncoding = 'binary'; + part.transferBuffer = ''; + + headerField = ''; + headerValue = ''; + }; + + parser.onHeaderField = function(b, start, end) { + headerField += b.toString(self.encoding, start, end); + }; + + parser.onHeaderValue = function(b, start, end) { + headerValue += b.toString(self.encoding, start, end); + }; + + parser.onHeaderEnd = function() { + headerField = headerField.toLowerCase(); + part.headers[headerField] = headerValue; + + // matches either a quoted-string or a token (RFC 2616 section 19.5.1) + var m = headerValue.match(/\bname=("([^"]*)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))/i); + if (headerField == 'content-disposition') { + if (m) { + part.name = m[2] || m[3] || ''; + } + + part.filename = self._fileName(headerValue); + } else if (headerField == 'content-type') { + part.mime = headerValue; + } else if (headerField == 'content-transfer-encoding') { + part.transferEncoding = headerValue.toLowerCase(); + } + + headerField = ''; + headerValue = ''; + }; + + parser.onHeadersEnd = function() { + switch(part.transferEncoding){ + case 'binary': + case '7bit': + case '8bit': + parser.onPartData = function(b, start, end) { + part.emit('data', b.slice(start, end)); + }; + + parser.onPartEnd = function() { + part.emit('end'); + }; + break; + + case 'base64': + parser.onPartData = function(b, start, end) { + part.transferBuffer += b.slice(start, end).toString('ascii'); + + /* + four bytes (chars) in base64 converts to three bytes in binary + encoding. So we should always work with a number of bytes that + can be divided by 4, it will result in a number of buytes that + can be divided vy 3. + */ + var offset = parseInt(part.transferBuffer.length / 4, 10) * 4; + part.emit('data', new Buffer(part.transferBuffer.substring(0, offset), 'base64')); + part.transferBuffer = part.transferBuffer.substring(offset); + }; + + parser.onPartEnd = function() { + part.emit('data', new Buffer(part.transferBuffer, 'base64')); + part.emit('end'); + }; + break; + + default: + return self._error(new Error('unknown transfer-encoding')); + } + + self.onPart(part); + }; + + + parser.onEnd = function() { + self.ended = true; + self._maybeEnd(); + }; + + this._parser = parser; +}; + +IncomingForm.prototype._fileName = function(headerValue) { + // matches either a quoted-string or a token (RFC 2616 section 19.5.1) + var m = headerValue.match(/\bfilename=("(.*?)"|([^\(\)<>@,;:\\"\/\[\]\?=\{\}\s\t/]+))($|;\s)/i); + if (!m) return; + + var match = m[2] || m[3] || ''; + var filename = match.substr(match.lastIndexOf('\\') + 1); + filename = filename.replace(/%22/g, '"'); + filename = filename.replace(/&#([\d]{4});/g, function(m, code) { + return String.fromCharCode(code); + }); + return filename; +}; + +IncomingForm.prototype._initUrlencoded = function() { + this.type = 'urlencoded'; + + var parser = new QuerystringParser(this.maxFields) + , self = this; + + parser.onField = function(key, val) { + self.emit('field', key, val); + }; + + parser.onEnd = function() { + self.ended = true; + self._maybeEnd(); + }; + + this._parser = parser; +}; + +IncomingForm.prototype._initOctetStream = function() { + this.type = 'octet-stream'; + var filename = this.headers['x-file-name']; + var mime = this.headers['content-type']; + + var file = new File({ + path: this._uploadPath(filename), + name: filename, + type: mime + }); + + this.emit('fileBegin', filename, file); + file.open(); + this.openedFiles.push(file); + this._flushing++; + + var self = this; + + self._parser = new OctetParser(); + + //Keep track of writes that haven't finished so we don't emit the file before it's done being written + var outstandingWrites = 0; + + self._parser.on('data', function(buffer){ + self.pause(); + outstandingWrites++; + + file.write(buffer, function() { + outstandingWrites--; + self.resume(); + + if(self.ended){ + self._parser.emit('doneWritingFile'); + } + }); + }); + + self._parser.on('end', function(){ + self._flushing--; + self.ended = true; + + var done = function(){ + file.end(function() { + self.emit('file', 'file', file); + self._maybeEnd(); + }); + }; + + if(outstandingWrites === 0){ + done(); + } else { + self._parser.once('doneWritingFile', done); + } + }); +}; + +IncomingForm.prototype._initJSONencoded = function() { + this.type = 'json'; + + var parser = new JSONParser(this) + , self = this; + + parser.onField = function(key, val) { + self.emit('field', key, val); + }; + + parser.onEnd = function() { + self.ended = true; + self._maybeEnd(); + }; + + this._parser = parser; +}; + +IncomingForm.prototype._uploadPath = function(filename) { + var buf = crypto.randomBytes(16); + var name = 'upload_' + buf.toString('hex'); + + if (this.keepExtensions) { + var ext = path.extname(filename); + ext = ext.replace(/(\.[a-z0-9]+).*/i, '$1'); + + name += ext; + } + + return path.join(this.uploadDir, name); +}; + +IncomingForm.prototype._maybeEnd = function() { + if (!this.ended || this._flushing || this.error) { + return; + } + + this.emit('end'); +}; diff --git a/node_modules/formidable/lib/index.js b/node_modules/formidable/lib/index.js new file mode 100644 index 0000000..7a6e3e1 --- /dev/null +++ b/node_modules/formidable/lib/index.js @@ -0,0 +1,3 @@ +var IncomingForm = require('./incoming_form').IncomingForm; +IncomingForm.IncomingForm = IncomingForm; +module.exports = IncomingForm; diff --git a/node_modules/formidable/lib/json_parser.js b/node_modules/formidable/lib/json_parser.js new file mode 100644 index 0000000..28a23ba --- /dev/null +++ b/node_modules/formidable/lib/json_parser.js @@ -0,0 +1,30 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +var Buffer = require('buffer').Buffer; + +function JSONParser(parent) { + this.parent = parent; + this.chunks = []; + this.bytesWritten = 0; +} +exports.JSONParser = JSONParser; + +JSONParser.prototype.write = function(buffer) { + this.bytesWritten += buffer.length; + this.chunks.push(buffer); + return buffer.length; +}; + +JSONParser.prototype.end = function() { + try { + var fields = JSON.parse(Buffer.concat(this.chunks)); + for (var field in fields) { + this.onField(field, fields[field]); + } + } catch (e) { + this.parent.emit('error', e); + } + this.data = null; + + this.onEnd(); +}; diff --git a/node_modules/formidable/lib/multipart_parser.js b/node_modules/formidable/lib/multipart_parser.js new file mode 100644 index 0000000..36de2b0 --- /dev/null +++ b/node_modules/formidable/lib/multipart_parser.js @@ -0,0 +1,332 @@ +var Buffer = require('buffer').Buffer, + s = 0, + S = + { PARSER_UNINITIALIZED: s++, + START: s++, + START_BOUNDARY: s++, + HEADER_FIELD_START: s++, + HEADER_FIELD: s++, + HEADER_VALUE_START: s++, + HEADER_VALUE: s++, + HEADER_VALUE_ALMOST_DONE: s++, + HEADERS_ALMOST_DONE: s++, + PART_DATA_START: s++, + PART_DATA: s++, + PART_END: s++, + END: s++ + }, + + f = 1, + F = + { PART_BOUNDARY: f, + LAST_BOUNDARY: f *= 2 + }, + + LF = 10, + CR = 13, + SPACE = 32, + HYPHEN = 45, + COLON = 58, + A = 97, + Z = 122, + + lower = function(c) { + return c | 0x20; + }; + +for (s in S) { + exports[s] = S[s]; +} + +function MultipartParser() { + this.boundary = null; + this.boundaryChars = null; + this.lookbehind = null; + this.state = S.PARSER_UNINITIALIZED; + + this.index = null; + this.flags = 0; +} +exports.MultipartParser = MultipartParser; + +MultipartParser.stateToString = function(stateNumber) { + for (var state in S) { + var number = S[state]; + if (number === stateNumber) return state; + } +}; + +MultipartParser.prototype.initWithBoundary = function(str) { + this.boundary = new Buffer(str.length+4); + this.boundary.write('\r\n--', 0); + this.boundary.write(str, 4); + this.lookbehind = new Buffer(this.boundary.length+8); + this.state = S.START; + + this.boundaryChars = {}; + for (var i = 0; i < this.boundary.length; i++) { + this.boundaryChars[this.boundary[i]] = true; + } +}; + +MultipartParser.prototype.write = function(buffer) { + var self = this, + i = 0, + len = buffer.length, + prevIndex = this.index, + index = this.index, + state = this.state, + flags = this.flags, + lookbehind = this.lookbehind, + boundary = this.boundary, + boundaryChars = this.boundaryChars, + boundaryLength = this.boundary.length, + boundaryEnd = boundaryLength - 1, + bufferLength = buffer.length, + c, + cl, + + mark = function(name) { + self[name+'Mark'] = i; + }, + clear = function(name) { + delete self[name+'Mark']; + }, + callback = function(name, buffer, start, end) { + if (start !== undefined && start === end) { + return; + } + + var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1); + if (callbackSymbol in self) { + self[callbackSymbol](buffer, start, end); + } + }, + dataCallback = function(name, clear) { + var markSymbol = name+'Mark'; + if (!(markSymbol in self)) { + return; + } + + if (!clear) { + callback(name, buffer, self[markSymbol], buffer.length); + self[markSymbol] = 0; + } else { + callback(name, buffer, self[markSymbol], i); + delete self[markSymbol]; + } + }; + + for (i = 0; i < len; i++) { + c = buffer[i]; + switch (state) { + case S.PARSER_UNINITIALIZED: + return i; + case S.START: + index = 0; + state = S.START_BOUNDARY; + case S.START_BOUNDARY: + if (index == boundary.length - 2) { + if (c == HYPHEN) { + flags |= F.LAST_BOUNDARY; + } else if (c != CR) { + return i; + } + index++; + break; + } else if (index - 1 == boundary.length - 2) { + if (flags & F.LAST_BOUNDARY && c == HYPHEN){ + callback('end'); + state = S.END; + flags = 0; + } else if (!(flags & F.LAST_BOUNDARY) && c == LF) { + index = 0; + callback('partBegin'); + state = S.HEADER_FIELD_START; + } else { + return i; + } + break; + } + + if (c != boundary[index+2]) { + index = -2; + } + if (c == boundary[index+2]) { + index++; + } + break; + case S.HEADER_FIELD_START: + state = S.HEADER_FIELD; + mark('headerField'); + index = 0; + case S.HEADER_FIELD: + if (c == CR) { + clear('headerField'); + state = S.HEADERS_ALMOST_DONE; + break; + } + + index++; + if (c == HYPHEN) { + break; + } + + if (c == COLON) { + if (index == 1) { + // empty header field + return i; + } + dataCallback('headerField', true); + state = S.HEADER_VALUE_START; + break; + } + + cl = lower(c); + if (cl < A || cl > Z) { + return i; + } + break; + case S.HEADER_VALUE_START: + if (c == SPACE) { + break; + } + + mark('headerValue'); + state = S.HEADER_VALUE; + case S.HEADER_VALUE: + if (c == CR) { + dataCallback('headerValue', true); + callback('headerEnd'); + state = S.HEADER_VALUE_ALMOST_DONE; + } + break; + case S.HEADER_VALUE_ALMOST_DONE: + if (c != LF) { + return i; + } + state = S.HEADER_FIELD_START; + break; + case S.HEADERS_ALMOST_DONE: + if (c != LF) { + return i; + } + + callback('headersEnd'); + state = S.PART_DATA_START; + break; + case S.PART_DATA_START: + state = S.PART_DATA; + mark('partData'); + case S.PART_DATA: + prevIndex = index; + + if (index === 0) { + // boyer-moore derrived algorithm to safely skip non-boundary data + i += boundaryEnd; + while (i < bufferLength && !(buffer[i] in boundaryChars)) { + i += boundaryLength; + } + i -= boundaryEnd; + c = buffer[i]; + } + + if (index < boundary.length) { + if (boundary[index] == c) { + if (index === 0) { + dataCallback('partData', true); + } + index++; + } else { + index = 0; + } + } else if (index == boundary.length) { + index++; + if (c == CR) { + // CR = part boundary + flags |= F.PART_BOUNDARY; + } else if (c == HYPHEN) { + // HYPHEN = end boundary + flags |= F.LAST_BOUNDARY; + } else { + index = 0; + } + } else if (index - 1 == boundary.length) { + if (flags & F.PART_BOUNDARY) { + index = 0; + if (c == LF) { + // unset the PART_BOUNDARY flag + flags &= ~F.PART_BOUNDARY; + callback('partEnd'); + callback('partBegin'); + state = S.HEADER_FIELD_START; + break; + } + } else if (flags & F.LAST_BOUNDARY) { + if (c == HYPHEN) { + callback('partEnd'); + callback('end'); + state = S.END; + flags = 0; + } else { + index = 0; + } + } else { + index = 0; + } + } + + if (index > 0) { + // when matching a possible boundary, keep a lookbehind reference + // in case it turns out to be a false lead + lookbehind[index-1] = c; + } else if (prevIndex > 0) { + // if our boundary turned out to be rubbish, the captured lookbehind + // belongs to partData + callback('partData', lookbehind, 0, prevIndex); + prevIndex = 0; + mark('partData'); + + // reconsider the current character even so it interrupted the sequence + // it could be the beginning of a new sequence + i--; + } + + break; + case S.END: + break; + default: + return i; + } + } + + dataCallback('headerField'); + dataCallback('headerValue'); + dataCallback('partData'); + + this.index = index; + this.state = state; + this.flags = flags; + + return len; +}; + +MultipartParser.prototype.end = function() { + var callback = function(self, name) { + var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1); + if (callbackSymbol in self) { + self[callbackSymbol](); + } + }; + if ((this.state == S.HEADER_FIELD_START && this.index === 0) || + (this.state == S.PART_DATA && this.index == this.boundary.length)) { + callback(this, 'partEnd'); + callback(this, 'end'); + } else if (this.state != S.END) { + return new Error('MultipartParser.end(): stream ended unexpectedly: ' + this.explain()); + } +}; + +MultipartParser.prototype.explain = function() { + return 'state = ' + MultipartParser.stateToString(this.state); +}; diff --git a/node_modules/formidable/lib/octet_parser.js b/node_modules/formidable/lib/octet_parser.js new file mode 100644 index 0000000..6e8b551 --- /dev/null +++ b/node_modules/formidable/lib/octet_parser.js @@ -0,0 +1,20 @@ +var EventEmitter = require('events').EventEmitter + , util = require('util'); + +function OctetParser(options){ + if(!(this instanceof OctetParser)) return new OctetParser(options); + EventEmitter.call(this); +} + +util.inherits(OctetParser, EventEmitter); + +exports.OctetParser = OctetParser; + +OctetParser.prototype.write = function(buffer) { + this.emit('data', buffer); + return buffer.length; +}; + +OctetParser.prototype.end = function() { + this.emit('end'); +}; diff --git a/node_modules/formidable/lib/querystring_parser.js b/node_modules/formidable/lib/querystring_parser.js new file mode 100644 index 0000000..fcaffe0 --- /dev/null +++ b/node_modules/formidable/lib/querystring_parser.js @@ -0,0 +1,27 @@ +if (global.GENTLY) require = GENTLY.hijack(require); + +// This is a buffering parser, not quite as nice as the multipart one. +// If I find time I'll rewrite this to be fully streaming as well +var querystring = require('querystring'); + +function QuerystringParser(maxKeys) { + this.maxKeys = maxKeys; + this.buffer = ''; +} +exports.QuerystringParser = QuerystringParser; + +QuerystringParser.prototype.write = function(buffer) { + this.buffer += buffer.toString('ascii'); + return buffer.length; +}; + +QuerystringParser.prototype.end = function() { + var fields = querystring.parse(this.buffer, '&', '=', { maxKeys: this.maxKeys }); + for (var field in fields) { + this.onField(field, fields[field]); + } + this.buffer = ''; + + this.onEnd(); +}; + diff --git a/node_modules/formidable/package.json b/node_modules/formidable/package.json new file mode 100644 index 0000000..d63b7b9 --- /dev/null +++ b/node_modules/formidable/package.json @@ -0,0 +1,60 @@ +{ + "_args": [ + [ + "formidable@1.2.2", + "/data/dev/Projets/FNS Electrode/Projets/FNS Electrode" + ] + ], + "_from": "formidable@1.2.2", + "_id": "formidable@1.2.2", + "_inBundle": false, + "_integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", + "_location": "/formidable", + "_phantomChildren": {}, + "_requested": { + "type": "version", + "registry": true, + "raw": "formidable@1.2.2", + "name": "formidable", + "escapedName": "formidable", + "rawSpec": "1.2.2", + "saveSpec": null, + "fetchSpec": "1.2.2" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz", + "_spec": "1.2.2", + "_where": "/data/dev/Projets/FNS Electrode/Projets/FNS Electrode", + "bugs": { + "url": "https://github.com/node-formidable/formidable/issues" + }, + "description": "A node.js module for parsing form data, especially file uploads.", + "devDependencies": { + "findit": "^0.1.2", + "gently": "^0.8.0", + "hashish": "^0.0.4", + "request": "^2.11.4", + "urun": "^0.0.6", + "utest": "^0.0.8" + }, + "files": [ + "lib", + "benchmark-2020-01-29_xeon-x3440.png" + ], + "funding": "https://ko-fi.com/tunnckoCore/commissions", + "homepage": "https://github.com/node-formidable/formidable", + "license": "MIT", + "main": "./lib/index.js", + "name": "formidable", + "repository": { + "type": "git", + "url": "git+https://github.com/node-formidable/formidable.git" + }, + "scripts": { + "clean": "rm test/tmp/*", + "test": "node test/run.js" + }, + "version": "1.2.2" +} |