Coder Social home page Coder Social logo

node-formidable / formidable Goto Github PK

View Code? Open in Web Editor NEW
6.9K 112.0 680.0 3.82 MB

The most used, flexible, fast and streaming parser for multipart form data. Supports uploading to serverless environments, AWS S3, Azure, GCP or the filesystem. Used in production.

License: MIT License

JavaScript 98.28% HTML 1.72%
form multipart-formdata multipart-parser incomingform querystring-parser formdata formidable file-upload aws-s3 aws-lambda

formidable's Introduction

npm formidable package logo

formidable npm version MIT license Libera Manifesto Twitter

A Node.js module for parsing form data, especially file uploads.

Code style codecoverage linux build status windows build status macos build status

If you have any how-to kind of questions, please read the Contributing Guide and Code of Conduct documents.
For bugs reports and feature requests, please create an issue or ping @tunnckoCore / @3a1FcBx0 at Twitter.

Conventional Commits Minimum Required Nodejs Tidelift Subscription Buy me a Kofi Renovate App Status Make A Pull Request

This project is semantically versioned and available as part of the Tidelift Subscription for professional grade assurances, enhanced support and security. Learn more.

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.

Project Status: Maintained

Check VERSION NOTES for more information on v1, v2, and v3 plans, NPM dist-tags and branches.

This module was initially developed by @felixge for Transloadit, 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! ❤️ Jump on issue #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.

Highlights

Install

This package is a dual ESM/commonjs package.

This project requires Node.js >= 10.13. Install it using yarn or npm.
We highly recommend to use Yarn when you think to contribute to this project.

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.

# v2
npm install formidable@v2

# v3
npm install formidable
npm install formidable@v3

Note: Future not ready releases will be published on *-next dist-tags for the corresponding version.

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.

import http from 'node:http';
import formidable, {errors as formidableErrors} from 'formidable';

const server = http.createServer(async (req, res) => {
  if (req.url === '/api/upload' && req.method.toLowerCase() === 'post') {
    // parse a file upload
    const form = formidable({});
    let fields;
    let files;
    try {
        [fields, files] = await form.parse(req);
    } catch (err) {
        // example to check for a very specific error
        if (err.code === formidableErrors.maxFieldsExceeded) {

        }
        console.error(err);
        res.writeHead(err.httpCode || 400, { 'Content-Type': 'text/plain' });
        res.end(String(err));
        return;
    }
    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 middleware.

Or try the examples/with-express.js

import express from 'express';
import formidable from '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({});

  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 the things are very similar. You can use formidable manually as shown below or through the 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.

import Koa from 'Koa';
import formidable from '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({});

    // not very elegant, but that's for now if you don't want to use `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

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

API

Formidable / IncomingForm

All shown are equivalent.

Please pass options to the function/constructor, not by assigning them to the instance form

import formidable from 'formidable';
const form = formidable(options);

Options

See it's defaults in src/Formidable.js DEFAULT_OPTIONS (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.allowEmptyFiles {boolean} - default false; allow upload empty files

  • options.minFileSize {number} - default 1 (1byte); the minium size of uploaded file.

  • options.maxFiles {number} - default Infinity; limit the amount of uploaded files, set Infinity for unlimited

  • options.maxFileSize {number} - default 200 * 1024 * 1024 (200mb); limit the size of each uploaded file.

  • options.maxTotalFileSize {number} - default options.maxFileSize; limit the size of the batch of uploaded files.

  • options.maxFields {number} - default 1000; limit the number of fields, set Infinity 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.hashAlgorithm {string | false} - default false; include checksums calculated for incoming files, set this to some hash algorithm, see crypto.createHash for available algorithms

  • options.fileWriteStreamHandler {function} - default null, which by default writes to host machine file system every file parsed; The function should return an instance of a Writable stream that will receive the uploaded file data. With this option, you can have any custom behavior regarding where the uploaded file data will be streamed for. If you are looking to write the file uploaded in other types of cloud storages (AWS S3, Azure blob storage, Google cloud storage) or private file storage, this is the option you're looking for. When this option is defined the default behavior of writing the file in the host machine file system is lost.

  • options.filename {function} - default undefined Use it to control newFilename. Must return a string. Will be joined with options.uploadDir.

  • options.filter {function} - default function that always returns true. Use it to filter files before they are uploaded. Must return a boolean. Will not make the form.parse error

  • options.createDirsFromUploads {boolean} - default false. If true, makes direct folder uploads possible. Use <input type="file" name="folders" webkitdirectory directory multiple> to create a form to upload folders. Has to be used with the options options.uploadDir and options.filename where options.filename has to return a string with the character / for folders to be created. The base will be options.uploadDir.

options.filename {function} function (name, ext, part, form) -> string

where part can be decomposed as

const { originalFilename, mimetype} = part;

Note: If this size of combined fields, or size of some file is exceeded, an 'error' event is fired.

// The amount of bytes received for this form so far.
form.bytesReceived;
// The expected number of bytes in this form.
form.bytesExpected;

options.filter {function} function ({name, originalFilename, mimetype}) -> boolean

Behaves like Array.filter: Returning false will simply ignore the file and go to the next.

const options = {
  filter: function ({name, originalFilename, mimetype}) {
    // keep only images
    return mimetype && mimetype.includes("image");
  }
};

Note: use an outside variable to cancel all uploads upon the first error

Note: use form.emit('error') to make form.parse error

let cancelUploads = false;// create variable at the same scope as form
const options = {
  filter: function ({name, originalFilename, mimetype}) {
    // keep only images
    const valid = mimetype && mimetype.includes("image");
    if (!valid) {
      form.emit('error', new formidableErrors.default('invalid type', 0, 400)); // optional make form.parse error
      cancelUploads = true; //variable to make filter return false after the first problem
    }
    return valid && !cancelUploads;
  }
};

.parse(request, ?callback)

Parses an incoming Node.js request containing form data. If callback is not provided a promise is returned.

const form = formidable({ uploadDir: __dirname });

form.parse(req, (err, fields, files) => {
  console.log('fields:', fields);
  console.log('files:', files);
});

// with Promise
const [fields, files] = await form.parse(req);

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.

About uploadDir, given the following directory structure

project-name
├── src
│   └── server.js
│       
└── uploads
    └── image.jpg

__dirname would be the same directory as the source file itself (src)

 `${__dirname}/../uploads`

to put files in uploads.

Omitting __dirname would make the path relative to the current working directory. This would be the same if server.js is launched from src but not project-name.

null will use default which is os.tmpdir()

Note: If the directory does not exist, the uploaded files are silently discarded. To make sure it exists:

import {createNecessaryDirectoriesSync} from "filesac";


const uploadPath = `${__dirname}/../uploads`;
createNecessaryDirectoriesSync(`${uploadPath}/x`);

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.

form.once('error', console.error);

form.on('fileBegin', (formname, file) => {
  form.emit('data', { name: 'fileBegin', formname, value: file });
});

form.on('file', (formname, file) => {
  form.emit('data', { name: 'file', formname, 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, formname, ...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:', formname, value);
  }
  if (name === 'fileBegin') {
    console.log('fileBegin:', formname, value);
  }
});

.use(plugin: Plugin)

A method that allows you to extend the Formidable library. By default we include 4 plugins, which essentially are adapters to plug the different built-in parsers.

The plugins added by this method are always enabled.

See src/plugins/ for more detailed look on default plugins.

The plugin param has such signature:

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.

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 which is used in src/plugins/multipart.js), then you can remove it from the options.enabledPlugins, like so

import formidable, {octetstream, querystring, json} from "formidable";
const form = formidable({
  hashAlgorithm: 'sha1',
  enabledPlugins: [octetstream, querystring, json],
});

Be aware that the order MAY be important too. The names corresponds 1:1 to files in 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 for inspiration, you can for example validate the mime-type.

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)

const form = formidable();

form.onPart = function (part) {
  // let formidable handle only non-file parts
  if (part.originalFilename === '' || !part.mimetype) {
    // used internally, please do not override!
    form._handlePart(part);
  }
};

File

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.filepath: string;

  // The name this file had according to the uploading client.
  file.originalFilename: string | null;
  
  // calculated based on options provided
  file.newFilename: string | null;

  // The mime type of this file, according to the uploading client.
  file.mimetype: 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.mtime: Date | null;

  file.hashAlgorithm: false | |'sha1' | 'md5' | 'sha256'
  // If `options.hashAlgorithm` calculation was set, you can read the hex digest out of this var (at the end it will be a string)
  file.hash: string | object | 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. Warning Use this only for server side progress bar. On the client side better use XMLHttpRequest with xhr.upload.onprogress =

form.on('progress', (bytesReceived, bytesExpected) => {});

'field'

Emitted whenever a field / value pair has been received.

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.

form.on('fileBegin', (formName, file) => {
    // accessible here 
    // formName the name in the form (<input name="thisname" type="file">) or http filename for octetstream
    // file.originalFilename http filename or null if there was a parsing error
    // file.newFilename generated hexoid or what options.filename returned
    // file.filepath default pathname as per options.uploadDir and options.filename
    // file.filepath = CUSTOM_PATH // to change the final path
});

'file'

Emitted whenever a field / file pair has been received. file is an instance of File.

form.on('file', (formname, file) => {
    // same as fileBegin, except
    // it is too late to change file.filepath
    // file.hash is available if options.hash was used
});

'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.

May have error.httpCode and error.code attached.

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).

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.

form.on('end', () => {});

Helpers

firstValues

Gets first values of fields, like pre 3.0.0 without multiples pass in a list of optional exceptions where arrays of strings is still wanted (<select multiple> for example)

import { firstValues } from 'formidable/src/helpers/firstValues.js';

// ...
form.parse(request, async (error, fieldsMultiple, files) => {
    if (error) {
        //...
    }
    const exceptions = ['thisshouldbeanarray'];
    const fieldsSingle = firstValues(form, fieldsMultiple, exceptions);
    // ...

readBooleans

Html form input type="checkbox" only send the value "on" if checked, convert it to booleans for each input that is expected to be sent as a checkbox, only use after firstValues or similar was called.

import { firstValues } from 'formidable/src/helpers/firstValues.js';
import { readBooleans } from 'formidable/src/helpers/readBooleans.js';

// ...
form.parse(request, async (error, fieldsMultiple, files) => {
    if (error) {
        //...
    }
    const fieldsSingle = firstValues(form, fieldsMultiple);
    
    const expectedBooleans = ['checkbox1', 'wantsNewsLetter', 'hasACar'];
    const fieldsWithBooleans = readBooleans(fieldsSingle, expectedBooleans);
    // ...

Changelog

./CHANGELOG.md

Ports & Credits

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. Pull requests are welcome!

Thanks goes to these wonderful people (emoji key):


Felix Geisendörfer

💻 🎨 🤔 📖

Charlike Mike Reagent

🐛 🚇 🎨 💻 📖 💡 🤔 🚧 ⚠️

Kedar

💻 ⚠️ 💬 🐛

Walle Cyril

💬 🐛 💻 💵 🤔 🚧

Xargs

💬 🐛 💻 🚧

Amit-A

💬 🐛 💻

Charmander

💬 🐛 💻 🤔 🚧

Dylan Piercey

🤔

Adam Dobrawy

🐛 📖

amitrohatgi

🤔

Jesse Feng

🐛

Nathanael Demacon

💬 💻 👀

MunMunMiao

🐛

Gabriel Petrovay

🐛 💻

Philip Woods

💻 🤔

Dmitry Ivonin

📖

Claudio Poli

💻

From a Felix blog post:

  • Sven Lito for fixing bugs and merging patches
  • egirshov for contributing many improvements to the node-formidable multipart parser
  • Andrew Kelley for also helping with fixing bugs and making improvements
  • Mike Frey for contributing JSON support

License

Formidable is licensed under the MIT License.

formidable's People

Contributors

allcontributors[bot] avatar andrewrk avatar bengourley avatar btrask avatar christian-fei avatar dependabot[bot] avatar egirshov avatar elmerbulthuis avatar felixge avatar grossacasac avatar jimbly avatar jimmywarting avatar kethinov avatar kornelski avatar leonardovillela avatar mdionisio avatar mikefrey avatar nicholaiii avatar nickstamas avatar nshahri avatar orangedog avatar renovate[bot] avatar sreuter avatar svnlto avatar taddei avatar tanukisharp avatar tim-smart avatar tj avatar tojocky avatar tunnckocore avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

formidable's Issues

commas

Please, consider fixing missing/redundant commas brought by the latest commit (look at the comments).

TIA,
--Vladimir

Cross Domain Ajax

honoring the 'access-control-request-method','origin', and other CDR headers could aid a lot of development to work around that.

Cannot find module 'utf8decoder'

Getting an error while running the sample in the docs.

    module:238
    throw new Error("Cannot find module '" + request + "'");
          ^
    Error: Cannot find module 'utf8decoder'
at loadModule (module:238:15)
at require (module:364:12)
at Object.<anonymous> (/Users/dodeja/.node_libraries/.npm/formidable/0.9.2/package/lib/formidable/incoming_form.js:8:19)
at Module._compile (module:384:23)
at Module._loadScriptSync (module:393:8)
at Module.loadSync (module:296:10)
at loadModule (module:241:16)
at require (module:364:12)
at Object.<anonymous> (/Users/dodeja/.node_libraries/.npm/formidable/0.9.2/package/lib/formidable/formidable.js:1:86)
at Module._compile (module:384:23)

I am using the latest node.js release. Is there an issue with some older dependency. I havent looked too hard but I cant seem to find utf8decoder in the node repo.

Thanks!

Multiple clients uploading at the same time

Hello, i am using the 'progress' event to spit the upload progress in another location of the http server e.g. "/status". The problem is when i upload from more than one location (for example 2 browser at the same time), the progress gives info about the last posted multipart form, the last upload started. Am i missing something?

IncomingForm.parse() doesn't stop on error

The pause() function of an incoming request doesn't immediately (or often ever) stop events being raised. This means that after an error in form parsing, the events keep coming and the callback can be called multiple times.

Example code:

var form = new formidable.IncomingForm();
form.on('progress', function() {
    form._error('Time to stop');
});
form.parse(request, function(err) {
    console.log('callback');
    console.log(err);
});

Output:
callback
Time to stop
callback
null

connect-form / formidable -> process out of memory server-side security issue

Hi, it seems that connect-form (/ formidable) doesn't handle fields of the same name.

  1. If I try to upload two files with the same field name, with a form, only the last file is returned as result, but also the first file was completely written to disk.
  • I test it also with curl ( 2 files and my url for upload) ->

    curl -i -F name=test -F filedata="@file1.jpg" -F filedata="@file2.jpg" http://server/upload

  1. Now, If I try to upload two big files (60MB each for example) with this type of curl call ->
curl -i -F name=test -F filedata="@file1.jpg,file2.jpg" http://servername/upload/

FATAL ERROR: JS Allocation failed - process out of memory

I can see, with a tool like htop, the process growing to 1GB of RAM with a 60MB file upload!

Then, if I'm not mistaken, it is possible to burn all the ram in the server

I try these upload tests with formaline:

  1. it writes well the two files, and returns them as results

  2. with this weird curl request , formaline doesn't write files on disk, and it doesn't burn the RAM.

I hope it helps.

uploadify.com

Hi,

Just been looking at integrating formidable with uploadify and have to go and sort the kids out. Here is where I'm at. Any help would be appreciated.

I have a test page that sends a text file at the moment. The request looks like this:

------------KM7ae0cH2ei4gL6ei4GI3KM7cH2KM7
Content-Disposition: form-data; name="Filename"

test.txt
------------KM7ae0cH2ei4gL6ei4GI3KM7cH2KM7
Content-Disposition: form-data; name="folder"

/uploads
------------KM7ae0cH2ei4gL6ei4GI3KM7cH2KM7
Content-Disposition: form-data; name="Filedata"; filename="test.txt"
Content-Type: application/octet-stream

test file contents
------------KM7ae0cH2ei4gL6ei4GI3KM7cH2KM7
Content-Disposition: form-data; name="Upload"

Submit Query
------------KM7ae0cH2ei4gL6ei4GI3KM7cH2KM7--

I'm putting it through this code:

var form = new formidable.IncomingForm(),
    files = [],
    fields = [];

form.uploadDir = 'testTemp/';

form
  .on('field', function(field, value) {
    p([field, value]);
    fields.push([field, value]);
  })
  .on('file', function(field, file) {
    p([field, file]);
    files.push([field, file]);
  })
  .on('end', function() {
    util.puts('-> upload done');
    res.writeHead(200, {'content-type': 'text/plain'});
    res.write('received fields:\n\n '+util.inspect(fields));
    res.write('\n\n');
    res.end('received files:\n\n '+util.inspect(files));
  });
try {
    form.parse(req);
} catch (err) {
    util.inspect(err)
}

and getting this error:
[ 'Filename', 'test.txt' ]
[ 'folder', '/uploads' ]

events.js:12
throw arguments[1]; // Unhandled 'error' event
^
Error: MultipartParser.end(): stream ended unexpectedly
at MultipartParser.end (/home/ed/node/ry-node-73318fa/formidable/multipart_parser.js:311:12)
at IncomingMessage. (/home/ed/node/ry-node- 73318fa/formidable/incoming_form.js:80:30)
at IncomingMessage.emit (events.js:27:15)
at HTTPParser.onMessageComplete (http.js:112:23)
at Stream.ondata (http.js:783:22)
at Stream._onReadable (net.js:566:27)
at IOWatcher.onReadable as callback

typo in readme

In the example of the readme file, the callback misses the error paramter:

form.parse(req, function(fields, files) {

filename on progress event

is it possible to know the filename on the progress event?

something like

Event: 'progress' (bytesReceived, bytesExpected, file) ?

Race condition of some sort

Sorry I can't give better details for this, but I've discovered that I'm able to cause formidable to fail by using a database session store with Connect (Express actually). It seems that the extra time that it takes for the session middleware to return means that the request can complete before the form parsing begins. Does this make any sense? If I don't send any files, the 'data' event is never picked up by formidable. If I send a small file, I get:

Error: parser error, 0 of 12888 bytes parsed
at IncomingForm.write (.../formidable/incoming_form.js:128:17)

and if I send a large file, it works fine.

I've tried putting formidable (connect-form actually) at the top of my middleware chain, but then the parsing completes before my route handler is reached (again because of the session retrieval delay I believe). I've also tried using req.pause() & req.resume() around handling the session, but I think this doesn't actually stop the reading of data, only the emission of data events.

Again, sorry I can't be more specific. I've been trying to trace this for 6 hours now and have gone in circles a few hundred times. Is there something that formidable can do to retrieve the form data if it has already arrived? (assuming that is what's happening to me)

Incorrect handling of binary uploads

A binary file upload (e.g. curl --data-binary) results in high memory usage (larger than the file itself) and ultimately no file upload or error condition.

Feature request: streaming support (and thus allow piping)

For my application, I need to pipe a file form upload to another stream (this is some socket connected to my server).

Formidable is closest to what I need, but it does not seem to have thought of such streaming. I tried to overwrite onPart, but these parts are not streams.

Adding streaming support (and thus allow piping to another stream) would greatly improve the possibilities with Formidable, I truely hope this will get some attention.

Support alternative parsers

I don't think I want to write or maintain a streamable JSON parser, but it should be possible to plug in any writeable node.js stream into formidable.

fortify doesn't like being inside a path.exists callback

i had a server setup to check for local files with path.exists, then if(exists) {serve file} else {... run through possible services including upload, but it did not work. Heres the error

events:12
throw arguments[1];
^
Error: parser error, 0 of 40960 bytes parsed
at IncomingForm.write (/usr/local/lib/node/.npm/formidable/0.9.8/package/lib/formidable/incoming_form.js:120:17)
at IncomingMessage. (/usr/local/lib/node/.npm/formidable/0.9.8/package/lib/formidable/incoming_form.js:73:12)
at IncomingMessage.emit (events:27:15)
at HTTPParser.onBody (http:100:23)
at Stream.ondata (http:763:22)
at IOWatcher.callback (net:494:29)
at node.js:768:9

moving the upload service code outside of the path.exists callback fixed this problem. I have no idea if this is a bug or just dumb architecture on my part but it was pretty obscure to figure out. Basically starting from scratch with your example and adding in all my required functionality piece by piece. To save others headaches, it would be good to maybe have a warning in the docs of this incompatibility if it is not fixable or not a bug.

this._readWatcher.stop(); issue

heres the trace
net:945
this._readWatcher.stop();
^
TypeError: Cannot call method 'stop' of null
at Stream.pause (net:945:21)
at IncomingMessage.pause (http:223:15)
at IncomingForm.pause (/Users/tj/.node_libraries/.npm/formidable/0.9.3/package/lib/formidable/incoming_form.js:34:9)
at IncomingForm._error (/Users/tj/.node_libraries/.npm/formidable/0.9.3/package/lib/formidable/incoming_form.js:203:8)
at IncomingForm.resume (/Users/tj/.node_libraries/.npm/formidable/0.9.3/package/lib/formidable/incoming_form.js:42:12)
at /Users/tj/.node_libraries/.npm/formidable/0.9.3/package/lib/formidable/incoming_form.js:153:12
at fs:842:25
at node.js:221:9

and the script i was using http://gist.github.com/457572

multipart_parser appears to mis-handle some specific content

formidable dies with -

listening on http://localhost:8001/
events:11
throw arguments[1];
                   ^
Error: MultipartParser.end(): stream ended unexpectedly
at MultipartParser.end (/home/k/chowder/lib/formidable-vanilla/lib/formidable/multipart_parser.js:299:12)
at IncomingMessage.<anonymous> (/home/k/chowder/lib/formidable-vanilla/lib/formidable/incoming_form.js:64:30)
at IncomingMessage.emit (events:25:26)
at HTTPParser.onMessageComplete (http:110:23)
at Stream.ondata (http:745:22)
at IOWatcher.callback (net:373:31)
at node.js:204:9

when trying to upload this file using examples/upload.js - http://www.robgalbraith.com/public_files/EOS-1D_Mark_III_C.Fn_I-II.pdf

Get filesize for each file.

Is there a way to get the file size for each file being uploaded before it's finished uploading? I'm working on using formidable to stream direct to S3.

Any ideas?

Every time I try and upload I get: 'parser error, 0 of 1460 bytes parsed'

Running the form example used to work, it now no longer does? I get this error:

events:12
    throw arguments[1];
                   ^
Error: parser error, 0 of 1460 bytes parsed
at IncomingForm.write (/usr/local/lib/node/.npm/formidable/0.9.11/package/lib/formidable/incoming_form.js:123:17)
at IncomingMessage.<anonymous> (/usr/local/lib/node/.npm/formidable/0.9.11/package/lib/formidable/incoming_form.js:73:12)
at IncomingMessage.emit (events:31:17)
at HTTPParser.onBody (http:100:23)
at Stream.ondata (http:763:22)
at IOWatcher.callback (net:494:29)
at node.js:773:9

Deal with empty POST requests

At the moment, a POST request without any data can fail due to lack of a Content-Type header. However, if Content-Length is 0 then Content-Type is not required by HTTP. There is no way to check for this beforehand, as multi-part requests do not have type and length headers accessible via Node's request.headers. Formidable should handle the empty-data case gracefully, and simply emit 'end'.

HTML5 FileAPI compatible naming scheme

What are your thoughts on making the file object api-compatible with the HTML5 FileAPI?

Namely changing (or aliasing) "filename" to "name", "length" to "size", and "mime" to "type":

{
    name: "name-of-file",
    size: 12345,
    type: 'text/plain'
}

Or perhaps an option for it?

I just created a HTML5 FileAPI wrapper for node and I'm working to keep as much of my code the same between the server and client as possible.

How to limit the upload image size(use the 'progress' event's bytesExpected)

Hello, when i upload a image,
i want to limit the image size to less than 100k.
So, i listen the progress event, when the bytesExpected is bigger than 100k,
I send the request back.
This is my code:

app.post('/img', function(req, res){
var form = new formidable.IncomingForm();
var fpath = form.uploadDir = __dirname + '/../public/upload';
form.parse(req, function(err, fields, files){
if(err){
res.send("the file is too big!");
return;
} else {
res.send('ok');
}
});

form.on('progress',function(bytesReceived, bytesExpected){
    if(bytesExpected > 100 * 1024){
        var headers = res.headers;
        headers["Connection"] = "close";
        res.headers = headers;
        form.emit('error','the file was too big');
        return;
    }
});

});

But it cannot works as expected.
Is there anything wrong?

parser.onEnd is being called when it should not

When I use the basic html4 form to upload multiple files this problem does not occur.

However, when I use HTML5 using Plupload (www.plupload.com), the multipart parser.onEnd method gets called right after the first file finished (thus not after a field part, but after the first file part).

This does not seem to be an issue with Plupload, because it works fine for a PHP server handling the files/parts.

It appears that this part is being called after the first file finished =>

parser.onEnd = function() {
self.ended = true;
self._maybeEnd();
};

Causing ended to be true, thus causing the form end event to be fired as well.

p dependent

Hi,

I think I must be missing a dependency.

I tried using formidable with node v2.4 but got an error message that said something like "p has been moved, require sys to bring it back"

So I upgraded to the latest version and now I have the message:

    p([field, value]);
    ^
ReferenceError: p is not defined

So I guess I must be missing a dependency somewhere. (I have "util = require('util')" in my script if that is any use)

Follow standard convention for Arrays

According to common convention (i.e. php, python, ruby) named fields ending with square brackets [] should be treated as arrays.

This example HTTP POST should produce a parsed object like the one shown here below:

Shorter snippet from link above:

-----------------------------114772229410704779042051621609
Content-Disposition: form-data; name="attachments[]"; filename="file1.txt"
Content-Type: text/plain

This is file 1

-----------------------------114772229410704779042051621609
Content-Disposition: form-data; name="attachments[]"; filename="file2.txt"
Content-Type: text/plain

This is file 2
It has three lines
And was created on OS X

Parsed Object:

{
    name: "AJ ONeal",
    email: "[email protected]",
    // <Object HTML5::FileAPI::File>
    avatar: {
        name: "smiley-cool.png",
        size: 869,
        type: "image/png",
        path: "/tmp/ab489fe1d9a4df.png"
    },
    attachments: [
        // <Object HTML5::FileAPI::File>
        {
            name: "file1.txt",
            size: 15,
            type: "text/plain",
            path: "/tmp/c3e29fa4de1d9f.png"
        },
        {
            name: "file2.txt",
            size: 58,
            type: "text/plain",
            path: "/tmp/9a4ab48dffe1d9.png"
        }
    ]
}

Publish on npm

It'd be really nice if node-formidable is published to npm registry since it already has a package.json. It'll make installation easy for itself and for other libraries using it.

uploadDir

Hi! When uploadDir doesn't exist, on a file arrival form.parse throws an unhandled exception (ENOENT), which has no way to be intercepted, since it is in the guts of the parser.

--Vladimir

MultipartParser does not like http://www.uploadify.com/

uploadify is a swf object that doesn't put the last CRLF chars after the LAST_BOUNDARY. This causes problems for the MultipartParser implementation because it won't end the stream correctly.

Here's the fix I hacked in:

      } else if (flags & F.LAST_BOUNDARY) {
        if (c == HYPHEN) {
          index++;
          if ((i+1) == len) {
            callback('partEnd');
            callback('end');
            state = S.END;
            break;
          };
        } else {
          index = 0;
        }

So, this checks if the buffer is exhausted and you've read in the last two HYPENs of the LAST_BOUNDARY. If that's the case, then ends the stream. Seems to work ok for uploadify.

bytesReceived does not update correctly on chunk receival

I'm overwriting form.onPart in order to stream incoming files instead of store them on the disk.

I then listen for the part's data event:

form.onPart = function(part) {
            util.debug('getting part...');

            //let formidable handle all non-file parts (fields)
            if (!part.filename) {
                form.handlePart(part);
                return;
            }

            //handle chunks of files
            part.on('data', function(chunk) {
                                    util.debug('chunk size: ' + chunk.length);
                util.debug('received / expected: ' + form.bytesReceived + ' / ' + form.bytesExpected);
            });
}

The following is an example output:

DEBUG: chunk size: 33434
DEBUG: received / expected: 33813 / 3776741
DEBUG: chunk size: 16713
DEBUG: received / expected: 74773 / 3776741
DEBUG: chunk size: 1
DEBUG: received / expected: 74773 / 3776741
DEBUG: chunk size: 22813
DEBUG: received / expected: 74773 / 3776741
DEBUG: chunk size: 1
DEBUG: received / expected: 74773 / 3776741
DEBUG: chunk size: 1432
DEBUG: received / expected: 74773 / 3776741
DEBUG: chunk size: 40960
DEBUG: received / expected: 115733 / 3776741
DEBUG: chunk size: 8635
DEBUG: received / expected: 156693 / 3776741
DEBUG: chunk size: 1
DEBUG: received / expected: 156693 / 3776741
DEBUG: chunk size: 32324
DEBUG: received / expected: 156693 / 3776741
DEBUG: chunk size: 21621
DEBUG: received / expected: 197653 / 3776741
DEBUG: chunk size: 1

The second chunk says to be 16713 characters long. Yet, the new bytesReceived is then 74773 rather than 50526.

The fourth chunk is 22813 characters long. Yet, the bytesReceived amount stays exactly the same.

UPDATE with TEST #2 :

Code:
module.exports = function(server, everyone) {
var util = require('util');
var formidable = require('formidable');

server.post('/upload', function(req, res) {
    util.debug('/upload request');
    if (isFormRequest(req)) {
        util.debug('this is a form request');

        //setup this form receiver
        var form = new formidable.IncomingForm();
        form.encoding = 'utf-8';
        form.keepExtensions = true; //keep extensions
        form.maxFieldsSize = 0.5 * 1024 * 1024; //max memory allocated of a field in bytes

        form.on('field', function(name, value) {
            util.debug('received field: ' + name + ' = ' + value);
        });
        form.on('error', function(err) {
            util.debug('error: ' + err);
        });
        form.on('end', function() {
            util.debug('stream end.');
        });

        //handle every part
        form.onPart = function(part) {
            util.debug('getting new part...');

            util.debug('form bytes received: ' + form.bytesReceived);
            util.debug('form bytes expected: ' + form.bytesExpected);

            //handle chunks of files
            part.on('data', function(chunk) {
                util.debug('received / expected: ' + form.bytesReceived + ' / ' + form.bytesExpected + ' (after chunk, size: ' + chunk.length);
            });

            //handle part end
            part.on('end', function() {
                util.debug('part end.');
            });
        };

        //start parsing this stream
        form.parse(req);
    }
});
};

Debug output:

DEBUG: /upload request
DEBUG: this is a form request
DEBUG: getting new part...
DEBUG: form bytes received: 34871
DEBUG: form bytes expected: 3176596
DEBUG: received / expected: 34871 / 3176596 (after chunk, size: 49
DEBUG: part end.
DEBUG: getting new part...
DEBUG: form bytes received: 34871
DEBUG: form bytes expected: 3176596
DEBUG: received / expected: 34871 / 3176596 (after chunk, size: 2334
DEBUG: received / expected: 34871 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 34871 / 3176596 (after chunk, size: 12867
DEBUG: received / expected: 34871 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 34871 / 3176596 (after chunk, size: 19329
DEBUG: received / expected: 75831 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 116791 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 157751 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 198711 / 3176596 (after chunk, size: 16999
DEBUG: received / expected: 198711 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 198711 / 3176596 (after chunk, size: 23960
DEBUG: received / expected: 239671 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 280631 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 321591 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 362551 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 403511 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 444471 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 485431 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 526391 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 567351 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 608311 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 649271 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 690231 / 3176596 (after chunk, size: 12170
DEBUG: received / expected: 690231 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 690231 / 3176596 (after chunk, size: 28789
DEBUG: received / expected: 731191 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 753664 / 3176596 (after chunk, size: 1116
DEBUG: received / expected: 753664 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 753664 / 3176596 (after chunk, size: 21356
DEBUG: received / expected: 770048 / 3176596 (after chunk, size: 16384
DEBUG: received / expected: 772151 / 3176596 (after chunk, size: 2103
DEBUG: received / expected: 813111 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 854071 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 895031 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 935991 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 976951 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1017911 / 3176596 (after chunk, size: 40910
DEBUG: received / expected: 1017911 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1017911 / 3176596 (after chunk, size: 22
DEBUG: received / expected: 1017911 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1017911 / 3176596 (after chunk, size: 26
DEBUG: received / expected: 1058871 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1099831 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1140791 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1181751 / 3176596 (after chunk, size: 22470
DEBUG: received / expected: 1181751 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1181751 / 3176596 (after chunk, size: 18489
DEBUG: received / expected: 1222711 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1263671 / 3176596 (after chunk, size: 40913
DEBUG: received / expected: 1263671 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1263671 / 3176596 (after chunk, size: 46
DEBUG: received / expected: 1304631 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1345591 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1386551 / 3176596 (after chunk, size: 53
DEBUG: received / expected: 1386551 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1386551 / 3176596 (after chunk, size: 40906
DEBUG: received / expected: 1427511 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1468471 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1509431 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1550391 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1591351 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1632311 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1673271 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1714231 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1755191 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1796151 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1837111 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1878071 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 1919031 / 3176596 (after chunk, size: 40481
DEBUG: received / expected: 1919031 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1919031 / 3176596 (after chunk, size: 450
DEBUG: received / expected: 1919031 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1919031 / 3176596 (after chunk, size: 27
DEBUG: received / expected: 1959991 / 3176596 (after chunk, size: 40916
DEBUG: received / expected: 1959991 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 1959991 / 3176596 (after chunk, size: 43
DEBUG: received / expected: 2000951 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2041911 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2082871 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2123831 / 3176596 (after chunk, size: 34649
DEBUG: received / expected: 2123831 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2123831 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2123831 / 3176596 (after chunk, size: 6309
DEBUG: received / expected: 2164791 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2205751 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2246711 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2287671 / 3176596 (after chunk, size: 31406
DEBUG: received / expected: 2287671 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2287671 / 3176596 (after chunk, size: 9553
DEBUG: received / expected: 2328631 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2369591 / 3176596 (after chunk, size: 40954
DEBUG: received / expected: 2369591 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2369591 / 3176596 (after chunk, size: 5
DEBUG: received / expected: 2410551 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2451511 / 3176596 (after chunk, size: 40908
DEBUG: received / expected: 2451511 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2451511 / 3176596 (after chunk, size: 51
DEBUG: received / expected: 2492471 / 3176596 (after chunk, size: 11315
DEBUG: received / expected: 2492471 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2492471 / 3176596 (after chunk, size: 29644
DEBUG: received / expected: 2533431 / 3176596 (after chunk, size: 4838
DEBUG: received / expected: 2533431 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2533431 / 3176596 (after chunk, size: 36121
DEBUG: received / expected: 2574391 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2615351 / 3176596 (after chunk, size: 31828
DEBUG: received / expected: 2615351 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2615351 / 3176596 (after chunk, size: 9131
DEBUG: received / expected: 2656311 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2697271 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2738231 / 3176596 (after chunk, size: 2018
DEBUG: received / expected: 2738231 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2738231 / 3176596 (after chunk, size: 38941
DEBUG: received / expected: 2779191 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2820151 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2861111 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2902071 / 3176596 (after chunk, size: 40954
DEBUG: received / expected: 2902071 / 3176596 (after chunk, size: 1
DEBUG: received / expected: 2902071 / 3176596 (after chunk, size: 5
DEBUG: received / expected: 2943031 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 2983991 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 3024951 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 3065911 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 3106871 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 3147831 / 3176596 (after chunk, size: 40960
DEBUG: received / expected: 3176596 / 3176596 (after chunk, size: 28708
DEBUG: part end.
DEBUG: stream end.

Update 2:

The problem remains using the example form.

 <form action="http://localhost:3000/upload" enctype="multipart/form-data" method="post">
     <input type="text" name="title"><br>
     <input type="file" name="upload" multiple="multiple"><br>
     <input type="submit" value="Upload">
 </form>

This is the debug output:

DEBUG: /upload request
DEBUG: this is a form request
DEBUG: getting new part...
DEBUG: form headers: { host: 'localhost:3000',
connection: 'keep-alive',
'content-length': '4118128',
'cache-control': 'max-age=0',
origin: 'null',
'user-agent': 'Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary6phZGjDVVbrRMCgz',
accept: 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,/;q=0.5',
'accept-encoding': 'gzip,deflate,sdch',
'accept-language': 'en-US,en;q=0.8',
'accept-charset': 'ISO-8859-1,utf-8;q=0.7,;q=0.3',
cookie: 'socketio=websocket' }
DEBUG: form bytes received: 40332
DEBUG: form bytes expected: 4118128
DEBUG: part end.
DEBUG: getting new part...
DEBUG: form headers: { host: 'localhost:3000',
connection: 'keep-alive',
'content-length': '4118128',
'cache-control': 'max-age=0',
origin: 'null',
'user-agent': 'Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Ubuntu/10.10 Chromium/10.0.648.133 Chrome/10.0.648.133 Safari/534.16',
'content-type': 'multipart/form-data; boundary=----WebKitFormBoundary6phZGjDVVbrRMCgz',
accept: 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,
/;q=0.5',
'accept-encoding': 'gzip,deflate,sdch',
'accept-language': 'en-US,en;q=0.8',
'accept-charset': 'ISO-8859-1,utf-8;q=0.7,
;q=0.3',
cookie: 'socketio=websocket' }
DEBUG: form bytes received: 40332
DEBUG: form bytes expected: 4118128
DEBUG: received / expected: 40332 / 4118128 (after chunk, size: 11579
DEBUG: received / expected: 40332 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 40332 / 4118128 (after chunk, size: 28477
DEBUG: received / expected: 81292 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 122252 / 4118128 (after chunk, size: 30989
DEBUG: received / expected: 122252 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 122252 / 4118128 (after chunk, size: 9970
DEBUG: received / expected: 163212 / 4118128 (after chunk, size: 30850
DEBUG: received / expected: 163212 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 163212 / 4118128 (after chunk, size: 10109
DEBUG: received / expected: 204172 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 245132 / 4118128 (after chunk, size: 27792
DEBUG: received / expected: 245132 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 245132 / 4118128 (after chunk, size: 13167
DEBUG: received / expected: 286092 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 327052 / 4118128 (after chunk, size: 23398
DEBUG: received / expected: 327052 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 327052 / 4118128 (after chunk, size: 17561
DEBUG: received / expected: 368012 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 408972 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 449932 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 490892 / 4118128 (after chunk, size: 30511
DEBUG: received / expected: 490892 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 490892 / 4118128 (after chunk, size: 10448
DEBUG: received / expected: 531852 / 4118128 (after chunk, size: 19269
DEBUG: received / expected: 531852 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 531852 / 4118128 (after chunk, size: 21690
DEBUG: received / expected: 572812 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 613772 / 4118128 (after chunk, size: 31716
DEBUG: received / expected: 613772 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 613772 / 4118128 (after chunk, size: 9243
DEBUG: received / expected: 654732 / 4118128 (after chunk, size: 6113
DEBUG: received / expected: 654732 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 654732 / 4118128 (after chunk, size: 34846
DEBUG: received / expected: 695692 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 736652 / 4118128 (after chunk, size: 37979
DEBUG: received / expected: 736652 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 736652 / 4118128 (after chunk, size: 2974
DEBUG: received / expected: 736652 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 736652 / 4118128 (after chunk, size: 5
DEBUG: received / expected: 777612 / 4118128 (after chunk, size: 26211
DEBUG: received / expected: 777612 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 777612 / 4118128 (after chunk, size: 14748
DEBUG: received / expected: 818572 / 4118128 (after chunk, size: 40167
DEBUG: received / expected: 818572 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 818572 / 4118128 (after chunk, size: 792
DEBUG: received / expected: 859532 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 900492 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 941452 / 4118128 (after chunk, size: 9274
DEBUG: received / expected: 941452 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 941452 / 4118128 (after chunk, size: 31685
DEBUG: received / expected: 982412 / 4118128 (after chunk, size: 18537
DEBUG: received / expected: 982412 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 982412 / 4118128 (after chunk, size: 22422
DEBUG: received / expected: 1023372 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1048576 / 4118128 (after chunk, size: 25204
DEBUG: received / expected: 1064332 / 4118128 (after chunk, size: 15756
DEBUG: received / expected: 1105292 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1146252 / 4118128 (after chunk, size: 5435
DEBUG: received / expected: 1146252 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1146252 / 4118128 (after chunk, size: 7716
DEBUG: received / expected: 1146252 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1146252 / 4118128 (after chunk, size: 27807
DEBUG: received / expected: 1179648 / 4118128 (after chunk, size: 33396
DEBUG: received / expected: 1187212 / 4118128 (after chunk, size: 7556
DEBUG: received / expected: 1187212 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1187212 / 4118128 (after chunk, size: 7
DEBUG: received / expected: 1228172 / 4118128 (after chunk, size: 27645
DEBUG: received / expected: 1228172 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1228172 / 4118128 (after chunk, size: 3240
DEBUG: received / expected: 1228172 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1228172 / 4118128 (after chunk, size: 10073
DEBUG: received / expected: 1269132 / 4118128 (after chunk, size: 20599
DEBUG: received / expected: 1269132 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1269132 / 4118128 (after chunk, size: 20360
DEBUG: received / expected: 1310092 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1310720 / 4118128 (after chunk, size: 628
DEBUG: received / expected: 1343488 / 4118128 (after chunk, size: 32768
DEBUG: received / expected: 1351052 / 4118128 (after chunk, size: 7564
DEBUG: received / expected: 1392012 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1432972 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1441792 / 4118128 (after chunk, size: 8820
DEBUG: received / expected: 1473932 / 4118128 (after chunk, size: 32140
DEBUG: received / expected: 1514892 / 4118128 (after chunk, size: 2150
DEBUG: received / expected: 1514892 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1514892 / 4118128 (after chunk, size: 8430
DEBUG: received / expected: 1514892 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1514892 / 4118128 (after chunk, size: 30378
DEBUG: received / expected: 1555852 / 4118128 (after chunk, size: 26312
DEBUG: received / expected: 1555852 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1555852 / 4118128 (after chunk, size: 14647
DEBUG: received / expected: 1572864 / 4118128 (after chunk, size: 16988
DEBUG: received / expected: 1572864 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1572864 / 4118128 (after chunk, size: 23
DEBUG: received / expected: 1596812 / 4118128 (after chunk, size: 23948
DEBUG: received / expected: 1637772 / 4118128 (after chunk, size: 29308
DEBUG: received / expected: 1637772 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1637772 / 4118128 (after chunk, size: 4637
DEBUG: received / expected: 1637772 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1637772 / 4118128 (after chunk, size: 7013
DEBUG: received / expected: 1678732 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1703936 / 4118128 (after chunk, size: 25204
DEBUG: received / expected: 1719692 / 4118128 (after chunk, size: 15756
DEBUG: received / expected: 1760652 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1801612 / 4118128 (after chunk, size: 26506
DEBUG: received / expected: 1801612 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1801612 / 4118128 (after chunk, size: 14433
DEBUG: received / expected: 1801612 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1801612 / 4118128 (after chunk, size: 19
DEBUG: received / expected: 1835008 / 4118128 (after chunk, size: 33396
DEBUG: received / expected: 1842572 / 4118128 (after chunk, size: 7564
DEBUG: received / expected: 1883532 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1924492 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 1965452 / 4118128 (after chunk, size: 17068
DEBUG: received / expected: 1965452 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1965452 / 4118128 (after chunk, size: 14756
DEBUG: received / expected: 1965452 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1965452 / 4118128 (after chunk, size: 9134
DEBUG: received / expected: 1966080 / 4118128 (after chunk, size: 628
DEBUG: received / expected: 1998848 / 4118128 (after chunk, size: 32761
DEBUG: received / expected: 1998848 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 1998848 / 4118128 (after chunk, size: 6
DEBUG: received / expected: 2006412 / 4118128 (after chunk, size: 7564
DEBUG: received / expected: 2047372 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2088332 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2097152 / 4118128 (after chunk, size: 8820
DEBUG: received / expected: 2129292 / 4118128 (after chunk, size: 32116
DEBUG: received / expected: 2129292 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2129292 / 4118128 (after chunk, size: 23
DEBUG: received / expected: 2170252 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2211212 / 4118128 (after chunk, size: 26140
DEBUG: received / expected: 2211212 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2211212 / 4118128 (after chunk, size: 14819
DEBUG: received / expected: 2228224 / 4118128 (after chunk, size: 16989
DEBUG: received / expected: 2228224 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2228224 / 4118128 (after chunk, size: 22
DEBUG: received / expected: 2252172 / 4118128 (after chunk, size: 23935
DEBUG: received / expected: 2252172 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2252172 / 4118128 (after chunk, size: 12
DEBUG: received / expected: 2293132 / 4118128 (after chunk, size: 40473
DEBUG: received / expected: 2293132 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2293132 / 4118128 (after chunk, size: 486
DEBUG: received / expected: 2334092 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2375052 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2416012 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2456972 / 4118128 (after chunk, size: 1435
DEBUG: received / expected: 2456972 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2456972 / 4118128 (after chunk, size: 39518
DEBUG: received / expected: 2456972 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2456972 / 4118128 (after chunk, size: 5
DEBUG: received / expected: 2497932 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2538892 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2579852 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2620812 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2661772 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2702732 / 4118128 (after chunk, size: 17578
DEBUG: received / expected: 2702732 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2702732 / 4118128 (after chunk, size: 23381
DEBUG: received / expected: 2743692 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2752512 / 4118128 (after chunk, size: 8820
DEBUG: received / expected: 2784652 / 4118128 (after chunk, size: 30728
DEBUG: received / expected: 2784652 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2784652 / 4118128 (after chunk, size: 1411
DEBUG: received / expected: 2825612 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2866572 / 4118128 (after chunk, size: 15597
DEBUG: received / expected: 2866572 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 2866572 / 4118128 (after chunk, size: 25362
DEBUG: received / expected: 2883584 / 4118128 (after chunk, size: 17012
DEBUG: received / expected: 2907532 / 4118128 (after chunk, size: 23948
DEBUG: received / expected: 2948492 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 2989452 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3014656 / 4118128 (after chunk, size: 25204
DEBUG: received / expected: 3030412 / 4118128 (after chunk, size: 15756
DEBUG: received / expected: 3071372 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3112332 / 4118128 (after chunk, size: 40923
DEBUG: received / expected: 3112332 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3112332 / 4118128 (after chunk, size: 36
DEBUG: received / expected: 3145728 / 4118128 (after chunk, size: 33396
DEBUG: received / expected: 3153292 / 4118128 (after chunk, size: 7564
DEBUG: received / expected: 3194252 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3235212 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3276172 / 4118128 (after chunk, size: 36422
DEBUG: received / expected: 3276172 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3276172 / 4118128 (after chunk, size: 4537
DEBUG: received / expected: 3276800 / 4118128 (after chunk, size: 628
DEBUG: received / expected: 3317132 / 4118128 (after chunk, size: 7125
DEBUG: received / expected: 3317132 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3317132 / 4118128 (after chunk, size: 33184
DEBUG: received / expected: 3317132 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3317132 / 4118128 (after chunk, size: 21
DEBUG: received / expected: 3358092 / 4118128 (after chunk, size: 28899
DEBUG: received / expected: 3358092 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3358092 / 4118128 (after chunk, size: 12060
DEBUG: received / expected: 3399052 / 4118128 (after chunk, size: 3495
DEBUG: received / expected: 3399052 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3399052 / 4118128 (after chunk, size: 37464
DEBUG: received / expected: 3407872 / 4118128 (after chunk, size: 8820
DEBUG: received / expected: 3424256 / 4118128 (after chunk, size: 16384
DEBUG: received / expected: 3440012 / 4118128 (after chunk, size: 15756
DEBUG: received / expected: 3480972 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3521932 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3538944 / 4118128 (after chunk, size: 17012
DEBUG: received / expected: 3562892 / 4118128 (after chunk, size: 23948
DEBUG: received / expected: 3603852 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3644812 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3670016 / 4118128 (after chunk, size: 25204
DEBUG: received / expected: 3685772 / 4118128 (after chunk, size: 15756
DEBUG: received / expected: 3726732 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3767692 / 4118128 (after chunk, size: 14756
DEBUG: received / expected: 3767692 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3767692 / 4118128 (after chunk, size: 19516
DEBUG: received / expected: 3767692 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3767692 / 4118128 (after chunk, size: 6686
DEBUG: received / expected: 3801088 / 4118128 (after chunk, size: 33396
DEBUG: received / expected: 3808652 / 4118128 (after chunk, size: 7564
DEBUG: received / expected: 3849612 / 4118128 (after chunk, size: 24792
DEBUG: received / expected: 3849612 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3849612 / 4118128 (after chunk, size: 7590
DEBUG: received / expected: 3849612 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3849612 / 4118128 (after chunk, size: 8576
DEBUG: received / expected: 3890572 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 3931532 / 4118128 (after chunk, size: 15312
DEBUG: received / expected: 3931532 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 3931532 / 4118128 (after chunk, size: 25647
DEBUG: received / expected: 3932160 / 4118128 (after chunk, size: 628
DEBUG: received / expected: 3972492 / 4118128 (after chunk, size: 40332
DEBUG: received / expected: 4013452 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 4054412 / 4118128 (after chunk, size: 40960
DEBUG: received / expected: 4063232 / 4118128 (after chunk, size: 8820
DEBUG: received / expected: 4095372 / 4118128 (after chunk, size: 32140
DEBUG: received / expected: 4118128 / 4118128 (after chunk, size: 4640
DEBUG: received / expected: 4118128 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 4118128 / 4118128 (after chunk, size: 18067
DEBUG: received / expected: 4118128 / 4118128 (after chunk, size: 1
DEBUG: received / expected: 4118128 / 4118128 (after chunk, size: 1
DEBUG: part end.
DEBUG: stream end.

Error handling confusion

The callback function supplied to the parse function takes an error as its first parameter (i.e. function parseCallback(err, fields, files)).

However, some errors cause the error event to be raised and the callback function is never called. For example, supplying a bogus form to the server raises the error "bad content-type header, no content-type", the callback is ignored and the node process exits if the error event isn't handled.

What's supposed to happen here? I'm new to this so I'm not sure whether the confusion is mine or formidable's.

incomingForm.parse hanging

I am attempting to use your module in my own project. In this file here https://github.com/sgoodwin/AppEngine/blob/master/server.js at line 128, I define the request using express where I should be able to POST a file to my server. Any logging I do before form.parse works just fine, but the callback function supplied to form.parse never gets called. I even tried subscribing to the 'error', 'field', and 'file' events the incomingForm should emit and nothing happens. Any attempt to POST by any client (regardless of language/connection library) simply times out. Am I doing something wrong? Is this a problem with formidable I haven't been able to figure out? This was done using the latest node from git and v0.2.5, same problem either way.

Error: bad content-type header, no content-type

I keep getting this error in the log, and then my serve crashes, can't seem to debug this, but it seems that some users trigger this, any clues to what might be wrong?

Error: bad content-type header, no content-type
at IncomingForm._parseContentType (/usr/local/lib/node/.npm/formidable/0.9.9/package/lib/formidable/incoming_form.js:196:17)
at IncomingForm.writeHeaders (/usr/local/lib/node/.npm/formidable/0.9.9/package/lib/formidable/incoming_form.js:109:8)
at IncomingForm.parse (/usr/local/lib/node/.npm/formidable/0.9.9/package/lib/formidable/incoming_form.js:65:8)
at upload_file (/raid/scripts/server.js:77:9)
at Server. (/raid/scripts/server.js:17:10)
at Server.emit (events:27:15)
at HTTPParser.onIncoming (http:831:10)
at HTTPParser.onHeadersComplete (http:87:31)
at Stream.ondata (http:763:22)
at IOWatcher.callback (net:494:29)

formidable fails to parse requests using mikeals' module

Hey there,

I put together a little example that fails with Error: parser error, 2 of 135 bytes parsed at IncomingForm.write but I don't see why. I thought it had to do with the unprefixed boundary value that the request module uses but that does not seem to be the case.

The following command lets me record the request which looks okay:
sudo tcpflow -i lo -c '(dst or src host 127.0.0.1) and (src or dst port 1234)'

The example is at https://gist.github.com/b6000d5777d28f9992ac .

Performance problems during large binary data POST

Hi,

I think, that this has nothing to do with formidable, but I post it here for securtity. (my main post is on google groups
I have discovered, what I think is a very serious issue with performance in node during a large binary upload via a POST request. Performance drops to under 0.2 mb/sec on my macbook pro, and it seems that this has nothing to do with Multipart parsing, but more with the socket blocking up somehow.
I am not sure, what is causing the issue though. (I have however attached the output of my profiling results - unfortunately I am not an expert, but it seems, that most of the time is spent in a call named _si_cache_add_item.

I have tested the following versions of node:
0.3.6
0.3.8
0.4.0
0.4.3

I have also set up a github repository with the (most simplified) test files (server.js and upload.js) and profiling results, which actually depend just on node-formidable and restler for the file POST (although I also tried with reston)

You can find the files here https://github.com/dotmaster/node-upload-bench

Any comments are welcome

Not getting any file data, just fields

I am testing this out using the example provided as a guide, but I am only getting the field data and no actual file data;

My output:

testing{ fields: [ [ 'upload', 'test.wxr' ], [ 'submit', 'Upload' ] ]
, files: []
}

I also noticed a method 'p' in your example which is undefined for me, I am assuming that is some test helper method?

I apologise if this is just my own stupidity I am just getting started with node. I've pushed my code up to github:
http://github.com/lucisferre/blogConverter

Hangs when there is no part

If the browser posts a multi-part POST request with no parts, then the http server hangs until the 2 minute timeout and then finishes properly. I tested every browser and they all will send this request out. I'm pretty sure it is a legal multi-part format.

I'm running node 0.4.1 and a recent version of Formidable with the patch to fix the problem where you cannot submit multiple fields with the same name.

upload progress

hey hey. all I am doing is POSTing some files, and planned on redirecting to a page that would poll the "progress" event, everything is set up fine but even though I immediately respond the redirect fails until the upload is complete. Any idea whats going on? do you know if this is just a user-agent issue? (id imagine maybe the browser does not want to redirect until complete, not sure)

cheers

HTML5 Multiple File Uploads <input type=file multiple>

I was having an issue where multiple form elements with the same name were not being saved correctly to 'fields' and 'files' objects that are passed to the IncomingForm#parse callback.

I created a patch that saves multiple items of the same name to an array. Let me know in anyone is interested in the code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.